* [PATCH 1/4] ethdev: report SFF-8636 lane status flags
2026-10-08 8:23 [PATCH 0/4] ethdev: report module signal status flags Roman Khromenok
@ 2026-10-08 8:23 ` Roman Khromenok
2026-10-08 8:23 ` [PATCH 2/4] test: check " Roman Khromenok
` (4 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Roman Khromenok @ 2026-10-08 8:23 UTC (permalink / raw)
To: dev; +Cc: thomas, andrew.rybchenko, stephen
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, each one only if the module
advertises it in the options of page 00h. A flag is shown as
"None" if no lane is flagged, or as a list per lane otherwise,
following the output of ethtool.
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 <roma55592@yandex.ru>
---
doc/guides/rel_notes/release_26_11.rst | 2 ++
lib/ethdev/sff_8636.c | 35 ++++++++++++++++++++++++++
lib/ethdev/sff_8636.h | 12 +++++++++
lib/ethdev/sff_common.c | 25 ++++++++++++++++++
lib/ethdev/sff_common.h | 2 ++
5 files changed, 76 insertions(+)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index d25dc72edf..08c554cedb 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -84,6 +84,8 @@ New Features
It can decode data read with ``rte_eth_dev_get_module_eeprom()``
or obtained from any other source with the same layout,
such as the Linux ethtool ``ETHTOOL_GMODULEEEPROM`` ioctl.
+ 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..8fc48e1798 100644
--- a/lib/ethdev/sff_8636.c
+++ b/lib/ethdev/sff_8636.c
@@ -452,6 +452,40 @@ 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 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];
+
+ /* There is no Rx LOS implemented bit, use the Tx one for both */
+ if (data[SFF_8636_OPTION_4_OFFSET] & SFF_8636_O4_TX_LOS) {
+ sff_show_lane_status("Rx loss of signal", SFF_MAX_CHANNEL_NUM,
+ SFF_8636_LANES_LOW(los), d);
+ 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 +795,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
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 2/4] test: check SFF-8636 lane status flags
2026-10-08 8:23 [PATCH 0/4] ethdev: report module signal status flags Roman Khromenok
2026-10-08 8:23 ` [PATCH 1/4] ethdev: report SFF-8636 lane " Roman Khromenok
@ 2026-10-08 8:23 ` Roman Khromenok
2026-10-08 8:23 ` [PATCH 3/4] ethdev: report SFF-8472 Rx LOS and Tx fault state Roman Khromenok
` (3 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Roman Khromenok @ 2026-10-08 8:23 UTC (permalink / raw)
To: dev; +Cc: thomas, andrew.rybchenko, stephen
Check that the SFF-8636 lane status flags are not reported
if the module does not advertise them, are reported as "None"
if no lane is flagged, and that each lane is mapped to the
right bit of the flag bytes.
Signed-off-by: Roman Khromenok <roma55592@yandex.ru>
---
app/test/test_ethdev_module_eeprom.c | 77 ++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/app/test/test_ethdev_module_eeprom.c b/app/test/test_ethdev_module_eeprom.c
index 1956fdd440..135ff5e5e3 100644
--- a/app/test/test_ethdev_module_eeprom.c
+++ b/app/test/test_ethdev_module_eeprom.c
@@ -243,6 +243,81 @@ test_module_eeprom_qsfp_8636_thresholds(void)
return TEST_SUCCESS;
}
+/* SFF-8636 lower page channel status flags and their implemented bits */
+#define QSFP_LOS_FLAGS 3
+#define QSFP_FAULT_FLAGS 4
+#define QSFP_LOL_FLAGS 5
+#define QSFP_OPTIONS_2 193
+#define QSFP_OPTIONS_3 194
+#define QSFP_OPTIONS_4 195
+
+static void
+fill_qsfp_signals(uint8_t *data)
+{
+ fill_qsfp(data);
+ data[QSFP_OPTIONS_2] = 0x08; /* Tx adaptive equalizers */
+ data[QSFP_OPTIONS_3] = 0x30; /* Tx and Rx CDR loss of lock */
+ data[QSFP_OPTIONS_4] = 0x0a; /* Tx fault and Tx loss of signal */
+}
+
+static int
+test_module_eeprom_qsfp_8636_signals_not_implemented(void)
+{
+ uint8_t data[RTE_ETH_MODULE_SFF_8636_LEN];
+
+ /* flags are raised but the module does not advertise them */
+ fill_qsfp(data);
+ data[QSFP_LOS_FLAGS] = 0xff;
+ data[QSFP_FAULT_FLAGS] = 0xff;
+ data[QSFP_LOL_FLAGS] = 0xff;
+
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8636, data, sizeof(data)),
+ "Failed to parse SFF-8636 data");
+ CHECK_NO_FIELD("Rx loss of signal");
+ CHECK_NO_FIELD("Tx loss of signal");
+ CHECK_NO_FIELD("Rx loss of lock");
+ CHECK_NO_FIELD("Tx loss of lock");
+ CHECK_NO_FIELD("Tx fault");
+ CHECK_NO_FIELD("Tx adaptive eq fault");
+ return TEST_SUCCESS;
+}
+
+static int
+test_module_eeprom_qsfp_8636_signals(void)
+{
+ uint8_t data[RTE_ETH_MODULE_SFF_8636_LEN];
+
+ fill_qsfp_signals(data);
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8636, data, sizeof(data)),
+ "Failed to parse SFF-8636 data without flags");
+ CHECK_FIELD("Rx loss of signal", "None");
+ CHECK_FIELD("Tx loss of signal", "None");
+ CHECK_FIELD("Rx loss of lock", "None");
+ CHECK_FIELD("Tx loss of lock", "None");
+ CHECK_FIELD("Tx fault", "None");
+ CHECK_FIELD("Tx adaptive eq fault", "None");
+
+ /* lane 1 is in the lowest bit of each half of the flag byte */
+ data[QSFP_LOS_FLAGS] = 0x21; /* Rx lane 1, Tx lane 2 */
+ data[QSFP_FAULT_FLAGS] = 0x84; /* Tx fault lane 3, Tx adaptive eq lane 4 */
+ data[QSFP_LOL_FLAGS] = 0x18; /* Rx lane 4, Tx lane 1 */
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8636, data, sizeof(data)),
+ "Failed to parse SFF-8636 data with flags");
+ CHECK_FIELD("Rx loss of signal", "[ Yes, No, No, No ]");
+ CHECK_FIELD("Tx loss of signal", "[ No, Yes, No, No ]");
+ CHECK_FIELD("Rx loss of lock", "[ No, No, No, Yes ]");
+ CHECK_FIELD("Tx loss of lock", "[ Yes, No, No, No ]");
+ CHECK_FIELD("Tx fault", "[ No, No, Yes, No ]");
+ CHECK_FIELD("Tx adaptive eq fault", "[ No, No, No, Yes ]");
+
+ data[QSFP_LOS_FLAGS] = 0x0f; /* Rx on all lanes, no Tx */
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8636, data, sizeof(data)),
+ "Failed to parse SFF-8636 data with Rx LOS on all lanes");
+ CHECK_FIELD("Rx loss of signal", "[ Yes, Yes, Yes, Yes ]");
+ CHECK_FIELD("Tx loss of signal", "None");
+ return TEST_SUCCESS;
+}
+
static int
test_module_eeprom_sfp_8472_ext_cal_unaligned(void)
{
@@ -453,6 +528,8 @@ static struct unit_test_suite module_eeprom_testsuite = {
TEST_CASE(test_module_eeprom_sfp_8472_cal_round),
TEST_CASE(test_module_eeprom_qsfp_8636),
TEST_CASE(test_module_eeprom_qsfp_8636_thresholds),
+ TEST_CASE(test_module_eeprom_qsfp_8636_signals_not_implemented),
+ TEST_CASE(test_module_eeprom_qsfp_8636_signals),
TEST_CASE(test_module_eeprom_invalid),
TEST_CASES_END()
}
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 3/4] ethdev: report SFF-8472 Rx LOS and Tx fault state
2026-10-08 8:23 [PATCH 0/4] ethdev: report module signal status flags Roman Khromenok
2026-10-08 8:23 ` [PATCH 1/4] ethdev: report SFF-8636 lane " Roman Khromenok
2026-10-08 8:23 ` [PATCH 2/4] test: check " Roman Khromenok
@ 2026-10-08 8:23 ` Roman Khromenok
2026-10-08 8:23 ` [PATCH 4/4] test: check " Roman Khromenok
` (2 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Roman Khromenok @ 2026-10-08 8:23 UTC (permalink / raw)
To: dev; +Cc: thomas, andrew.rybchenko, stephen
The SFF-8472 decoder shows the digital diagnostics of SFP modules,
but not whether the module detects a loss of the received signal
or a transmitter fault.
Report the Rx_LOS and TX_FAULT state from the status byte 110
of page A2h, each one only if the module advertises the soft
monitoring of it in the enhanced options of page A0h.
Unlike the SFF-8636 channel status flags, these bits reflect
the current state of the pins and are not latched.
Signed-off-by: Roman Khromenok <roma55592@yandex.ru>
---
doc/guides/rel_notes/release_26_11.rst | 1 +
lib/ethdev/sff_8472.c | 16 ++++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 08c554cedb..601233d6ac 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -86,6 +86,7 @@ New Features
such as the Linux ethtool ``ETHTOOL_GMODULEEEPROM`` ioctl.
The SFF-8636 decoder also reports the per-lane loss of signal,
loss of lock and Tx fault flags.
+ The SFF-8472 decoder reports the Rx loss of signal and Tx fault state.
* **Updated AF_XDP driver.**
diff --git a/lib/ethdev/sff_8472.c b/lib/ethdev/sff_8472.c
index 88d1f4a0a5..f9fd668731 100644
--- a/lib/ethdev/sff_8472.c
+++ b/lib/ethdev/sff_8472.c
@@ -25,6 +25,8 @@
#define SFF_A0_DOM_PWRT RTE_BIT32(3)
#define SFF_A0_OPTIONS_AW RTE_BIT32(7)
+#define SFF_A0_OPTIONS_SOFT_TX_FAULT RTE_BIT32(5)
+#define SFF_A0_OPTIONS_SOFT_RX_LOS RTE_BIT32(4)
/*
* This is the offset at which the A2 page is in the EEPROM
@@ -63,6 +65,10 @@
#define SFF_A2_RX_PWR_HWARN 36
#define SFF_A2_RX_PWR_LWARN 38
+#define SFF_A2_STATUS 110
+#define SFF_A2_STATUS_TX_FAULT RTE_BIT32(2)
+#define SFF_A2_STATUS_RX_LOS RTE_BIT32(1)
+
#define SFF_A2_ALRM_FLG 112
#define SFF_A2_WARN_FLG 116
@@ -302,6 +308,16 @@ void sff_8472_show_all(const uint8_t *data, struct sff_output *d)
SFF_SPRINT_VCC(val_string, sd.sfp_voltage[SFF_MCURR]);
sff_output_field(d, "Module voltage", val_string);
+ /* Real-time state of the pins, unlike the latched SFF-8636 flags */
+ if (data[SFF_A0_OPTIONS] & SFF_A0_OPTIONS_SOFT_RX_LOS)
+ sff_output_field(d, "Rx loss of signal",
+ data[SFF_A2_BASE + SFF_A2_STATUS] & SFF_A2_STATUS_RX_LOS ?
+ "Yes" : "No");
+ if (data[SFF_A0_OPTIONS] & SFF_A0_OPTIONS_SOFT_TX_FAULT)
+ sff_output_field(d, "Tx fault",
+ data[SFF_A2_BASE + SFF_A2_STATUS] & SFF_A2_STATUS_TX_FAULT ?
+ "Yes" : "No");
+
sff_output_field(d, "Alarm/warning flags implemented",
(sd.supports_alarms ? "Yes" : "No"));
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 4/4] test: check SFF-8472 Rx LOS and Tx fault state
2026-10-08 8:23 [PATCH 0/4] ethdev: report module signal status flags Roman Khromenok
` (2 preceding siblings ...)
2026-10-08 8:23 ` [PATCH 3/4] ethdev: report SFF-8472 Rx LOS and Tx fault state Roman Khromenok
@ 2026-10-08 8:23 ` Roman Khromenok
2026-10-08 17:45 ` [PATCH 0/4] ethdev: report module signal status flags Stephen Hemminger
2026-10-08 18:02 ` [PATCH v2 " Roman Khromenok
5 siblings, 0 replies; 11+ messages in thread
From: Roman Khromenok @ 2026-10-08 8:23 UTC (permalink / raw)
To: dev; +Cc: thomas, andrew.rybchenko, stephen
Check that the SFF-8472 Rx loss of signal and Tx fault state
are not reported if the module does not advertise them,
and that each one is mapped to the right bit of the status byte.
Signed-off-by: Roman Khromenok <roma55592@yandex.ru>
---
app/test/test_ethdev_module_eeprom.c | 40 ++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/app/test/test_ethdev_module_eeprom.c b/app/test/test_ethdev_module_eeprom.c
index 135ff5e5e3..1b2f43c4c2 100644
--- a/app/test/test_ethdev_module_eeprom.c
+++ b/app/test/test_ethdev_module_eeprom.c
@@ -243,6 +243,45 @@ test_module_eeprom_qsfp_8636_thresholds(void)
return TEST_SUCCESS;
}
+/* SFF-8472 status bits and their implemented bits */
+#define SFP_ENH_OPTIONS 93
+#define SFP_A2_STATUS 110
+
+static int
+test_module_eeprom_sfp_8472_status(void)
+{
+ uint8_t data[RTE_ETH_MODULE_SFF_8472_LEN];
+ uint8_t *a2 = data + RTE_ETH_MODULE_SFF_8079_LEN;
+
+ /* state is raised but the module does not advertise it */
+ fill_sfp(data);
+ a2[SFP_A2_STATUS] = 0x06;
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8472, data, sizeof(data)),
+ "Failed to parse SFF-8472 data");
+ CHECK_NO_FIELD("Rx loss of signal");
+ CHECK_NO_FIELD("Tx fault");
+
+ data[SFP_ENH_OPTIONS] = 0x30; /* soft Tx fault and Rx LOS monitoring */
+ a2[SFP_A2_STATUS] = 0;
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8472, data, sizeof(data)),
+ "Failed to parse SFF-8472 data without status bits");
+ CHECK_FIELD("Rx loss of signal", "No");
+ CHECK_FIELD("Tx fault", "No");
+
+ a2[SFP_A2_STATUS] = 0x02; /* Rx LOS */
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8472, data, sizeof(data)),
+ "Failed to parse SFF-8472 data with Rx LOS");
+ CHECK_FIELD("Rx loss of signal", "Yes");
+ CHECK_FIELD("Tx fault", "No");
+
+ a2[SFP_A2_STATUS] = 0x04; /* Tx fault */
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8472, data, sizeof(data)),
+ "Failed to parse SFF-8472 data with Tx fault");
+ CHECK_FIELD("Rx loss of signal", "No");
+ CHECK_FIELD("Tx fault", "Yes");
+ return TEST_SUCCESS;
+}
+
/* SFF-8636 lower page channel status flags and their implemented bits */
#define QSFP_LOS_FLAGS 3
#define QSFP_FAULT_FLAGS 4
@@ -526,6 +565,7 @@ static struct unit_test_suite module_eeprom_testsuite = {
TEST_CASE(test_module_eeprom_sfp_8472_cal_saturate_max),
TEST_CASE(test_module_eeprom_sfp_8472_cal_saturate_min),
TEST_CASE(test_module_eeprom_sfp_8472_cal_round),
+ TEST_CASE(test_module_eeprom_sfp_8472_status),
TEST_CASE(test_module_eeprom_qsfp_8636),
TEST_CASE(test_module_eeprom_qsfp_8636_thresholds),
TEST_CASE(test_module_eeprom_qsfp_8636_signals_not_implemented),
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 0/4] ethdev: report module signal status flags
2026-10-08 8:23 [PATCH 0/4] ethdev: report module signal status flags Roman Khromenok
` (3 preceding siblings ...)
2026-10-08 8:23 ` [PATCH 4/4] test: check " Roman Khromenok
@ 2026-10-08 17:45 ` Stephen Hemminger
2026-10-08 18:02 ` [PATCH v2 " Roman Khromenok
5 siblings, 0 replies; 11+ messages in thread
From: Stephen Hemminger @ 2026-10-08 17:45 UTC (permalink / raw)
To: Roman Khromenok; +Cc: dev, thomas, andrew.rybchenko
On Thu, 8 Oct 2026 10:23:22 +0200
Roman Khromenok <roma55592@yandex.ru> wrote:
> The module EEPROM decoder shows the identity and the digital
> diagnostics of a module, but not the signal status, which is
> usually the first thing to check when a link does not come up.
>
> Patches 1-2 report the SFF-8636 per-lane loss of signal,
> CDR loss of lock and Tx fault flags, as ethtool does since
> commit 045d8db ("sff-8636: report LOL / LOS / Tx Fault").
> The code is written for DPDK, not copied from ethtool.
>
> Patches 3-4 report the SFF-8472 Rx_LOS and TX_FAULT state
> from page A2h byte 110. ethtool does not show it, so it is
> split out and can be dropped independently of patches 1-2.
>
> The SFF-8636 flags are latched and cleared on read,
> so they report the events since the previous read;
> the SFF-8472 bits are the current state of the pins.
>
> The series is based on next-net/for-main. It extends the same
> release notes entry as the testpmd patch 170851 ("app/testpmd: add
> command to decode module EEPROM"), so whichever is applied second
> needs a trivial context fixup there.
>
> Roman Khromenok (4):
> ethdev: report SFF-8636 lane status flags
> test: check SFF-8636 lane status flags
> ethdev: report SFF-8472 Rx LOS and Tx fault state
> test: check SFF-8472 Rx LOS and Tx fault state
I am not an expert in this area, deferred to AI for review
and it reported one item worth checking.
Series: [PATCH 1/4..4/4] ethdev: report SFF module status flags
Author: Roman Khromenok
Summary
-------
Bit and offset mapping checked against SFF-8636 and SFF-8472:
bytes 3-5 lane split, Options 2/3/4 implemented bits, A0 byte 93
bits 4/5 and A2 byte 110 bits 1/2 are all correct. Lane string
format matches ethtool output. The SFF-8472 status is only shown
when DOM is supported (early return in sff_8472_show_all), which
is correct since byte 110 lives in A2.
Series depends on the module EEPROM decode series (the test file
and the release note entry are not in main yet); say so in the
cover letter.
Patch 1/4
---------
Warning: Rx LOS gated on Tx LOS implemented bit.
/* There is no Rx LOS implemented bit, use the Tx one for both */
if (data[SFF_8636_OPTION_4_OFFSET] & SFF_8636_O4_TX_LOS) {
Rx LOS has no implemented bit because it is not optional in
SFF-8636; only Tx LOS is (Options 4 bit 1). Gating Rx on the Tx
bit hides the most useful flag on every module without Tx LOS,
which is the case the commit message says this is for. ethtool
has the same limitation; no reason to copy it. Show Rx LOS
unconditionally:
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);
and update the not_implemented test in 2/4 to expect
CHECK_FIELD("Rx loss of signal", "[ Yes, Yes, Yes, Yes ]").
Patch 2/4
---------
Info: fill_qsfp_signals() overwrites option bytes 193-195 instead
of setting bits. Any bits fill_qsfp() set there (page 01h/02h
provided, etc.) are lost, which can silently change what the
other decoders see. Use |= :
data[QSFP_OPTIONS_2] |= 0x08;
data[QSFP_OPTIONS_3] |= 0x30;
data[QSFP_OPTIONS_4] |= 0x0a;
Patch 3/4
---------
Info: SFP shows "No" when clear, QSFP shows "None" for the same
field names ("Rx loss of signal", "Tx fault"). Telemetry
consumers keyed on name get two value conventions. Either use
"None"/"[ Yes ]" style for SFP too, or accept it and note it in
the commit message.
Info: release note line reads as a separate feature; "The
SFF-8472 decoder also reports ..." to match the 8636 line.
Patch 4/4
---------
Info: same as 2/4, data[SFP_ENH_OPTIONS] = 0x30 clears the
alarm/warning implemented bit (bit 7) if fill_sfp() sets it.
Use |= 0x30.
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v2 0/4] ethdev: report module signal status flags
2026-10-08 8:23 [PATCH 0/4] ethdev: report module signal status flags Roman Khromenok
` (4 preceding siblings ...)
2026-10-08 17:45 ` [PATCH 0/4] ethdev: report module signal status flags Stephen Hemminger
@ 2026-10-08 18:02 ` Roman Khromenok
2026-10-08 18:02 ` [PATCH v2 1/4] ethdev: report SFF-8636 lane " Roman Khromenok
` (3 more replies)
5 siblings, 4 replies; 11+ messages in thread
From: Roman Khromenok @ 2026-10-08 18:02 UTC (permalink / raw)
To: dev; +Cc: thomas, andrew.rybchenko, stephen
The module EEPROM decoder shows the identity and the digital
diagnostics of a module, but not the signal status, which is
usually the first thing to check when a link does not come up.
Patches 1-2 report the SFF-8636 per-lane loss of signal,
CDR loss of lock and Tx fault flags, as ethtool does since
commit 045d8db ("sff-8636: report LOL / LOS / Tx Fault").
The code is written for DPDK, not copied from ethtool.
Patches 3-4 report the SFF-8472 Rx_LOS and TX_FAULT state
from page A2h byte 110. ethtool does not show it, so it is
split out and can be dropped independently of patches 1-2.
The SFF-8636 flags are latched and cleared on read,
so they report the events since the previous read;
the SFF-8472 bits are the current state of the pins.
The series depends on the module EEPROM decode API series and on
the testpmd decode command, which are in next-net but not in main
yet. It is based on next-net/for-main with patch 170851 applied,
so the release notes entry no longer conflicts.
Depends-on: series-39436 ("ethdev: add API to decode module EEPROM")
Depends-on: series-39455 ("ethdev: fix SFF-8472 external Rx power calibration")
Depends-on: series-39480 ("ethdev: fix SFF-8472 calibration overflow")
Depends-on: patch-170851 ("app/testpmd: add command to decode module EEPROM")
v2:
- 1/4: always report the Rx loss of signal instead of gating it on
the Tx loss of signal implemented bit. SFF-8636 Rev 2.12 Table 6-5
lists the Rx LOS flags as optional, but there is no implemented
bit for them, and a module without them reads as not flagged.
- 2/4, 4/4: set the option bits with |= in the tests.
- 3/4: use the SFF-8636 format with a single lane ("None" or
"[ Yes ]") for the same field names, which also removes the
multi-line ternaries; "also reports" in the release notes.
- rebased on next-net/for-main with patch 170851 applied.
Roman Khromenok (4):
ethdev: report SFF-8636 lane status flags
test: check SFF-8636 lane status flags
ethdev: report SFF-8472 Rx LOS and Tx fault state
test: check SFF-8472 Rx LOS and Tx fault state
app/test/test_ethdev_module_eeprom.c | 118 +++++++++++++++++++++++++
doc/guides/rel_notes/release_26_11.rst | 3 +
lib/ethdev/sff_8472.c | 19 ++++
lib/ethdev/sff_8636.c | 34 +++++++
lib/ethdev/sff_8636.h | 12 +++
lib/ethdev/sff_common.c | 25 ++++++
lib/ethdev/sff_common.h | 2 +
7 files changed, 213 insertions(+)
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v2 1/4] ethdev: report SFF-8636 lane status flags
2026-10-08 18:02 ` [PATCH v2 " Roman Khromenok
@ 2026-10-08 18:02 ` Roman Khromenok
2026-10-08 18:02 ` [PATCH v2 2/4] test: check " Roman Khromenok
` (2 subsequent siblings)
3 siblings, 0 replies; 11+ messages in thread
From: Roman Khromenok @ 2026-10-08 18:02 UTC (permalink / raw)
To: dev; +Cc: thomas, andrew.rybchenko, stephen
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 <roma55592@yandex.ru>
---
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
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 2/4] test: check SFF-8636 lane status flags
2026-10-08 18:02 ` [PATCH v2 " Roman Khromenok
2026-10-08 18:02 ` [PATCH v2 1/4] ethdev: report SFF-8636 lane " Roman Khromenok
@ 2026-10-08 18:02 ` Roman Khromenok
2026-10-08 18:02 ` [PATCH v2 3/4] ethdev: report SFF-8472 Rx LOS and Tx fault state Roman Khromenok
2026-10-08 18:02 ` [PATCH v2 4/4] test: check " Roman Khromenok
3 siblings, 0 replies; 11+ messages in thread
From: Roman Khromenok @ 2026-10-08 18:02 UTC (permalink / raw)
To: dev; +Cc: thomas, andrew.rybchenko, stephen
Check that the SFF-8636 lane status flags are not reported
if the module does not advertise them, except the Rx loss of
signal which is always reported, that they are reported as "None"
if no lane is flagged, and that each lane is mapped to the
right bit of the flag bytes.
Signed-off-by: Roman Khromenok <roma55592@yandex.ru>
---
app/test/test_ethdev_module_eeprom.c | 78 ++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/app/test/test_ethdev_module_eeprom.c b/app/test/test_ethdev_module_eeprom.c
index 1956fdd440..1cad8ede97 100644
--- a/app/test/test_ethdev_module_eeprom.c
+++ b/app/test/test_ethdev_module_eeprom.c
@@ -243,6 +243,82 @@ test_module_eeprom_qsfp_8636_thresholds(void)
return TEST_SUCCESS;
}
+/* SFF-8636 lower page channel status flags and their implemented bits */
+#define QSFP_LOS_FLAGS 3
+#define QSFP_FAULT_FLAGS 4
+#define QSFP_LOL_FLAGS 5
+#define QSFP_OPTIONS_2 193
+#define QSFP_OPTIONS_3 194
+#define QSFP_OPTIONS_4 195
+
+static void
+fill_qsfp_signals(uint8_t *data)
+{
+ fill_qsfp(data);
+ data[QSFP_OPTIONS_2] |= 0x08; /* Tx adaptive equalizers */
+ data[QSFP_OPTIONS_3] |= 0x30; /* Tx and Rx CDR loss of lock */
+ data[QSFP_OPTIONS_4] |= 0x0a; /* Tx fault and Tx loss of signal */
+}
+
+static int
+test_module_eeprom_qsfp_8636_signals_not_implemented(void)
+{
+ uint8_t data[RTE_ETH_MODULE_SFF_8636_LEN];
+
+ /* flags are raised but the module does not advertise them */
+ fill_qsfp(data);
+ data[QSFP_LOS_FLAGS] = 0xff;
+ data[QSFP_FAULT_FLAGS] = 0xff;
+ data[QSFP_LOL_FLAGS] = 0xff;
+
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8636, data, sizeof(data)),
+ "Failed to parse SFF-8636 data");
+ /* Rx LOS has no implemented bit and is always reported */
+ CHECK_FIELD("Rx loss of signal", "[ Yes, Yes, Yes, Yes ]");
+ CHECK_NO_FIELD("Tx loss of signal");
+ CHECK_NO_FIELD("Rx loss of lock");
+ CHECK_NO_FIELD("Tx loss of lock");
+ CHECK_NO_FIELD("Tx fault");
+ CHECK_NO_FIELD("Tx adaptive eq fault");
+ return TEST_SUCCESS;
+}
+
+static int
+test_module_eeprom_qsfp_8636_signals(void)
+{
+ uint8_t data[RTE_ETH_MODULE_SFF_8636_LEN];
+
+ fill_qsfp_signals(data);
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8636, data, sizeof(data)),
+ "Failed to parse SFF-8636 data without flags");
+ CHECK_FIELD("Rx loss of signal", "None");
+ CHECK_FIELD("Tx loss of signal", "None");
+ CHECK_FIELD("Rx loss of lock", "None");
+ CHECK_FIELD("Tx loss of lock", "None");
+ CHECK_FIELD("Tx fault", "None");
+ CHECK_FIELD("Tx adaptive eq fault", "None");
+
+ /* lane 1 is in the lowest bit of each half of the flag byte */
+ data[QSFP_LOS_FLAGS] = 0x21; /* Rx lane 1, Tx lane 2 */
+ data[QSFP_FAULT_FLAGS] = 0x84; /* Tx fault lane 3, Tx adaptive eq lane 4 */
+ data[QSFP_LOL_FLAGS] = 0x18; /* Rx lane 4, Tx lane 1 */
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8636, data, sizeof(data)),
+ "Failed to parse SFF-8636 data with flags");
+ CHECK_FIELD("Rx loss of signal", "[ Yes, No, No, No ]");
+ CHECK_FIELD("Tx loss of signal", "[ No, Yes, No, No ]");
+ CHECK_FIELD("Rx loss of lock", "[ No, No, No, Yes ]");
+ CHECK_FIELD("Tx loss of lock", "[ Yes, No, No, No ]");
+ CHECK_FIELD("Tx fault", "[ No, No, Yes, No ]");
+ CHECK_FIELD("Tx adaptive eq fault", "[ No, No, No, Yes ]");
+
+ data[QSFP_LOS_FLAGS] = 0x0f; /* Rx on all lanes, no Tx */
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8636, data, sizeof(data)),
+ "Failed to parse SFF-8636 data with Rx LOS on all lanes");
+ CHECK_FIELD("Rx loss of signal", "[ Yes, Yes, Yes, Yes ]");
+ CHECK_FIELD("Tx loss of signal", "None");
+ return TEST_SUCCESS;
+}
+
static int
test_module_eeprom_sfp_8472_ext_cal_unaligned(void)
{
@@ -453,6 +529,8 @@ static struct unit_test_suite module_eeprom_testsuite = {
TEST_CASE(test_module_eeprom_sfp_8472_cal_round),
TEST_CASE(test_module_eeprom_qsfp_8636),
TEST_CASE(test_module_eeprom_qsfp_8636_thresholds),
+ TEST_CASE(test_module_eeprom_qsfp_8636_signals_not_implemented),
+ TEST_CASE(test_module_eeprom_qsfp_8636_signals),
TEST_CASE(test_module_eeprom_invalid),
TEST_CASES_END()
}
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 3/4] ethdev: report SFF-8472 Rx LOS and Tx fault state
2026-10-08 18:02 ` [PATCH v2 " Roman Khromenok
2026-10-08 18:02 ` [PATCH v2 1/4] ethdev: report SFF-8636 lane " Roman Khromenok
2026-10-08 18:02 ` [PATCH v2 2/4] test: check " Roman Khromenok
@ 2026-10-08 18:02 ` Roman Khromenok
2026-10-08 18:02 ` [PATCH v2 4/4] test: check " Roman Khromenok
3 siblings, 0 replies; 11+ messages in thread
From: Roman Khromenok @ 2026-10-08 18:02 UTC (permalink / raw)
To: dev; +Cc: thomas, andrew.rybchenko, stephen
The SFF-8472 decoder shows the digital diagnostics of SFP modules,
but not whether the module detects a loss of the received signal
or a transmitter fault.
Report the Rx_LOS and TX_FAULT state from the status byte 110
of page A2h, each one only if the module advertises the soft
monitoring of it in the enhanced options of page A0h.
They use the same field names and format as the SFF-8636 lane
status flags, with a single lane: "None" or "[ Yes ]".
Unlike the SFF-8636 channel status flags, these bits reflect
the current state of the pins and are not latched.
Signed-off-by: Roman Khromenok <roma55592@yandex.ru>
---
doc/guides/rel_notes/release_26_11.rst | 1 +
lib/ethdev/sff_8472.c | 19 +++++++++++++++++++
2 files changed, 20 insertions(+)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index c3f8ccdccf..6ca8efd98f 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -88,6 +88,7 @@ New Features
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.
+ The SFF-8472 decoder also reports the Rx loss of signal and Tx fault state.
* **Updated AF_XDP driver.**
diff --git a/lib/ethdev/sff_8472.c b/lib/ethdev/sff_8472.c
index 88d1f4a0a5..ae37fee0fd 100644
--- a/lib/ethdev/sff_8472.c
+++ b/lib/ethdev/sff_8472.c
@@ -25,6 +25,8 @@
#define SFF_A0_DOM_PWRT RTE_BIT32(3)
#define SFF_A0_OPTIONS_AW RTE_BIT32(7)
+#define SFF_A0_OPTIONS_SOFT_TX_FAULT RTE_BIT32(5)
+#define SFF_A0_OPTIONS_SOFT_RX_LOS RTE_BIT32(4)
/*
* This is the offset at which the A2 page is in the EEPROM
@@ -63,6 +65,10 @@
#define SFF_A2_RX_PWR_HWARN 36
#define SFF_A2_RX_PWR_LWARN 38
+#define SFF_A2_STATUS 110
+#define SFF_A2_STATUS_TX_FAULT RTE_BIT32(2)
+#define SFF_A2_STATUS_RX_LOS RTE_BIT32(1)
+
#define SFF_A2_ALRM_FLG 112
#define SFF_A2_WARN_FLG 116
@@ -272,6 +278,7 @@ void sff_8472_show_all(const uint8_t *data, struct sff_output *d)
struct sff_diags sd = {0};
const char *rx_power_string = NULL;
char val_string[SFF_ITEM_VAL_COMPOSE_SIZE];
+ uint8_t status;
int i;
sff_8472_parse_eeprom(data, &sd);
@@ -302,6 +309,18 @@ void sff_8472_show_all(const uint8_t *data, struct sff_output *d)
SFF_SPRINT_VCC(val_string, sd.sfp_voltage[SFF_MCURR]);
sff_output_field(d, "Module voltage", val_string);
+ /*
+ * Real-time state of the pins, unlike the latched SFF-8636 flags,
+ * reported in the same single lane format.
+ */
+ status = data[SFF_A2_BASE + SFF_A2_STATUS];
+ if (data[SFF_A0_OPTIONS] & SFF_A0_OPTIONS_SOFT_RX_LOS)
+ sff_show_lane_status("Rx loss of signal", 1,
+ !!(status & SFF_A2_STATUS_RX_LOS), d);
+ if (data[SFF_A0_OPTIONS] & SFF_A0_OPTIONS_SOFT_TX_FAULT)
+ sff_show_lane_status("Tx fault", 1,
+ !!(status & SFF_A2_STATUS_TX_FAULT), d);
+
sff_output_field(d, "Alarm/warning flags implemented",
(sd.supports_alarms ? "Yes" : "No"));
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 4/4] test: check SFF-8472 Rx LOS and Tx fault state
2026-10-08 18:02 ` [PATCH v2 " Roman Khromenok
` (2 preceding siblings ...)
2026-10-08 18:02 ` [PATCH v2 3/4] ethdev: report SFF-8472 Rx LOS and Tx fault state Roman Khromenok
@ 2026-10-08 18:02 ` Roman Khromenok
3 siblings, 0 replies; 11+ messages in thread
From: Roman Khromenok @ 2026-10-08 18:02 UTC (permalink / raw)
To: dev; +Cc: thomas, andrew.rybchenko, stephen
Check that the SFF-8472 Rx loss of signal and Tx fault state
are not reported if the module does not advertise them,
and that each one is mapped to the right bit of the status byte.
Signed-off-by: Roman Khromenok <roma55592@yandex.ru>
---
app/test/test_ethdev_module_eeprom.c | 40 ++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/app/test/test_ethdev_module_eeprom.c b/app/test/test_ethdev_module_eeprom.c
index 1cad8ede97..25307678a1 100644
--- a/app/test/test_ethdev_module_eeprom.c
+++ b/app/test/test_ethdev_module_eeprom.c
@@ -243,6 +243,45 @@ test_module_eeprom_qsfp_8636_thresholds(void)
return TEST_SUCCESS;
}
+/* SFF-8472 status bits and their implemented bits */
+#define SFP_ENH_OPTIONS 93
+#define SFP_A2_STATUS 110
+
+static int
+test_module_eeprom_sfp_8472_status(void)
+{
+ uint8_t data[RTE_ETH_MODULE_SFF_8472_LEN];
+ uint8_t *a2 = data + RTE_ETH_MODULE_SFF_8079_LEN;
+
+ /* state is raised but the module does not advertise it */
+ fill_sfp(data);
+ a2[SFP_A2_STATUS] = 0x06;
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8472, data, sizeof(data)),
+ "Failed to parse SFF-8472 data");
+ CHECK_NO_FIELD("Rx loss of signal");
+ CHECK_NO_FIELD("Tx fault");
+
+ data[SFP_ENH_OPTIONS] |= 0x30; /* soft Tx fault and Rx LOS monitoring */
+ a2[SFP_A2_STATUS] = 0;
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8472, data, sizeof(data)),
+ "Failed to parse SFF-8472 data without status bits");
+ CHECK_FIELD("Rx loss of signal", "None");
+ CHECK_FIELD("Tx fault", "None");
+
+ a2[SFP_A2_STATUS] = 0x02; /* Rx LOS */
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8472, data, sizeof(data)),
+ "Failed to parse SFF-8472 data with Rx LOS");
+ CHECK_FIELD("Rx loss of signal", "[ Yes ]");
+ CHECK_FIELD("Tx fault", "None");
+
+ a2[SFP_A2_STATUS] = 0x04; /* Tx fault */
+ TEST_ASSERT_SUCCESS(parse(RTE_ETH_MODULE_SFF_8472, data, sizeof(data)),
+ "Failed to parse SFF-8472 data with Tx fault");
+ CHECK_FIELD("Rx loss of signal", "None");
+ CHECK_FIELD("Tx fault", "[ Yes ]");
+ return TEST_SUCCESS;
+}
+
/* SFF-8636 lower page channel status flags and their implemented bits */
#define QSFP_LOS_FLAGS 3
#define QSFP_FAULT_FLAGS 4
@@ -527,6 +566,7 @@ static struct unit_test_suite module_eeprom_testsuite = {
TEST_CASE(test_module_eeprom_sfp_8472_cal_saturate_max),
TEST_CASE(test_module_eeprom_sfp_8472_cal_saturate_min),
TEST_CASE(test_module_eeprom_sfp_8472_cal_round),
+ TEST_CASE(test_module_eeprom_sfp_8472_status),
TEST_CASE(test_module_eeprom_qsfp_8636),
TEST_CASE(test_module_eeprom_qsfp_8636_thresholds),
TEST_CASE(test_module_eeprom_qsfp_8636_signals_not_implemented),
--
2.47.3
^ permalink raw reply related [flat|nested] 11+ messages in thread