mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
Add SFP quirk for devices that misreport DDM capability
On a QSFPTEK QT-SFP+-T (RTL8261C) 10GBase-T module, the diag type field (92) comes back as 0x00, but there's actually some statistics available like temperature. Other metrics may be hard-coded values. Add a basic struct that allows matching on vendor and/or model, using a bitfield to allow multiple quirks for a given SFP module. Only SFP_QUIRK_DDM is implemented. For modules matching SFP_QUIRK_DDM, attempt an I2C read of the MSB of module voltage during probe if DDM is "unsupported" - if it's not 0xff, override the reported options so we can pull the diagnostic data. To allow simpler comparisons, convert the ASCII fields (vendor, model, serial) from space-padded to standard NULL-terminated strings. strcmp() is moved from httpd.c to rtlplayground.c alongside other string functions and shared between them. The __reentrant keyword is used for the new functions to avoid using up additional OSEG space. This allocates the variables on the stack, which is OK for this particular code path. The JSON assembly in send_status() is slightly modified to treat the sfp_module_* data as standard NULL-terminated strings, and a repeated subtraction was moved into a uint8_t to declutter the code.
This commit is contained in:
+2
-1
@@ -50,6 +50,7 @@ __xdata char port_names[9][PORT_NAME_SIZE];
|
||||
extern __xdata uint16_t management_vlan;
|
||||
extern __xdata uint8_t sfp_speed[2];
|
||||
extern __xdata uint8_t sfp_pins_last;
|
||||
extern __xdata uint8_t sfp_options[2];
|
||||
__xdata uint8_t gpio_last_value[8] = { 0 };
|
||||
|
||||
// Temporatly for str to hex convertion value.
|
||||
@@ -741,7 +742,7 @@ void parse_mtu(void)
|
||||
void sfp_print_measurements(uint8_t sfp)
|
||||
{
|
||||
print_string("Options: "); print_byte(sfp_read_reg(sfp, 92)); write_char('\n');
|
||||
if (!(sfp_read_reg(sfp, 92) & 0x40))
|
||||
if (!(sfp_options[sfp] & 0x40))
|
||||
return;
|
||||
print_string("Temp: "); print_byte(sfp_read_reg(sfp, 224)); print_byte(sfp_read_reg(sfp, 225)); write_char('\n');
|
||||
print_string("Vcc: "); print_byte(sfp_read_reg(sfp, 226)); print_byte(sfp_read_reg(sfp, 227)); write_char('\n');
|
||||
|
||||
@@ -101,21 +101,6 @@ uint8_t find_entry(__xdata uint8_t *e)
|
||||
}
|
||||
|
||||
|
||||
char strcmp(__xdata uint8_t *c, __code uint8_t * __xdata d)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
||||
while (d[i] && (d[i] == c[i]))
|
||||
i++;
|
||||
|
||||
if (c[i] < d[i])
|
||||
return -1;
|
||||
else if (c[i] > d[i])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
||||
{
|
||||
uint8_t u, c;
|
||||
|
||||
+25
-24
@@ -660,52 +660,53 @@ void send_status(void)
|
||||
slen += strtox(outbuf + slen, "\"");
|
||||
|
||||
if (machine.is_sfp[i]) {
|
||||
uint8_t sfp = machine.is_sfp[i] - 1;
|
||||
slen += strtox(outbuf + slen, ",\"isSFP\":1,\"enabled\":");
|
||||
if (!(sfp_pins_last & (0x1 << ((machine.is_sfp[i] - 1) << 2)))) {
|
||||
if (!(sfp_pins_last & (0x1 << (sfp << 2)))) {
|
||||
bool_to_html(1);
|
||||
slen += strtox(outbuf + slen,",\"sfp_options\":\"0x");
|
||||
byte_to_html(sfp_options[machine.is_sfp[i]-1]);
|
||||
if (sfp_options[machine.is_sfp[i]-1] & 0x40) {
|
||||
byte_to_html(sfp_options[sfp]);
|
||||
if (sfp_options[sfp] & 0x40) {
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_temp\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 224, 2);
|
||||
sfp_send_data(sfp, 224, 2);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_vcc\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 226, 2);
|
||||
sfp_send_data(sfp, 226, 2);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_txbias\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 228, 2);
|
||||
sfp_send_data(sfp, 228, 2);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_txpower\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 230, 2);
|
||||
sfp_send_data(sfp, 230, 2);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_rxpower\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 232, 2);
|
||||
if (sfp_options[machine.is_sfp[i]-1] & 0x10) {
|
||||
sfp_send_data(sfp, 232, 2);
|
||||
if (sfp_options[sfp] & 0x10) {
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_temp_cal\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 212, 4);
|
||||
sfp_send_data(sfp, 212, 4);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_vcc_cal\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 216, 4);
|
||||
sfp_send_data(sfp, 216, 4);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_txbias_cal\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 204, 4);
|
||||
sfp_send_data(sfp, 204, 4);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_txpower_cal\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 208, 4);
|
||||
sfp_send_data(sfp, 208, 4);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_rxpower_cal\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 184, 16);
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 200, 4);
|
||||
sfp_send_data(sfp, 184, 16);
|
||||
sfp_send_data(sfp, 200, 4);
|
||||
}
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_state\":\"0x");
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 238, 1);
|
||||
sfp_send_data(sfp, 238, 1);
|
||||
}
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\"");
|
||||
for (register uint8_t s = 0; s < 16; s++)
|
||||
outbuf[slen++] = sfp_module_vendor[machine.is_sfp[i]-1][s];
|
||||
for (register uint8_t s = 0; s < 16 && sfp_module_vendor[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_vendor[sfp][s];
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_model\":\"");
|
||||
for (register uint8_t s = 0; s < 16; s++)
|
||||
outbuf[slen++] = sfp_module_model[machine.is_sfp[i]-1][s];
|
||||
for (register uint8_t s = 0; s < 16 && sfp_module_model[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_model[sfp][s];
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_serial\":\"");
|
||||
for (register uint8_t s = 0; s < 16; s++)
|
||||
outbuf[slen++] = sfp_module_serial[machine.is_sfp[i]-1][s];
|
||||
for (register uint8_t s = 0; s < 16 && sfp_module_serial[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_serial[sfp][s];
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_los\":");
|
||||
if (machine.sfp_port[machine.is_sfp[i]-1].pin_los == GPIO_NA) {
|
||||
if (machine.sfp_port[sfp].pin_los == GPIO_NA) {
|
||||
slen += strtox(outbuf + slen,"null");
|
||||
} else {
|
||||
bool_to_html(sfp_pins_last & (0x2 << (((machine.is_sfp[i]-1) << 2))));
|
||||
bool_to_html(sfp_pins_last & (0x2 << (sfp << 2)));
|
||||
}
|
||||
} else {
|
||||
bool_to_html(0);
|
||||
|
||||
@@ -158,6 +158,7 @@ uint16_t strlen(register __code const char *s);
|
||||
uint16_t strlen_x(register __xdata const char *s);
|
||||
uint16_t strtox(register __xdata uint8_t *dst, register __code const char *s);
|
||||
uint16_t strcpy(register __xdata uint8_t *dst, register const char *s);
|
||||
char strcmp(register __xdata const uint8_t *a, register __code const uint8_t *b);
|
||||
void tcpip_output(void);
|
||||
uint8_t read_flash(uint8_t bank, __code uint8_t *addr);
|
||||
void get_random_32(void);
|
||||
|
||||
+68
-9
@@ -138,10 +138,25 @@ __xdata char sfp_module_model[2][17];
|
||||
__xdata char sfp_module_serial[2][17];
|
||||
__xdata uint8_t sfp_options[2];
|
||||
__xdata uint8_t sfp_speed[2];
|
||||
__xdata uint8_t sfp_quirks[2];
|
||||
__xdata bool button_last;
|
||||
__xdata uint8_t button_sec_counter_last;
|
||||
volatile __bit tx_buf_empty;
|
||||
|
||||
__code enum sfp_quirk {
|
||||
SFP_QUIRK_DDM = (1 << 0),
|
||||
};
|
||||
|
||||
struct sfp_quirk_entry {
|
||||
__code char *vendor; // Set vendor or model to 0 to act as wildcard
|
||||
__code char *model;
|
||||
uint8_t quirks;
|
||||
};
|
||||
|
||||
static __code struct sfp_quirk_entry sfp_quirk_table[] = {
|
||||
{ "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM },
|
||||
};
|
||||
|
||||
struct eth_in {
|
||||
struct uip_eth_addr dst;
|
||||
struct uip_eth_addr src;
|
||||
@@ -327,6 +342,21 @@ uint16_t strlen_x(register __xdata const char *s)
|
||||
}
|
||||
|
||||
|
||||
char strcmp(register __xdata const uint8_t *a, register __code const uint8_t *b)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
||||
while (b[i] && (b[i] == a[i]))
|
||||
i++;
|
||||
|
||||
if (a[i] < b[i])
|
||||
return -1;
|
||||
else if (a[i] > b[i])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void print_short(uint16_t a)
|
||||
{
|
||||
// allocating the registers first improves the sdcc code here
|
||||
@@ -1199,18 +1229,46 @@ void sfp_print_info(uint8_t sfp)
|
||||
print_string("\n");
|
||||
}
|
||||
|
||||
// Normalize strings from EEPROM by removing any trailing spaces; this allows simpler comparisons
|
||||
void sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __reentrant
|
||||
{
|
||||
dst[length] = '\0';
|
||||
|
||||
for (uint8_t i = 0; i < length; i++)
|
||||
dst[i] = sfp_read_reg(sfp, start + i);
|
||||
|
||||
while (length > 0 && dst[--length] == ' ')
|
||||
dst[length] = '\0';
|
||||
}
|
||||
|
||||
void sfp_get_info(uint8_t sfp)
|
||||
{
|
||||
for (uint8_t i = 20; i < 36; i++)
|
||||
sfp_module_vendor[sfp][i-20] = sfp_read_reg(sfp, i);
|
||||
sfp_module_vendor[sfp][16] = '\0';
|
||||
for (uint8_t i = 40; i < 56; i++)
|
||||
sfp_module_model[sfp][i-40] = sfp_read_reg(sfp, i);
|
||||
sfp_module_model[sfp][16] = '\0';
|
||||
for (uint8_t i = 68; i < 84; i++)
|
||||
sfp_module_serial[sfp][i-68] = sfp_read_reg(sfp, i);
|
||||
sfp_module_serial[sfp][16] = '\0';
|
||||
sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16);
|
||||
sfp_read_field(sfp_module_model[sfp], sfp, 40, 16);
|
||||
sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16);
|
||||
}
|
||||
|
||||
void sfp_apply_quirks(uint8_t sfp) __reentrant
|
||||
{
|
||||
sfp_quirks[sfp] = 0;
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(sfp_quirk_table) / sizeof(*sfp_quirk_table); i++) {
|
||||
if (!sfp_quirk_table[i].vendor || !strcmp(sfp_module_vendor[sfp], sfp_quirk_table[i].vendor)) {
|
||||
if (!sfp_quirk_table[i].model || !strcmp(sfp_module_model[sfp], sfp_quirk_table[i].model)) {
|
||||
sfp_quirks[sfp] |= sfp_quirk_table[i].quirks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sfp_quirks[sfp] & SFP_QUIRK_DDM) {
|
||||
if (!(sfp_options[sfp] & 0x40)) {
|
||||
// The module reports that DDM is not implemented, but try a dummy read to confirm
|
||||
// 0xff would mean a failed I2C read or an impossible (per spec) voltage greater than 6.5V
|
||||
if (sfp_read_reg(sfp, 226) != 0xff) {
|
||||
sfp_options[sfp] |= 0x40;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1255,6 +1313,7 @@ void handle_sfp(void)
|
||||
print_string("\n");
|
||||
sfp_options[sfp] = sfp_read_reg(sfp, 92);
|
||||
sfp_get_info(sfp);
|
||||
sfp_apply_quirks(sfp);
|
||||
sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate));
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user