The SFF-8636 decoder shows the module identity and the digital diagnostics, but not the channel status flags, which are usually the first thing to check when a QSFP link does not come up.
Report the per-lane Rx and Tx loss of signal, Rx and Tx CDR loss of lock, Tx fault and Tx adaptive equalization fault flags from bytes 3 to 5 of the lower page. A flag is shown as "None" if no lane is flagged, or as a list per lane otherwise, following the output of ethtool. Each flag is reported only if the module advertises it in the options of page 00h, except the Rx loss of signal: it is optional but has no implemented bit, so it is always reported, and a module without it reads as not flagged. Gating it on the Tx loss of signal bit, as ethtool does, would hide it on modules supporting Rx only. These flags are latched and cleared on read, so they report the events since the previous read of the module. Signed-off-by: Roman Khromenok <[email protected]> --- doc/guides/rel_notes/release_26_11.rst | 2 ++ lib/ethdev/sff_8636.c | 34 ++++++++++++++++++++++++++ lib/ethdev/sff_8636.h | 12 +++++++++ lib/ethdev/sff_common.c | 25 +++++++++++++++++++ lib/ethdev/sff_common.h | 2 ++ 5 files changed, 75 insertions(+) diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst index d0c896634b..c3f8ccdccf 100644 --- a/doc/guides/rel_notes/release_26_11.rst +++ b/doc/guides/rel_notes/release_26_11.rst @@ -86,6 +86,8 @@ New Features such as the Linux ethtool ``ETHTOOL_GMODULEEEPROM`` ioctl. The testpmd command ``show port (port_id) module_eeprom decode`` uses it to display the decoded module EEPROM. + The SFF-8636 decoder also reports the per-lane loss of signal, + loss of lock and Tx fault flags. * **Updated AF_XDP driver.** diff --git a/lib/ethdev/sff_8636.c b/lib/ethdev/sff_8636.c index 40e5404caf..ad36927540 100644 --- a/lib/ethdev/sff_8636.c +++ b/lib/ethdev/sff_8636.c @@ -452,6 +452,39 @@ static void sff_8636_show_rate_identifier(const uint8_t *data, struct sff_output sff_output_field(d, "Rate identifier", val_string); } +/* + * Channel status flags are latched and cleared when read by the host, + * so they report the events since the previous read of the module. + * Each flag except Rx LOS is reported only if the module advertises it. + */ +static void sff_8636_show_signals(const uint8_t *data, struct sff_output *d) +{ + uint8_t los = data[SFF_8636_LOS_AW_OFFSET]; + uint8_t fault = data[SFF_8636_FAULT_AW_OFFSET]; + uint8_t lol = data[SFF_8636_LOL_AW_OFFSET]; + + /* Rx LOS has no implemented bit, it reads as not flagged if absent */ + sff_show_lane_status("Rx loss of signal", SFF_MAX_CHANNEL_NUM, + SFF_8636_LANES_LOW(los), d); + if (data[SFF_8636_OPTION_4_OFFSET] & SFF_8636_O4_TX_LOS) + sff_show_lane_status("Tx loss of signal", SFF_MAX_CHANNEL_NUM, + SFF_8636_LANES_HIGH(los), d); + + if (data[SFF_8636_OPTION_3_OFFSET] & SFF_8636_O3_RX_LOL) + sff_show_lane_status("Rx loss of lock", SFF_MAX_CHANNEL_NUM, + SFF_8636_LANES_LOW(lol), d); + if (data[SFF_8636_OPTION_3_OFFSET] & SFF_8636_O3_TX_LOL) + sff_show_lane_status("Tx loss of lock", SFF_MAX_CHANNEL_NUM, + SFF_8636_LANES_HIGH(lol), d); + + if (data[SFF_8636_OPTION_4_OFFSET] & SFF_8636_O4_TX_FAULT) + sff_show_lane_status("Tx fault", SFF_MAX_CHANNEL_NUM, + SFF_8636_LANES_LOW(fault), d); + if (data[SFF_8636_OPTION_2_OFFSET] & SFF_8636_O2_TX_EQ_AUTO) + sff_show_lane_status("Tx adaptive eq fault", SFF_MAX_CHANNEL_NUM, + SFF_8636_LANES_HIGH(fault), d); +} + static void sff_8636_show_oui(const uint8_t *data, struct sff_output *d) { sff_8024_show_oui(data, SFF_8636_VENDOR_OUI_OFFSET, d); @@ -761,6 +794,7 @@ void sff_8636_show_all(const uint8_t *data, uint32_t eeprom_len, struct sff_outp sff_show_ascii(data, SFF_8636_DATE_YEAR_OFFSET, SFF_8636_DATE_VENDOR_LOT_OFFSET + 1, "Date code", d); sff_8636_show_revision_compliance(data, d); + sff_8636_show_signals(data, d); sff_8636_show_dom(data, eeprom_len, d); } } diff --git a/lib/ethdev/sff_8636.h b/lib/ethdev/sff_8636.h index cf11a2c247..d2a923a7c0 100644 --- a/lib/ethdev/sff_8636.h +++ b/lib/ethdev/sff_8636.h @@ -55,6 +55,12 @@ #define SFF_8636_TX2_FAULT_AW RTE_BIT32(1) #define SFF_8636_TX1_FAULT_AW RTE_BIT32(0) +#define SFF_8636_LOL_AW_OFFSET 0x05 + +/* Lanes 1-4 of the channel status flags are in bits 0-3 or 4-7 */ +#define SFF_8636_LANES_LOW(val) ((val) & 0xf) +#define SFF_8636_LANES_HIGH(val) (((val) >> 4) & 0xf) + /* Module Monitor Interrupt Flags - 6-8 */ #define SFF_8636_TEMP_AW_OFFSET 0x06 #define SFF_8636_TEMP_HALARM_STATUS RTE_BIT32(7) @@ -488,9 +494,15 @@ #define SFF_8636_ETHERNET_100G_ACC2 0x19 #define SFF_8636_OPTION_2_OFFSET 0xC1 +/* Tx input equalizers auto-adaptive */ +#define SFF_8636_O2_TX_EQ_AUTO RTE_BIT32(3) /* Rx output amplitude */ #define SFF_8636_O2_RX_OUTPUT_AMP RTE_BIT32(0) #define SFF_8636_OPTION_3_OFFSET 0xC2 +/* Tx CDR Loss of Lock flag implemented */ +#define SFF_8636_O3_TX_LOL RTE_BIT32(5) +/* Rx CDR Loss of Lock flag implemented */ +#define SFF_8636_O3_RX_LOL RTE_BIT32(4) /* Rx Squelch Disable */ #define SFF_8636_O3_RX_SQL_DSBL RTE_BIT32(3) /* Rx Output Disable capable */ diff --git a/lib/ethdev/sff_common.c b/lib/ethdev/sff_common.c index a36bf83026..0fc498edb0 100644 --- a/lib/ethdev/sff_common.c +++ b/lib/ethdev/sff_common.c @@ -84,6 +84,31 @@ void sff_show_ascii(const uint8_t *data, unsigned int first_reg, sff_output_field(d, name, val_string); } +/* + * Report a per-lane status bitmap, lane 1 in bit 0: + * "None" if no lane is flagged, otherwise "[ Yes, No, ... ]". + */ +void sff_show_lane_status(const char *name, unsigned int lane_cnt, + unsigned int value, struct sff_output *d) +{ + char val_string[SFF_ITEM_VAL_COMPOSE_SIZE]; + unsigned int lane; + + if (value == 0) { + sff_output_field(d, name, "None"); + return; + } + + strlcpy(val_string, "[", sizeof(val_string)); + for (lane = 0; lane < lane_cnt; lane++) { + strlcat(val_string, (value & RTE_BIT32(lane)) ? " Yes" : " No", + sizeof(val_string)); + strlcat(val_string, lane + 1 < lane_cnt ? "," : " ]", + sizeof(val_string)); + } + sff_output_field(d, name, val_string); +} + void sff_8024_show_oui(const uint8_t *data, int id_offset, struct sff_output *d) { char val_string[SFF_ITEM_VAL_COMPOSE_SIZE]; diff --git a/lib/ethdev/sff_common.h b/lib/ethdev/sff_common.h index d346e1b378..9041f8ed17 100644 --- a/lib/ethdev/sff_common.h +++ b/lib/ethdev/sff_common.h @@ -191,6 +191,8 @@ void sff_show_value_with_unit(const uint8_t *data, unsigned int reg, void sff_show_ascii(const uint8_t *data, unsigned int first_reg, unsigned int last_reg, const char *name, struct sff_output *d); void sff_show_thresholds(struct sff_diags sd, struct sff_output *d); +void sff_show_lane_status(const char *name, unsigned int lane_cnt, + unsigned int value, struct sff_output *d); void sff_8024_show_oui(const uint8_t *data, int id_offset, struct sff_output *d); void sff_8024_show_identifier(const uint8_t *data, int id_offset, struct sff_output *d); -- 2.47.3

