DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] ethdev: report module signal status flags
@ 2026-10-08  8:23 Roman Khromenok
  2026-10-08  8:23 ` [PATCH 1/4] ethdev: report SFF-8636 lane " Roman Khromenok
                   ` (5 more replies)
  0 siblings, 6 replies; 15+ messages in thread
From: Roman Khromenok @ 2026-10-08  8:23 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 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

 app/test/test_ethdev_module_eeprom.c   | 117 +++++++++++++++++++++++++
 doc/guides/rel_notes/release_26_11.rst |   3 +
 lib/ethdev/sff_8472.c                  |  16 ++++
 lib/ethdev/sff_8636.c                  |  35 ++++++++
 lib/ethdev/sff_8636.h                  |  12 +++
 lib/ethdev/sff_common.c                |  25 ++++++
 lib/ethdev/sff_common.h                |   2 +
 7 files changed, 210 insertions(+)

-- 
2.47.3


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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
                     ` (4 more replies)
  5 siblings, 5 replies; 15+ 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] 15+ 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
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 15+ 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] 15+ 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
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 15+ 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] 15+ 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
  2026-10-09 18:22   ` [PATCH v2 0/4] ethdev: report module signal status flags Stephen Hemminger
  4 siblings, 0 replies; 15+ 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] 15+ 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
  2026-10-09 18:22   ` [PATCH v2 0/4] ethdev: report module signal status flags Stephen Hemminger
  4 siblings, 0 replies; 15+ 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] 15+ messages in thread

* Re: [PATCH v2 0/4] ethdev: report module signal status flags
  2026-10-08 18:02 ` [PATCH v2 " Roman Khromenok
                     ` (3 preceding siblings ...)
  2026-10-08 18:02   ` [PATCH v2 4/4] test: check " Roman Khromenok
@ 2026-10-09 18:22   ` Stephen Hemminger
  2026-10-09 19:21     ` Roman Khromenok
  4 siblings, 1 reply; 15+ messages in thread
From: Stephen Hemminger @ 2026-10-09 18:22 UTC (permalink / raw)
  To: Roman Khromenok; +Cc: dev, thomas, andrew.rybchenko

On Thu,  8 Oct 2026 20:02:34 +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 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")


Applied to next-net.

I wonder if the eeprom really belongs in its on library, really it is not
part of standard ethdev.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/4] ethdev: report module signal status flags
  2026-10-09 18:22   ` [PATCH v2 0/4] ethdev: report module signal status flags Stephen Hemminger
@ 2026-10-09 19:21     ` Roman Khromenok
  2026-10-09 20:34       ` Thomas Monjalon
  0 siblings, 1 reply; 15+ messages in thread
From: Roman Khromenok @ 2026-10-09 19:21 UTC (permalink / raw)
  To: dev; +Cc: stephen, thomas, andrew.rybchenko

On Fri, 9 Oct 2026, Stephen Hemminger wrote:
> Applied to next-net.
>
> I wonder if the eeprom really belongs in its on library, really it is not
> part of standard ethdev.

Thanks, Stephen.

Agreed, the decoder does not need a device: it only parses a buffer
and works without EAL. Only rte_eth_dev_get_module_eeprom() and the
telemetry command are really ethdev.

If Thomas and Andrew are fine with it, I can send an RFC for 27.03
moving the SFF decoders into a small library with its own API, with
the ethdev telemetry command on top of it. rte_eth_module_eeprom_parse()
is experimental, so it can stay as a thin wrapper or be removed.
A separate library would also be the place for CMIS (QSFP-DD, OSFP)
decoding later, which does not fit the SFF naming, so a neutral name
like lib/xcvr may be better than lib/sff.

I am willing to maintain this library.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/4] ethdev: report module signal status flags
  2026-10-09 19:21     ` Roman Khromenok
@ 2026-10-09 20:34       ` Thomas Monjalon
  2026-10-09 20:57         ` Roman Khromenok
  0 siblings, 1 reply; 15+ messages in thread
From: Thomas Monjalon @ 2026-10-09 20:34 UTC (permalink / raw)
  To: Roman Khromenok; +Cc: dev, stephen, andrew.rybchenko

09/10/2026 21:21, Roman Khromenok:
> On Fri, 9 Oct 2026, Stephen Hemminger wrote:
> > Applied to next-net.
> >
> > I wonder if the eeprom really belongs in its on library, really it is not
> > part of standard ethdev.
> 
> Thanks, Stephen.
> 
> Agreed, the decoder does not need a device: it only parses a buffer
> and works without EAL. Only rte_eth_dev_get_module_eeprom() and the
> telemetry command are really ethdev.
> 
> If Thomas and Andrew are fine with it, I can send an RFC for 27.03
> moving the SFF decoders into a small library with its own API, with
> the ethdev telemetry command on top of it. rte_eth_module_eeprom_parse()
> is experimental, so it can stay as a thin wrapper or be removed.
> A separate library would also be the place for CMIS (QSFP-DD, OSFP)
> decoding later, which does not fit the SFF naming, so a neutral name
> like lib/xcvr may be better than lib/sff.
> 
> I am willing to maintain this library.

This is specific to networking devices, right?
So it has to be linked with ethdev probably.
But if it is not specific to any driver,
we may consider moving it to separate library.
I'm not sure which place is best.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/4] ethdev: report module signal status flags
  2026-10-09 20:34       ` Thomas Monjalon
@ 2026-10-09 20:57         ` Roman Khromenok
  0 siblings, 0 replies; 15+ messages in thread
From: Roman Khromenok @ 2026-10-09 20:57 UTC (permalink / raw)
  To: dev; +Cc: thomas, stephen, andrew.rybchenko

On Fri, 9 Oct 2026, Thomas Monjalon wrote:
> This is specific to networking devices, right?
> So it has to be linked with ethdev probably.
> But if it is not specific to any driver,
> we may consider moving it to separate library.
> I'm not sure which place is best.

Yes, these are the pluggable transceivers of network ports, but
nothing in the decoding is driver specific. Drivers only return
the raw EEPROM bytes through the get_module_eeprom op, and the
decoding follows the SFF specifications. The decoder (about 2700
lines) uses ethdev only for the RTE_ETH_MODULE_SFF_* type values
and the callback typedef.

So ethdev would keep linking it, the same way it depends on net
and meter: ethdev depends on the new library, not the other way.
rte_eth_dev_get_module_eeprom() and the telemetry command stay
in ethdev and call the library.

The decoder is also useful for ports which are not ethdev ports:
in our firewall, the kernel ports are read with the ethtool ioctls
and decoded with a copy of the same code. This already works with
rte_eth_module_eeprom_parse(), so a separate library is mostly
about keeping ethdev smaller, especially when CMIS is added,
which is about the size of the SFF-8636 decoder.

Keeping it in ethdev is fine with me too. If you prefer that,
I will add CMIS there.

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-10-09 20:58 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 3/4] ethdev: report SFF-8472 Rx LOS and Tx fault state Roman Khromenok
2026-10-08  8:23 ` [PATCH 4/4] test: check " 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
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   ` [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
2026-10-09 18:22   ` [PATCH v2 0/4] ethdev: report module signal status flags Stephen Hemminger
2026-10-09 19:21     ` Roman Khromenok
2026-10-09 20:34       ` Thomas Monjalon
2026-10-09 20:57         ` Roman Khromenok

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox