DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/13] net/txgbe: fix e56 PHY configuration error
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
@ 2026-08-27 11:41 ` Zaiyu Wang
  2026-08-27 11:41 ` [PATCH 02/13] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:41 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

The e56 PHY RXS ring equalizer/tap configuration is written to the
wrong bit field: set_fields_e56(&rdata, 9, 4, 0x366) targets the
unrelated lower bits, so the configured tap values are never applied
and the equalizer stays at its default setting, which can degrade
the received signal on both the 40G and 10G paths.

Fix the field range to (21, 12), so the equalizer/tap configuration
takes effect.

Fixes: f7cfc21e9f75 ("net/txgbe: fix link stability for 40G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_e56.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index cbcc05333e..2711863f2c 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -423,7 +423,7 @@ u32 txgbe_e56_cfg_40g(struct txgbe_hw *hw)
 
 		addr  = E56PHY_RXS_RINGO_0_ADDR + (E56PHY_RXS_OFFSET * i);
 		rdata = rd32_ephy(hw, addr);
-		set_fields_e56(&rdata, 9, 4, 0x366);
+		set_fields_e56(&rdata, 21, 12, 0x366);
 		wr32_ephy(hw, addr, rdata);
 	}
 
-- 
2.55.0.windows.2


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

* [PATCH 02/13] net/txgbe: fix incorrect link state in 10G forced mode
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
  2026-08-27 11:41 ` [PATCH 01/13] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
@ 2026-08-27 11:41 ` Zaiyu Wang
  2026-08-27 11:41 ` [PATCH 03/13] net/txgbe: do not force reconfig on link retry Zaiyu Wang
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:41 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

When an AML40 port is configured in 10G forced mode (auto_neg=0),
the hardware can link up but the driver keeps reporting link down
after a peer link failure: link_valid is cleared on timeout but
never restored when the peer recovers, so the link stays down until
the port is restarted.

Restore hw->link_valid = true in the success path of
txgbe_setup_phy_link_aml40(), symmetric to the 40G path.

Fixes: f7cfc21e9f75 ("net/txgbe: fix link stability for 40G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 1098efe5e6..05eac68f3b 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -197,6 +197,8 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
 	ret_status = txgbe_set_link_to_amlite(hw, speed);
 	if (ret_status == TXGBE_ERR_TIMEOUT)
 		hw->link_valid = false;
+	else
+		hw->link_valid = true;
 	rte_spinlock_unlock(&hw->phy_lock);
 
 	for (i = 0; i < 4; i++) {
-- 
2.55.0.windows.2


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

* [PATCH 03/13] net/txgbe: do not force reconfig on link retry
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
  2026-08-27 11:41 ` [PATCH 01/13] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
  2026-08-27 11:41 ` [PATCH 02/13] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
@ 2026-08-27 11:41 ` Zaiyu Wang
  2026-08-27 11:41 ` [PATCH 04/13] net/txgbe: set i2c sda hold time Zaiyu Wang
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:41 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

The link alarm retry calls mac.setup_link() with
autoneg_wait_to_complete = true. On the AN73/xpcs path, setup_link
skips reconfiguration when the link is already up and AN is done
only if the flag is false. With true, a retry that arrives after the
link is up still runs set_phy_link_mode() and resets the established
AN73 link, which then drops and never recovers (e.g. after DAC
hot-plug).

Pass false from the retry path instead.

Fixes: 6104fd11086e ("net/txgbe: fix link stability for 25G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_ethdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 4d2746371b..b0d2bc3450 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3286,7 +3286,7 @@ txgbe_dev_setup_link_alarm_handler_aml(void *param)
 		return;
 	}
 
-	hw->mac.setup_link(hw, speed, true);
+	hw->mac.setup_link(hw, speed, false);
 
 	u32 link_speed = TXGBE_LINK_SPEED_UNKNOWN;
 	bool link_up = false;
-- 
2.55.0.windows.2


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

* [PATCH 04/13] net/txgbe: set i2c sda hold time
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (2 preceding siblings ...)
  2026-08-27 11:41 ` [PATCH 03/13] net/txgbe: do not force reconfig on link retry Zaiyu Wang
@ 2026-08-27 11:41 ` Zaiyu Wang
  2026-08-27 11:41 ` [PATCH 05/13] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:41 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

The data_in_hold_time measured on the oscilloscope does not meet the
hardware requirement, which can corrupt SFP EEPROM reads over I2C.

Set the I2C SDA hold time to 100 (0x64) I2C clock periods for both
RX and TX in txgbe_i2c_start().

Fixes: 00970f6398c8 ("net/txgbe: fix reading SFP module SFF-8472 data")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_phy.c  | 3 +++
 drivers/net/txgbe/base/txgbe_regs.h | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index 2fbe50e242..8b653f0aeb 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1334,6 +1334,9 @@ static void txgbe_i2c_start(struct txgbe_hw *hw, u8 dev_addr)
 	wr32(hw, TXGBE_I2CSCLTMOUT, 0xFFFFFF);
 	wr32(hw, TXGBE_I2CSDATMOUT, 0xFFFFFF);
 
+	wr32m(hw, TXGBE_I2C_SDA_HOLD,
+		TXGBE_I2C_SDA_RX_HOLD | TXGBE_I2C_SDA_TX_HOLD, 0x640064);
+
 	wr32(hw, TXGBE_I2CICM, 0);
 	wr32(hw, TXGBE_I2CENA, 1);
 }
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index bf46a80862..b0042dc0d6 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -1610,6 +1610,9 @@ enum txgbe_5tuple_protocol {
 #define   TXGBE_I2CSTAT_MST          ((1U << 5))
 #define TXGBE_I2CSCLTMOUT            0x0149AC
 #define TXGBE_I2CSDATMOUT            0x0149B0 /*I2C SDA Stuck at Low Timeout*/
+#define TXGBE_I2C_SDA_HOLD              0x1497C /* SDA hold time length reg */
+#define TXGBE_I2C_SDA_RX_HOLD           0xff0000 /* SDA rx hold time length reg */
+#define TXGBE_I2C_SDA_TX_HOLD           0xffff /* SDA tx hold time length reg */
 
 /* port cfg Registers */
 #define TXGBE_PORTSTAT                  0x014404
-- 
2.55.0.windows.2


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

* [PATCH 05/13] net/txgbe: fix link speed display info for 10G mode
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (3 preceding siblings ...)
  2026-08-27 11:41 ` [PATCH 04/13] net/txgbe: set i2c sda hold time Zaiyu Wang
@ 2026-08-27 11:41 ` Zaiyu Wang
  2026-08-27 11:41 ` [PATCH 06/13] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:41 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

When an AML40 port links up at 10G, DPDK reports the speed as 100M
instead of 10G. The 10G link status bit is not recognized in
txgbe_check_mac_link_aml40(), so any non-40G speed falls through to
the default case (UNKNOWN) which is then reported as 100M.

Add the 10G port status bit recognition, and include 10G in the
default advertised speed mask in txgbe_dev_start() so a 10G link is
reported with the correct speed.

Fixes: abf042d32b39 ("net/txgbe: add Amber-Lite 25G/40G NICs")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c | 3 +++
 drivers/net/txgbe/txgbe_ethdev.c     | 3 ++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 05eac68f3b..90d4453b06 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -85,6 +85,9 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
 		if ((links_reg & TXGBE_CFG_PORT_ST_AML_LINK_40G) ==
 			TXGBE_CFG_PORT_ST_AML_LINK_40G)
 			*speed = TXGBE_LINK_SPEED_40GB_FULL;
+		else if ((links_reg & TXGBE_CFG_PORT_ST_AML_LINK_10G) ==
+			TXGBE_CFG_PORT_ST_AML_LINK_10G)
+			*speed = TXGBE_LINK_SPEED_10GB_FULL;
 	} else {
 		*speed = TXGBE_LINK_SPEED_UNKNOWN;
 	}
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index b0d2bc3450..ae755996e6 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -1912,7 +1912,8 @@ txgbe_dev_start(struct rte_eth_dev *dev)
 	speed = 0x0;
 	if (*link_speeds == RTE_ETH_LINK_SPEED_AUTONEG) {
 		if (hw->mac.type == txgbe_mac_aml40) {
-			speed = TXGBE_LINK_SPEED_40GB_FULL;
+			speed = TXGBE_LINK_SPEED_40GB_FULL |
+				TXGBE_LINK_SPEED_10GB_FULL;
 		} else  if (hw->mac.type == txgbe_mac_aml) {
 			speed = (TXGBE_LINK_SPEED_10GB_FULL |
 				 TXGBE_LINK_SPEED_25GB_FULL);
-- 
2.55.0.windows.2


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

* [PATCH 06/13] net/txgbe: remove stale outer UDP checksum offload flag
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (4 preceding siblings ...)
  2026-08-27 11:41 ` [PATCH 05/13] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
@ 2026-08-27 11:41 ` Zaiyu Wang
  2026-08-27 11:41 ` [PATCH 07/13] net/txgbe: add offload support for tunnel type UDP Zaiyu Wang
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:41 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

RTE_MBUF_F_TX_OUTER_UDP_CKSUM is no longer advertised in
dev_info->tx_offload_capa, but it is still listed in
TXGBE_TX_OFFLOAD_MASK. The two are now inconsistent: a packet
carrying the flag is accepted by the offload mask check although the
driver no longer handles it.

Drop the flag from TXGBE_TX_OFFLOAD_MASK so the advertised
capability and the accepted offload flags match.

Fixes: 25fe1c780d39 ("net/txgbe: remove outer UDP checksum capability")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_rxtx.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index 794ba041a4..a295666f9d 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -61,7 +61,6 @@ static const u64 TXGBE_TX_OFFLOAD_MASK = (RTE_MBUF_F_TX_IP_CKSUM |
 		RTE_MBUF_F_TX_UDP_SEG |
 		RTE_MBUF_F_TX_TUNNEL_MASK |
 		RTE_MBUF_F_TX_OUTER_IP_CKSUM |
-		RTE_MBUF_F_TX_OUTER_UDP_CKSUM |
 #ifdef RTE_LIB_SECURITY
 		RTE_MBUF_F_TX_SEC_OFFLOAD |
 #endif
-- 
2.55.0.windows.2


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

* [PATCH 07/13] net/txgbe: add offload support for tunnel type UDP
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (5 preceding siblings ...)
  2026-08-27 11:41 ` [PATCH 06/13] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
@ 2026-08-27 11:41 ` Zaiyu Wang
  2026-08-27 11:42 ` [PATCH 08/13] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:41 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

The non-standard RTE_MBUF_F_TX_TUNNEL_UDP tunnel type (UDP
encapsulation carrying either VXLAN or GENEVE) is not handled:
txgbe_set_xmit_ctx() falls into the "unknown tunnel type" case and
txgbe_get_tun_len() cannot compute the tunnel length, so tunneled
packets are sent with a wrong descriptor or dropped.

Handle RTE_MBUF_F_TX_TUNNEL_UDP by parsing the UDP destination port
(6081 -> GENEVE, otherwise VXLAN) to select the inner tunnel type, so
the correct tunnel length and packet type are reported.

Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_rxtx.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index a295666f9d..cd958b4aab 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -419,6 +419,7 @@ txgbe_set_xmit_ctx(struct txgbe_tx_queue *txq,
 			break;
 		case RTE_MBUF_F_TX_TUNNEL_VXLAN:
 		case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+		case RTE_MBUF_F_TX_TUNNEL_UDP:
 		case RTE_MBUF_F_TX_TUNNEL_GENEVE:
 			tunnel_seed |= TXGBE_TXD_ETYPE_UDP;
 			break;
@@ -593,6 +594,7 @@ tx_desc_ol_flags_to_ptype(uint64_t oflags)
 	switch (oflags & RTE_MBUF_F_TX_TUNNEL_MASK) {
 	case RTE_MBUF_F_TX_TUNNEL_VXLAN:
 	case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+	case RTE_MBUF_F_TX_TUNNEL_UDP:
 		ptype |= RTE_PTYPE_TUNNEL_GRENAT;
 		break;
 	case RTE_MBUF_F_TX_TUNNEL_GRE:
@@ -713,8 +715,21 @@ txgbe_get_tun_len(struct rte_mbuf *mbuf)
 	const struct txgbe_genevehdr *gh;
 	const struct txgbe_grehdr *grh;
 	struct txgbe_grehdr grehdr;
+	struct txgbe_udphdr udphdr;
+	const struct txgbe_udphdr *uh;
 	uint8_t tun_len;
 
+	/* Check for UDP tunneling */
+	if ((mbuf->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) == RTE_MBUF_F_TX_TUNNEL_UDP) {
+		mbuf->ol_flags &= ~RTE_MBUF_F_TX_TUNNEL_UDP;
+		uh = rte_pktmbuf_read(mbuf, mbuf->outer_l2_len + mbuf->outer_l3_len,
+				      sizeof(udphdr), &udphdr);
+		if (uh->dest == rte_cpu_to_be_16(6081))
+			mbuf->ol_flags |= RTE_MBUF_F_TX_TUNNEL_GENEVE;
+		else
+			mbuf->ol_flags |= RTE_MBUF_F_TX_TUNNEL_VXLAN;
+	}
+
 	switch (mbuf->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
 	case RTE_MBUF_F_TX_TUNNEL_IPIP:
 		tun_len = 0;
-- 
2.55.0.windows.2


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

* [PATCH 08/13] net/txgbe: fix SFP hot-plug when auto-negotiation is on
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (6 preceding siblings ...)
  2026-08-27 11:41 ` [PATCH 07/13] net/txgbe: add offload support for tunnel type UDP Zaiyu Wang
@ 2026-08-27 11:42 ` Zaiyu Wang
  2026-08-27 11:42 ` [PATCH 09/13] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:42 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

When a port is started before the DAC cable is plugged in,
hot-plugging the cable never brings the link up and the port has to
be stopped and started again.

The AN73 watchdog txgbe_dev_e56_check_bp_event() is armed once in
txgbe_dev_start(). Its first tick finds no module, so
txgbe_xpcs_an_enabled() returns false and the handler returns without
re-arming itself. Once the cable is inserted, nobody polls the AN73
completion any more and the link stays down.

Re-arm the watchdog from txgbe_dev_detect_sfp() once a module has
been identified, cancelling any pending instance first so that only
one of them is running at a time. On the removal path, drop the
cached SFP type and cancel the watchdog. Also sample the
module-present pin (GPIO_EXT bit 2 on 25G, bit 4 on 40G) on every
watchdog tick, so that pulling the cable is noticed even if no GPIO
interrupt is delivered.

Fixes: 234ce0d1fa9d ("net/txgbe: fix link stability for Amber-Lite backplane mode")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_ethdev.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index ae755996e6..9a29539f14 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2987,6 +2987,20 @@ void txgbe_dev_e56_check_bp_event(void *param)
 	if (!hw)
 		return;
 
+	/* Sample the module-present pin on every tick. When the cable is
+	 * pulled, drop the cached SFP type so that txgbe_xpcs_an_enabled()
+	 * turns false and this alarm stops re-arming itself.
+	 */
+	if (hw->mac.type == txgbe_mac_aml)
+		value = rd32(hw, TXGBE_GPIOEXT) & TXGBE_SFP1_MOD_ABS_LS;
+	else if (hw->mac.type == txgbe_mac_aml40)
+		value = rd32(hw, TXGBE_GPIOEXT) & TXGBE_SFP1_MOD_PRST_LS;
+
+	if (value != 0 && hw->phy.sfp_type != txgbe_sfp_type_not_present) {
+		PMD_DRV_LOG(INFO, "SFP module removed, stop AN73 watchdog.");
+		hw->phy.sfp_type = txgbe_sfp_type_not_present;
+	}
+
 	if (!(txgbe_xpcs_an_enabled(hw)))
 		return;
 
@@ -3110,10 +3124,22 @@ txgbe_dev_detect_sfp(void *param)
 		PMD_DRV_LOG(ERR, "Unsupported SFP+ module type was detected.");
 	} else if (err == TXGBE_ERR_SFP_NOT_PRESENT) {
 		PMD_DRV_LOG(INFO, "SFP not present.");
+		/* Module removed: drop the cached type and stop the watchdog. */
+		hw->phy.sfp_type = txgbe_sfp_type_not_present;
+		rte_eal_alarm_cancel(txgbe_dev_e56_check_bp_event, dev);
 	} else if (err == 0) {
 		hw->mac.setup_sfp(hw);
 		PMD_DRV_LOG(INFO, "detected SFP+: %d", hw->phy.sfp_type);
 		txgbe_dev_setup_link_alarm_handler(dev);
+		/* Re-arm the AN73 watchdog for the newly inserted module, so
+		 * that only one instance of it is running at a time.
+		 */
+		if (hw->mac.type == txgbe_mac_aml ||
+		    hw->mac.type == txgbe_mac_aml40) {
+			rte_eal_alarm_cancel(txgbe_dev_e56_check_bp_event, dev);
+			rte_eal_alarm_set(hw->bp_event_interval,
+					  txgbe_dev_e56_check_bp_event, dev);
+		}
 		txgbe_dev_link_update(dev, 0);
 	}
 }
-- 
2.55.0.windows.2


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

* [PATCH 09/13] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (7 preceding siblings ...)
  2026-08-27 11:42 ` [PATCH 08/13] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
@ 2026-08-27 11:42 ` Zaiyu Wang
  2026-08-27 11:42 ` [PATCH 10/13] net/txgbe: add backplane FFE and capability devargs Zaiyu Wang
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:42 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

Hot-plugging a DAC cable while an Amber-Lite 40G port is running
does not bring the link up. Two problems are in the way.

First, the 40G NIC never delivers the GPIO interrupt for module
insertion or removal, so txgbe_dev_detect_sfp() is not called and the
new module is never identified (the 25G part is not affected). Poll
the module-present level every 2 seconds instead. The poll skips the
identify step while the level is unchanged, and only re-arms itself
while the port is started, so that it cannot survive txgbe_dev_stop().

Second, when the port is started with no module plugged in,
txgbe_set_link_to_amlite() times out and leaves hw->link_valid false.
The xpcs path of txgbe_setup_phy_link_aml40() never restores it, so
txgbe_e56_check_phy_link() and txgbe_check_mac_link_aml40() keep
forcing the link down even once AN73 has brought it up. Restore
link_valid on the xpcs path, as the non-xpcs path already does.

Fixes: a2d92608d3b0 ("net/txgbe: add GPIO configuration")
Fixes: f7cfc21e9f75 ("net/txgbe: fix link stability for 40G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c |  7 +++++++
 drivers/net/txgbe/txgbe_ethdev.c     | 17 ++++++++++++++++-
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 90d4453b06..bfb8a4bc7f 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -176,6 +176,13 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
 		rte_spinlock_lock(&hw->phy_lock);
 		txgbe_e56_set_phy_link_mode(hw, 40, autoneg_wait_to_complete);
 		rte_spinlock_unlock(&hw->phy_lock);
+		/* Restore link_valid, as the non-xpcs path below does. An
+		 * earlier txgbe_set_link_to_amlite() timeout, for example when
+		 * the port was started with no module plugged in, left it
+		 * false, which keeps the check_phy_link and check_mac_link
+		 * gates forcing the link down even after AN73 brings it up.
+		 */
+		hw->link_valid = true;
 		return status;
 	}
 
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 9a29539f14..38c58323e7 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2015,6 +2015,11 @@ txgbe_dev_start(struct rte_eth_dev *dev)
 	if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) {
 		rte_eal_alarm_set(hw->bp_event_interval, txgbe_dev_e56_check_bp_event, dev);
 		rte_eal_alarm_set(1000 * 1000 * 2, txgbe_dev_check_aml_temp_event, dev);
+		/* The 40G NIC does not deliver a GPIO interrupt on module
+		 * insertion or removal, so poll the module-present level.
+		 */
+		if (hw->mac.type == txgbe_mac_aml40 && !txgbe_is_backplane(hw))
+			rte_eal_alarm_set(2000 * 1000, txgbe_dev_detect_sfp, dev);
 	}
 
 	if (tm_conf->root && !tm_conf->committed)
@@ -3096,7 +3101,7 @@ txgbe_dev_detect_sfp(void *param)
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
 	struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
 	u32 value = 0;
-	s32 err;
+	s32 err = 0;
 
 	if (hw->mac.type == txgbe_mac_aml40) {
 		value = rd32(hw, TXGBE_GPIOEXT);
@@ -3104,6 +3109,11 @@ txgbe_dev_detect_sfp(void *param)
 			err = TXGBE_ERR_SFP_NOT_PRESENT;
 			goto out;
 		}
+		/* The level is unchanged since the last poll, so the cached
+		 * module type is still valid and identify can be skipped.
+		 */
+		if (hw->phy.sfp_type != txgbe_sfp_type_not_present)
+			goto rearm;
 	}
 
 	if (hw->mac.type == txgbe_mac_aml) {
@@ -3142,6 +3152,11 @@ txgbe_dev_detect_sfp(void *param)
 		}
 		txgbe_dev_link_update(dev, 0);
 	}
+
+rearm:
+	if (hw->mac.type == txgbe_mac_aml40 && !txgbe_is_backplane(hw) &&
+	    dev->data->dev_started)
+		rte_eal_alarm_set(2000 * 1000, txgbe_dev_detect_sfp, dev);
 }
 
 static void
-- 
2.55.0.windows.2



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

* [PATCH 10/13] net/txgbe: add backplane FFE and capability devargs
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (8 preceding siblings ...)
  2026-08-27 11:42 ` [PATCH 09/13] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
@ 2026-08-27 11:42 ` Zaiyu Wang
  2026-08-27 11:42 ` [PATCH 11/13] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:42 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

Two backplane configuration knobs are missing.

The 25G E56 PHY has a second pre-cursor tap that cannot be tuned:
with ffe_set enabled, the pre2 value is never applied. On the 40G
PHY, a user supplied FFE value only reaches the first lane, because
the register holds one FFE byte per lane and the value is not
replicated over the four lanes.

The advertised 40G backplane capability is hardwired to KR4+CR4;
there is no way to advertise only 40GBASE-KR4 or only 40GBASE-CR4.

Add the ffe_pre2 and bp_capa devargs, use the E56 PHY FFE defaults
for AML/AML40 when ffe_set is enabled, and replicate the user FFE
value over the four 40G lanes. The devargs are parsed after the
shared code init so the MAC type is known when picking the defaults.

Fixes: 6104fd11086e ("net/txgbe: fix link stability for 25G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 doc/guides/nics/txgbe.rst           | 11 ++++++++
 drivers/net/txgbe/base/txgbe_e56.h  |  5 ++++
 drivers/net/txgbe/base/txgbe_type.h | 12 ++++++---
 drivers/net/txgbe/txgbe_ethdev.c    | 39 +++++++++++++++++++++++++++--
 4 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/doc/guides/nics/txgbe.rst b/doc/guides/nics/txgbe.rst
index 90c55141f1..d56fb3b99a 100644
--- a/doc/guides/nics/txgbe.rst
+++ b/doc/guides/nics/txgbe.rst
@@ -142,6 +142,11 @@ Please note that following ``devargs`` are only set for backplane NICs.
   PHY parameter used for user debugging. Setting other values to
   take effect requires setting the ``ffe_set``.
 
+- ``ffe_pre2`` (default **0**)
+
+  PHY parameter used for user debugging, only for the Amber-Lite E56 PHY.
+  Setting other values to take effect requires setting the ``ffe_set``.
+
 - ``ffe_post`` (default **44**)
 
   PHY parameter used for user debugging. Setting other values to
@@ -177,6 +182,12 @@ Please note that following ``devargs`` are only set for Amber-Lite NICs.
   In this mode, the hardware merges and writes back a group of RX descriptors
   together to reduce memory access times, which helps improve performance.
 
+- ``bp_capa`` (default **0**)
+
+  Backplane capability selection for the 40G NIC. Set 0 for both
+  40GBASE-KR4 and 40GBASE-CR4, set 1 for 40GBASE-KR4 only, set 2 for
+  40GBASE-CR4 only.
+
 Driver compilation and testing
 ------------------------------
 
diff --git a/drivers/net/txgbe/base/txgbe_e56.h b/drivers/net/txgbe/base/txgbe_e56.h
index 1922a2eb92..fe9a83ae01 100644
--- a/drivers/net/txgbe/base/txgbe_e56.h
+++ b/drivers/net/txgbe/base/txgbe_e56.h
@@ -1714,6 +1714,11 @@ typedef union {
 #define S40G_TX_FFE_CFG_PRE2        0x0
 #define S40G_TX_FFE_CFG_POST        0x11111111
 
+/* The 40G PHY holds one FFE byte per lane, so a user supplied value has to
+ * be replicated over the four lanes.
+ */
+#define S40G_TX_FFE_4LANE(v)        ((u32)((v) & 0xFF) * 0x01010101u)
+
 #define BYPASS_CTLE_TAG             0x0
 
 #define S10G_PHY_RX_CTLE_TAPWT_WEIGHT1      0x1
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index f9b5cbe61a..f56cd70c6f 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -739,10 +739,10 @@ struct txgbe_phy_info {
 
 	/* Some features need tri-state capability */
 	u16 ffe_set;
-	u16 ffe_main;
-	u16 ffe_pre;
-	u16 ffe_pre2;
-	u16 ffe_post;
+	u32 ffe_main;
+	u32 ffe_pre;
+	u32 ffe_pre2; /* only for the Amber-Lite E56 PHY */
+	u32 ffe_post;
 	u16 fec_mode;
 	u16 bp_capa;
 };
@@ -754,12 +754,14 @@ struct txgbe_phy_info {
 #define TXGBE_DEVARG_FFE_SET		"ffe_set"
 #define TXGBE_DEVARG_FFE_MAIN		"ffe_main"
 #define TXGBE_DEVARG_FFE_PRE		"ffe_pre"
+#define TXGBE_DEVARG_FFE_PRE2		"ffe_pre2"
 #define TXGBE_DEVARG_FFE_POST		"ffe_post"
 #define TXGBE_DEVARG_FDIR_PBALLOC	"pkt-filter-size"
 #define TXGBE_DEVARG_FDIR_DROP_QUEUE	"pkt-filter-drop-queue"
 #define TXGBE_DEVARG_TX_HEAD_WB		"tx_headwb"
 #define TXGBE_DEVARG_TX_HEAD_WB_SIZE	"tx_headwb_size"
 #define TXGBE_DEVARG_RX_DESC_MERGE	"rx_desc_merge"
+#define TXGBE_DEVARG_BP_CAPA		"bp_capa"
 
 static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_BP_AUTO,
@@ -769,12 +771,14 @@ static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_FFE_SET,
 	TXGBE_DEVARG_FFE_MAIN,
 	TXGBE_DEVARG_FFE_PRE,
+	TXGBE_DEVARG_FFE_PRE2,
 	TXGBE_DEVARG_FFE_POST,
 	TXGBE_DEVARG_FDIR_PBALLOC,
 	TXGBE_DEVARG_FDIR_DROP_QUEUE,
 	TXGBE_DEVARG_TX_HEAD_WB,
 	TXGBE_DEVARG_TX_HEAD_WB_SIZE,
 	TXGBE_DEVARG_RX_DESC_MERGE,
+	TXGBE_DEVARG_BP_CAPA,
 	NULL
 };
 
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 38c58323e7..181a1df523 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -531,6 +531,7 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 ffe_set = 0;
 	u16 ffe_main = 27;
 	u16 ffe_pre = 8;
+	u16 ffe_pre2 = 0;
 	u16 ffe_post = 44;
 	/* FDIR args */
 	u8 pballoc = 0;
@@ -539,6 +540,22 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 tx_headwb = 1;
 	u16 tx_headwb_size = 16;
 	u16 rx_desc_merge = 1;
+	u16 bp_capa = 0;
+
+	/* The E56 PHY needs its own FFE defaults, as the ones above only
+	 * apply to the Sapphire PHY.
+	 */
+	if (hw->mac.type == txgbe_mac_aml) {
+		ffe_main = S25G_TX_FFE_CFG_DAC_MAIN;
+		ffe_pre = S25G_TX_FFE_CFG_DAC_PRE1;
+		ffe_pre2 = S25G_TX_FFE_CFG_DAC_PRE2;
+		ffe_post = S25G_TX_FFE_CFG_DAC_POST;
+	} else if (hw->mac.type == txgbe_mac_aml40) {
+		ffe_main = S40G_TX_FFE_CFG_MAIN & 0xFF;
+		ffe_pre = S40G_TX_FFE_CFG_PRE1 & 0xFF;
+		ffe_pre2 = S40G_TX_FFE_CFG_PRE2 & 0xFF;
+		ffe_post = S40G_TX_FFE_CFG_POST & 0xFF;
+	}
 
 	if (devargs == NULL)
 		goto null;
@@ -561,6 +578,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 			   &txgbe_handle_devarg, &ffe_main);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_PRE,
 			   &txgbe_handle_devarg, &ffe_pre);
+	rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_PRE2,
+			   &txgbe_handle_devarg, &ffe_pre2);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_POST,
 			   &txgbe_handle_devarg, &ffe_post);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_FDIR_PBALLOC,
@@ -573,6 +592,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 			   &txgbe_handle_devarg, &tx_headwb_size);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_RX_DESC_MERGE,
 			   &txgbe_handle_devarg, &rx_desc_merge);
+	rte_kvargs_process(kvlist, TXGBE_DEVARG_BP_CAPA,
+			   &txgbe_handle_devarg, &bp_capa);
 	rte_kvargs_free(kvlist);
 
 null:
@@ -586,7 +607,17 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	hw->phy.ffe_set = ffe_set;
 	hw->phy.ffe_main = ffe_main;
 	hw->phy.ffe_pre = ffe_pre;
+	hw->phy.ffe_pre2 = ffe_pre2;
 	hw->phy.ffe_post = ffe_post;
+	hw->phy.bp_capa = bp_capa;
+
+	/* The 40G PHY expects one FFE byte per lane. */
+	if (hw->mac.type == txgbe_mac_aml40) {
+		hw->phy.ffe_main = S40G_TX_FFE_4LANE(ffe_main);
+		hw->phy.ffe_pre = S40G_TX_FFE_4LANE(ffe_pre);
+		hw->phy.ffe_pre2 = S40G_TX_FFE_4LANE(ffe_pre2);
+		hw->phy.ffe_post = S40G_TX_FFE_4LANE(ffe_post);
+	}
 
 	fdir_conf->pballoc = pballoc;
 	fdir_conf->drop_queue = drop_queue;
@@ -690,7 +721,6 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
 	hw->isb_dma = TMZ_PADDR(mz);
 	hw->isb_mem = TMZ_VADDR(mz);
 
-	txgbe_parse_devargs(eth_dev);
 	/* Initialize the shared code (base driver) */
 	err = txgbe_init_shared_code(hw);
 	if (err != 0) {
@@ -698,6 +728,9 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
 		return -EIO;
 	}
 
+	/* Parsing the devargs requires a known MAC type. */
+	txgbe_parse_devargs(eth_dev);
+
 	if (hw->mac.type == txgbe_mac_aml)
 		txgbe_override_mac_ops(hw);
 
@@ -6478,12 +6511,14 @@ RTE_PMD_REGISTER_PARAM_STRING(net_txgbe,
 			      TXGBE_DEVARG_FFE_SET "=<0-4>"
 			      TXGBE_DEVARG_FFE_MAIN "=<uint16>"
 			      TXGBE_DEVARG_FFE_PRE "=<uint16>"
+			      TXGBE_DEVARG_FFE_PRE2 "=<uint16>"
 			      TXGBE_DEVARG_FFE_POST "=<uint16>"
 			      TXGBE_DEVARG_FDIR_PBALLOC "=<0|1|2>"
 			      TXGBE_DEVARG_FDIR_DROP_QUEUE "=<uint8>"
 			      TXGBE_DEVARG_TX_HEAD_WB "=<0|1>"
 			      TXGBE_DEVARG_TX_HEAD_WB_SIZE "=<1|16>"
-			      TXGBE_DEVARG_RX_DESC_MERGE "=<0|1>");
+			      TXGBE_DEVARG_RX_DESC_MERGE "=<0|1>"
+			      TXGBE_DEVARG_BP_CAPA "=<0|1|2>");
 
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_init, init, NOTICE);
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_driver, driver, NOTICE);
-- 
2.55.0.windows.2


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

* [PATCH 11/13] net/txgbe: add devarg to turn off Tx laser for 40G NIC
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (9 preceding siblings ...)
  2026-08-27 11:42 ` [PATCH 10/13] net/txgbe: add backplane FFE and capability devargs Zaiyu Wang
@ 2026-08-27 11:42 ` Zaiyu Wang
  2026-08-27 11:42 ` [PATCH 12/13] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:42 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, Jiawen Wu

When the port is brought down, the Tx laser stays on, so the peer
keeps seeing a live signal and cannot detect the link loss (e.g. for
link-state tracking at the peer).

Add a laser_off devarg: when enabled, bring the Tx laser down on
port stop -- for DAC cables disable the PCS, for QSFP modules write
the Tx disable bit via I2C -- and restore the Tx enable state when
the link comes up.

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 doc/guides/nics/txgbe.rst           |  7 +++++++
 drivers/net/txgbe/base/txgbe_hw.c   | 22 ++++++++++++++++++++++
 drivers/net/txgbe/base/txgbe_type.h |  3 +++
 drivers/net/txgbe/txgbe_ethdev.c    |  7 ++++++-
 4 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/txgbe.rst b/doc/guides/nics/txgbe.rst
index d56fb3b99a..a580450726 100644
--- a/doc/guides/nics/txgbe.rst
+++ b/doc/guides/nics/txgbe.rst
@@ -188,6 +188,13 @@ Please note that following ``devargs`` are only set for Amber-Lite NICs.
   40GBASE-KR4 and 40GBASE-CR4, set 1 for 40GBASE-KR4 only, set 2 for
   40GBASE-CR4 only.
 
+- ``laser_off`` (default **0**)
+
+  Toggle behavior to disable the Tx laser when the port is brought down
+  on the 40G NIC. By default the Tx laser is left on. When enabled, for
+  DAC cables the PCS is disabled, for QSFP modules the Tx disable bit is
+  written via I2C.
+
 Driver compilation and testing
 ------------------------------
 
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 2650b8b7f1..2b44c30883 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -11,6 +11,7 @@
 #include "txgbe_eeprom.h"
 #include "txgbe_mng.h"
 #include "txgbe_hw.h"
+#include "txgbe_e56.h"
 #include "txgbe_aml.h"
 #include "txgbe_aml40.h"
 
@@ -3259,6 +3260,24 @@ void txgbe_disable_tx_laser_multispeed_fiber(struct txgbe_hw *hw)
 	if (hw->mac.type == txgbe_mac_aml40) {
 		wr32m(hw, TXGBE_GPIODIR, TXGBE_GPIOBIT_1, TXGBE_GPIOBIT_1);
 		esdp_reg &= ~TXGBE_GPIOBIT_1;
+		if (hw->devarg.laser_off) {
+			if (txgbe_is_dac_cable(hw) ||
+			    hw->phy.sfp_type == txgbe_sfp_type_unknown) {
+				u32 rdata = 0;
+
+				rte_spinlock_lock(&hw->phy_lock);
+				rdata = rd32_ephy(hw, 0x1400);
+				set_fields_e56(&rdata, 19, 16, 0x0);
+				set_fields_e56(&rdata, 15, 12, 0x0);
+				set_fields_e56(&rdata, 1, 1, 0x0);
+				wr32_ephy(hw, 0x1400, rdata);
+				rte_spinlock_unlock(&hw->phy_lock);
+			} else {
+				txgbe_acquire_swfw_sync(hw, 1);
+				hw->phy.write_i2c_eeprom(hw, 86, 0xf);
+				txgbe_release_swfw_sync(hw, 1);
+			}
+		}
 	} else if (hw->mac.type == txgbe_mac_aml) {
 		esdp_reg |= TXGBE_GPIOBIT_1;
 	} else {
@@ -3288,6 +3307,9 @@ void txgbe_enable_tx_laser_multispeed_fiber(struct txgbe_hw *hw)
 	if (hw->mac.type == txgbe_mac_aml40) {
 		wr32m(hw, TXGBE_GPIODIR, TXGBE_GPIOBIT_1, TXGBE_GPIOBIT_1);
 		esdp_reg |= TXGBE_GPIOBIT_1;
+		txgbe_acquire_swfw_sync(hw, 1);
+		hw->phy.write_i2c_eeprom(hw, 86, 0x0);
+		txgbe_release_swfw_sync(hw, 1);
 	} else {
 		esdp_reg &= ~(TXGBE_GPIOBIT_0 | TXGBE_GPIOBIT_1);
 	}
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index f56cd70c6f..39a70746a7 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -762,6 +762,7 @@ struct txgbe_phy_info {
 #define TXGBE_DEVARG_TX_HEAD_WB_SIZE	"tx_headwb_size"
 #define TXGBE_DEVARG_RX_DESC_MERGE	"rx_desc_merge"
 #define TXGBE_DEVARG_BP_CAPA		"bp_capa"
+#define TXGBE_DEVARG_LASER_OFF		"laser_off"
 
 static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_BP_AUTO,
@@ -779,6 +780,7 @@ static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_TX_HEAD_WB_SIZE,
 	TXGBE_DEVARG_RX_DESC_MERGE,
 	TXGBE_DEVARG_BP_CAPA,
+	TXGBE_DEVARG_LASER_OFF,
 	NULL
 };
 
@@ -834,6 +836,7 @@ struct txgbe_devargs {
 	u16 tx_headwb;
 	u16 tx_headwb_size;
 	u16 rx_desc_merge;
+	u16 laser_off;
 };
 
 struct txgbe_hw {
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 181a1df523..ef30e0c40a 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -541,6 +541,7 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 tx_headwb_size = 16;
 	u16 rx_desc_merge = 1;
 	u16 bp_capa = 0;
+	u16 laser_off = 0;
 
 	/* The E56 PHY needs its own FFE defaults, as the ones above only
 	 * apply to the Sapphire PHY.
@@ -594,6 +595,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 			   &txgbe_handle_devarg, &rx_desc_merge);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_BP_CAPA,
 			   &txgbe_handle_devarg, &bp_capa);
+	rte_kvargs_process(kvlist, TXGBE_DEVARG_LASER_OFF,
+			   &txgbe_handle_devarg, &laser_off);
 	rte_kvargs_free(kvlist);
 
 null:
@@ -604,6 +607,7 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	hw->devarg.tx_headwb = tx_headwb;
 	hw->devarg.tx_headwb_size = tx_headwb_size;
 	hw->devarg.rx_desc_merge = rx_desc_merge;
+	hw->devarg.laser_off = laser_off;
 	hw->phy.ffe_set = ffe_set;
 	hw->phy.ffe_main = ffe_main;
 	hw->phy.ffe_pre = ffe_pre;
@@ -6518,7 +6522,8 @@ RTE_PMD_REGISTER_PARAM_STRING(net_txgbe,
 			      TXGBE_DEVARG_TX_HEAD_WB "=<0|1>"
 			      TXGBE_DEVARG_TX_HEAD_WB_SIZE "=<1|16>"
 			      TXGBE_DEVARG_RX_DESC_MERGE "=<0|1>"
-			      TXGBE_DEVARG_BP_CAPA "=<0|1|2>");
+			      TXGBE_DEVARG_BP_CAPA "=<0|1|2>"
+			      TXGBE_DEVARG_LASER_OFF "=<0|1>");
 
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_init, init, NOTICE);
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_driver, driver, NOTICE);
-- 
2.55.0.windows.2


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

* [PATCH 12/13] net/txgbe: fix CR/KR link training and recovery
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (10 preceding siblings ...)
  2026-08-27 11:42 ` [PATCH 11/13] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
@ 2026-08-27 11:42 ` Zaiyu Wang
  2026-08-27 11:42 ` [PATCH 13/13] net/txgbe: align link capabilities and DAC classification Zaiyu Wang
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:42 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

Backplane CR/KR link training on the E56 PHY is unreliable and does
not recover after a link event: the completion poll can block for a
second on a condition that never triggers, the page exchange is only
run once and its result is assumed to stay valid, and the FFE init
mode and calibration ordering are also wrong.

- Poll the AN FSM (0x78010, value 0x9) for CL72 completion with a
  1 ms step and a 400 ms budget, replacing the ephy 0x163c mask-0xe
  poll that tested the wrong condition; the per-lane TX-FFE dumps
  move into txgbe_e56_get_txffe(), called once AN completes.
- Re-run the page exchange on every AN next-page interrupt from the
  event handler (50 x 1 ms poll, explicit next-page handshake,
  -ETIMEDOUT on expiry) and only enter training after it succeeds;
  the inline exchange in the AN73 flow is removed and a CL72 failure
  no longer aborts the flow, so every link event re-runs the
  exchange instead of assuming the previous one is still valid.
- Initialize the FFE init mode bits in cfg_40g()/cfg_10g(), run
  txgbe_e56_set_rxs_ufine_le_max() after the RXS osc init, and write
  0x78001 = 0x7 in the AN programming sequence.
- Clear hw->bp_link_mode in txgbe_set_link_to_sfi() so a port that
  trained on the backplane does not keep a stale backplane mode
  after switching to SFI.

Fixes: 234ce0d1fa9d ("net/txgbe: fix link stability for Amber-Lite backplane mode")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_e56.c    |   3 +
 drivers/net/txgbe/base/txgbe_e56.h    |   1 +
 drivers/net/txgbe/base/txgbe_e56_bp.c | 161 +++++++++++++++-----------
 drivers/net/txgbe/base/txgbe_e56_bp.h |   2 +
 drivers/net/txgbe/base/txgbe_phy.c    |   3 +
 drivers/net/txgbe/txgbe_ethdev.c      |  28 ++++-
 6 files changed, 129 insertions(+), 69 deletions(-)

diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index 2711863f2c..8e986daf96 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -551,6 +551,7 @@ u32 txgbe_e56_cfg_40g(struct txgbe_hw *hw)
 
 	addr  = E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR;
 	rdata = rd32_ephy(hw, addr);
+	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_0, 0x2);
 	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2, 0x2);
 	wr32_ephy(hw, addr, rdata);
 
@@ -1377,6 +1378,8 @@ txgbe_e56_cfg_10g(struct txgbe_hw *hw)
 
 	addr = E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR;
 	rdata = rd32_ephy(hw, addr);
+	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_0,
+		       0x2);
 	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2,
 		       0x2);
 	wr32_ephy(hw, addr, rdata);
diff --git a/drivers/net/txgbe/base/txgbe_e56.h b/drivers/net/txgbe/base/txgbe_e56.h
index fe9a83ae01..32d95b61b9 100644
--- a/drivers/net/txgbe/base/txgbe_e56.h
+++ b/drivers/net/txgbe/base/txgbe_e56.h
@@ -435,6 +435,7 @@ typedef union {
 #define E56PHY_KRT_TFSM_CFGKRT_TFSM_HOLDOFF_TIMER_X256K 23, 16
 
 #define E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR   (E56PHY_PMD_BASE_ADDR + 0x2BC)
+#define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_0 1, 0
 #define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2 9, 8
 #define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_3 13, 12
 
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.c b/drivers/net/txgbe/base/txgbe_e56_bp.c
index d376d918df..f840e6b5dd 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.c
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.c
@@ -813,6 +813,7 @@ static int txgbe_e56_phy_rxs_calib_adapt_seq(struct txgbe_hw *hw,
 		status |= txgbe_e56_ctle_bypass_seq(hw, bp_link_mode);
 
 	status |= txgbe_e56_rxs_osc_init_for_temp_track_range(hw, bp_link_mode);
+	txgbe_e56_set_rxs_ufine_le_max(hw, bp_link_mode);
 
 	/* Wait an fsm_rx_sts 25G */
 	BP_LOG("Wait CTRL_FSM_RX_STAT[0]::ctrl_fsm_rx0_st to be ready ...\n");
@@ -2123,6 +2124,7 @@ int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
 	set_fields_e56(&rdata, 12, 12, 0x1);
 	wr32_epcs(hw, 0x070000, rdata);
 	wr32_epcs(hw, 0x078002, 0x0000);
+	wr32_epcs(hw, 0x78001, 0x7);
 	/* pcs case fec en to work around first */
 	wr32_epcs(hw, 0x100ab, 1);
 
@@ -2351,24 +2353,29 @@ static int chk_bkp_ability(struct txgbe_hw *hw,
 	return 0;
 }
 
-static int txgbe_e56_exchange_page(struct txgbe_hw *hw)
+int txgbe_e56_exchange_page(struct txgbe_hw *hw)
 {
 	struct txgbe_backplane_ability local_ability = {0}, lp_ability = {0};
 	u32 an_int, base_page = 0;
-	int count = 0;
+	int count = 0, count2 = 0;
 
 	an_int = rd32_epcs(hw, 0x78002);
-	/* 500ms timeout */
 	if (!(an_int & VR_AN_INTR_PG_RCV))
 		return -EINVAL;
 
-	for (count = 0; count < 500; count++) {
+	/* 50ms timeout */
+	for (count = 0; count < 50; count++) {
 		u32 fsm = rd32_epcs(hw, 0x78010);
-		u32 rdata = rd32_epcs(hw, 0x78002);
+		u32 next_page = 0;
+		u32 rdata;
+
+		count2++;
 
 		BP_LOG("-----count----- %d - fsm: %x\n", count, fsm);
-		BP_LOG("read 78002 data %0x and clear pacv\n", rdata);
+		rdata = rd32_epcs(hw, 0x78002);
+		/* clear an pacv int */
 		an_int = rdata;
+		BP_LOG("read 78002 data %0x and clear pacv\n", rdata);
 		set_fields_e56(&rdata, 2, 2, 0x0);
 		wr32_epcs(hw, 0x78002, rdata);
 		if (an_int & VR_AN_INTR_PG_RCV) {
@@ -2383,31 +2390,84 @@ static int txgbe_e56_exchange_page(struct txgbe_hw *hw)
 					wr32_epcs(hw, 0x70016, 0x2001);
 					BP_LOG("write 70016 0x%0x\n",
 					       0x2001);
+					next_page = 1;
+					count = 0; /* reset count to wait next page */
+				} else {
+					next_page = 0;
 				}
 				base_page = 1;
 			}
 		}
-		if ((fsm & 0x8) == 0x8) {
-			hw->fsm = 0x8;
-			goto check_ability;
+		if (!next_page) {
+			if ((fsm & 0x8) == 0x8) {
+				hw->fsm = 0x8;
+				goto check_ability;
+			}
 		}
-		usec_delay(100);
+		usec_delay(1000);
 	}
 
 check_ability:
+	if (count == 50) {
+		BP_LOG("Wait for next page timeout\n");
+		return -ETIMEDOUT;
+	}
+	BP_LOG("AN exchange page done in %d ms\n", count2);
 	return chk_bkp_ability(hw, local_ability, lp_ability);
 }
 
+void txgbe_e56_get_txffe(struct txgbe_hw *hw)
+{
+	/* 21. read txffe to check kr training status */
+	u32 rdata = 0, pmd_ctrl = 0, lane_idx = 0, lane_num = 0, txffe = 0;
+
+	switch (hw->bp_link_mode) {
+	case 10:
+		lane_num = 1;
+		break;
+	case 40:
+		lane_num = 4;
+		break;
+	case 25:
+		lane_num = 1;
+		break;
+	default:
+		BP_LOG("%s %d :Invalid speed\n", __func__, __LINE__);
+		return;
+	}
+
+	BP_LOG("%dG phy kr training check.... fsm: %x\n",
+	       hw->bp_link_mode, rd32_epcs(hw, 0x78010));
+	rdata = rd32_ephy(hw, 0x163c) & GENMASK(lane_num, 1);
+	pmd_ctrl = rd32_ephy(hw, 0x1644);
+	BP_LOG("KR TRAINNING CHECK = %x. pmd_ctrl:%lx-%lx-%lx-%lx\n",
+	       rdata,
+	       FIELD_GET_M(GENMASK(3, 0), pmd_ctrl),
+	       FIELD_GET_M(GENMASK(7, 4), pmd_ctrl),
+	       FIELD_GET_M(GENMASK(11, 8), pmd_ctrl),
+	       FIELD_GET_M(GENMASK(15, 12), pmd_ctrl));
+	BP_LOG("before: %x-%x-%x-%x\n",
+	       rd32_ephy(hw, 0x141c), rd32_ephy(hw, 0x1420),
+	       rd32_ephy(hw, 0x1424), rd32_ephy(hw, 0x1428));
+	for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
+		txffe = rd32_ephy(hw, 0x828 + lane_idx * 0x100);
+		BP_LOG("after[%x]: %lx-%lx-%lx-%lx\n", lane_idx,
+		       FIELD_GET_M(GENMASK(6, 0), txffe),
+		       FIELD_GET_M(GENMASK(21, 16), txffe),
+		       FIELD_GET_M(GENMASK(29, 24), txffe),
+		       FIELD_GET_M(GENMASK(13, 8), txffe));
+	}
+}
+
 static int txgbe_e56_cl72_training(struct txgbe_hw *hw)
 {
 	u32 bylinkmode = hw->bp_link_mode;
 	u8 bypass_ctle = hw->bypass_ctle;
 	int status = 0, temp_data = 0;
-	u32 lane_num = 0, lane_idx = 0;
-	u32 __rte_unused pmd_ctrl = 0, txffe = 0;
+	u32 lane_num = 0;
+	u32 __rte_unused pmd_ctrl = 0;
 	int ret = 0;
 	u32 rdata;
-
 	u8 pll_en_cfg = 0;
 	u8 pmd_mode = 0;
 
@@ -2463,52 +2523,48 @@ static int txgbe_e56_cl72_training(struct txgbe_hw *hw)
 
 	/* 18 */
 	/* 19. rxs calibration and adaptation sequence */
-	BP_LOG("2.4 Wait %dG RXS.... fsm: %x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
+	BP_LOG("2.4 Wait %dG RXS.... fsm: %x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
 	status = txgbe_e56_phy_rxs_calib_adapt_seq(hw, bylinkmode, bypass_ctle);
 	ret |= status;
 	/* 20 */
-	BP_LOG("2.5 Wait %dG phy calibration.... fsm: %x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
-	txgbe_e56_set_rxs_ufine_le_max(hw, bylinkmode);
+	BP_LOG("2.5 Wait %dG phy calibration.... fsm: %x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
 	status = txgbe_e56_get_temp(hw, &temp_data);
 	if (bylinkmode == 40)
 		status = txgbe_temp_track_seq_40g(hw, TXGBE_LINK_SPEED_40GB_FULL);
 	else
 		status = txgbe_e56_rxs_post_cdr_lock_temp_track_seq(hw, bylinkmode);
+
+	ret |= status;
 	/* 21 */
-	BP_LOG("2.6 Wait %dG phy kr training check.... fsm: %x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
-	status = kr_read_poll(rd32_ephy, rdata,
-				  ((rdata & 0xe) & GENMASK(lane_num, 1)) ==
-				  (0xe & GENMASK(lane_num, 1)), 100,
-				   10000, hw, 0x163c);
+	BP_LOG("2.6 Wait %dG phy kr fsm check : %x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
+	status = kr_read_poll(rd32_epcs, rdata,
+			      (rdata & 0x9) == 0x9, 1000,
+			      400, hw, 0x78010);
 	pmd_ctrl = rd32_ephy(hw, 0x1644);
-	BP_LOG("KR TRAINING CHECK = %x, %s. pmd_ctrl:%lx-%lx-%lx-%lx\n",
+	BP_LOG("KR FSM CHECK = %x, %s. pmd_ctrl:%lx-%lx-%lx-%lx\n",
 	       rdata, status ? "FAILED" : "SUCCESS",
 	       FIELD_GET_M(GENMASK(3, 0), pmd_ctrl),
 	       FIELD_GET_M(GENMASK(7, 4), pmd_ctrl),
 	       FIELD_GET_M(GENMASK(11, 8), pmd_ctrl),
 	       FIELD_GET_M(GENMASK(15, 12), pmd_ctrl));
 	ret |= status;
-	BP_LOG("before: %x-%x-%x-%x\n",
-	       rd32_ephy(hw, 0x141c), rd32_ephy(hw, 0x1420),
-	       rd32_ephy(hw, 0x1424), rd32_ephy(hw, 0x1428));
-
-	for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
-		txffe = rd32_ephy(hw, 0x828 + lane_idx * 0x100);
-		BP_LOG("after[%x]: %lx-%lx-%lx-%lx\n", lane_idx,
-		       FIELD_GET_M(GENMASK(6, 0), txffe),
-		       FIELD_GET_M(GENMASK(21, 16), txffe),
-		       FIELD_GET_M(GENMASK(29, 24), txffe),
-		       FIELD_GET_M(GENMASK(13, 8), txffe));
-	}
 
 	/* 22 */
-	BP_LOG("2.7 Wait %dG phy Rx adc.... fsm:%x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
+	BP_LOG("2.7 Wait %dG phy Rx adc.... fsm:%x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
 	status = txgbe_e56_rxs_adc_adapt_seq(hw, bypass_ctle);
 
+	BP_LOG("2.8 ===end ret : %d.... fsm:%x, an_int: %x\n",
+	       ret, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
+
 	return ret;
 }
 
@@ -2517,27 +2573,7 @@ int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw)
 	int status = 0;
 	u32 rdata;
 
-	BP_LOG("2.1 Wait page changed ....\n");
-	status = txgbe_e56_exchange_page(hw);
-	if (status) {
-		BP_LOG("Exchange page failed\n");
-		return status;
-	}
-
-	BP_LOG("2.2 Wait page changed ..done..\n");
-	wr32_epcs(hw, 0x100ab, 0);
-	if (AN_TRAINING_MODE) {
-		rdata = rd32_epcs(hw, 0x70000);
-		BP_LOG("read 0x70000 data %0x\n", rdata);
-		wr32_epcs(hw, 0x70000, 0);
-		BP_LOG("write 0x70000 0x%0x\n", 0);
-	}
-
-	rdata = rd32_epcs(hw, 0x78002);
-	BP_LOG("read 78002 data %0x and clear page int\n", rdata);
-	set_fields_e56(&rdata, 2, 2, 0x0);
-	wr32_epcs(hw, 0x78002, rdata);
-
+	/* 10  RXS_DISABLE - TXS_DISABLE - CMS_DISABLE */
 	/* dis phy tx/rx lane */
 	rdata = rd32_ephy(hw, 0x1400);
 	set_fields_e56(&rdata, 19, 16, 0x0);
@@ -2583,11 +2619,6 @@ int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw)
 	}
 
 	status = txgbe_e56_cl72_training(hw);
-	if (status) {
-		BP_LOG("CL72 training failed, status = %d\n", status);
-		return status;
-	}
-
 	rdata = rd32_ephy(hw, E56PHY_RXS_IDLE_DETECT_1_ADDR);
 	set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MAX, 0x28);
 	set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MIN, 0xa);
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.h b/drivers/net/txgbe/base/txgbe_e56_bp.h
index d2c49c2fce..da0d02b79f 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.h
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.h
@@ -279,4 +279,6 @@ typedef union {
 int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
 				u8 bp_link_mode, u32 need_restart);
 int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw);
+int txgbe_e56_exchange_page(struct txgbe_hw *hw);
+void txgbe_e56_get_txffe(struct txgbe_hw *hw);
 #endif
diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index 8b653f0aeb..10df23afae 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1947,6 +1947,9 @@ txgbe_set_link_to_sfi(struct txgbe_hw *hw,
 	s32 err = 0;
 	u32 value = 0;
 
+	/* Switching to SFI mode clears backplane link mode. */
+	hw->bp_link_mode = 0;
+
 	/* Set the module link speed */
 	hw->mac.set_rate_select_speed(hw, speed);
 	/* 1. Wait xpcs power-up good */
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index ef30e0c40a..269e0aadd9 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3025,6 +3025,7 @@ void txgbe_dev_e56_check_bp_event(void *param)
 	u32 __rte_unused an_int = 0;
 	int ret = 0;
 	bool need_link_update = false;
+	bool exchange_done = false;
 
 	if (!hw)
 		return;
@@ -3043,8 +3044,10 @@ void txgbe_dev_e56_check_bp_event(void *param)
 		hw->phy.sfp_type = txgbe_sfp_type_not_present;
 	}
 
-	if (!(txgbe_xpcs_an_enabled(hw)))
+	if (!(txgbe_xpcs_an_enabled(hw))) {
+		BP_LOG("%s %d\n", __func__, __LINE__);
 		return;
+	}
 
 	if (!hw->devarg.auto_neg)
 		return;
@@ -3063,6 +3066,7 @@ void txgbe_dev_e56_check_bp_event(void *param)
 		need_link_update = true;
 		value &= ~VR_AN_INTR_CMPLT;
 		wr32_epcs(hw, VR_AN_INTR, value);
+		txgbe_e56_get_txffe(hw);
 	}
 
 	if (value & VR_AN_INTR_LINK) {
@@ -3080,7 +3084,21 @@ void txgbe_dev_e56_check_bp_event(void *param)
 	}
 
 	if (value & VR_AN_INTR_PG_RCV) {
-		BP_LOG("%d Enter training\n", hw->port_id);
+		BP_LOG("%d 2.1 *** Wait page changed ....\n", hw->port_id);
+		ret = txgbe_e56_exchange_page(hw);
+		if (ret) {
+			BP_LOG("%d 2.2 *** Exchange page failed\n", hw->port_id);
+			goto an_status;
+		} else {
+			BP_LOG("%d 2.2 *** Wait page changed ..done..\n",
+			       hw->port_id);
+			wr32_epcs(hw, 0x100ab, 0);
+			exchange_done = true;
+		}
+	}
+
+	if (exchange_done) {
+		BP_LOG("%d 2.2.2 *** Enter training\n", hw->port_id);
 		ret = txgbe_handle_e56_bkp_an73_flow(hw);
 		if (!AN_TRAINING_MODE) {
 			fsm = rd32_epcs(hw, 0x78010);
@@ -3783,8 +3801,10 @@ txgbe_dev_interrupt_get_status(struct rte_eth_dev *dev,
 	if (eicr & TXGBE_ICRMISC_LSC)
 		intr->flags |= TXGBE_FLAG_NEED_LINK_UPDATE;
 
-	if (eicr & TXGBE_ICRMISC_ANDONE)
-		intr->flags |= TXGBE_FLAG_NEED_AN_CONFIG;
+	if (eicr & TXGBE_ICRMISC_ANDONE) {
+		PMD_DRV_LOG(DEBUG, "an int eicr=0x%08x", eicr);
+		intr->flags |= TXGBE_FLAG_NEED_AN_CONFIG;//aml40-to-do
+	}
 
 	if (eicr & TXGBE_ICRMISC_VFMBX)
 		intr->flags |= TXGBE_FLAG_MAILBOX;
-- 
2.55.0.windows.2


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

* [PATCH 13/13] net/txgbe: align link capabilities and DAC classification
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (11 preceding siblings ...)
  2026-08-27 11:42 ` [PATCH 12/13] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
@ 2026-08-27 11:42 ` Zaiyu Wang
  2026-09-08 12:38 ` [PATCH v2 00/15] Wangxun fixes and new features Zaiyu Wang
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-08-27 11:42 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

An active DAC can be misidentified as a 40G optical module, in which
case the driver reports 40G and enables autoneg for a module that
does not support it; DACs and optical modules are also treated
differently in the FFE, CTLE and capability-report paths.

Rework the AML40/AML link capabilities and DAC classification:

- Port the five-branch capability layout to AML40:
  backplane, DAC (txgbe_is_dac_cable() plus the 10G-only AN-off
  case), multispeed fiber, 40G QSFP and 10G SFP. Modules previously
  misreported as 40G through the fallback now report the correct
  speed and autoneg.
- Add the 40G-active transceiver identification (sfp_type enum and
  identify branch).
- Unify DAC classification on txgbe_is_dac_cable(), so active DACs
  are no longer treated as optical modules.

Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml.c   |  3 +-
 drivers/net/txgbe/base/txgbe_aml40.c | 71 ++++++++++++++++++++++++----
 drivers/net/txgbe/base/txgbe_e56.c   |  6 +--
 drivers/net/txgbe/base/txgbe_phy.c   |  7 +++
 drivers/net/txgbe/base/txgbe_phy.h   |  1 +
 drivers/net/txgbe/base/txgbe_type.h  |  2 +
 6 files changed, 74 insertions(+), 16 deletions(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml.c b/drivers/net/txgbe/base/txgbe_aml.c
index ac80d85f08..fe4becf198 100644
--- a/drivers/net/txgbe/base/txgbe_aml.c
+++ b/drivers/net/txgbe/base/txgbe_aml.c
@@ -103,8 +103,7 @@ s32 txgbe_get_link_capabilities_aml(struct txgbe_hw *hw,
 		*speed = TXGBE_LINK_SPEED_10GB_FULL |
 			 TXGBE_LINK_SPEED_25GB_FULL;
 		*autoneg = true;
-	} else if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
-		   hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1) {
+	} else if (txgbe_is_dac_cable(hw)) {
 		if (hw->phy.fiber_suppport_speed ==
 		    TXGBE_LINK_SPEED_10GB_FULL) {
 			hw->devarg.auto_neg = false;
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index bfb8a4bc7f..b4371921cd 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -95,26 +95,77 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
 	return 0;
 }
 
+static int txgbe_is_40g_fiber_qsfp(struct txgbe_hw *hw)
+{
+	if (hw->phy.sfp_type == txgbe_qsfp_type_40g_sr_core0 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_sr_core1 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_lr_core0 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_lr_core1 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_active_core0 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_active_core1)
+		return true;
+
+	return false;
+}
+
+static int txgbe_is_10g_fiber_sfp(struct txgbe_hw *hw)
+{
+	if (hw->phy.sfp_type == txgbe_sfp_type_srlr_core0 ||
+	    hw->phy.sfp_type == txgbe_sfp_type_srlr_core1)
+		return true;
+
+	return false;
+}
+
 s32 txgbe_get_link_capabilities_aml40(struct txgbe_hw *hw,
 				      u32 *speed,
 				      bool *autoneg)
 {
-	if (hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
-	    hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1) {
-		*speed = TXGBE_LINK_SPEED_40GB_FULL;
+	PMD_DRV_LOG(DEBUG, "port[%d]hw->phy.sfp_type = %d",
+		    hw->bus.lan_id, hw->phy.sfp_type);
+
+	/* Backplane */
+	if (txgbe_is_backplane(hw)) {
+		*speed = TXGBE_LINK_SPEED_10GB_FULL |
+			 TXGBE_LINK_SPEED_40GB_FULL;
+		/* Backplane supports autonegotiation */
+		*autoneg = hw->devarg.auto_neg;
+		return 0;
+	}
+
+	/* Fiber or DAC cable */
+	if (txgbe_is_dac_cable(hw)) {
+		/*
+		 * 10G-only DAC cable: legacy build-time AUTO=0/1 default
+		 * mode forces AN off. DPDK equivalent: devarg.auto_neg == 0.
+		 */
+		if (hw->phy.fiber_suppport_speed ==
+		    TXGBE_LINK_SPEED_10GB_FULL &&
+		    hw->devarg.auto_neg == 0) {
+			*autoneg = false;
+		} else {
+			*autoneg = hw->devarg.auto_neg;
+		}
+		*speed = hw->phy.fiber_suppport_speed;
+	} else if (hw->phy.multispeed_fiber) {
+		/* multispeed fiber must come before single-sfp/qsfp fiber */
+		*speed = TXGBE_LINK_SPEED_10GB_FULL |
+			 TXGBE_LINK_SPEED_40GB_FULL;
 		*autoneg = true;
-	} else if (txgbe_is_backplane(hw)) {
+	} else if (txgbe_is_40g_fiber_qsfp(hw)) {
 		*speed = TXGBE_LINK_SPEED_40GB_FULL;
-		*autoneg = true;
+		*autoneg = false;
+	} else if (txgbe_is_10g_fiber_sfp(hw)) {
+		*speed = TXGBE_LINK_SPEED_10GB_FULL;
+		*autoneg = false;
 	} else {
 		/*
-		 * Temporary workaround: set speed to 40G even if sfp not present
-		 * to avoid TXGBE_ERR_LINK_SETUP returned by setup_mac_link, but
-		 * a more reasonable solution is don't execute setup_mac_link when
-		 * sfp module not present.
+		 * Unknown / unsupported module: keep 40G default to avoid
+		 * TXGBE_ERR_LINK_SETUP returned by setup_mac_link, mirroring
+		 * the temporary workaround in the previous version.
 		 */
 		*speed = TXGBE_LINK_SPEED_40GB_FULL;
-		*autoneg = true;
+		*autoneg = false;
 	}
 
 	return 0;
diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index 8e986daf96..cc168a9f81 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -73,8 +73,7 @@ u32 txgbe_e56_tx_ffe_cfg(struct txgbe_hw *hw, u32 speed)
 		pre2 = S10G_TX_FFE_CFG_PRE2;
 		post = S10G_TX_FFE_CFG_POST;
 	} else if (speed == TXGBE_LINK_SPEED_25GB_FULL) {
-		if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
-		    hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1 ||
+		if (txgbe_is_dac_cable(hw) ||
 		    txgbe_is_backplane(hw)) {
 			ffe_main = S25G_TX_FFE_CFG_DAC_MAIN;
 			pre1 = S25G_TX_FFE_CFG_DAC_PRE1;
@@ -2622,8 +2621,7 @@ txgbe_e56_rxs_calib_adapt_seq(struct txgbe_hw *hw, u32 speed)
 	u32 rdata = 0x0;
 	bool bypass_ctle = true;
 
-	if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
-	    hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1)
+	if (txgbe_is_dac_cable(hw))
 		bypass_ctle = 0;
 
 	if (hw->mac.type == txgbe_mac_aml) {
diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index 10df23afae..e52f1da87d 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1156,6 +1156,13 @@ s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw)
 			else
 				hw->phy.sfp_type = txgbe_qsfp_type_40g_lr_core1;
 		}
+
+		if (transceiver_type & TXGBE_SFF_ETHERNET_40G_ACTIVE) {
+			if (hw->bus.lan_id == 0)
+				hw->phy.sfp_type = txgbe_qsfp_type_40g_active_core0;
+			else
+				hw->phy.sfp_type = txgbe_qsfp_type_40g_active_core1;
+		}
 	}
 
 	hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h
index a5df015a4d..b00f00931c 100644
--- a/drivers/net/txgbe/base/txgbe_phy.h
+++ b/drivers/net/txgbe/base/txgbe_phy.h
@@ -310,6 +310,7 @@
 #define TXGBE_SFF_ETHERNET_40G_CR4		MS(3, 0x1)
 #define TXGBE_SFF_ETHERNET_40G_SR4		MS(2, 0x1)
 #define TXGBE_SFF_ETHERNET_40G_LR4		MS(1, 0x1)
+#define TXGBE_SFF_ETHERNET_40G_ACTIVE		MS(0, 0x1)
 
 #define TXGBE_SFF_SOFT_RS_SELECT_MASK		0x8
 #define TXGBE_SFF_SOFT_RS_SELECT_10G		0x8
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index 39a70746a7..91771b9cbd 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -249,6 +249,8 @@ enum txgbe_sfp_type {
 	txgbe_qsfp_type_40g_sr_core1,
 	txgbe_qsfp_type_40g_lr_core0,
 	txgbe_qsfp_type_40g_lr_core1,
+	txgbe_qsfp_type_40g_active_core0,
+	txgbe_qsfp_type_40g_active_core1,
 	txgbe_sfp_type_not_present = 0xFFFE,
 	txgbe_sfp_type_not_known = 0xFFFF
 };
-- 
2.55.0.windows.2


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

* [PATCH v2 00/15] Wangxun fixes and new features
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (12 preceding siblings ...)
  2026-08-27 11:42 ` [PATCH 13/13] net/txgbe: align link capabilities and DAC classification Zaiyu Wang
@ 2026-09-08 12:38 ` Zaiyu Wang
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang

This series addresses link-related issues on Wangxun Amber-lite 25G/40G NICs (CR/KR training, hot-plug, 10G link state), and additionally refines U
DP offload handling.

---
v2:
 - add a new commit to handle 10G config on dual-speed DAC
 - P02: handle TXGBE_ERR_PHY_INIT_NOT_DONE before the timeout split and leave link_valid untouched.
 - P07: resolve the inner tunnel type in a local variable instead of rewriting mbuf->ol_flags.
        check the rte_pktmbuf_read() result for short or mis-annotated packets.
        use RTE_GENEVE_DEFAULT_PORT instead of the literal 6081.
        add a Fixes: tag pointing to the commit that introduced the tunnel offload handling.
 - P10: split into a bug-fix commit and a feature commit.
        document both devargs in the NIC guide and the release notes.
 - P11: check the acquire_swfw_sync() result and only touch I2C while the semaphore is held.
        replace the magic numbers with named constants.
        add the release notes entry.
 - P12: drop the stray C99 comment on the AN-config flag assignment that checkpatch rejects.
 - P13: reword the message to state that 40G active cables are handled through the optical path.
        use txgbe_is_dac_cable() in the 40G FFE selection to match the 25G path.
---

---
Not changed in this revision:

 - P11: enable_tx_laser() is not gated by laser_off. laser_off only
   controls whether the Tx laser is brought down on port stop, while
   enable_tx_laser() is unconditionally called from dev_start() and
   dev_set_link_up() and must always bring the laser up, otherwise the
   default (laser_off=0) configuration would never bring the link up.

 - P11: no extra restore of PMD_CFG0 bit 1 on the DAC path. Bits 19:12
   are restored by txgbe_e56_set_phy_link_mode() and
   txgbe_set_link_to_amlite(); bit 1 (PMD enable) is also restored by
   txgbe_e56_set_phy_link_mode(), which the xpcs AN path calls on link
   up, so no additional write is required.

 - P12: no total iteration bound was added to txgbe_e56_exchange_page().
   The loop is bounded per page and exits when the AN FSM reaches 0x8,
   so it does not hang in a normal Clause 73 flow. As this is hardware
   related configuration, we leave the current behaviour unchanged for
   now.
---

Zaiyu Wang (15):
  net/txgbe: fix failure to configure 10G on dual-speed DAC
  net/txgbe: fix e56 PHY configuration error
  net/txgbe: fix incorrect link state in 10G forced mode
  net/txgbe: do not force reconfig on link retry
  net/txgbe: set i2c sda hold time
  net/txgbe: fix link speed display info for 10G mode
  net/txgbe: remove stale outer UDP checksum offload flag
  net/txgbe: add offload support for tunnel type UDP
  net/txgbe: fix SFP hot-plug when auto-negotiation is on
  net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation
  net/txgbe: fix 40G FFE tuning applied to first lane only
  net/txgbe: add pre2 and backplane capability devargs
  net/txgbe: add devarg to turn off Tx laser for 40G NIC
  net/txgbe: fix CR/KR link training and recovery
  net/txgbe: align link capabilities and DAC classification

 doc/guides/nics/txgbe.rst              |  18 +++
 doc/guides/rel_notes/release_26_07.rst |   8 ++
 drivers/net/txgbe/base/txgbe_aml.c     |   3 +-
 drivers/net/txgbe/base/txgbe_aml40.c   | 100 +++++++++++++--
 drivers/net/txgbe/base/txgbe_e56.c     |  14 +--
 drivers/net/txgbe/base/txgbe_e56.h     |   6 +
 drivers/net/txgbe/base/txgbe_e56_bp.c  | 161 +++++++++++++++----------
 drivers/net/txgbe/base/txgbe_e56_bp.h  |   2 +
 drivers/net/txgbe/base/txgbe_hw.c      |  37 ++++++
 drivers/net/txgbe/base/txgbe_phy.c     |  13 ++
 drivers/net/txgbe/base/txgbe_phy.h     |   7 ++
 drivers/net/txgbe/base/txgbe_regs.h    |   3 +
 drivers/net/txgbe/base/txgbe_type.h    |  17 ++-
 drivers/net/txgbe/txgbe_ethdev.c       | 120 ++++++++++++++++--
 drivers/net/txgbe/txgbe_rxtx.c         |  29 ++++-
 15 files changed, 437 insertions(+), 101 deletions(-)

-- 
2.55.0.windows.2


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

* [PATCH v2 01/15] net/txgbe: fix failure to configure 10G on dual-speed DAC
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 02/15] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
                     ` (13 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

Setting "port config speed 10000" on a 10G/40G dual-speed DAC cable
fails with LINK_SETUP_ERR, and the AN base page always advertises
only 40G.

Three checks independently blocked 10G:

1. allowed_speeds in dev_start was restricted to 40G, so the user
   request was rejected before reaching setup_link.
2. get_link_capabilities_aml40() returned only 40G for all DAC
   cables, so the link_capabilities mask in setup_phy_link_aml40()
   stripped any 10G bit from the caller speed.
3. setup_phy_link_aml40() on the AN path passed a hardcoded 40 to
   txgbe_e56_set_phy_link_mode(), ignoring the caller speed.

Remove each of these restrictions so 10G flows through from user
configuration to the AN base page advertisement. On DAC cables the
capability is read from hw->phy.fiber_suppport_speed, which reflects
the actual SFP module.

Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c | 17 ++++++++++++-----
 drivers/net/txgbe/txgbe_ethdev.c     |  2 +-
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 1098efe5e6..7476759d4d 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -98,11 +98,12 @@ s32 txgbe_get_link_capabilities_aml40(struct txgbe_hw *hw,
 {
 	if (hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
 	    hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1) {
-		*speed = TXGBE_LINK_SPEED_40GB_FULL;
-		*autoneg = true;
+		*speed = hw->phy.fiber_suppport_speed;
+		*autoneg = hw->devarg.auto_neg;
 	} else if (txgbe_is_backplane(hw)) {
-		*speed = TXGBE_LINK_SPEED_40GB_FULL;
-		*autoneg = true;
+		*speed = TXGBE_LINK_SPEED_40GB_FULL |
+			 TXGBE_LINK_SPEED_10GB_FULL;
+		*autoneg = hw->devarg.auto_neg;
 	} else {
 		/*
 		 * Temporary workaround: set speed to 40G even if sfp not present
@@ -171,11 +172,17 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
 		if (link_up && hw->an_done && !autoneg_wait_to_complete)
 			return status;
 		rte_spinlock_lock(&hw->phy_lock);
-		txgbe_e56_set_phy_link_mode(hw, 40, autoneg_wait_to_complete);
+		txgbe_e56_set_phy_link_mode(hw, speed, autoneg_wait_to_complete);
 		rte_spinlock_unlock(&hw->phy_lock);
 		return status;
 	}
 
+	/* setup the highest link when no autoneg */
+	if (speed & TXGBE_LINK_SPEED_40GB_FULL)
+		speed = TXGBE_LINK_SPEED_40GB_FULL;
+	else if (speed & TXGBE_LINK_SPEED_10GB_FULL)
+		speed = TXGBE_LINK_SPEED_10GB_FULL;
+
 	if (txgbe_is_backplane(hw) || txgbe_is_dac_cable(hw) ||
 	    hw->phy.ffe_set) {
 		rte_spinlock_lock(&hw->phy_lock);
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 4d2746371b..bc2e11e801 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -1896,7 +1896,7 @@ txgbe_dev_start(struct rte_eth_dev *dev)
 		goto error;
 
 	if (hw->mac.type == txgbe_mac_aml40)
-		allowed_speeds = RTE_ETH_LINK_SPEED_40G;
+		allowed_speeds = RTE_ETH_LINK_SPEED_10G | RTE_ETH_LINK_SPEED_40G;
 	else if (hw->mac.type == txgbe_mac_aml)
 		allowed_speeds = RTE_ETH_LINK_SPEED_10G | RTE_ETH_LINK_SPEED_25G;
 	else
-- 
2.55.0.windows.2


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

* [PATCH v2 02/15] net/txgbe: fix e56 PHY configuration error
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
  2026-09-08 12:38   ` [PATCH v2 01/15] net/txgbe: fix failure to configure 10G on dual-speed DAC Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 03/15] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
                     ` (12 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

The e56 PHY RXS ring equalizer/tap configuration is written to the
wrong bit field: set_fields_e56(&rdata, 9, 4, 0x366) targets the
unrelated lower bits, so the configured tap values are never applied
and the equalizer stays at its default setting, which can degrade
the received signal on both the 40G and 10G paths.

Fix the field range to (21, 12), so the equalizer/tap configuration
takes effect.

Fixes: f7cfc21e9f75 ("net/txgbe: fix link stability for 40G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_e56.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index cbcc05333e..2711863f2c 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -423,7 +423,7 @@ u32 txgbe_e56_cfg_40g(struct txgbe_hw *hw)
 
 		addr  = E56PHY_RXS_RINGO_0_ADDR + (E56PHY_RXS_OFFSET * i);
 		rdata = rd32_ephy(hw, addr);
-		set_fields_e56(&rdata, 9, 4, 0x366);
+		set_fields_e56(&rdata, 21, 12, 0x366);
 		wr32_ephy(hw, addr, rdata);
 	}
 
-- 
2.55.0.windows.2


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

* [PATCH v2 03/15] net/txgbe: fix incorrect link state in 10G forced mode
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
  2026-09-08 12:38   ` [PATCH v2 01/15] net/txgbe: fix failure to configure 10G on dual-speed DAC Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 02/15] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 04/15] net/txgbe: do not force reconfig on link retry Zaiyu Wang
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

When an AML40 port is configured in 10G forced mode (auto_neg=0),
the hardware can link up but the driver keeps reporting link down
after a peer link failure: link_valid is cleared on timeout but
never restored when the peer recovers, so the link stays down until
the port is restarted.

Restore hw->link_valid = true in the success path of
txgbe_setup_phy_link_aml40(), symmetric to the 40G path. Handle
TXGBE_ERR_PHY_INIT_NOT_DONE before the timeout split and leave
link_valid untouched, matching the 25G path in
txgbe_setup_phy_link_aml(); the alarm retry then attempts the
setup again.

Fixes: f7cfc21e9f75 ("net/txgbe: fix link stability for 40G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 7476759d4d..5fa7c6a243 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -202,9 +202,18 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
 
 	rte_spinlock_lock(&hw->phy_lock);
 	ret_status = txgbe_set_link_to_amlite(hw, speed);
+	rte_spinlock_unlock(&hw->phy_lock);
+
+	/* The PHY did not come out of reset; leave link_valid alone and
+	 * let the retry in the alarm handler attempt the setup again.
+	 */
+	if (ret_status == TXGBE_ERR_PHY_INIT_NOT_DONE)
+		goto out;
+
 	if (ret_status == TXGBE_ERR_TIMEOUT)
 		hw->link_valid = false;
-	rte_spinlock_unlock(&hw->phy_lock);
+	else
+		hw->link_valid = true;
 
 	for (i = 0; i < 4; i++) {
 		txgbe_e56_check_phy_link(hw, &link_speed, &link_up);
-- 
2.55.0.windows.2


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

* [PATCH v2 04/15] net/txgbe: do not force reconfig on link retry
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (2 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 03/15] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 05/15] net/txgbe: set i2c sda hold time Zaiyu Wang
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

The link alarm retry calls mac.setup_link() with
autoneg_wait_to_complete = true. On the AN73/xpcs path, setup_link
skips reconfiguration when the link is already up and AN is done
only if the flag is false. With true, a retry that arrives after the
link is up still runs set_phy_link_mode() and resets the established
AN73 link, which then drops and never recovers (e.g. after DAC
hot-plug).

Pass false from the retry path instead.

Fixes: 6104fd11086e ("net/txgbe: fix link stability for 25G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_ethdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index bc2e11e801..9e4eca40cf 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3286,7 +3286,7 @@ txgbe_dev_setup_link_alarm_handler_aml(void *param)
 		return;
 	}
 
-	hw->mac.setup_link(hw, speed, true);
+	hw->mac.setup_link(hw, speed, false);
 
 	u32 link_speed = TXGBE_LINK_SPEED_UNKNOWN;
 	bool link_up = false;
-- 
2.55.0.windows.2


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

* [PATCH v2 05/15] net/txgbe: set i2c sda hold time
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (3 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 04/15] net/txgbe: do not force reconfig on link retry Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 06/15] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

The data_in_hold_time measured on the oscilloscope does not meet the
hardware requirement, which can corrupt SFP EEPROM reads over I2C.

Set the I2C SDA hold time to 100 (0x64) I2C clock periods for both
RX and TX in txgbe_i2c_start().

Fixes: 00970f6398c8 ("net/txgbe: fix reading SFP module SFF-8472 data")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_phy.c  | 3 +++
 drivers/net/txgbe/base/txgbe_regs.h | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index 2fbe50e242..8b653f0aeb 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1334,6 +1334,9 @@ static void txgbe_i2c_start(struct txgbe_hw *hw, u8 dev_addr)
 	wr32(hw, TXGBE_I2CSCLTMOUT, 0xFFFFFF);
 	wr32(hw, TXGBE_I2CSDATMOUT, 0xFFFFFF);
 
+	wr32m(hw, TXGBE_I2C_SDA_HOLD,
+		TXGBE_I2C_SDA_RX_HOLD | TXGBE_I2C_SDA_TX_HOLD, 0x640064);
+
 	wr32(hw, TXGBE_I2CICM, 0);
 	wr32(hw, TXGBE_I2CENA, 1);
 }
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index bf46a80862..b0042dc0d6 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -1610,6 +1610,9 @@ enum txgbe_5tuple_protocol {
 #define   TXGBE_I2CSTAT_MST          ((1U << 5))
 #define TXGBE_I2CSCLTMOUT            0x0149AC
 #define TXGBE_I2CSDATMOUT            0x0149B0 /*I2C SDA Stuck at Low Timeout*/
+#define TXGBE_I2C_SDA_HOLD              0x1497C /* SDA hold time length reg */
+#define TXGBE_I2C_SDA_RX_HOLD           0xff0000 /* SDA rx hold time length reg */
+#define TXGBE_I2C_SDA_TX_HOLD           0xffff /* SDA tx hold time length reg */
 
 /* port cfg Registers */
 #define TXGBE_PORTSTAT                  0x014404
-- 
2.55.0.windows.2


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

* [PATCH v2 06/15] net/txgbe: fix link speed display info for 10G mode
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (4 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 05/15] net/txgbe: set i2c sda hold time Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 07/15] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

When an AML40 port links up at 10G, DPDK reports the speed as 100M
instead of 10G. The 10G link status bit is not recognized in
txgbe_check_mac_link_aml40(), so any non-40G speed falls through to
the default case (UNKNOWN) which is then reported as 100M.

Add the 10G port status bit recognition, and include 10G in the
default advertised speed mask in txgbe_dev_start() so a 10G link is
reported with the correct speed.

Fixes: abf042d32b39 ("net/txgbe: add Amber-Lite 25G/40G NICs")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c | 3 +++
 drivers/net/txgbe/txgbe_ethdev.c     | 3 ++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 5fa7c6a243..d812adac69 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -85,6 +85,9 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
 		if ((links_reg & TXGBE_CFG_PORT_ST_AML_LINK_40G) ==
 			TXGBE_CFG_PORT_ST_AML_LINK_40G)
 			*speed = TXGBE_LINK_SPEED_40GB_FULL;
+		else if ((links_reg & TXGBE_CFG_PORT_ST_AML_LINK_10G) ==
+			TXGBE_CFG_PORT_ST_AML_LINK_10G)
+			*speed = TXGBE_LINK_SPEED_10GB_FULL;
 	} else {
 		*speed = TXGBE_LINK_SPEED_UNKNOWN;
 	}
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 9e4eca40cf..bb4ff3c492 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -1912,7 +1912,8 @@ txgbe_dev_start(struct rte_eth_dev *dev)
 	speed = 0x0;
 	if (*link_speeds == RTE_ETH_LINK_SPEED_AUTONEG) {
 		if (hw->mac.type == txgbe_mac_aml40) {
-			speed = TXGBE_LINK_SPEED_40GB_FULL;
+			speed = TXGBE_LINK_SPEED_40GB_FULL |
+				TXGBE_LINK_SPEED_10GB_FULL;
 		} else  if (hw->mac.type == txgbe_mac_aml) {
 			speed = (TXGBE_LINK_SPEED_10GB_FULL |
 				 TXGBE_LINK_SPEED_25GB_FULL);
-- 
2.55.0.windows.2


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

* [PATCH v2 07/15] net/txgbe: remove stale outer UDP checksum offload flag
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (5 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 06/15] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 08/15] net/txgbe: add offload support for tunnel type UDP Zaiyu Wang
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

RTE_MBUF_F_TX_OUTER_UDP_CKSUM is no longer advertised in
dev_info->tx_offload_capa, but it is still listed in
TXGBE_TX_OFFLOAD_MASK. The two are now inconsistent: a packet
carrying the flag is accepted by the offload mask check although the
driver no longer handles it.

Drop the flag from TXGBE_TX_OFFLOAD_MASK so the advertised
capability and the accepted offload flags match.

Fixes: 25fe1c780d39 ("net/txgbe: remove outer UDP checksum capability")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_rxtx.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index 794ba041a4..a295666f9d 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -61,7 +61,6 @@ static const u64 TXGBE_TX_OFFLOAD_MASK = (RTE_MBUF_F_TX_IP_CKSUM |
 		RTE_MBUF_F_TX_UDP_SEG |
 		RTE_MBUF_F_TX_TUNNEL_MASK |
 		RTE_MBUF_F_TX_OUTER_IP_CKSUM |
-		RTE_MBUF_F_TX_OUTER_UDP_CKSUM |
 #ifdef RTE_LIB_SECURITY
 		RTE_MBUF_F_TX_SEC_OFFLOAD |
 #endif
-- 
2.55.0.windows.2


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

* [PATCH v2 08/15] net/txgbe: add offload support for tunnel type UDP
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (6 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 07/15] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 09/15] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu, Ferruh Yigit

The non-standard RTE_MBUF_F_TX_TUNNEL_UDP tunnel type (UDP
encapsulation carrying either VXLAN or GENEVE) is not handled:
txgbe_set_xmit_ctx() falls into the "unknown tunnel type" case and
txgbe_get_tun_len() cannot compute the tunnel length, so tunneled
packets are sent with a wrong descriptor or dropped.

Resolve RTE_MBUF_F_TX_TUNNEL_UDP by parsing the UDP destination
port in a local variable instead of rewriting the mbuf: the
application still owns the mbuf and may re-transmit it (cloned or
multicast paths), so a second pass would otherwise see the resolved
VXLAN/GENEVE type instead of UDP. The outer_l2_len/outer_l3_len
used for the offset are application supplied and not validated by
the driver, so check the rte_pktmbuf_read() result and fall back to
a zero tunnel length on a short or mis-annotated packet. Use
RTE_GENEVE_DEFAULT_PORT for the GENEVE destination port.

Fixes: ca46fcd753b1 ("net/txgbe: support Tx with hardware offload")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_rxtx.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index a295666f9d..ad90df5f69 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -21,6 +21,7 @@
 #include <rte_debug.h>
 #include <rte_ethdev.h>
 #include <ethdev_driver.h>
+#include <rte_geneve.h>
 #include <rte_security_driver.h>
 #include <rte_memzone.h>
 #include <rte_atomic.h>
@@ -419,6 +420,7 @@ txgbe_set_xmit_ctx(struct txgbe_tx_queue *txq,
 			break;
 		case RTE_MBUF_F_TX_TUNNEL_VXLAN:
 		case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+		case RTE_MBUF_F_TX_TUNNEL_UDP:
 		case RTE_MBUF_F_TX_TUNNEL_GENEVE:
 			tunnel_seed |= TXGBE_TXD_ETYPE_UDP;
 			break;
@@ -593,6 +595,7 @@ tx_desc_ol_flags_to_ptype(uint64_t oflags)
 	switch (oflags & RTE_MBUF_F_TX_TUNNEL_MASK) {
 	case RTE_MBUF_F_TX_TUNNEL_VXLAN:
 	case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+	case RTE_MBUF_F_TX_TUNNEL_UDP:
 		ptype |= RTE_PTYPE_TUNNEL_GRENAT;
 		break;
 	case RTE_MBUF_F_TX_TUNNEL_GRE:
@@ -713,9 +716,32 @@ txgbe_get_tun_len(struct rte_mbuf *mbuf)
 	const struct txgbe_genevehdr *gh;
 	const struct txgbe_grehdr *grh;
 	struct txgbe_grehdr grehdr;
+	struct txgbe_udphdr udphdr;
+	const struct txgbe_udphdr *uh;
+	uint64_t tun_type;
 	uint8_t tun_len;
 
-	switch (mbuf->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
+	/* Resolve the UDP tunnel to its inner type without rewriting the
+	 * mbuf: the application still owns it and may re-transmit it.
+	 */
+	tun_type = mbuf->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK;
+	if (tun_type == RTE_MBUF_F_TX_TUNNEL_UDP) {
+		uh = rte_pktmbuf_read(mbuf,
+				      mbuf->outer_l2_len + mbuf->outer_l3_len,
+				      sizeof(udphdr), &udphdr);
+		if (uh == NULL) {
+			/* The outer offsets are application supplied and may
+			 * point past the end of the packet.
+			 */
+			return 0;
+		}
+		tun_type = (uh->dest ==
+			    rte_cpu_to_be_16(RTE_GENEVE_DEFAULT_PORT)) ?
+			   RTE_MBUF_F_TX_TUNNEL_GENEVE :
+			   RTE_MBUF_F_TX_TUNNEL_VXLAN;
+	}
+
+	switch (tun_type) {
 	case RTE_MBUF_F_TX_TUNNEL_IPIP:
 		tun_len = 0;
 		break;
-- 
2.55.0.windows.2


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

* [PATCH v2 09/15] net/txgbe: fix SFP hot-plug when auto-negotiation is on
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (7 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 08/15] net/txgbe: add offload support for tunnel type UDP Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 10/15] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

When a port is started before the DAC cable is plugged in,
hot-plugging the cable never brings the link up and the port has to
be stopped and started again.

The AN73 watchdog txgbe_dev_e56_check_bp_event() is armed once in
txgbe_dev_start(). Its first tick finds no module, so
txgbe_xpcs_an_enabled() returns false and the handler returns without
re-arming itself. Once the cable is inserted, nobody polls the AN73
completion any more and the link stays down.

Re-arm the watchdog from txgbe_dev_detect_sfp() once a module has
been identified, cancelling any pending instance first so that only
one of them is running at a time. On the removal path, drop the
cached SFP type and cancel the watchdog. Also sample the
module-present pin (GPIO_EXT bit 2 on 25G, bit 4 on 40G) on every
watchdog tick, so that pulling the cable is noticed even if no GPIO
interrupt is delivered.

Fixes: 234ce0d1fa9d ("net/txgbe: fix link stability for Amber-Lite backplane mode")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_ethdev.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index bb4ff3c492..0711a28a5c 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2987,6 +2987,20 @@ void txgbe_dev_e56_check_bp_event(void *param)
 	if (!hw)
 		return;
 
+	/* Sample the module-present pin on every tick. When the cable is
+	 * pulled, drop the cached SFP type so that txgbe_xpcs_an_enabled()
+	 * turns false and this alarm stops re-arming itself.
+	 */
+	if (hw->mac.type == txgbe_mac_aml)
+		value = rd32(hw, TXGBE_GPIOEXT) & TXGBE_SFP1_MOD_ABS_LS;
+	else if (hw->mac.type == txgbe_mac_aml40)
+		value = rd32(hw, TXGBE_GPIOEXT) & TXGBE_SFP1_MOD_PRST_LS;
+
+	if (value != 0 && hw->phy.sfp_type != txgbe_sfp_type_not_present) {
+		PMD_DRV_LOG(INFO, "SFP module removed, stop AN73 watchdog.");
+		hw->phy.sfp_type = txgbe_sfp_type_not_present;
+	}
+
 	if (!(txgbe_xpcs_an_enabled(hw)))
 		return;
 
@@ -3110,10 +3124,22 @@ txgbe_dev_detect_sfp(void *param)
 		PMD_DRV_LOG(ERR, "Unsupported SFP+ module type was detected.");
 	} else if (err == TXGBE_ERR_SFP_NOT_PRESENT) {
 		PMD_DRV_LOG(INFO, "SFP not present.");
+		/* Module removed: drop the cached type and stop the watchdog. */
+		hw->phy.sfp_type = txgbe_sfp_type_not_present;
+		rte_eal_alarm_cancel(txgbe_dev_e56_check_bp_event, dev);
 	} else if (err == 0) {
 		hw->mac.setup_sfp(hw);
 		PMD_DRV_LOG(INFO, "detected SFP+: %d", hw->phy.sfp_type);
 		txgbe_dev_setup_link_alarm_handler(dev);
+		/* Re-arm the AN73 watchdog for the newly inserted module, so
+		 * that only one instance of it is running at a time.
+		 */
+		if (hw->mac.type == txgbe_mac_aml ||
+		    hw->mac.type == txgbe_mac_aml40) {
+			rte_eal_alarm_cancel(txgbe_dev_e56_check_bp_event, dev);
+			rte_eal_alarm_set(hw->bp_event_interval,
+					  txgbe_dev_e56_check_bp_event, dev);
+		}
 		txgbe_dev_link_update(dev, 0);
 	}
 }
-- 
2.55.0.windows.2


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

* [PATCH v2 10/15] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (8 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 09/15] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 11/15] net/txgbe: fix 40G FFE tuning applied to first lane only Zaiyu Wang
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

Hot-plugging a DAC cable while an Amber-Lite 40G port is running
does not bring the link up. Two problems are in the way.

First, the 40G NIC never delivers the GPIO interrupt for module
insertion or removal, so txgbe_dev_detect_sfp() is not called and the
new module is never identified (the 25G part is not affected). Poll
the module-present level every 2 seconds instead. The poll skips the
identify step while the level is unchanged, and only re-arms itself
while the port is started, so that it cannot survive txgbe_dev_stop().

Second, when the port is started with no module plugged in,
txgbe_set_link_to_amlite() times out and leaves hw->link_valid false.
The xpcs path of txgbe_setup_phy_link_aml40() never restores it, so
txgbe_e56_check_phy_link() and txgbe_check_mac_link_aml40() keep
forcing the link down even once AN73 has brought it up. Restore
link_valid on the xpcs path, as the non-xpcs path already does.

Fixes: a2d92608d3b0 ("net/txgbe: add GPIO configuration")
Fixes: f7cfc21e9f75 ("net/txgbe: fix link stability for 40G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c |  7 +++++++
 drivers/net/txgbe/txgbe_ethdev.c     | 17 ++++++++++++++++-
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index d812adac69..2d3b32839c 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -177,6 +177,13 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
 		rte_spinlock_lock(&hw->phy_lock);
 		txgbe_e56_set_phy_link_mode(hw, speed, autoneg_wait_to_complete);
 		rte_spinlock_unlock(&hw->phy_lock);
+		/* Restore link_valid, as the non-xpcs path below does. An
+		 * earlier txgbe_set_link_to_amlite() timeout, for example when
+		 * the port was started with no module plugged in, left it
+		 * false, which keeps the check_phy_link and check_mac_link
+		 * gates forcing the link down even after AN73 brings it up.
+		 */
+		hw->link_valid = true;
 		return status;
 	}
 
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0711a28a5c..0aa2d5719b 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2015,6 +2015,11 @@ txgbe_dev_start(struct rte_eth_dev *dev)
 	if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) {
 		rte_eal_alarm_set(hw->bp_event_interval, txgbe_dev_e56_check_bp_event, dev);
 		rte_eal_alarm_set(1000 * 1000 * 2, txgbe_dev_check_aml_temp_event, dev);
+		/* The 40G NIC does not deliver a GPIO interrupt on module
+		 * insertion or removal, so poll the module-present level.
+		 */
+		if (hw->mac.type == txgbe_mac_aml40 && !txgbe_is_backplane(hw))
+			rte_eal_alarm_set(2000 * 1000, txgbe_dev_detect_sfp, dev);
 	}
 
 	if (tm_conf->root && !tm_conf->committed)
@@ -3096,7 +3101,7 @@ txgbe_dev_detect_sfp(void *param)
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
 	struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
 	u32 value = 0;
-	s32 err;
+	s32 err = 0;
 
 	if (hw->mac.type == txgbe_mac_aml40) {
 		value = rd32(hw, TXGBE_GPIOEXT);
@@ -3104,6 +3109,11 @@ txgbe_dev_detect_sfp(void *param)
 			err = TXGBE_ERR_SFP_NOT_PRESENT;
 			goto out;
 		}
+		/* The level is unchanged since the last poll, so the cached
+		 * module type is still valid and identify can be skipped.
+		 */
+		if (hw->phy.sfp_type != txgbe_sfp_type_not_present)
+			goto rearm;
 	}
 
 	if (hw->mac.type == txgbe_mac_aml) {
@@ -3142,6 +3152,11 @@ txgbe_dev_detect_sfp(void *param)
 		}
 		txgbe_dev_link_update(dev, 0);
 	}
+
+rearm:
+	if (hw->mac.type == txgbe_mac_aml40 && !txgbe_is_backplane(hw) &&
+	    dev->data->dev_started)
+		rte_eal_alarm_set(2000 * 1000, txgbe_dev_detect_sfp, dev);
 }
 
 static void
-- 
2.55.0.windows.2


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

* [PATCH v2 11/15] net/txgbe: fix 40G FFE tuning applied to first lane only
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (9 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 10/15] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 12/15] net/txgbe: add pre2 and backplane capability devargs Zaiyu Wang
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

On the 40G NIC, an FFE value only reaches the first of the four
lanes: the E56 PHY holds one FFE byte per lane, but the tuned taps
were written as a single byte value, so the other three lanes keep
their default equalizer setting and the received signal on them can
be degraded.

Use the E56 PHY FFE defaults on the 40G NIC and replicate each tap
value over the four lanes. The FFE fields grow to 32 bits to hold
the replicated value, and the devargs are parsed after the shared
code init so the MAC type is known when the 40G defaults are picked.

Fixes: 6104fd11086e ("net/txgbe: fix link stability for 25G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_e56.h  |  5 +++++
 drivers/net/txgbe/base/txgbe_type.h |  8 ++++----
 drivers/net/txgbe/txgbe_ethdev.c    | 22 +++++++++++++++++++++-
 3 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/net/txgbe/base/txgbe_e56.h b/drivers/net/txgbe/base/txgbe_e56.h
index 1922a2eb92..fe9a83ae01 100644
--- a/drivers/net/txgbe/base/txgbe_e56.h
+++ b/drivers/net/txgbe/base/txgbe_e56.h
@@ -1714,6 +1714,11 @@ typedef union {
 #define S40G_TX_FFE_CFG_PRE2        0x0
 #define S40G_TX_FFE_CFG_POST        0x11111111
 
+/* The 40G PHY holds one FFE byte per lane, so a user supplied value has to
+ * be replicated over the four lanes.
+ */
+#define S40G_TX_FFE_4LANE(v)        ((u32)((v) & 0xFF) * 0x01010101u)
+
 #define BYPASS_CTLE_TAG             0x0
 
 #define S10G_PHY_RX_CTLE_TAPWT_WEIGHT1      0x1
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index f9b5cbe61a..4ed4737043 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -739,10 +739,10 @@ struct txgbe_phy_info {
 
 	/* Some features need tri-state capability */
 	u16 ffe_set;
-	u16 ffe_main;
-	u16 ffe_pre;
-	u16 ffe_pre2;
-	u16 ffe_post;
+	u32 ffe_main;
+	u32 ffe_pre;
+	u32 ffe_pre2;
+	u32 ffe_post;
 	u16 fec_mode;
 	u16 bp_capa;
 };
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0aa2d5719b..afed59d4cf 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -531,6 +531,7 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 ffe_set = 0;
 	u16 ffe_main = 27;
 	u16 ffe_pre = 8;
+	u16 ffe_pre2 = 0;
 	u16 ffe_post = 44;
 	/* FDIR args */
 	u8 pballoc = 0;
@@ -540,6 +541,15 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 tx_headwb_size = 16;
 	u16 rx_desc_merge = 1;
 
+	/* The 40G NIC holds one FFE byte per lane, so the E56 PHY defaults
+	 * below are later replicated over the four lanes.
+	 */
+	if (hw->mac.type == txgbe_mac_aml40) {
+		ffe_main = S40G_TX_FFE_CFG_MAIN & 0xFF;
+		ffe_pre = S40G_TX_FFE_CFG_PRE1 & 0xFF;
+		ffe_post = S40G_TX_FFE_CFG_POST & 0xFF;
+	}
+
 	if (devargs == NULL)
 		goto null;
 
@@ -588,6 +598,14 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	hw->phy.ffe_pre = ffe_pre;
 	hw->phy.ffe_post = ffe_post;
 
+	/* The 40G PHY expects one FFE byte per lane. */
+	if (hw->mac.type == txgbe_mac_aml40) {
+		hw->phy.ffe_main = S40G_TX_FFE_4LANE(ffe_main);
+		hw->phy.ffe_pre = S40G_TX_FFE_4LANE(ffe_pre);
+		hw->phy.ffe_pre2 = S40G_TX_FFE_4LANE(ffe_pre2);
+		hw->phy.ffe_post = S40G_TX_FFE_4LANE(ffe_post);
+	}
+
 	fdir_conf->pballoc = pballoc;
 	fdir_conf->drop_queue = drop_queue;
 }
@@ -690,7 +708,6 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
 	hw->isb_dma = TMZ_PADDR(mz);
 	hw->isb_mem = TMZ_VADDR(mz);
 
-	txgbe_parse_devargs(eth_dev);
 	/* Initialize the shared code (base driver) */
 	err = txgbe_init_shared_code(hw);
 	if (err != 0) {
@@ -698,6 +715,9 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
 		return -EIO;
 	}
 
+	/* Parsing the devargs requires a known MAC type. */
+	txgbe_parse_devargs(eth_dev);
+
 	if (hw->mac.type == txgbe_mac_aml)
 		txgbe_override_mac_ops(hw);
 
-- 
2.55.0.windows.2


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

* [PATCH v2 12/15] net/txgbe: add pre2 and backplane capability devargs
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (10 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 11/15] net/txgbe: fix 40G FFE tuning applied to first lane only Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 13/15] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, Jiawen Wu

The 25G E56 PHY has a second pre-cursor tap that cannot be tuned
with the existing devargs: with ffe_set enabled, pre2 stays at the
default value because no devarg feeds it.

The advertised 40G backplane capability is hardwired to KR4+CR4,
so there is no way to advertise only 40GBASE-KR4 or only 40GBASE-CR4.

Add the ffe_pre2 and bp_capa device arguments. ffe_pre2 configures
the E56 PHY second pre-cursor tap, bp_capa selects the backplane
capability advertised on the 40G NIC, and both are documented in the
NIC guide and the release notes.

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 doc/guides/nics/txgbe.rst              | 11 +++++++++++
 doc/guides/rel_notes/release_26_07.rst |  5 +++++
 drivers/net/txgbe/base/txgbe_type.h    |  6 +++++-
 drivers/net/txgbe/txgbe_ethdev.c       | 23 +++++++++++++++++++----
 4 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/doc/guides/nics/txgbe.rst b/doc/guides/nics/txgbe.rst
index 90c55141f1..d56fb3b99a 100644
--- a/doc/guides/nics/txgbe.rst
+++ b/doc/guides/nics/txgbe.rst
@@ -142,6 +142,11 @@ Please note that following ``devargs`` are only set for backplane NICs.
   PHY parameter used for user debugging. Setting other values to
   take effect requires setting the ``ffe_set``.
 
+- ``ffe_pre2`` (default **0**)
+
+  PHY parameter used for user debugging, only for the Amber-Lite E56 PHY.
+  Setting other values to take effect requires setting the ``ffe_set``.
+
 - ``ffe_post`` (default **44**)
 
   PHY parameter used for user debugging. Setting other values to
@@ -177,6 +182,12 @@ Please note that following ``devargs`` are only set for Amber-Lite NICs.
   In this mode, the hardware merges and writes back a group of RX descriptors
   together to reduce memory access times, which helps improve performance.
 
+- ``bp_capa`` (default **0**)
+
+  Backplane capability selection for the 40G NIC. Set 0 for both
+  40GBASE-KR4 and 40GBASE-CR4, set 1 for 40GBASE-KR4 only, set 2 for
+  40GBASE-CR4 only.
+
 Driver compilation and testing
 ------------------------------
 
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 3d18ba2dd0..f65044c9b9 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -163,6 +163,11 @@ New Features
     so the application can reset the VF and resume normal packet Rx/Tx.
   * Added VF support for the Amber-Lite 40G NIC variant,
     with new device IDs ``0x503f`` and ``0x513f``.
+  * Added the ``ffe_pre2`` device argument to tune the second pre-cursor
+    tap of the Amber-Lite E56 PHY (requires ``ffe_set``).
+  * Added the ``bp_capa`` device argument to select the advertised
+    backplane capability on the 40G NIC
+    (0 for 40GBASE-KR4 + 40GBASE-CR4, 1 for KR4 only, 2 for CR4 only).
 
 * **Updated Intel qat crypto driver dependency requirements.**
 
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index 4ed4737043..f56cd70c6f 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -741,7 +741,7 @@ struct txgbe_phy_info {
 	u16 ffe_set;
 	u32 ffe_main;
 	u32 ffe_pre;
-	u32 ffe_pre2;
+	u32 ffe_pre2; /* only for the Amber-Lite E56 PHY */
 	u32 ffe_post;
 	u16 fec_mode;
 	u16 bp_capa;
@@ -754,12 +754,14 @@ struct txgbe_phy_info {
 #define TXGBE_DEVARG_FFE_SET		"ffe_set"
 #define TXGBE_DEVARG_FFE_MAIN		"ffe_main"
 #define TXGBE_DEVARG_FFE_PRE		"ffe_pre"
+#define TXGBE_DEVARG_FFE_PRE2		"ffe_pre2"
 #define TXGBE_DEVARG_FFE_POST		"ffe_post"
 #define TXGBE_DEVARG_FDIR_PBALLOC	"pkt-filter-size"
 #define TXGBE_DEVARG_FDIR_DROP_QUEUE	"pkt-filter-drop-queue"
 #define TXGBE_DEVARG_TX_HEAD_WB		"tx_headwb"
 #define TXGBE_DEVARG_TX_HEAD_WB_SIZE	"tx_headwb_size"
 #define TXGBE_DEVARG_RX_DESC_MERGE	"rx_desc_merge"
+#define TXGBE_DEVARG_BP_CAPA		"bp_capa"
 
 static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_BP_AUTO,
@@ -769,12 +771,14 @@ static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_FFE_SET,
 	TXGBE_DEVARG_FFE_MAIN,
 	TXGBE_DEVARG_FFE_PRE,
+	TXGBE_DEVARG_FFE_PRE2,
 	TXGBE_DEVARG_FFE_POST,
 	TXGBE_DEVARG_FDIR_PBALLOC,
 	TXGBE_DEVARG_FDIR_DROP_QUEUE,
 	TXGBE_DEVARG_TX_HEAD_WB,
 	TXGBE_DEVARG_TX_HEAD_WB_SIZE,
 	TXGBE_DEVARG_RX_DESC_MERGE,
+	TXGBE_DEVARG_BP_CAPA,
 	NULL
 };
 
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index afed59d4cf..27a6ff0b2e 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -540,13 +540,20 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 tx_headwb = 1;
 	u16 tx_headwb_size = 16;
 	u16 rx_desc_merge = 1;
+	u16 bp_capa = 0;
 
-	/* The 40G NIC holds one FFE byte per lane, so the E56 PHY defaults
-	 * below are later replicated over the four lanes.
+	/* The E56 PHY needs its own FFE defaults, as the ones above only
+	 * apply to the Sapphire PHY.
 	 */
-	if (hw->mac.type == txgbe_mac_aml40) {
+	if (hw->mac.type == txgbe_mac_aml) {
+		ffe_main = S25G_TX_FFE_CFG_DAC_MAIN;
+		ffe_pre = S25G_TX_FFE_CFG_DAC_PRE1;
+		ffe_pre2 = S25G_TX_FFE_CFG_DAC_PRE2;
+		ffe_post = S25G_TX_FFE_CFG_DAC_POST;
+	} else if (hw->mac.type == txgbe_mac_aml40) {
 		ffe_main = S40G_TX_FFE_CFG_MAIN & 0xFF;
 		ffe_pre = S40G_TX_FFE_CFG_PRE1 & 0xFF;
+		ffe_pre2 = S40G_TX_FFE_CFG_PRE2 & 0xFF;
 		ffe_post = S40G_TX_FFE_CFG_POST & 0xFF;
 	}
 
@@ -571,6 +578,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 			   &txgbe_handle_devarg, &ffe_main);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_PRE,
 			   &txgbe_handle_devarg, &ffe_pre);
+	rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_PRE2,
+			   &txgbe_handle_devarg, &ffe_pre2);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_POST,
 			   &txgbe_handle_devarg, &ffe_post);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_FDIR_PBALLOC,
@@ -583,6 +592,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 			   &txgbe_handle_devarg, &tx_headwb_size);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_RX_DESC_MERGE,
 			   &txgbe_handle_devarg, &rx_desc_merge);
+	rte_kvargs_process(kvlist, TXGBE_DEVARG_BP_CAPA,
+			   &txgbe_handle_devarg, &bp_capa);
 	rte_kvargs_free(kvlist);
 
 null:
@@ -596,7 +607,9 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	hw->phy.ffe_set = ffe_set;
 	hw->phy.ffe_main = ffe_main;
 	hw->phy.ffe_pre = ffe_pre;
+	hw->phy.ffe_pre2 = ffe_pre2;
 	hw->phy.ffe_post = ffe_post;
+	hw->phy.bp_capa = bp_capa;
 
 	/* The 40G PHY expects one FFE byte per lane. */
 	if (hw->mac.type == txgbe_mac_aml40) {
@@ -6498,12 +6511,14 @@ RTE_PMD_REGISTER_PARAM_STRING(net_txgbe,
 			      TXGBE_DEVARG_FFE_SET "=<0-4>"
 			      TXGBE_DEVARG_FFE_MAIN "=<uint16>"
 			      TXGBE_DEVARG_FFE_PRE "=<uint16>"
+			      TXGBE_DEVARG_FFE_PRE2 "=<uint16>"
 			      TXGBE_DEVARG_FFE_POST "=<uint16>"
 			      TXGBE_DEVARG_FDIR_PBALLOC "=<0|1|2>"
 			      TXGBE_DEVARG_FDIR_DROP_QUEUE "=<uint8>"
 			      TXGBE_DEVARG_TX_HEAD_WB "=<0|1>"
 			      TXGBE_DEVARG_TX_HEAD_WB_SIZE "=<1|16>"
-			      TXGBE_DEVARG_RX_DESC_MERGE "=<0|1>");
+			      TXGBE_DEVARG_RX_DESC_MERGE "=<0|1>"
+			      TXGBE_DEVARG_BP_CAPA "=<0|1|2>");
 
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_init, init, NOTICE);
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_driver, driver, NOTICE);
-- 
2.55.0.windows.2


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

* [PATCH v2 13/15] net/txgbe: add devarg to turn off Tx laser for 40G NIC
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (11 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 12/15] net/txgbe: add pre2 and backplane capability devargs Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:38   ` [PATCH v2 14/15] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
  2026-09-08 12:39   ` [PATCH v2 15/15] net/txgbe: align link capabilities and DAC classification Zaiyu Wang
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, Jiawen Wu

When the port is brought down, the Tx laser stays on, so the peer
keeps seeing a live signal and cannot detect the link loss (e.g. for
link-state tracking at the peer).

Add a laser_off devarg: when enabled, bring the Tx laser down on
port stop -- for DAC cables disable the PCS, for QSFP modules write
the Tx disable bit via I2C -- and restore the Tx enable state when
the link comes up. The SFF-8636 Tx disable register is only touched
while the management semaphore is held, and the acquire_swfw_sync()
result is checked so a failed acquire does not release a semaphore
that is not held. Replace the raw register offsets and bit masks
with named constants (PMD_CFG0, E56PHY_PMD_CFG_0_RX_EN_CFG,
TXGBE_MNGSEM_SWPHY, TXGBE_SFF_8636_TX_DISABLE).

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 doc/guides/nics/txgbe.rst              |  7 +++++
 doc/guides/rel_notes/release_26_07.rst |  3 +++
 drivers/net/txgbe/base/txgbe_hw.c      | 37 ++++++++++++++++++++++++++
 drivers/net/txgbe/base/txgbe_phy.h     |  6 +++++
 drivers/net/txgbe/base/txgbe_type.h    |  3 +++
 drivers/net/txgbe/txgbe_ethdev.c       |  7 ++++-
 6 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/txgbe.rst b/doc/guides/nics/txgbe.rst
index d56fb3b99a..a580450726 100644
--- a/doc/guides/nics/txgbe.rst
+++ b/doc/guides/nics/txgbe.rst
@@ -188,6 +188,13 @@ Please note that following ``devargs`` are only set for Amber-Lite NICs.
   40GBASE-KR4 and 40GBASE-CR4, set 1 for 40GBASE-KR4 only, set 2 for
   40GBASE-CR4 only.
 
+- ``laser_off`` (default **0**)
+
+  Toggle behavior to disable the Tx laser when the port is brought down
+  on the 40G NIC. By default the Tx laser is left on. When enabled, for
+  DAC cables the PCS is disabled, for QSFP modules the Tx disable bit is
+  written via I2C.
+
 Driver compilation and testing
 ------------------------------
 
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index f65044c9b9..4c302540d8 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -168,6 +168,9 @@ New Features
   * Added the ``bp_capa`` device argument to select the advertised
     backplane capability on the 40G NIC
     (0 for 40GBASE-KR4 + 40GBASE-CR4, 1 for KR4 only, 2 for CR4 only).
+  * Added the ``laser_off`` device argument: when set, the 40G NIC
+    turns its Tx laser off on port down
+    (PCS disable for DAC cables, SFF-8636 Tx disable for QSFP modules).
 
 * **Updated Intel qat crypto driver dependency requirements.**
 
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 2650b8b7f1..891f1ed0c4 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -11,6 +11,7 @@
 #include "txgbe_eeprom.h"
 #include "txgbe_mng.h"
 #include "txgbe_hw.h"
+#include "txgbe_e56.h"
 #include "txgbe_aml.h"
 #include "txgbe_aml40.h"
 
@@ -3259,6 +3260,33 @@ void txgbe_disable_tx_laser_multispeed_fiber(struct txgbe_hw *hw)
 	if (hw->mac.type == txgbe_mac_aml40) {
 		wr32m(hw, TXGBE_GPIODIR, TXGBE_GPIOBIT_1, TXGBE_GPIOBIT_1);
 		esdp_reg &= ~TXGBE_GPIOBIT_1;
+		if (hw->devarg.laser_off) {
+			if (txgbe_is_dac_cable(hw) ||
+			    hw->phy.sfp_type == txgbe_sfp_type_unknown) {
+				u32 rdata = 0;
+
+				rte_spinlock_lock(&hw->phy_lock);
+				rdata = rd32_ephy(hw, PMD_CFG0);
+				set_fields_e56(&rdata,
+					       E56PHY_PMD_CFG_0_RX_EN_CFG,
+					       0x0);
+				set_fields_e56(&rdata, 15, 12, 0x0);
+				set_fields_e56(&rdata, 1, 1, 0x0);
+				wr32_ephy(hw, PMD_CFG0, rdata);
+				rte_spinlock_unlock(&hw->phy_lock);
+			} else if (txgbe_acquire_swfw_sync(hw,
+							    TXGBE_MNGSEM_SWPHY) == 0) {
+				int err;
+
+				err = hw->phy.write_i2c_eeprom(hw,
+					TXGBE_SFF_8636_TX_DISABLE,
+					TXGBE_SFF_8636_TX_DISABLE_ALL_LANES);
+				if (err)
+					DEBUGOUT("Disable Tx laser failed %d\n", err);
+				txgbe_release_swfw_sync(hw,
+							TXGBE_MNGSEM_SWPHY);
+			}
+		}
 	} else if (hw->mac.type == txgbe_mac_aml) {
 		esdp_reg |= TXGBE_GPIOBIT_1;
 	} else {
@@ -3288,6 +3316,15 @@ void txgbe_enable_tx_laser_multispeed_fiber(struct txgbe_hw *hw)
 	if (hw->mac.type == txgbe_mac_aml40) {
 		wr32m(hw, TXGBE_GPIODIR, TXGBE_GPIOBIT_1, TXGBE_GPIOBIT_1);
 		esdp_reg |= TXGBE_GPIOBIT_1;
+		if (txgbe_acquire_swfw_sync(hw, TXGBE_MNGSEM_SWPHY) == 0) {
+			int err;
+
+			err = hw->phy.write_i2c_eeprom(hw,
+				TXGBE_SFF_8636_TX_DISABLE, 0x0);
+			if (err)
+				DEBUGOUT("Enable Tx laser failed %d\n", err);
+			txgbe_release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
+		}
 	} else {
 		esdp_reg &= ~(TXGBE_GPIOBIT_0 | TXGBE_GPIOBIT_1);
 	}
diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h
index a5df015a4d..a06c0eb04e 100644
--- a/drivers/net/txgbe/base/txgbe_phy.h
+++ b/drivers/net/txgbe/base/txgbe_phy.h
@@ -251,6 +251,12 @@
 #define TXGBE_SFF_VENDOR_OUI_BYTE1	0x26
 #define TXGBE_SFF_VENDOR_OUI_BYTE2	0x27
 #define TXGBE_SFF_1GBE_COMP_CODES	0x06
+
+/* SFF-8636 PMD Tx disable register (byte 0x56); bit per lane,
+ * 0xF disables the transmitter on all four lanes.
+ */
+#define TXGBE_SFF_8636_TX_DISABLE		0x56
+#define TXGBE_SFF_8636_TX_DISABLE_ALL_LANES	0x0F
 #define TXGBE_SFF_10GBE_COMP_CODES	0x03
 #define TXGBE_SFF_25GBE_COMP_CODES	0x24
 #define TXGBE_SFF_COPPER_LENGTH		0x12
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index f56cd70c6f..39a70746a7 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -762,6 +762,7 @@ struct txgbe_phy_info {
 #define TXGBE_DEVARG_TX_HEAD_WB_SIZE	"tx_headwb_size"
 #define TXGBE_DEVARG_RX_DESC_MERGE	"rx_desc_merge"
 #define TXGBE_DEVARG_BP_CAPA		"bp_capa"
+#define TXGBE_DEVARG_LASER_OFF		"laser_off"
 
 static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_BP_AUTO,
@@ -779,6 +780,7 @@ static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_TX_HEAD_WB_SIZE,
 	TXGBE_DEVARG_RX_DESC_MERGE,
 	TXGBE_DEVARG_BP_CAPA,
+	TXGBE_DEVARG_LASER_OFF,
 	NULL
 };
 
@@ -834,6 +836,7 @@ struct txgbe_devargs {
 	u16 tx_headwb;
 	u16 tx_headwb_size;
 	u16 rx_desc_merge;
+	u16 laser_off;
 };
 
 struct txgbe_hw {
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 27a6ff0b2e..9c31b2cfed 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -541,6 +541,7 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 tx_headwb_size = 16;
 	u16 rx_desc_merge = 1;
 	u16 bp_capa = 0;
+	u16 laser_off = 0;
 
 	/* The E56 PHY needs its own FFE defaults, as the ones above only
 	 * apply to the Sapphire PHY.
@@ -594,6 +595,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 			   &txgbe_handle_devarg, &rx_desc_merge);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_BP_CAPA,
 			   &txgbe_handle_devarg, &bp_capa);
+	rte_kvargs_process(kvlist, TXGBE_DEVARG_LASER_OFF,
+			   &txgbe_handle_devarg, &laser_off);
 	rte_kvargs_free(kvlist);
 
 null:
@@ -604,6 +607,7 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	hw->devarg.tx_headwb = tx_headwb;
 	hw->devarg.tx_headwb_size = tx_headwb_size;
 	hw->devarg.rx_desc_merge = rx_desc_merge;
+	hw->devarg.laser_off = laser_off;
 	hw->phy.ffe_set = ffe_set;
 	hw->phy.ffe_main = ffe_main;
 	hw->phy.ffe_pre = ffe_pre;
@@ -6518,7 +6522,8 @@ RTE_PMD_REGISTER_PARAM_STRING(net_txgbe,
 			      TXGBE_DEVARG_TX_HEAD_WB "=<0|1>"
 			      TXGBE_DEVARG_TX_HEAD_WB_SIZE "=<1|16>"
 			      TXGBE_DEVARG_RX_DESC_MERGE "=<0|1>"
-			      TXGBE_DEVARG_BP_CAPA "=<0|1|2>");
+			      TXGBE_DEVARG_BP_CAPA "=<0|1|2>"
+			      TXGBE_DEVARG_LASER_OFF "=<0|1>");
 
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_init, init, NOTICE);
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_driver, driver, NOTICE);
-- 
2.55.0.windows.2


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

* [PATCH v2 14/15] net/txgbe: fix CR/KR link training and recovery
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (12 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 13/15] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
@ 2026-09-08 12:38   ` Zaiyu Wang
  2026-09-08 12:39   ` [PATCH v2 15/15] net/txgbe: align link capabilities and DAC classification Zaiyu Wang
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:38 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

Backplane CR/KR link training on the E56 PHY is unreliable and does
not recover after a link event: the completion poll can block for a
second on a condition that never triggers, the page exchange is only
run once and its result is assumed to stay valid, and the FFE init
mode and calibration ordering are also wrong.

- Poll the AN FSM (0x78010, value 0x9) for CL72 completion with a
  1 ms step and a 400 ms budget, replacing the ephy 0x163c mask-0xe
  poll that tested the wrong condition; the per-lane TX-FFE dumps
  move into txgbe_e56_get_txffe(), called once AN completes.
- Re-run the page exchange on every AN next-page interrupt from the
  event handler (50 x 1 ms poll, explicit next-page handshake,
  -ETIMEDOUT on expiry) and only enter training after it succeeds;
  the inline exchange in the AN73 flow is removed and a CL72 failure
  no longer aborts the flow, so every link event re-runs the
  exchange instead of assuming the previous one is still valid.
- Initialize the FFE init mode bits in cfg_40g()/cfg_10g(), run
  txgbe_e56_set_rxs_ufine_le_max() after the RXS osc init, and write
  0x78001 = 0x7 in the AN programming sequence.
- Clear hw->bp_link_mode in txgbe_set_link_to_sfi() so a port that
  trained on the backplane does not keep a stale backplane mode
  after switching to SFI.
- Drop a stray C99 comment left on the AN-config flag assignment.

Fixes: 234ce0d1fa9d ("net/txgbe: fix link stability for Amber-Lite backplane mode")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_e56.c    |   3 +
 drivers/net/txgbe/base/txgbe_e56.h    |   1 +
 drivers/net/txgbe/base/txgbe_e56_bp.c | 161 +++++++++++++++-----------
 drivers/net/txgbe/base/txgbe_e56_bp.h |   2 +
 drivers/net/txgbe/base/txgbe_phy.c    |   3 +
 drivers/net/txgbe/txgbe_ethdev.c      |  26 ++++-
 6 files changed, 128 insertions(+), 68 deletions(-)

diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index 2711863f2c..8e986daf96 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -551,6 +551,7 @@ u32 txgbe_e56_cfg_40g(struct txgbe_hw *hw)
 
 	addr  = E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR;
 	rdata = rd32_ephy(hw, addr);
+	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_0, 0x2);
 	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2, 0x2);
 	wr32_ephy(hw, addr, rdata);
 
@@ -1377,6 +1378,8 @@ txgbe_e56_cfg_10g(struct txgbe_hw *hw)
 
 	addr = E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR;
 	rdata = rd32_ephy(hw, addr);
+	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_0,
+		       0x2);
 	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2,
 		       0x2);
 	wr32_ephy(hw, addr, rdata);
diff --git a/drivers/net/txgbe/base/txgbe_e56.h b/drivers/net/txgbe/base/txgbe_e56.h
index fe9a83ae01..32d95b61b9 100644
--- a/drivers/net/txgbe/base/txgbe_e56.h
+++ b/drivers/net/txgbe/base/txgbe_e56.h
@@ -435,6 +435,7 @@ typedef union {
 #define E56PHY_KRT_TFSM_CFGKRT_TFSM_HOLDOFF_TIMER_X256K 23, 16
 
 #define E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR   (E56PHY_PMD_BASE_ADDR + 0x2BC)
+#define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_0 1, 0
 #define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2 9, 8
 #define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_3 13, 12
 
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.c b/drivers/net/txgbe/base/txgbe_e56_bp.c
index d376d918df..f840e6b5dd 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.c
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.c
@@ -813,6 +813,7 @@ static int txgbe_e56_phy_rxs_calib_adapt_seq(struct txgbe_hw *hw,
 		status |= txgbe_e56_ctle_bypass_seq(hw, bp_link_mode);
 
 	status |= txgbe_e56_rxs_osc_init_for_temp_track_range(hw, bp_link_mode);
+	txgbe_e56_set_rxs_ufine_le_max(hw, bp_link_mode);
 
 	/* Wait an fsm_rx_sts 25G */
 	BP_LOG("Wait CTRL_FSM_RX_STAT[0]::ctrl_fsm_rx0_st to be ready ...\n");
@@ -2123,6 +2124,7 @@ int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
 	set_fields_e56(&rdata, 12, 12, 0x1);
 	wr32_epcs(hw, 0x070000, rdata);
 	wr32_epcs(hw, 0x078002, 0x0000);
+	wr32_epcs(hw, 0x78001, 0x7);
 	/* pcs case fec en to work around first */
 	wr32_epcs(hw, 0x100ab, 1);
 
@@ -2351,24 +2353,29 @@ static int chk_bkp_ability(struct txgbe_hw *hw,
 	return 0;
 }
 
-static int txgbe_e56_exchange_page(struct txgbe_hw *hw)
+int txgbe_e56_exchange_page(struct txgbe_hw *hw)
 {
 	struct txgbe_backplane_ability local_ability = {0}, lp_ability = {0};
 	u32 an_int, base_page = 0;
-	int count = 0;
+	int count = 0, count2 = 0;
 
 	an_int = rd32_epcs(hw, 0x78002);
-	/* 500ms timeout */
 	if (!(an_int & VR_AN_INTR_PG_RCV))
 		return -EINVAL;
 
-	for (count = 0; count < 500; count++) {
+	/* 50ms timeout */
+	for (count = 0; count < 50; count++) {
 		u32 fsm = rd32_epcs(hw, 0x78010);
-		u32 rdata = rd32_epcs(hw, 0x78002);
+		u32 next_page = 0;
+		u32 rdata;
+
+		count2++;
 
 		BP_LOG("-----count----- %d - fsm: %x\n", count, fsm);
-		BP_LOG("read 78002 data %0x and clear pacv\n", rdata);
+		rdata = rd32_epcs(hw, 0x78002);
+		/* clear an pacv int */
 		an_int = rdata;
+		BP_LOG("read 78002 data %0x and clear pacv\n", rdata);
 		set_fields_e56(&rdata, 2, 2, 0x0);
 		wr32_epcs(hw, 0x78002, rdata);
 		if (an_int & VR_AN_INTR_PG_RCV) {
@@ -2383,31 +2390,84 @@ static int txgbe_e56_exchange_page(struct txgbe_hw *hw)
 					wr32_epcs(hw, 0x70016, 0x2001);
 					BP_LOG("write 70016 0x%0x\n",
 					       0x2001);
+					next_page = 1;
+					count = 0; /* reset count to wait next page */
+				} else {
+					next_page = 0;
 				}
 				base_page = 1;
 			}
 		}
-		if ((fsm & 0x8) == 0x8) {
-			hw->fsm = 0x8;
-			goto check_ability;
+		if (!next_page) {
+			if ((fsm & 0x8) == 0x8) {
+				hw->fsm = 0x8;
+				goto check_ability;
+			}
 		}
-		usec_delay(100);
+		usec_delay(1000);
 	}
 
 check_ability:
+	if (count == 50) {
+		BP_LOG("Wait for next page timeout\n");
+		return -ETIMEDOUT;
+	}
+	BP_LOG("AN exchange page done in %d ms\n", count2);
 	return chk_bkp_ability(hw, local_ability, lp_ability);
 }
 
+void txgbe_e56_get_txffe(struct txgbe_hw *hw)
+{
+	/* 21. read txffe to check kr training status */
+	u32 rdata = 0, pmd_ctrl = 0, lane_idx = 0, lane_num = 0, txffe = 0;
+
+	switch (hw->bp_link_mode) {
+	case 10:
+		lane_num = 1;
+		break;
+	case 40:
+		lane_num = 4;
+		break;
+	case 25:
+		lane_num = 1;
+		break;
+	default:
+		BP_LOG("%s %d :Invalid speed\n", __func__, __LINE__);
+		return;
+	}
+
+	BP_LOG("%dG phy kr training check.... fsm: %x\n",
+	       hw->bp_link_mode, rd32_epcs(hw, 0x78010));
+	rdata = rd32_ephy(hw, 0x163c) & GENMASK(lane_num, 1);
+	pmd_ctrl = rd32_ephy(hw, 0x1644);
+	BP_LOG("KR TRAINNING CHECK = %x. pmd_ctrl:%lx-%lx-%lx-%lx\n",
+	       rdata,
+	       FIELD_GET_M(GENMASK(3, 0), pmd_ctrl),
+	       FIELD_GET_M(GENMASK(7, 4), pmd_ctrl),
+	       FIELD_GET_M(GENMASK(11, 8), pmd_ctrl),
+	       FIELD_GET_M(GENMASK(15, 12), pmd_ctrl));
+	BP_LOG("before: %x-%x-%x-%x\n",
+	       rd32_ephy(hw, 0x141c), rd32_ephy(hw, 0x1420),
+	       rd32_ephy(hw, 0x1424), rd32_ephy(hw, 0x1428));
+	for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
+		txffe = rd32_ephy(hw, 0x828 + lane_idx * 0x100);
+		BP_LOG("after[%x]: %lx-%lx-%lx-%lx\n", lane_idx,
+		       FIELD_GET_M(GENMASK(6, 0), txffe),
+		       FIELD_GET_M(GENMASK(21, 16), txffe),
+		       FIELD_GET_M(GENMASK(29, 24), txffe),
+		       FIELD_GET_M(GENMASK(13, 8), txffe));
+	}
+}
+
 static int txgbe_e56_cl72_training(struct txgbe_hw *hw)
 {
 	u32 bylinkmode = hw->bp_link_mode;
 	u8 bypass_ctle = hw->bypass_ctle;
 	int status = 0, temp_data = 0;
-	u32 lane_num = 0, lane_idx = 0;
-	u32 __rte_unused pmd_ctrl = 0, txffe = 0;
+	u32 lane_num = 0;
+	u32 __rte_unused pmd_ctrl = 0;
 	int ret = 0;
 	u32 rdata;
-
 	u8 pll_en_cfg = 0;
 	u8 pmd_mode = 0;
 
@@ -2463,52 +2523,48 @@ static int txgbe_e56_cl72_training(struct txgbe_hw *hw)
 
 	/* 18 */
 	/* 19. rxs calibration and adaptation sequence */
-	BP_LOG("2.4 Wait %dG RXS.... fsm: %x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
+	BP_LOG("2.4 Wait %dG RXS.... fsm: %x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
 	status = txgbe_e56_phy_rxs_calib_adapt_seq(hw, bylinkmode, bypass_ctle);
 	ret |= status;
 	/* 20 */
-	BP_LOG("2.5 Wait %dG phy calibration.... fsm: %x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
-	txgbe_e56_set_rxs_ufine_le_max(hw, bylinkmode);
+	BP_LOG("2.5 Wait %dG phy calibration.... fsm: %x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
 	status = txgbe_e56_get_temp(hw, &temp_data);
 	if (bylinkmode == 40)
 		status = txgbe_temp_track_seq_40g(hw, TXGBE_LINK_SPEED_40GB_FULL);
 	else
 		status = txgbe_e56_rxs_post_cdr_lock_temp_track_seq(hw, bylinkmode);
+
+	ret |= status;
 	/* 21 */
-	BP_LOG("2.6 Wait %dG phy kr training check.... fsm: %x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
-	status = kr_read_poll(rd32_ephy, rdata,
-				  ((rdata & 0xe) & GENMASK(lane_num, 1)) ==
-				  (0xe & GENMASK(lane_num, 1)), 100,
-				   10000, hw, 0x163c);
+	BP_LOG("2.6 Wait %dG phy kr fsm check : %x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
+	status = kr_read_poll(rd32_epcs, rdata,
+			      (rdata & 0x9) == 0x9, 1000,
+			      400, hw, 0x78010);
 	pmd_ctrl = rd32_ephy(hw, 0x1644);
-	BP_LOG("KR TRAINING CHECK = %x, %s. pmd_ctrl:%lx-%lx-%lx-%lx\n",
+	BP_LOG("KR FSM CHECK = %x, %s. pmd_ctrl:%lx-%lx-%lx-%lx\n",
 	       rdata, status ? "FAILED" : "SUCCESS",
 	       FIELD_GET_M(GENMASK(3, 0), pmd_ctrl),
 	       FIELD_GET_M(GENMASK(7, 4), pmd_ctrl),
 	       FIELD_GET_M(GENMASK(11, 8), pmd_ctrl),
 	       FIELD_GET_M(GENMASK(15, 12), pmd_ctrl));
 	ret |= status;
-	BP_LOG("before: %x-%x-%x-%x\n",
-	       rd32_ephy(hw, 0x141c), rd32_ephy(hw, 0x1420),
-	       rd32_ephy(hw, 0x1424), rd32_ephy(hw, 0x1428));
-
-	for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
-		txffe = rd32_ephy(hw, 0x828 + lane_idx * 0x100);
-		BP_LOG("after[%x]: %lx-%lx-%lx-%lx\n", lane_idx,
-		       FIELD_GET_M(GENMASK(6, 0), txffe),
-		       FIELD_GET_M(GENMASK(21, 16), txffe),
-		       FIELD_GET_M(GENMASK(29, 24), txffe),
-		       FIELD_GET_M(GENMASK(13, 8), txffe));
-	}
 
 	/* 22 */
-	BP_LOG("2.7 Wait %dG phy Rx adc.... fsm:%x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
+	BP_LOG("2.7 Wait %dG phy Rx adc.... fsm:%x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
 	status = txgbe_e56_rxs_adc_adapt_seq(hw, bypass_ctle);
 
+	BP_LOG("2.8 ===end ret : %d.... fsm:%x, an_int: %x\n",
+	       ret, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
+
 	return ret;
 }
 
@@ -2517,27 +2573,7 @@ int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw)
 	int status = 0;
 	u32 rdata;
 
-	BP_LOG("2.1 Wait page changed ....\n");
-	status = txgbe_e56_exchange_page(hw);
-	if (status) {
-		BP_LOG("Exchange page failed\n");
-		return status;
-	}
-
-	BP_LOG("2.2 Wait page changed ..done..\n");
-	wr32_epcs(hw, 0x100ab, 0);
-	if (AN_TRAINING_MODE) {
-		rdata = rd32_epcs(hw, 0x70000);
-		BP_LOG("read 0x70000 data %0x\n", rdata);
-		wr32_epcs(hw, 0x70000, 0);
-		BP_LOG("write 0x70000 0x%0x\n", 0);
-	}
-
-	rdata = rd32_epcs(hw, 0x78002);
-	BP_LOG("read 78002 data %0x and clear page int\n", rdata);
-	set_fields_e56(&rdata, 2, 2, 0x0);
-	wr32_epcs(hw, 0x78002, rdata);
-
+	/* 10  RXS_DISABLE - TXS_DISABLE - CMS_DISABLE */
 	/* dis phy tx/rx lane */
 	rdata = rd32_ephy(hw, 0x1400);
 	set_fields_e56(&rdata, 19, 16, 0x0);
@@ -2583,11 +2619,6 @@ int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw)
 	}
 
 	status = txgbe_e56_cl72_training(hw);
-	if (status) {
-		BP_LOG("CL72 training failed, status = %d\n", status);
-		return status;
-	}
-
 	rdata = rd32_ephy(hw, E56PHY_RXS_IDLE_DETECT_1_ADDR);
 	set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MAX, 0x28);
 	set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MIN, 0xa);
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.h b/drivers/net/txgbe/base/txgbe_e56_bp.h
index d2c49c2fce..da0d02b79f 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.h
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.h
@@ -279,4 +279,6 @@ typedef union {
 int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
 				u8 bp_link_mode, u32 need_restart);
 int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw);
+int txgbe_e56_exchange_page(struct txgbe_hw *hw);
+void txgbe_e56_get_txffe(struct txgbe_hw *hw);
 #endif
diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index 8b653f0aeb..10df23afae 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1947,6 +1947,9 @@ txgbe_set_link_to_sfi(struct txgbe_hw *hw,
 	s32 err = 0;
 	u32 value = 0;
 
+	/* Switching to SFI mode clears backplane link mode. */
+	hw->bp_link_mode = 0;
+
 	/* Set the module link speed */
 	hw->mac.set_rate_select_speed(hw, speed);
 	/* 1. Wait xpcs power-up good */
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 9c31b2cfed..5e3403646c 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3025,6 +3025,7 @@ void txgbe_dev_e56_check_bp_event(void *param)
 	u32 __rte_unused an_int = 0;
 	int ret = 0;
 	bool need_link_update = false;
+	bool exchange_done = false;
 
 	if (!hw)
 		return;
@@ -3043,8 +3044,10 @@ void txgbe_dev_e56_check_bp_event(void *param)
 		hw->phy.sfp_type = txgbe_sfp_type_not_present;
 	}
 
-	if (!(txgbe_xpcs_an_enabled(hw)))
+	if (!(txgbe_xpcs_an_enabled(hw))) {
+		BP_LOG("%s %d\n", __func__, __LINE__);
 		return;
+	}
 
 	if (!hw->devarg.auto_neg)
 		return;
@@ -3063,6 +3066,7 @@ void txgbe_dev_e56_check_bp_event(void *param)
 		need_link_update = true;
 		value &= ~VR_AN_INTR_CMPLT;
 		wr32_epcs(hw, VR_AN_INTR, value);
+		txgbe_e56_get_txffe(hw);
 	}
 
 	if (value & VR_AN_INTR_LINK) {
@@ -3080,7 +3084,21 @@ void txgbe_dev_e56_check_bp_event(void *param)
 	}
 
 	if (value & VR_AN_INTR_PG_RCV) {
-		BP_LOG("%d Enter training\n", hw->port_id);
+		BP_LOG("%d 2.1 *** Wait page changed ....\n", hw->port_id);
+		ret = txgbe_e56_exchange_page(hw);
+		if (ret) {
+			BP_LOG("%d 2.2 *** Exchange page failed\n", hw->port_id);
+			goto an_status;
+		} else {
+			BP_LOG("%d 2.2 *** Wait page changed ..done..\n",
+			       hw->port_id);
+			wr32_epcs(hw, 0x100ab, 0);
+			exchange_done = true;
+		}
+	}
+
+	if (exchange_done) {
+		BP_LOG("%d 2.2.2 *** Enter training\n", hw->port_id);
 		ret = txgbe_handle_e56_bkp_an73_flow(hw);
 		if (!AN_TRAINING_MODE) {
 			fsm = rd32_epcs(hw, 0x78010);
@@ -3783,8 +3801,10 @@ txgbe_dev_interrupt_get_status(struct rte_eth_dev *dev,
 	if (eicr & TXGBE_ICRMISC_LSC)
 		intr->flags |= TXGBE_FLAG_NEED_LINK_UPDATE;
 
-	if (eicr & TXGBE_ICRMISC_ANDONE)
+	if (eicr & TXGBE_ICRMISC_ANDONE) {
+		PMD_DRV_LOG(DEBUG, "an int eicr=0x%08x", eicr);
 		intr->flags |= TXGBE_FLAG_NEED_AN_CONFIG;
+	}
 
 	if (eicr & TXGBE_ICRMISC_VFMBX)
 		intr->flags |= TXGBE_FLAG_MAILBOX;
-- 
2.55.0.windows.2


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

* [PATCH v2 15/15] net/txgbe: align link capabilities and DAC classification
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
                     ` (13 preceding siblings ...)
  2026-09-08 12:38   ` [PATCH v2 14/15] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
@ 2026-09-08 12:39   ` Zaiyu Wang
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 12:39 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

An active DAC can be misidentified as a 40G optical module, in which
case the driver reports 40G and enables autoneg for a module that
does not support it; DACs and optical modules are also treated
differently in the FFE, CTLE and capability-report paths.

Rework the AML40/AML link capabilities and DAC classification:

- Port the five-branch capability layout to AML40:
  backplane, DAC (txgbe_is_dac_cable() plus the 10G-only AN-off
  case), multispeed fiber, 40G QSFP and 10G SFP. Modules previously
  misreported as 40G through the fallback now report the correct
  speed and autoneg.
- Add the 40G-active transceiver identification (sfp_type enum and
  identify branch). Like the kernel driver, 40G active cables are
  handled through the optical path, as SFF-8636 byte 131 bit 0
  ("40G Active Cable") also covers active optical cables.
- Unify DAC classification on txgbe_is_dac_cable(), including the
  40G FFE selection in txgbe_e56_tx_ffe_cfg() which still
  open-coded the qsfp_type_40g_cu check; the 10G active cable type
  (da_act_lmt) is no longer treated as an optical module.

Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml.c   |  3 +-
 drivers/net/txgbe/base/txgbe_aml40.c | 74 +++++++++++++++++++++++-----
 drivers/net/txgbe/base/txgbe_e56.c   |  9 ++--
 drivers/net/txgbe/base/txgbe_phy.c   |  7 +++
 drivers/net/txgbe/base/txgbe_phy.h   |  1 +
 drivers/net/txgbe/base/txgbe_type.h  |  2 +
 6 files changed, 76 insertions(+), 20 deletions(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml.c b/drivers/net/txgbe/base/txgbe_aml.c
index ac80d85f08..fe4becf198 100644
--- a/drivers/net/txgbe/base/txgbe_aml.c
+++ b/drivers/net/txgbe/base/txgbe_aml.c
@@ -103,8 +103,7 @@ s32 txgbe_get_link_capabilities_aml(struct txgbe_hw *hw,
 		*speed = TXGBE_LINK_SPEED_10GB_FULL |
 			 TXGBE_LINK_SPEED_25GB_FULL;
 		*autoneg = true;
-	} else if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
-		   hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1) {
+	} else if (txgbe_is_dac_cable(hw)) {
 		if (hw->phy.fiber_suppport_speed ==
 		    TXGBE_LINK_SPEED_10GB_FULL) {
 			hw->devarg.auto_neg = false;
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 2d3b32839c..512b8ba331 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -95,27 +95,77 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
 	return 0;
 }
 
+static int txgbe_is_40g_fiber_qsfp(struct txgbe_hw *hw)
+{
+	if (hw->phy.sfp_type == txgbe_qsfp_type_40g_sr_core0 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_sr_core1 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_lr_core0 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_lr_core1 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_active_core0 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_active_core1)
+		return true;
+
+	return false;
+}
+
+static int txgbe_is_10g_fiber_sfp(struct txgbe_hw *hw)
+{
+	if (hw->phy.sfp_type == txgbe_sfp_type_srlr_core0 ||
+	    hw->phy.sfp_type == txgbe_sfp_type_srlr_core1)
+		return true;
+
+	return false;
+}
+
 s32 txgbe_get_link_capabilities_aml40(struct txgbe_hw *hw,
 				      u32 *speed,
 				      bool *autoneg)
 {
-	if (hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
-	    hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1) {
-		*speed = hw->phy.fiber_suppport_speed;
-		*autoneg = hw->devarg.auto_neg;
-	} else if (txgbe_is_backplane(hw)) {
-		*speed = TXGBE_LINK_SPEED_40GB_FULL |
-			 TXGBE_LINK_SPEED_10GB_FULL;
+	PMD_DRV_LOG(DEBUG, "port[%d]hw->phy.sfp_type = %d",
+		    hw->bus.lan_id, hw->phy.sfp_type);
+
+	/* Backplane */
+	if (txgbe_is_backplane(hw)) {
+		*speed = TXGBE_LINK_SPEED_10GB_FULL |
+			 TXGBE_LINK_SPEED_40GB_FULL;
+		/* Backplane supports autonegotiation */
 		*autoneg = hw->devarg.auto_neg;
+		return 0;
+	}
+
+	/* Fiber or DAC cable */
+	if (txgbe_is_dac_cable(hw)) {
+		/*
+		 * 10G-only DAC cable: legacy build-time AUTO=0/1 default
+		 * mode forces AN off. DPDK equivalent: devarg.auto_neg == 0.
+		 */
+		if (hw->phy.fiber_suppport_speed ==
+		    TXGBE_LINK_SPEED_10GB_FULL &&
+		    hw->devarg.auto_neg == 0) {
+			*autoneg = false;
+		} else {
+			*autoneg = hw->devarg.auto_neg;
+		}
+		*speed = hw->phy.fiber_suppport_speed;
+	} else if (hw->phy.multispeed_fiber) {
+		/* multispeed fiber must come before single-sfp/qsfp fiber */
+		*speed = TXGBE_LINK_SPEED_10GB_FULL |
+			 TXGBE_LINK_SPEED_40GB_FULL;
+		*autoneg = true;
+	} else if (txgbe_is_40g_fiber_qsfp(hw)) {
+		*speed = TXGBE_LINK_SPEED_40GB_FULL;
+		*autoneg = false;
+	} else if (txgbe_is_10g_fiber_sfp(hw)) {
+		*speed = TXGBE_LINK_SPEED_10GB_FULL;
+		*autoneg = false;
 	} else {
 		/*
-		 * Temporary workaround: set speed to 40G even if sfp not present
-		 * to avoid TXGBE_ERR_LINK_SETUP returned by setup_mac_link, but
-		 * a more reasonable solution is don't execute setup_mac_link when
-		 * sfp module not present.
+		 * Unknown / unsupported module: keep 40G default to avoid
+		 * TXGBE_ERR_LINK_SETUP returned by setup_mac_link, mirroring
+		 * the temporary workaround in the previous version.
 		 */
 		*speed = TXGBE_LINK_SPEED_40GB_FULL;
-		*autoneg = true;
+		*autoneg = false;
 	}
 
 	return 0;
diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index 8e986daf96..f996113ab8 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -73,8 +73,7 @@ u32 txgbe_e56_tx_ffe_cfg(struct txgbe_hw *hw, u32 speed)
 		pre2 = S10G_TX_FFE_CFG_PRE2;
 		post = S10G_TX_FFE_CFG_POST;
 	} else if (speed == TXGBE_LINK_SPEED_25GB_FULL) {
-		if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
-		    hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1 ||
+		if (txgbe_is_dac_cable(hw) ||
 		    txgbe_is_backplane(hw)) {
 			ffe_main = S25G_TX_FFE_CFG_DAC_MAIN;
 			pre1 = S25G_TX_FFE_CFG_DAC_PRE1;
@@ -92,8 +91,7 @@ u32 txgbe_e56_tx_ffe_cfg(struct txgbe_hw *hw, u32 speed)
 		pre2 = S10G_TX_FFE_CFG_PRE2;
 		post = S10G_TX_FFE_CFG_POST;
 
-		if (hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
-		    hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1 ||
+		if (txgbe_is_dac_cable(hw) ||
 		    txgbe_is_backplane(hw)) {
 			ffe_main = S40G_TX_FFE_CFG_MAIN;
 			pre1 = S40G_TX_FFE_CFG_PRE1;
@@ -2622,8 +2620,7 @@ txgbe_e56_rxs_calib_adapt_seq(struct txgbe_hw *hw, u32 speed)
 	u32 rdata = 0x0;
 	bool bypass_ctle = true;
 
-	if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
-	    hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1)
+	if (txgbe_is_dac_cable(hw))
 		bypass_ctle = 0;
 
 	if (hw->mac.type == txgbe_mac_aml) {
diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index 10df23afae..e52f1da87d 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1156,6 +1156,13 @@ s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw)
 			else
 				hw->phy.sfp_type = txgbe_qsfp_type_40g_lr_core1;
 		}
+
+		if (transceiver_type & TXGBE_SFF_ETHERNET_40G_ACTIVE) {
+			if (hw->bus.lan_id == 0)
+				hw->phy.sfp_type = txgbe_qsfp_type_40g_active_core0;
+			else
+				hw->phy.sfp_type = txgbe_qsfp_type_40g_active_core1;
+		}
 	}
 
 	hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h
index a06c0eb04e..552fedadab 100644
--- a/drivers/net/txgbe/base/txgbe_phy.h
+++ b/drivers/net/txgbe/base/txgbe_phy.h
@@ -316,6 +316,7 @@
 #define TXGBE_SFF_ETHERNET_40G_CR4		MS(3, 0x1)
 #define TXGBE_SFF_ETHERNET_40G_SR4		MS(2, 0x1)
 #define TXGBE_SFF_ETHERNET_40G_LR4		MS(1, 0x1)
+#define TXGBE_SFF_ETHERNET_40G_ACTIVE		MS(0, 0x1)
 
 #define TXGBE_SFF_SOFT_RS_SELECT_MASK		0x8
 #define TXGBE_SFF_SOFT_RS_SELECT_10G		0x8
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index 39a70746a7..91771b9cbd 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -249,6 +249,8 @@ enum txgbe_sfp_type {
 	txgbe_qsfp_type_40g_sr_core1,
 	txgbe_qsfp_type_40g_lr_core0,
 	txgbe_qsfp_type_40g_lr_core1,
+	txgbe_qsfp_type_40g_active_core0,
+	txgbe_qsfp_type_40g_active_core1,
 	txgbe_sfp_type_not_present = 0xFFFE,
 	txgbe_sfp_type_not_known = 0xFFFF
 };
-- 
2.55.0.windows.2



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

* [PATCH v3 00/15] Wangxun fixes and new features
       [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
                   ` (14 preceding siblings ...)
       [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
@ 2026-09-08 13:25 ` Zaiyu Wang
  2026-09-08 14:20   ` Stephen Hemminger
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
  16 siblings, 1 reply; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang

This series addresses link-related issues on Wangxun Amber-lite 25G/40G NICs
(CR/KR training, hot-plug, 10G link state), and additionally refines UDP
offload handling.

---
v2:
 - add a new commit to handle 10G config on dual-speed DAC
 - P02: handle TXGBE_ERR_PHY_INIT_NOT_DONE before the timeout split and leave link_valid untouched.
 - P07: resolve the inner tunnel type in a local variable instead of rewriting mbuf->ol_flags.
        check the rte_pktmbuf_read() result for short or mis-annotated packets.
        use RTE_GENEVE_DEFAULT_PORT instead of the literal 6081.
        add a Fixes: tag pointing to the commit that introduced the tunnel offload handling.
 - P10: split into a bug-fix commit and a feature commit.
        document both devargs in the NIC guide and the release notes.
 - P11: check the acquire_swfw_sync() result and only touch I2C while the semaphore is held.
        replace the magic numbers with named constants.
        add the release notes entry.
 - P12: drop the stray C99 comment on the AN-config flag assignment that checkpatch rejects.
 - P13: reword the message to state that 40G active cables are handled through the optical path.
        use txgbe_is_dac_cable() in the 40G FFE selection to match the 25G path.
---

---
Not changed in this revision:

 - P11: enable_tx_laser() is not gated by laser_off. laser_off only
   controls whether the Tx laser is brought down on port stop, while
   enable_tx_laser() is unconditionally called from dev_start() and
   dev_set_link_up() and must always bring the laser up, otherwise the
   default (laser_off=0) configuration would never bring the link up.

 - P11: no extra restore of PMD_CFG0 bit 1 on the DAC path. Bits 19:12
   are restored by txgbe_e56_set_phy_link_mode() and
   txgbe_set_link_to_amlite(); bit 1 (PMD enable) is also restored by
   txgbe_e56_set_phy_link_mode(), which the xpcs AN path calls on link
   up, so no additional write is required.

 - P12: no total iteration bound was added to txgbe_e56_exchange_page().
   The loop is bounded per page and exits when the AN FSM reaches 0x8,
   so it does not hang in a normal Clause 73 flow. As this is hardware
   related configuration, we leave the current behaviour unchanged for
   now.
---

Zaiyu Wang (15):
  net/txgbe: fix failure to configure 10G on dual-speed DAC
  net/txgbe: fix e56 PHY configuration error
  net/txgbe: fix incorrect link state in 10G forced mode
  net/txgbe: do not force reconfig on link retry
  net/txgbe: set i2c sda hold time
  net/txgbe: fix link speed display info for 10G mode
  net/txgbe: remove stale outer UDP checksum offload flag
  net/txgbe: add offload support for tunnel type UDP
  net/txgbe: fix SFP hot-plug when auto-negotiation is on
  net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation
  net/txgbe: fix 40G FFE tuning applied to first lane only
  net/txgbe: add pre2 and backplane capability devargs
  net/txgbe: add devarg to turn off Tx laser for 40G NIC
  net/txgbe: fix CR/KR link training and recovery
  net/txgbe: align link capabilities and DAC classification

 doc/guides/nics/txgbe.rst              |  18 +++
 doc/guides/rel_notes/release_26_11.rst |  11 ++
 drivers/net/txgbe/base/txgbe_aml.c     |   3 +-
 drivers/net/txgbe/base/txgbe_aml40.c   | 100 +++++++++++++--
 drivers/net/txgbe/base/txgbe_e56.c     |  14 +--
 drivers/net/txgbe/base/txgbe_e56.h     |   6 +
 drivers/net/txgbe/base/txgbe_e56_bp.c  | 161 +++++++++++++++----------
 drivers/net/txgbe/base/txgbe_e56_bp.h  |   2 +
 drivers/net/txgbe/base/txgbe_hw.c      |  29 +++++
 drivers/net/txgbe/base/txgbe_phy.c     |  13 ++
 drivers/net/txgbe/base/txgbe_phy.h     |   7 ++
 drivers/net/txgbe/base/txgbe_regs.h    |   3 +
 drivers/net/txgbe/base/txgbe_type.h    |  17 ++-
 drivers/net/txgbe/txgbe_ethdev.c       | 120 ++++++++++++++++--
 drivers/net/txgbe/txgbe_rxtx.c         |  29 ++++-
 15 files changed, 432 insertions(+), 101 deletions(-)

-- 
2.55.0.windows.2


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

* [PATCH v3 01/15] net/txgbe: fix failure to configure 10G on dual-speed DAC
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 02/15] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
                     ` (13 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

Setting "port config speed 10000" on a 10G/40G dual-speed DAC cable
fails with LINK_SETUP_ERR, and the AN base page always advertises
only 40G.

Three checks independently blocked 10G:

1. allowed_speeds in dev_start was restricted to 40G, so the user
   request was rejected before reaching setup_link.
2. get_link_capabilities_aml40() returned only 40G for all DAC
   cables, so the link_capabilities mask in setup_phy_link_aml40()
   stripped any 10G bit from the caller speed.
3. setup_phy_link_aml40() on the AN path passed a hardcoded 40 to
   txgbe_e56_set_phy_link_mode(), ignoring the caller speed.

Remove each of these restrictions so 10G flows through from user
configuration to the AN base page advertisement. On DAC cables the
capability is read from hw->phy.fiber_suppport_speed, which reflects
the actual SFP module.

Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c | 17 ++++++++++++-----
 drivers/net/txgbe/txgbe_ethdev.c     |  2 +-
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 1098efe5e6..7476759d4d 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -98,11 +98,12 @@ s32 txgbe_get_link_capabilities_aml40(struct txgbe_hw *hw,
 {
 	if (hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
 	    hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1) {
-		*speed = TXGBE_LINK_SPEED_40GB_FULL;
-		*autoneg = true;
+		*speed = hw->phy.fiber_suppport_speed;
+		*autoneg = hw->devarg.auto_neg;
 	} else if (txgbe_is_backplane(hw)) {
-		*speed = TXGBE_LINK_SPEED_40GB_FULL;
-		*autoneg = true;
+		*speed = TXGBE_LINK_SPEED_40GB_FULL |
+			 TXGBE_LINK_SPEED_10GB_FULL;
+		*autoneg = hw->devarg.auto_neg;
 	} else {
 		/*
 		 * Temporary workaround: set speed to 40G even if sfp not present
@@ -171,11 +172,17 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
 		if (link_up && hw->an_done && !autoneg_wait_to_complete)
 			return status;
 		rte_spinlock_lock(&hw->phy_lock);
-		txgbe_e56_set_phy_link_mode(hw, 40, autoneg_wait_to_complete);
+		txgbe_e56_set_phy_link_mode(hw, speed, autoneg_wait_to_complete);
 		rte_spinlock_unlock(&hw->phy_lock);
 		return status;
 	}
 
+	/* setup the highest link when no autoneg */
+	if (speed & TXGBE_LINK_SPEED_40GB_FULL)
+		speed = TXGBE_LINK_SPEED_40GB_FULL;
+	else if (speed & TXGBE_LINK_SPEED_10GB_FULL)
+		speed = TXGBE_LINK_SPEED_10GB_FULL;
+
 	if (txgbe_is_backplane(hw) || txgbe_is_dac_cable(hw) ||
 	    hw->phy.ffe_set) {
 		rte_spinlock_lock(&hw->phy_lock);
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 4d2746371b..bc2e11e801 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -1896,7 +1896,7 @@ txgbe_dev_start(struct rte_eth_dev *dev)
 		goto error;
 
 	if (hw->mac.type == txgbe_mac_aml40)
-		allowed_speeds = RTE_ETH_LINK_SPEED_40G;
+		allowed_speeds = RTE_ETH_LINK_SPEED_10G | RTE_ETH_LINK_SPEED_40G;
 	else if (hw->mac.type == txgbe_mac_aml)
 		allowed_speeds = RTE_ETH_LINK_SPEED_10G | RTE_ETH_LINK_SPEED_25G;
 	else
-- 
2.55.0.windows.2


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

* [PATCH v3 02/15] net/txgbe: fix e56 PHY configuration error
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
  2026-09-08 13:25   ` [PATCH v3 01/15] net/txgbe: fix failure to configure 10G on dual-speed DAC Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 03/15] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
                     ` (12 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

The e56 PHY RXS ring equalizer/tap configuration is written to the
wrong bit field: set_fields_e56(&rdata, 9, 4, 0x366) targets the
unrelated lower bits, so the configured tap values are never applied
and the equalizer stays at its default setting, which can degrade
the received signal on both the 40G and 10G paths.

Fix the field range to (21, 12), so the equalizer/tap configuration
takes effect.

Fixes: f7cfc21e9f75 ("net/txgbe: fix link stability for 40G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_e56.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index cbcc05333e..2711863f2c 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -423,7 +423,7 @@ u32 txgbe_e56_cfg_40g(struct txgbe_hw *hw)
 
 		addr  = E56PHY_RXS_RINGO_0_ADDR + (E56PHY_RXS_OFFSET * i);
 		rdata = rd32_ephy(hw, addr);
-		set_fields_e56(&rdata, 9, 4, 0x366);
+		set_fields_e56(&rdata, 21, 12, 0x366);
 		wr32_ephy(hw, addr, rdata);
 	}
 
-- 
2.55.0.windows.2


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

* [PATCH v3 03/15] net/txgbe: fix incorrect link state in 10G forced mode
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
  2026-09-08 13:25   ` [PATCH v3 01/15] net/txgbe: fix failure to configure 10G on dual-speed DAC Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 02/15] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 04/15] net/txgbe: do not force reconfig on link retry Zaiyu Wang
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

When an AML40 port is configured in 10G forced mode (auto_neg=0),
the hardware can link up but the driver keeps reporting link down
after a peer link failure: link_valid is cleared on timeout but
never restored when the peer recovers, so the link stays down until
the port is restarted.

Restore hw->link_valid = true in the success path of
txgbe_setup_phy_link_aml40(), symmetric to the 40G path. Handle
TXGBE_ERR_PHY_INIT_NOT_DONE before the timeout split and leave
link_valid untouched, matching the 25G path in
txgbe_setup_phy_link_aml(); the alarm retry then attempts the
setup again.

Fixes: f7cfc21e9f75 ("net/txgbe: fix link stability for 40G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 7476759d4d..5fa7c6a243 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -202,9 +202,18 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
 
 	rte_spinlock_lock(&hw->phy_lock);
 	ret_status = txgbe_set_link_to_amlite(hw, speed);
+	rte_spinlock_unlock(&hw->phy_lock);
+
+	/* The PHY did not come out of reset; leave link_valid alone and
+	 * let the retry in the alarm handler attempt the setup again.
+	 */
+	if (ret_status == TXGBE_ERR_PHY_INIT_NOT_DONE)
+		goto out;
+
 	if (ret_status == TXGBE_ERR_TIMEOUT)
 		hw->link_valid = false;
-	rte_spinlock_unlock(&hw->phy_lock);
+	else
+		hw->link_valid = true;
 
 	for (i = 0; i < 4; i++) {
 		txgbe_e56_check_phy_link(hw, &link_speed, &link_up);
-- 
2.55.0.windows.2


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

* [PATCH v3 04/15] net/txgbe: do not force reconfig on link retry
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (2 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 03/15] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 05/15] net/txgbe: set i2c sda hold time Zaiyu Wang
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

The link alarm retry calls mac.setup_link() with
autoneg_wait_to_complete = true. On the AN73/xpcs path, setup_link
skips reconfiguration when the link is already up and AN is done
only if the flag is false. With true, a retry that arrives after the
link is up still runs set_phy_link_mode() and resets the established
AN73 link, which then drops and never recovers (e.g. after DAC
hot-plug).

Pass false from the retry path instead.

Fixes: 6104fd11086e ("net/txgbe: fix link stability for 25G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_ethdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index bc2e11e801..9e4eca40cf 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3286,7 +3286,7 @@ txgbe_dev_setup_link_alarm_handler_aml(void *param)
 		return;
 	}
 
-	hw->mac.setup_link(hw, speed, true);
+	hw->mac.setup_link(hw, speed, false);
 
 	u32 link_speed = TXGBE_LINK_SPEED_UNKNOWN;
 	bool link_up = false;
-- 
2.55.0.windows.2


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

* [PATCH v3 05/15] net/txgbe: set i2c sda hold time
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (3 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 04/15] net/txgbe: do not force reconfig on link retry Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 06/15] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

The data_in_hold_time measured on the oscilloscope does not meet the
hardware requirement, which can corrupt SFP EEPROM reads over I2C.

Set the I2C SDA hold time to 100 (0x64) I2C clock periods for both
RX and TX in txgbe_i2c_start().

Fixes: 00970f6398c8 ("net/txgbe: fix reading SFP module SFF-8472 data")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_phy.c  | 3 +++
 drivers/net/txgbe/base/txgbe_regs.h | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index 2fbe50e242..8b653f0aeb 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1334,6 +1334,9 @@ static void txgbe_i2c_start(struct txgbe_hw *hw, u8 dev_addr)
 	wr32(hw, TXGBE_I2CSCLTMOUT, 0xFFFFFF);
 	wr32(hw, TXGBE_I2CSDATMOUT, 0xFFFFFF);
 
+	wr32m(hw, TXGBE_I2C_SDA_HOLD,
+		TXGBE_I2C_SDA_RX_HOLD | TXGBE_I2C_SDA_TX_HOLD, 0x640064);
+
 	wr32(hw, TXGBE_I2CICM, 0);
 	wr32(hw, TXGBE_I2CENA, 1);
 }
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index bf46a80862..b0042dc0d6 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -1610,6 +1610,9 @@ enum txgbe_5tuple_protocol {
 #define   TXGBE_I2CSTAT_MST          ((1U << 5))
 #define TXGBE_I2CSCLTMOUT            0x0149AC
 #define TXGBE_I2CSDATMOUT            0x0149B0 /*I2C SDA Stuck at Low Timeout*/
+#define TXGBE_I2C_SDA_HOLD              0x1497C /* SDA hold time length reg */
+#define TXGBE_I2C_SDA_RX_HOLD           0xff0000 /* SDA rx hold time length reg */
+#define TXGBE_I2C_SDA_TX_HOLD           0xffff /* SDA tx hold time length reg */
 
 /* port cfg Registers */
 #define TXGBE_PORTSTAT                  0x014404
-- 
2.55.0.windows.2


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

* [PATCH v3 06/15] net/txgbe: fix link speed display info for 10G mode
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (4 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 05/15] net/txgbe: set i2c sda hold time Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 07/15] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

When an AML40 port links up at 10G, DPDK reports the speed as 100M
instead of 10G. The 10G link status bit is not recognized in
txgbe_check_mac_link_aml40(), so any non-40G speed falls through to
the default case (UNKNOWN) which is then reported as 100M.

Add the 10G port status bit recognition, and include 10G in the
default advertised speed mask in txgbe_dev_start() so a 10G link is
reported with the correct speed.

Fixes: abf042d32b39 ("net/txgbe: add Amber-Lite 25G/40G NICs")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c | 3 +++
 drivers/net/txgbe/txgbe_ethdev.c     | 3 ++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 5fa7c6a243..d812adac69 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -85,6 +85,9 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
 		if ((links_reg & TXGBE_CFG_PORT_ST_AML_LINK_40G) ==
 			TXGBE_CFG_PORT_ST_AML_LINK_40G)
 			*speed = TXGBE_LINK_SPEED_40GB_FULL;
+		else if ((links_reg & TXGBE_CFG_PORT_ST_AML_LINK_10G) ==
+			TXGBE_CFG_PORT_ST_AML_LINK_10G)
+			*speed = TXGBE_LINK_SPEED_10GB_FULL;
 	} else {
 		*speed = TXGBE_LINK_SPEED_UNKNOWN;
 	}
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 9e4eca40cf..bb4ff3c492 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -1912,7 +1912,8 @@ txgbe_dev_start(struct rte_eth_dev *dev)
 	speed = 0x0;
 	if (*link_speeds == RTE_ETH_LINK_SPEED_AUTONEG) {
 		if (hw->mac.type == txgbe_mac_aml40) {
-			speed = TXGBE_LINK_SPEED_40GB_FULL;
+			speed = TXGBE_LINK_SPEED_40GB_FULL |
+				TXGBE_LINK_SPEED_10GB_FULL;
 		} else  if (hw->mac.type == txgbe_mac_aml) {
 			speed = (TXGBE_LINK_SPEED_10GB_FULL |
 				 TXGBE_LINK_SPEED_25GB_FULL);
-- 
2.55.0.windows.2


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

* [PATCH v3 07/15] net/txgbe: remove stale outer UDP checksum offload flag
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (5 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 06/15] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 08/15] net/txgbe: add offload support for tunnel type UDP Zaiyu Wang
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

RTE_MBUF_F_TX_OUTER_UDP_CKSUM is no longer advertised in
dev_info->tx_offload_capa, but it is still listed in
TXGBE_TX_OFFLOAD_MASK. The two are now inconsistent: a packet
carrying the flag is accepted by the offload mask check although the
driver no longer handles it.

Drop the flag from TXGBE_TX_OFFLOAD_MASK so the advertised
capability and the accepted offload flags match.

Fixes: 25fe1c780d39 ("net/txgbe: remove outer UDP checksum capability")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_rxtx.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index 794ba041a4..a295666f9d 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -61,7 +61,6 @@ static const u64 TXGBE_TX_OFFLOAD_MASK = (RTE_MBUF_F_TX_IP_CKSUM |
 		RTE_MBUF_F_TX_UDP_SEG |
 		RTE_MBUF_F_TX_TUNNEL_MASK |
 		RTE_MBUF_F_TX_OUTER_IP_CKSUM |
-		RTE_MBUF_F_TX_OUTER_UDP_CKSUM |
 #ifdef RTE_LIB_SECURITY
 		RTE_MBUF_F_TX_SEC_OFFLOAD |
 #endif
-- 
2.55.0.windows.2


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

* [PATCH v3 08/15] net/txgbe: add offload support for tunnel type UDP
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (6 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 07/15] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 09/15] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu, Ferruh Yigit

The non-standard RTE_MBUF_F_TX_TUNNEL_UDP tunnel type (UDP
encapsulation carrying either VXLAN or GENEVE) is not handled:
txgbe_set_xmit_ctx() falls into the "unknown tunnel type" case and
txgbe_get_tun_len() cannot compute the tunnel length, so tunneled
packets are sent with a wrong descriptor or dropped.

Resolve RTE_MBUF_F_TX_TUNNEL_UDP by parsing the UDP destination
port in a local variable instead of rewriting the mbuf: the
application still owns the mbuf and may re-transmit it (cloned or
multicast paths), so a second pass would otherwise see the resolved
VXLAN/GENEVE type instead of UDP. The outer_l2_len/outer_l3_len
used for the offset are application supplied and not validated by
the driver, so check the rte_pktmbuf_read() result and fall back to
a zero tunnel length on a short or mis-annotated packet. Use
RTE_GENEVE_DEFAULT_PORT for the GENEVE destination port.

Fixes: ca46fcd753b1 ("net/txgbe: support Tx with hardware offload")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_rxtx.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index a295666f9d..ad90df5f69 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -21,6 +21,7 @@
 #include <rte_debug.h>
 #include <rte_ethdev.h>
 #include <ethdev_driver.h>
+#include <rte_geneve.h>
 #include <rte_security_driver.h>
 #include <rte_memzone.h>
 #include <rte_atomic.h>
@@ -419,6 +420,7 @@ txgbe_set_xmit_ctx(struct txgbe_tx_queue *txq,
 			break;
 		case RTE_MBUF_F_TX_TUNNEL_VXLAN:
 		case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+		case RTE_MBUF_F_TX_TUNNEL_UDP:
 		case RTE_MBUF_F_TX_TUNNEL_GENEVE:
 			tunnel_seed |= TXGBE_TXD_ETYPE_UDP;
 			break;
@@ -593,6 +595,7 @@ tx_desc_ol_flags_to_ptype(uint64_t oflags)
 	switch (oflags & RTE_MBUF_F_TX_TUNNEL_MASK) {
 	case RTE_MBUF_F_TX_TUNNEL_VXLAN:
 	case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+	case RTE_MBUF_F_TX_TUNNEL_UDP:
 		ptype |= RTE_PTYPE_TUNNEL_GRENAT;
 		break;
 	case RTE_MBUF_F_TX_TUNNEL_GRE:
@@ -713,9 +716,32 @@ txgbe_get_tun_len(struct rte_mbuf *mbuf)
 	const struct txgbe_genevehdr *gh;
 	const struct txgbe_grehdr *grh;
 	struct txgbe_grehdr grehdr;
+	struct txgbe_udphdr udphdr;
+	const struct txgbe_udphdr *uh;
+	uint64_t tun_type;
 	uint8_t tun_len;
 
-	switch (mbuf->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
+	/* Resolve the UDP tunnel to its inner type without rewriting the
+	 * mbuf: the application still owns it and may re-transmit it.
+	 */
+	tun_type = mbuf->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK;
+	if (tun_type == RTE_MBUF_F_TX_TUNNEL_UDP) {
+		uh = rte_pktmbuf_read(mbuf,
+				      mbuf->outer_l2_len + mbuf->outer_l3_len,
+				      sizeof(udphdr), &udphdr);
+		if (uh == NULL) {
+			/* The outer offsets are application supplied and may
+			 * point past the end of the packet.
+			 */
+			return 0;
+		}
+		tun_type = (uh->dest ==
+			    rte_cpu_to_be_16(RTE_GENEVE_DEFAULT_PORT)) ?
+			   RTE_MBUF_F_TX_TUNNEL_GENEVE :
+			   RTE_MBUF_F_TX_TUNNEL_VXLAN;
+	}
+
+	switch (tun_type) {
 	case RTE_MBUF_F_TX_TUNNEL_IPIP:
 		tun_len = 0;
 		break;
-- 
2.55.0.windows.2


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

* [PATCH v3 09/15] net/txgbe: fix SFP hot-plug when auto-negotiation is on
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (7 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 08/15] net/txgbe: add offload support for tunnel type UDP Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 10/15] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

When a port is started before the DAC cable is plugged in,
hot-plugging the cable never brings the link up and the port has to
be stopped and started again.

The AN73 watchdog txgbe_dev_e56_check_bp_event() is armed once in
txgbe_dev_start(). Its first tick finds no module, so
txgbe_xpcs_an_enabled() returns false and the handler returns without
re-arming itself. Once the cable is inserted, nobody polls the AN73
completion any more and the link stays down.

Re-arm the watchdog from txgbe_dev_detect_sfp() once a module has
been identified, cancelling any pending instance first so that only
one of them is running at a time. On the removal path, drop the
cached SFP type and cancel the watchdog. Also sample the
module-present pin (GPIO_EXT bit 2 on 25G, bit 4 on 40G) on every
watchdog tick, so that pulling the cable is noticed even if no GPIO
interrupt is delivered.

Fixes: 234ce0d1fa9d ("net/txgbe: fix link stability for Amber-Lite backplane mode")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_ethdev.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index bb4ff3c492..0711a28a5c 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2987,6 +2987,20 @@ void txgbe_dev_e56_check_bp_event(void *param)
 	if (!hw)
 		return;
 
+	/* Sample the module-present pin on every tick. When the cable is
+	 * pulled, drop the cached SFP type so that txgbe_xpcs_an_enabled()
+	 * turns false and this alarm stops re-arming itself.
+	 */
+	if (hw->mac.type == txgbe_mac_aml)
+		value = rd32(hw, TXGBE_GPIOEXT) & TXGBE_SFP1_MOD_ABS_LS;
+	else if (hw->mac.type == txgbe_mac_aml40)
+		value = rd32(hw, TXGBE_GPIOEXT) & TXGBE_SFP1_MOD_PRST_LS;
+
+	if (value != 0 && hw->phy.sfp_type != txgbe_sfp_type_not_present) {
+		PMD_DRV_LOG(INFO, "SFP module removed, stop AN73 watchdog.");
+		hw->phy.sfp_type = txgbe_sfp_type_not_present;
+	}
+
 	if (!(txgbe_xpcs_an_enabled(hw)))
 		return;
 
@@ -3110,10 +3124,22 @@ txgbe_dev_detect_sfp(void *param)
 		PMD_DRV_LOG(ERR, "Unsupported SFP+ module type was detected.");
 	} else if (err == TXGBE_ERR_SFP_NOT_PRESENT) {
 		PMD_DRV_LOG(INFO, "SFP not present.");
+		/* Module removed: drop the cached type and stop the watchdog. */
+		hw->phy.sfp_type = txgbe_sfp_type_not_present;
+		rte_eal_alarm_cancel(txgbe_dev_e56_check_bp_event, dev);
 	} else if (err == 0) {
 		hw->mac.setup_sfp(hw);
 		PMD_DRV_LOG(INFO, "detected SFP+: %d", hw->phy.sfp_type);
 		txgbe_dev_setup_link_alarm_handler(dev);
+		/* Re-arm the AN73 watchdog for the newly inserted module, so
+		 * that only one instance of it is running at a time.
+		 */
+		if (hw->mac.type == txgbe_mac_aml ||
+		    hw->mac.type == txgbe_mac_aml40) {
+			rte_eal_alarm_cancel(txgbe_dev_e56_check_bp_event, dev);
+			rte_eal_alarm_set(hw->bp_event_interval,
+					  txgbe_dev_e56_check_bp_event, dev);
+		}
 		txgbe_dev_link_update(dev, 0);
 	}
 }
-- 
2.55.0.windows.2


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

* [PATCH v3 10/15] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (8 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 09/15] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 11/15] net/txgbe: fix 40G FFE tuning applied to first lane only Zaiyu Wang
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

Hot-plugging a DAC cable while an Amber-Lite 40G port is running
does not bring the link up. Two problems are in the way.

First, the 40G NIC never delivers the GPIO interrupt for module
insertion or removal, so txgbe_dev_detect_sfp() is not called and the
new module is never identified (the 25G part is not affected). Poll
the module-present level every 2 seconds instead. The poll skips the
identify step while the level is unchanged, and only re-arms itself
while the port is started, so that it cannot survive txgbe_dev_stop().

Second, when the port is started with no module plugged in,
txgbe_set_link_to_amlite() times out and leaves hw->link_valid false.
The xpcs path of txgbe_setup_phy_link_aml40() never restores it, so
txgbe_e56_check_phy_link() and txgbe_check_mac_link_aml40() keep
forcing the link down even once AN73 has brought it up. Restore
link_valid on the xpcs path, as the non-xpcs path already does.

Fixes: a2d92608d3b0 ("net/txgbe: add GPIO configuration")
Fixes: f7cfc21e9f75 ("net/txgbe: fix link stability for 40G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml40.c |  7 +++++++
 drivers/net/txgbe/txgbe_ethdev.c     | 17 ++++++++++++++++-
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index d812adac69..2d3b32839c 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -177,6 +177,13 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
 		rte_spinlock_lock(&hw->phy_lock);
 		txgbe_e56_set_phy_link_mode(hw, speed, autoneg_wait_to_complete);
 		rte_spinlock_unlock(&hw->phy_lock);
+		/* Restore link_valid, as the non-xpcs path below does. An
+		 * earlier txgbe_set_link_to_amlite() timeout, for example when
+		 * the port was started with no module plugged in, left it
+		 * false, which keeps the check_phy_link and check_mac_link
+		 * gates forcing the link down even after AN73 brings it up.
+		 */
+		hw->link_valid = true;
 		return status;
 	}
 
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0711a28a5c..0aa2d5719b 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2015,6 +2015,11 @@ txgbe_dev_start(struct rte_eth_dev *dev)
 	if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) {
 		rte_eal_alarm_set(hw->bp_event_interval, txgbe_dev_e56_check_bp_event, dev);
 		rte_eal_alarm_set(1000 * 1000 * 2, txgbe_dev_check_aml_temp_event, dev);
+		/* The 40G NIC does not deliver a GPIO interrupt on module
+		 * insertion or removal, so poll the module-present level.
+		 */
+		if (hw->mac.type == txgbe_mac_aml40 && !txgbe_is_backplane(hw))
+			rte_eal_alarm_set(2000 * 1000, txgbe_dev_detect_sfp, dev);
 	}
 
 	if (tm_conf->root && !tm_conf->committed)
@@ -3096,7 +3101,7 @@ txgbe_dev_detect_sfp(void *param)
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
 	struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
 	u32 value = 0;
-	s32 err;
+	s32 err = 0;
 
 	if (hw->mac.type == txgbe_mac_aml40) {
 		value = rd32(hw, TXGBE_GPIOEXT);
@@ -3104,6 +3109,11 @@ txgbe_dev_detect_sfp(void *param)
 			err = TXGBE_ERR_SFP_NOT_PRESENT;
 			goto out;
 		}
+		/* The level is unchanged since the last poll, so the cached
+		 * module type is still valid and identify can be skipped.
+		 */
+		if (hw->phy.sfp_type != txgbe_sfp_type_not_present)
+			goto rearm;
 	}
 
 	if (hw->mac.type == txgbe_mac_aml) {
@@ -3142,6 +3152,11 @@ txgbe_dev_detect_sfp(void *param)
 		}
 		txgbe_dev_link_update(dev, 0);
 	}
+
+rearm:
+	if (hw->mac.type == txgbe_mac_aml40 && !txgbe_is_backplane(hw) &&
+	    dev->data->dev_started)
+		rte_eal_alarm_set(2000 * 1000, txgbe_dev_detect_sfp, dev);
 }
 
 static void
-- 
2.55.0.windows.2


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

* [PATCH v3 11/15] net/txgbe: fix 40G FFE tuning applied to first lane only
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (9 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 10/15] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 12/15] net/txgbe: add pre2 and backplane capability devargs Zaiyu Wang
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

On the 40G NIC, an FFE value only reaches the first of the four
lanes: the E56 PHY holds one FFE byte per lane, but the tuned taps
were written as a single byte value, so the other three lanes keep
their default equalizer setting and the received signal on them can
be degraded.

Use the E56 PHY FFE defaults on the 40G NIC and replicate each tap
value over the four lanes. The FFE fields grow to 32 bits to hold
the replicated value, and the devargs are parsed after the shared
code init so the MAC type is known when the 40G defaults are picked.

Fixes: 6104fd11086e ("net/txgbe: fix link stability for 25G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_e56.h  |  5 +++++
 drivers/net/txgbe/base/txgbe_type.h |  8 ++++----
 drivers/net/txgbe/txgbe_ethdev.c    | 22 +++++++++++++++++++++-
 3 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/net/txgbe/base/txgbe_e56.h b/drivers/net/txgbe/base/txgbe_e56.h
index 1922a2eb92..fe9a83ae01 100644
--- a/drivers/net/txgbe/base/txgbe_e56.h
+++ b/drivers/net/txgbe/base/txgbe_e56.h
@@ -1714,6 +1714,11 @@ typedef union {
 #define S40G_TX_FFE_CFG_PRE2        0x0
 #define S40G_TX_FFE_CFG_POST        0x11111111
 
+/* The 40G PHY holds one FFE byte per lane, so a user supplied value has to
+ * be replicated over the four lanes.
+ */
+#define S40G_TX_FFE_4LANE(v)        ((u32)((v) & 0xFF) * 0x01010101u)
+
 #define BYPASS_CTLE_TAG             0x0
 
 #define S10G_PHY_RX_CTLE_TAPWT_WEIGHT1      0x1
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index f9b5cbe61a..4ed4737043 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -739,10 +739,10 @@ struct txgbe_phy_info {
 
 	/* Some features need tri-state capability */
 	u16 ffe_set;
-	u16 ffe_main;
-	u16 ffe_pre;
-	u16 ffe_pre2;
-	u16 ffe_post;
+	u32 ffe_main;
+	u32 ffe_pre;
+	u32 ffe_pre2;
+	u32 ffe_post;
 	u16 fec_mode;
 	u16 bp_capa;
 };
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0aa2d5719b..afed59d4cf 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -531,6 +531,7 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 ffe_set = 0;
 	u16 ffe_main = 27;
 	u16 ffe_pre = 8;
+	u16 ffe_pre2 = 0;
 	u16 ffe_post = 44;
 	/* FDIR args */
 	u8 pballoc = 0;
@@ -540,6 +541,15 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 tx_headwb_size = 16;
 	u16 rx_desc_merge = 1;
 
+	/* The 40G NIC holds one FFE byte per lane, so the E56 PHY defaults
+	 * below are later replicated over the four lanes.
+	 */
+	if (hw->mac.type == txgbe_mac_aml40) {
+		ffe_main = S40G_TX_FFE_CFG_MAIN & 0xFF;
+		ffe_pre = S40G_TX_FFE_CFG_PRE1 & 0xFF;
+		ffe_post = S40G_TX_FFE_CFG_POST & 0xFF;
+	}
+
 	if (devargs == NULL)
 		goto null;
 
@@ -588,6 +598,14 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	hw->phy.ffe_pre = ffe_pre;
 	hw->phy.ffe_post = ffe_post;
 
+	/* The 40G PHY expects one FFE byte per lane. */
+	if (hw->mac.type == txgbe_mac_aml40) {
+		hw->phy.ffe_main = S40G_TX_FFE_4LANE(ffe_main);
+		hw->phy.ffe_pre = S40G_TX_FFE_4LANE(ffe_pre);
+		hw->phy.ffe_pre2 = S40G_TX_FFE_4LANE(ffe_pre2);
+		hw->phy.ffe_post = S40G_TX_FFE_4LANE(ffe_post);
+	}
+
 	fdir_conf->pballoc = pballoc;
 	fdir_conf->drop_queue = drop_queue;
 }
@@ -690,7 +708,6 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
 	hw->isb_dma = TMZ_PADDR(mz);
 	hw->isb_mem = TMZ_VADDR(mz);
 
-	txgbe_parse_devargs(eth_dev);
 	/* Initialize the shared code (base driver) */
 	err = txgbe_init_shared_code(hw);
 	if (err != 0) {
@@ -698,6 +715,9 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
 		return -EIO;
 	}
 
+	/* Parsing the devargs requires a known MAC type. */
+	txgbe_parse_devargs(eth_dev);
+
 	if (hw->mac.type == txgbe_mac_aml)
 		txgbe_override_mac_ops(hw);
 
-- 
2.55.0.windows.2


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

* [PATCH v3 12/15] net/txgbe: add pre2 and backplane capability devargs
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (10 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 11/15] net/txgbe: fix 40G FFE tuning applied to first lane only Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 13/15] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, Jiawen Wu

The 25G E56 PHY has a second pre-cursor tap that cannot be tuned
with the existing devargs: with ffe_set enabled, pre2 stays at the
default value because no devarg feeds it.

The advertised 40G backplane capability is hardwired to KR4+CR4,
so there is no way to advertise only 40GBASE-KR4 or only 40GBASE-CR4.

Add the ffe_pre2 and bp_capa device arguments. ffe_pre2 configures
the E56 PHY second pre-cursor tap, bp_capa selects the backplane
capability advertised on the 40G NIC, and both are documented in the
NIC guide and the release notes.

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 doc/guides/nics/txgbe.rst              | 11 +++++++++++
 doc/guides/rel_notes/release_26_11.rst |  8 ++++++++
 drivers/net/txgbe/base/txgbe_type.h    |  6 +++++-
 drivers/net/txgbe/txgbe_ethdev.c       | 23 +++++++++++++++++++----
 4 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/doc/guides/nics/txgbe.rst b/doc/guides/nics/txgbe.rst
index 90c55141f1..d56fb3b99a 100644
--- a/doc/guides/nics/txgbe.rst
+++ b/doc/guides/nics/txgbe.rst
@@ -142,6 +142,11 @@ Please note that following ``devargs`` are only set for backplane NICs.
   PHY parameter used for user debugging. Setting other values to
   take effect requires setting the ``ffe_set``.
 
+- ``ffe_pre2`` (default **0**)
+
+  PHY parameter used for user debugging, only for the Amber-Lite E56 PHY.
+  Setting other values to take effect requires setting the ``ffe_set``.
+
 - ``ffe_post`` (default **44**)
 
   PHY parameter used for user debugging. Setting other values to
@@ -177,6 +182,12 @@ Please note that following ``devargs`` are only set for Amber-Lite NICs.
   In this mode, the hardware merges and writes back a group of RX descriptors
   together to reduce memory access times, which helps improve performance.
 
+- ``bp_capa`` (default **0**)
+
+  Backplane capability selection for the 40G NIC. Set 0 for both
+  40GBASE-KR4 and 40GBASE-CR4, set 1 for 40GBASE-KR4 only, set 2 for
+  40GBASE-CR4 only.
+
 Driver compilation and testing
 ------------------------------
 
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 87c7e81bde..822cd36d20 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -56,6 +56,14 @@ New Features
      =======================================================
 
 
+* **Updated Wangxun txgbe driver.**
+
+  * Added the ``ffe_pre2`` device argument to tune the second pre-cursor
+    tap of the Amber-Lite E56 PHY (requires ``ffe_set``).
+  * Added the ``bp_capa`` device argument to select the advertised
+    backplane capability on the 40G NIC
+    (0 for 40GBASE-KR4 + 40GBASE-CR4, 1 for KR4 only, 2 for CR4 only).
+
 Removed Items
 -------------
 
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index 4ed4737043..f56cd70c6f 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -741,7 +741,7 @@ struct txgbe_phy_info {
 	u16 ffe_set;
 	u32 ffe_main;
 	u32 ffe_pre;
-	u32 ffe_pre2;
+	u32 ffe_pre2; /* only for the Amber-Lite E56 PHY */
 	u32 ffe_post;
 	u16 fec_mode;
 	u16 bp_capa;
@@ -754,12 +754,14 @@ struct txgbe_phy_info {
 #define TXGBE_DEVARG_FFE_SET		"ffe_set"
 #define TXGBE_DEVARG_FFE_MAIN		"ffe_main"
 #define TXGBE_DEVARG_FFE_PRE		"ffe_pre"
+#define TXGBE_DEVARG_FFE_PRE2		"ffe_pre2"
 #define TXGBE_DEVARG_FFE_POST		"ffe_post"
 #define TXGBE_DEVARG_FDIR_PBALLOC	"pkt-filter-size"
 #define TXGBE_DEVARG_FDIR_DROP_QUEUE	"pkt-filter-drop-queue"
 #define TXGBE_DEVARG_TX_HEAD_WB		"tx_headwb"
 #define TXGBE_DEVARG_TX_HEAD_WB_SIZE	"tx_headwb_size"
 #define TXGBE_DEVARG_RX_DESC_MERGE	"rx_desc_merge"
+#define TXGBE_DEVARG_BP_CAPA		"bp_capa"
 
 static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_BP_AUTO,
@@ -769,12 +771,14 @@ static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_FFE_SET,
 	TXGBE_DEVARG_FFE_MAIN,
 	TXGBE_DEVARG_FFE_PRE,
+	TXGBE_DEVARG_FFE_PRE2,
 	TXGBE_DEVARG_FFE_POST,
 	TXGBE_DEVARG_FDIR_PBALLOC,
 	TXGBE_DEVARG_FDIR_DROP_QUEUE,
 	TXGBE_DEVARG_TX_HEAD_WB,
 	TXGBE_DEVARG_TX_HEAD_WB_SIZE,
 	TXGBE_DEVARG_RX_DESC_MERGE,
+	TXGBE_DEVARG_BP_CAPA,
 	NULL
 };
 
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index afed59d4cf..27a6ff0b2e 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -540,13 +540,20 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 tx_headwb = 1;
 	u16 tx_headwb_size = 16;
 	u16 rx_desc_merge = 1;
+	u16 bp_capa = 0;
 
-	/* The 40G NIC holds one FFE byte per lane, so the E56 PHY defaults
-	 * below are later replicated over the four lanes.
+	/* The E56 PHY needs its own FFE defaults, as the ones above only
+	 * apply to the Sapphire PHY.
 	 */
-	if (hw->mac.type == txgbe_mac_aml40) {
+	if (hw->mac.type == txgbe_mac_aml) {
+		ffe_main = S25G_TX_FFE_CFG_DAC_MAIN;
+		ffe_pre = S25G_TX_FFE_CFG_DAC_PRE1;
+		ffe_pre2 = S25G_TX_FFE_CFG_DAC_PRE2;
+		ffe_post = S25G_TX_FFE_CFG_DAC_POST;
+	} else if (hw->mac.type == txgbe_mac_aml40) {
 		ffe_main = S40G_TX_FFE_CFG_MAIN & 0xFF;
 		ffe_pre = S40G_TX_FFE_CFG_PRE1 & 0xFF;
+		ffe_pre2 = S40G_TX_FFE_CFG_PRE2 & 0xFF;
 		ffe_post = S40G_TX_FFE_CFG_POST & 0xFF;
 	}
 
@@ -571,6 +578,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 			   &txgbe_handle_devarg, &ffe_main);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_PRE,
 			   &txgbe_handle_devarg, &ffe_pre);
+	rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_PRE2,
+			   &txgbe_handle_devarg, &ffe_pre2);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_FFE_POST,
 			   &txgbe_handle_devarg, &ffe_post);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_FDIR_PBALLOC,
@@ -583,6 +592,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 			   &txgbe_handle_devarg, &tx_headwb_size);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_RX_DESC_MERGE,
 			   &txgbe_handle_devarg, &rx_desc_merge);
+	rte_kvargs_process(kvlist, TXGBE_DEVARG_BP_CAPA,
+			   &txgbe_handle_devarg, &bp_capa);
 	rte_kvargs_free(kvlist);
 
 null:
@@ -596,7 +607,9 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	hw->phy.ffe_set = ffe_set;
 	hw->phy.ffe_main = ffe_main;
 	hw->phy.ffe_pre = ffe_pre;
+	hw->phy.ffe_pre2 = ffe_pre2;
 	hw->phy.ffe_post = ffe_post;
+	hw->phy.bp_capa = bp_capa;
 
 	/* The 40G PHY expects one FFE byte per lane. */
 	if (hw->mac.type == txgbe_mac_aml40) {
@@ -6498,12 +6511,14 @@ RTE_PMD_REGISTER_PARAM_STRING(net_txgbe,
 			      TXGBE_DEVARG_FFE_SET "=<0-4>"
 			      TXGBE_DEVARG_FFE_MAIN "=<uint16>"
 			      TXGBE_DEVARG_FFE_PRE "=<uint16>"
+			      TXGBE_DEVARG_FFE_PRE2 "=<uint16>"
 			      TXGBE_DEVARG_FFE_POST "=<uint16>"
 			      TXGBE_DEVARG_FDIR_PBALLOC "=<0|1|2>"
 			      TXGBE_DEVARG_FDIR_DROP_QUEUE "=<uint8>"
 			      TXGBE_DEVARG_TX_HEAD_WB "=<0|1>"
 			      TXGBE_DEVARG_TX_HEAD_WB_SIZE "=<1|16>"
-			      TXGBE_DEVARG_RX_DESC_MERGE "=<0|1>");
+			      TXGBE_DEVARG_RX_DESC_MERGE "=<0|1>"
+			      TXGBE_DEVARG_BP_CAPA "=<0|1|2>");
 
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_init, init, NOTICE);
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_driver, driver, NOTICE);
-- 
2.55.0.windows.2


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

* [PATCH v3 13/15] net/txgbe: add devarg to turn off Tx laser for 40G NIC
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (11 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 12/15] net/txgbe: add pre2 and backplane capability devargs Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:25   ` [PATCH v3 14/15] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
  2026-09-08 13:26   ` [PATCH v3 15/15] net/txgbe: align link capabilities and DAC classification Zaiyu Wang
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, Jiawen Wu

When the port is brought down, the Tx laser stays on, so the peer
keeps seeing a live signal and cannot detect the link loss (e.g. for
link-state tracking at the peer).

Add a laser_off devarg: when enabled, bring the Tx laser down on
port stop -- for DAC cables disable the PCS, for QSFP modules write
the Tx disable bit via I2C -- and restore the Tx enable state when
the link comes up. The SFF-8636 Tx disable register is only touched
while the management semaphore is held, and the acquire_swfw_sync()
result is checked so a failed acquire does not release a semaphore
that is not held. Replace the raw register offsets and bit masks
with named constants (PMD_CFG0, E56PHY_PMD_CFG_0_RX_EN_CFG,
TXGBE_MNGSEM_SWPHY, TXGBE_SFF_8636_TX_DISABLE).

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 doc/guides/nics/txgbe.rst              |  7 +++++++
 doc/guides/rel_notes/release_26_11.rst |  3 +++
 drivers/net/txgbe/base/txgbe_hw.c      | 29 ++++++++++++++++++++++++++
 drivers/net/txgbe/base/txgbe_phy.h     |  6 ++++++
 drivers/net/txgbe/base/txgbe_type.h    |  3 +++
 drivers/net/txgbe/txgbe_ethdev.c       |  7 ++++++-
 6 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/txgbe.rst b/doc/guides/nics/txgbe.rst
index d56fb3b99a..a580450726 100644
--- a/doc/guides/nics/txgbe.rst
+++ b/doc/guides/nics/txgbe.rst
@@ -188,6 +188,13 @@ Please note that following ``devargs`` are only set for Amber-Lite NICs.
   40GBASE-KR4 and 40GBASE-CR4, set 1 for 40GBASE-KR4 only, set 2 for
   40GBASE-CR4 only.
 
+- ``laser_off`` (default **0**)
+
+  Toggle behavior to disable the Tx laser when the port is brought down
+  on the 40G NIC. By default the Tx laser is left on. When enabled, for
+  DAC cables the PCS is disabled, for QSFP modules the Tx disable bit is
+  written via I2C.
+
 Driver compilation and testing
 ------------------------------
 
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 822cd36d20..95a9552915 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -63,6 +63,9 @@ New Features
   * Added the ``bp_capa`` device argument to select the advertised
     backplane capability on the 40G NIC
     (0 for 40GBASE-KR4 + 40GBASE-CR4, 1 for KR4 only, 2 for CR4 only).
+  * Added the ``laser_off`` device argument: when set, the 40G NIC
+    turns its Tx laser off on port down
+    (PCS disable for DAC cables, SFF-8636 Tx disable for QSFP modules).
 
 Removed Items
 -------------
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 2650b8b7f1..f79439c523 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -11,6 +11,7 @@
 #include "txgbe_eeprom.h"
 #include "txgbe_mng.h"
 #include "txgbe_hw.h"
+#include "txgbe_e56.h"
 #include "txgbe_aml.h"
 #include "txgbe_aml40.h"
 
@@ -3259,6 +3260,29 @@ void txgbe_disable_tx_laser_multispeed_fiber(struct txgbe_hw *hw)
 	if (hw->mac.type == txgbe_mac_aml40) {
 		wr32m(hw, TXGBE_GPIODIR, TXGBE_GPIOBIT_1, TXGBE_GPIOBIT_1);
 		esdp_reg &= ~TXGBE_GPIOBIT_1;
+		if (hw->devarg.laser_off) {
+			if (txgbe_is_dac_cable(hw) ||
+			    hw->phy.sfp_type == txgbe_sfp_type_unknown) {
+				u32 rdata = 0;
+
+				rte_spinlock_lock(&hw->phy_lock);
+				rdata = rd32_ephy(hw, PMD_CFG0);
+				set_fields_e56(&rdata,
+					       E56PHY_PMD_CFG_0_RX_EN_CFG,
+					       0x0);
+				set_fields_e56(&rdata, 15, 12, 0x0);
+				set_fields_e56(&rdata, 1, 1, 0x0);
+				wr32_ephy(hw, PMD_CFG0, rdata);
+				rte_spinlock_unlock(&hw->phy_lock);
+			} else if (hw->mac.acquire_swfw_sync(hw,
+							    TXGBE_MNGSEM_SWPHY) == 0) {
+				hw->phy.write_i2c_eeprom(hw,
+					TXGBE_SFF_8636_TX_DISABLE,
+					TXGBE_SFF_8636_TX_DISABLE_ALL_LANES);
+				hw->mac.release_swfw_sync(hw,
+							TXGBE_MNGSEM_SWPHY);
+			}
+		}
 	} else if (hw->mac.type == txgbe_mac_aml) {
 		esdp_reg |= TXGBE_GPIOBIT_1;
 	} else {
@@ -3288,6 +3312,11 @@ void txgbe_enable_tx_laser_multispeed_fiber(struct txgbe_hw *hw)
 	if (hw->mac.type == txgbe_mac_aml40) {
 		wr32m(hw, TXGBE_GPIODIR, TXGBE_GPIOBIT_1, TXGBE_GPIOBIT_1);
 		esdp_reg |= TXGBE_GPIOBIT_1;
+		if (hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWPHY) == 0) {
+			hw->phy.write_i2c_eeprom(hw,
+				TXGBE_SFF_8636_TX_DISABLE, 0x0);
+			hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
+		}
 	} else {
 		esdp_reg &= ~(TXGBE_GPIOBIT_0 | TXGBE_GPIOBIT_1);
 	}
diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h
index a5df015a4d..a06c0eb04e 100644
--- a/drivers/net/txgbe/base/txgbe_phy.h
+++ b/drivers/net/txgbe/base/txgbe_phy.h
@@ -251,6 +251,12 @@
 #define TXGBE_SFF_VENDOR_OUI_BYTE1	0x26
 #define TXGBE_SFF_VENDOR_OUI_BYTE2	0x27
 #define TXGBE_SFF_1GBE_COMP_CODES	0x06
+
+/* SFF-8636 PMD Tx disable register (byte 0x56); bit per lane,
+ * 0xF disables the transmitter on all four lanes.
+ */
+#define TXGBE_SFF_8636_TX_DISABLE		0x56
+#define TXGBE_SFF_8636_TX_DISABLE_ALL_LANES	0x0F
 #define TXGBE_SFF_10GBE_COMP_CODES	0x03
 #define TXGBE_SFF_25GBE_COMP_CODES	0x24
 #define TXGBE_SFF_COPPER_LENGTH		0x12
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index f56cd70c6f..39a70746a7 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -762,6 +762,7 @@ struct txgbe_phy_info {
 #define TXGBE_DEVARG_TX_HEAD_WB_SIZE	"tx_headwb_size"
 #define TXGBE_DEVARG_RX_DESC_MERGE	"rx_desc_merge"
 #define TXGBE_DEVARG_BP_CAPA		"bp_capa"
+#define TXGBE_DEVARG_LASER_OFF		"laser_off"
 
 static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_BP_AUTO,
@@ -779,6 +780,7 @@ static const char * const txgbe_valid_arguments[] = {
 	TXGBE_DEVARG_TX_HEAD_WB_SIZE,
 	TXGBE_DEVARG_RX_DESC_MERGE,
 	TXGBE_DEVARG_BP_CAPA,
+	TXGBE_DEVARG_LASER_OFF,
 	NULL
 };
 
@@ -834,6 +836,7 @@ struct txgbe_devargs {
 	u16 tx_headwb;
 	u16 tx_headwb_size;
 	u16 rx_desc_merge;
+	u16 laser_off;
 };
 
 struct txgbe_hw {
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 27a6ff0b2e..9c31b2cfed 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -541,6 +541,7 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	u16 tx_headwb_size = 16;
 	u16 rx_desc_merge = 1;
 	u16 bp_capa = 0;
+	u16 laser_off = 0;
 
 	/* The E56 PHY needs its own FFE defaults, as the ones above only
 	 * apply to the Sapphire PHY.
@@ -594,6 +595,8 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 			   &txgbe_handle_devarg, &rx_desc_merge);
 	rte_kvargs_process(kvlist, TXGBE_DEVARG_BP_CAPA,
 			   &txgbe_handle_devarg, &bp_capa);
+	rte_kvargs_process(kvlist, TXGBE_DEVARG_LASER_OFF,
+			   &txgbe_handle_devarg, &laser_off);
 	rte_kvargs_free(kvlist);
 
 null:
@@ -604,6 +607,7 @@ txgbe_parse_devargs(struct rte_eth_dev *dev)
 	hw->devarg.tx_headwb = tx_headwb;
 	hw->devarg.tx_headwb_size = tx_headwb_size;
 	hw->devarg.rx_desc_merge = rx_desc_merge;
+	hw->devarg.laser_off = laser_off;
 	hw->phy.ffe_set = ffe_set;
 	hw->phy.ffe_main = ffe_main;
 	hw->phy.ffe_pre = ffe_pre;
@@ -6518,7 +6522,8 @@ RTE_PMD_REGISTER_PARAM_STRING(net_txgbe,
 			      TXGBE_DEVARG_TX_HEAD_WB "=<0|1>"
 			      TXGBE_DEVARG_TX_HEAD_WB_SIZE "=<1|16>"
 			      TXGBE_DEVARG_RX_DESC_MERGE "=<0|1>"
-			      TXGBE_DEVARG_BP_CAPA "=<0|1|2>");
+			      TXGBE_DEVARG_BP_CAPA "=<0|1|2>"
+			      TXGBE_DEVARG_LASER_OFF "=<0|1>");
 
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_init, init, NOTICE);
 RTE_LOG_REGISTER_SUFFIX(txgbe_logtype_driver, driver, NOTICE);
-- 
2.55.0.windows.2


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

* [PATCH v3 14/15] net/txgbe: fix CR/KR link training and recovery
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (12 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 13/15] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
@ 2026-09-08 13:25   ` Zaiyu Wang
  2026-09-08 13:26   ` [PATCH v3 15/15] net/txgbe: align link capabilities and DAC classification Zaiyu Wang
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:25 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

Backplane CR/KR link training on the E56 PHY is unreliable and does
not recover after a link event: the completion poll can block for a
second on a condition that never triggers, the page exchange is only
run once and its result is assumed to stay valid, and the FFE init
mode and calibration ordering are also wrong.

- Poll the AN FSM (0x78010, value 0x9) for CL72 completion with a
  1 ms step and a 400 ms budget, replacing the ephy 0x163c mask-0xe
  poll that tested the wrong condition; the per-lane TX-FFE dumps
  move into txgbe_e56_get_txffe(), called once AN completes.
- Re-run the page exchange on every AN next-page interrupt from the
  event handler (50 x 1 ms poll, explicit next-page handshake,
  -ETIMEDOUT on expiry) and only enter training after it succeeds;
  the inline exchange in the AN73 flow is removed and a CL72 failure
  no longer aborts the flow, so every link event re-runs the
  exchange instead of assuming the previous one is still valid.
- Initialize the FFE init mode bits in cfg_40g()/cfg_10g(), run
  txgbe_e56_set_rxs_ufine_le_max() after the RXS osc init, and write
  0x78001 = 0x7 in the AN programming sequence.
- Clear hw->bp_link_mode in txgbe_set_link_to_sfi() so a port that
  trained on the backplane does not keep a stale backplane mode
  after switching to SFI.
- Drop a stray C99 comment left on the AN-config flag assignment.

Fixes: 234ce0d1fa9d ("net/txgbe: fix link stability for Amber-Lite backplane mode")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_e56.c    |   3 +
 drivers/net/txgbe/base/txgbe_e56.h    |   1 +
 drivers/net/txgbe/base/txgbe_e56_bp.c | 161 +++++++++++++++-----------
 drivers/net/txgbe/base/txgbe_e56_bp.h |   2 +
 drivers/net/txgbe/base/txgbe_phy.c    |   3 +
 drivers/net/txgbe/txgbe_ethdev.c      |  26 ++++-
 6 files changed, 128 insertions(+), 68 deletions(-)

diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index 2711863f2c..8e986daf96 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -551,6 +551,7 @@ u32 txgbe_e56_cfg_40g(struct txgbe_hw *hw)
 
 	addr  = E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR;
 	rdata = rd32_ephy(hw, addr);
+	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_0, 0x2);
 	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2, 0x2);
 	wr32_ephy(hw, addr, rdata);
 
@@ -1377,6 +1378,8 @@ txgbe_e56_cfg_10g(struct txgbe_hw *hw)
 
 	addr = E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR;
 	rdata = rd32_ephy(hw, addr);
+	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_0,
+		       0x2);
 	set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2,
 		       0x2);
 	wr32_ephy(hw, addr, rdata);
diff --git a/drivers/net/txgbe/base/txgbe_e56.h b/drivers/net/txgbe/base/txgbe_e56.h
index fe9a83ae01..32d95b61b9 100644
--- a/drivers/net/txgbe/base/txgbe_e56.h
+++ b/drivers/net/txgbe/base/txgbe_e56.h
@@ -435,6 +435,7 @@ typedef union {
 #define E56PHY_KRT_TFSM_CFGKRT_TFSM_HOLDOFF_TIMER_X256K 23, 16
 
 #define E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR   (E56PHY_PMD_BASE_ADDR + 0x2BC)
+#define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_0 1, 0
 #define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2 9, 8
 #define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_3 13, 12
 
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.c b/drivers/net/txgbe/base/txgbe_e56_bp.c
index d376d918df..f840e6b5dd 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.c
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.c
@@ -813,6 +813,7 @@ static int txgbe_e56_phy_rxs_calib_adapt_seq(struct txgbe_hw *hw,
 		status |= txgbe_e56_ctle_bypass_seq(hw, bp_link_mode);
 
 	status |= txgbe_e56_rxs_osc_init_for_temp_track_range(hw, bp_link_mode);
+	txgbe_e56_set_rxs_ufine_le_max(hw, bp_link_mode);
 
 	/* Wait an fsm_rx_sts 25G */
 	BP_LOG("Wait CTRL_FSM_RX_STAT[0]::ctrl_fsm_rx0_st to be ready ...\n");
@@ -2123,6 +2124,7 @@ int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
 	set_fields_e56(&rdata, 12, 12, 0x1);
 	wr32_epcs(hw, 0x070000, rdata);
 	wr32_epcs(hw, 0x078002, 0x0000);
+	wr32_epcs(hw, 0x78001, 0x7);
 	/* pcs case fec en to work around first */
 	wr32_epcs(hw, 0x100ab, 1);
 
@@ -2351,24 +2353,29 @@ static int chk_bkp_ability(struct txgbe_hw *hw,
 	return 0;
 }
 
-static int txgbe_e56_exchange_page(struct txgbe_hw *hw)
+int txgbe_e56_exchange_page(struct txgbe_hw *hw)
 {
 	struct txgbe_backplane_ability local_ability = {0}, lp_ability = {0};
 	u32 an_int, base_page = 0;
-	int count = 0;
+	int count = 0, count2 = 0;
 
 	an_int = rd32_epcs(hw, 0x78002);
-	/* 500ms timeout */
 	if (!(an_int & VR_AN_INTR_PG_RCV))
 		return -EINVAL;
 
-	for (count = 0; count < 500; count++) {
+	/* 50ms timeout */
+	for (count = 0; count < 50; count++) {
 		u32 fsm = rd32_epcs(hw, 0x78010);
-		u32 rdata = rd32_epcs(hw, 0x78002);
+		u32 next_page = 0;
+		u32 rdata;
+
+		count2++;
 
 		BP_LOG("-----count----- %d - fsm: %x\n", count, fsm);
-		BP_LOG("read 78002 data %0x and clear pacv\n", rdata);
+		rdata = rd32_epcs(hw, 0x78002);
+		/* clear an pacv int */
 		an_int = rdata;
+		BP_LOG("read 78002 data %0x and clear pacv\n", rdata);
 		set_fields_e56(&rdata, 2, 2, 0x0);
 		wr32_epcs(hw, 0x78002, rdata);
 		if (an_int & VR_AN_INTR_PG_RCV) {
@@ -2383,31 +2390,84 @@ static int txgbe_e56_exchange_page(struct txgbe_hw *hw)
 					wr32_epcs(hw, 0x70016, 0x2001);
 					BP_LOG("write 70016 0x%0x\n",
 					       0x2001);
+					next_page = 1;
+					count = 0; /* reset count to wait next page */
+				} else {
+					next_page = 0;
 				}
 				base_page = 1;
 			}
 		}
-		if ((fsm & 0x8) == 0x8) {
-			hw->fsm = 0x8;
-			goto check_ability;
+		if (!next_page) {
+			if ((fsm & 0x8) == 0x8) {
+				hw->fsm = 0x8;
+				goto check_ability;
+			}
 		}
-		usec_delay(100);
+		usec_delay(1000);
 	}
 
 check_ability:
+	if (count == 50) {
+		BP_LOG("Wait for next page timeout\n");
+		return -ETIMEDOUT;
+	}
+	BP_LOG("AN exchange page done in %d ms\n", count2);
 	return chk_bkp_ability(hw, local_ability, lp_ability);
 }
 
+void txgbe_e56_get_txffe(struct txgbe_hw *hw)
+{
+	/* 21. read txffe to check kr training status */
+	u32 rdata = 0, pmd_ctrl = 0, lane_idx = 0, lane_num = 0, txffe = 0;
+
+	switch (hw->bp_link_mode) {
+	case 10:
+		lane_num = 1;
+		break;
+	case 40:
+		lane_num = 4;
+		break;
+	case 25:
+		lane_num = 1;
+		break;
+	default:
+		BP_LOG("%s %d :Invalid speed\n", __func__, __LINE__);
+		return;
+	}
+
+	BP_LOG("%dG phy kr training check.... fsm: %x\n",
+	       hw->bp_link_mode, rd32_epcs(hw, 0x78010));
+	rdata = rd32_ephy(hw, 0x163c) & GENMASK(lane_num, 1);
+	pmd_ctrl = rd32_ephy(hw, 0x1644);
+	BP_LOG("KR TRAINNING CHECK = %x. pmd_ctrl:%lx-%lx-%lx-%lx\n",
+	       rdata,
+	       FIELD_GET_M(GENMASK(3, 0), pmd_ctrl),
+	       FIELD_GET_M(GENMASK(7, 4), pmd_ctrl),
+	       FIELD_GET_M(GENMASK(11, 8), pmd_ctrl),
+	       FIELD_GET_M(GENMASK(15, 12), pmd_ctrl));
+	BP_LOG("before: %x-%x-%x-%x\n",
+	       rd32_ephy(hw, 0x141c), rd32_ephy(hw, 0x1420),
+	       rd32_ephy(hw, 0x1424), rd32_ephy(hw, 0x1428));
+	for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
+		txffe = rd32_ephy(hw, 0x828 + lane_idx * 0x100);
+		BP_LOG("after[%x]: %lx-%lx-%lx-%lx\n", lane_idx,
+		       FIELD_GET_M(GENMASK(6, 0), txffe),
+		       FIELD_GET_M(GENMASK(21, 16), txffe),
+		       FIELD_GET_M(GENMASK(29, 24), txffe),
+		       FIELD_GET_M(GENMASK(13, 8), txffe));
+	}
+}
+
 static int txgbe_e56_cl72_training(struct txgbe_hw *hw)
 {
 	u32 bylinkmode = hw->bp_link_mode;
 	u8 bypass_ctle = hw->bypass_ctle;
 	int status = 0, temp_data = 0;
-	u32 lane_num = 0, lane_idx = 0;
-	u32 __rte_unused pmd_ctrl = 0, txffe = 0;
+	u32 lane_num = 0;
+	u32 __rte_unused pmd_ctrl = 0;
 	int ret = 0;
 	u32 rdata;
-
 	u8 pll_en_cfg = 0;
 	u8 pmd_mode = 0;
 
@@ -2463,52 +2523,48 @@ static int txgbe_e56_cl72_training(struct txgbe_hw *hw)
 
 	/* 18 */
 	/* 19. rxs calibration and adaptation sequence */
-	BP_LOG("2.4 Wait %dG RXS.... fsm: %x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
+	BP_LOG("2.4 Wait %dG RXS.... fsm: %x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
 	status = txgbe_e56_phy_rxs_calib_adapt_seq(hw, bylinkmode, bypass_ctle);
 	ret |= status;
 	/* 20 */
-	BP_LOG("2.5 Wait %dG phy calibration.... fsm: %x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
-	txgbe_e56_set_rxs_ufine_le_max(hw, bylinkmode);
+	BP_LOG("2.5 Wait %dG phy calibration.... fsm: %x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
 	status = txgbe_e56_get_temp(hw, &temp_data);
 	if (bylinkmode == 40)
 		status = txgbe_temp_track_seq_40g(hw, TXGBE_LINK_SPEED_40GB_FULL);
 	else
 		status = txgbe_e56_rxs_post_cdr_lock_temp_track_seq(hw, bylinkmode);
+
+	ret |= status;
 	/* 21 */
-	BP_LOG("2.6 Wait %dG phy kr training check.... fsm: %x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
-	status = kr_read_poll(rd32_ephy, rdata,
-				  ((rdata & 0xe) & GENMASK(lane_num, 1)) ==
-				  (0xe & GENMASK(lane_num, 1)), 100,
-				   10000, hw, 0x163c);
+	BP_LOG("2.6 Wait %dG phy kr fsm check : %x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
+	status = kr_read_poll(rd32_epcs, rdata,
+			      (rdata & 0x9) == 0x9, 1000,
+			      400, hw, 0x78010);
 	pmd_ctrl = rd32_ephy(hw, 0x1644);
-	BP_LOG("KR TRAINING CHECK = %x, %s. pmd_ctrl:%lx-%lx-%lx-%lx\n",
+	BP_LOG("KR FSM CHECK = %x, %s. pmd_ctrl:%lx-%lx-%lx-%lx\n",
 	       rdata, status ? "FAILED" : "SUCCESS",
 	       FIELD_GET_M(GENMASK(3, 0), pmd_ctrl),
 	       FIELD_GET_M(GENMASK(7, 4), pmd_ctrl),
 	       FIELD_GET_M(GENMASK(11, 8), pmd_ctrl),
 	       FIELD_GET_M(GENMASK(15, 12), pmd_ctrl));
 	ret |= status;
-	BP_LOG("before: %x-%x-%x-%x\n",
-	       rd32_ephy(hw, 0x141c), rd32_ephy(hw, 0x1420),
-	       rd32_ephy(hw, 0x1424), rd32_ephy(hw, 0x1428));
-
-	for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
-		txffe = rd32_ephy(hw, 0x828 + lane_idx * 0x100);
-		BP_LOG("after[%x]: %lx-%lx-%lx-%lx\n", lane_idx,
-		       FIELD_GET_M(GENMASK(6, 0), txffe),
-		       FIELD_GET_M(GENMASK(21, 16), txffe),
-		       FIELD_GET_M(GENMASK(29, 24), txffe),
-		       FIELD_GET_M(GENMASK(13, 8), txffe));
-	}
 
 	/* 22 */
-	BP_LOG("2.7 Wait %dG phy Rx adc.... fsm:%x\n",
-	       bylinkmode, rd32_epcs(hw, 0x78010));
+	BP_LOG("2.7 Wait %dG phy Rx adc.... fsm:%x, an_int: %x\n",
+	       bylinkmode, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
 	status = txgbe_e56_rxs_adc_adapt_seq(hw, bypass_ctle);
 
+	BP_LOG("2.8 ===end ret : %d.... fsm:%x, an_int: %x\n",
+	       ret, rd32_epcs(hw, 0x78010),
+	       rd32_epcs(hw, 0x78002));
+
 	return ret;
 }
 
@@ -2517,27 +2573,7 @@ int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw)
 	int status = 0;
 	u32 rdata;
 
-	BP_LOG("2.1 Wait page changed ....\n");
-	status = txgbe_e56_exchange_page(hw);
-	if (status) {
-		BP_LOG("Exchange page failed\n");
-		return status;
-	}
-
-	BP_LOG("2.2 Wait page changed ..done..\n");
-	wr32_epcs(hw, 0x100ab, 0);
-	if (AN_TRAINING_MODE) {
-		rdata = rd32_epcs(hw, 0x70000);
-		BP_LOG("read 0x70000 data %0x\n", rdata);
-		wr32_epcs(hw, 0x70000, 0);
-		BP_LOG("write 0x70000 0x%0x\n", 0);
-	}
-
-	rdata = rd32_epcs(hw, 0x78002);
-	BP_LOG("read 78002 data %0x and clear page int\n", rdata);
-	set_fields_e56(&rdata, 2, 2, 0x0);
-	wr32_epcs(hw, 0x78002, rdata);
-
+	/* 10  RXS_DISABLE - TXS_DISABLE - CMS_DISABLE */
 	/* dis phy tx/rx lane */
 	rdata = rd32_ephy(hw, 0x1400);
 	set_fields_e56(&rdata, 19, 16, 0x0);
@@ -2583,11 +2619,6 @@ int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw)
 	}
 
 	status = txgbe_e56_cl72_training(hw);
-	if (status) {
-		BP_LOG("CL72 training failed, status = %d\n", status);
-		return status;
-	}
-
 	rdata = rd32_ephy(hw, E56PHY_RXS_IDLE_DETECT_1_ADDR);
 	set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MAX, 0x28);
 	set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MIN, 0xa);
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.h b/drivers/net/txgbe/base/txgbe_e56_bp.h
index d2c49c2fce..da0d02b79f 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.h
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.h
@@ -279,4 +279,6 @@ typedef union {
 int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
 				u8 bp_link_mode, u32 need_restart);
 int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw);
+int txgbe_e56_exchange_page(struct txgbe_hw *hw);
+void txgbe_e56_get_txffe(struct txgbe_hw *hw);
 #endif
diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index 8b653f0aeb..10df23afae 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1947,6 +1947,9 @@ txgbe_set_link_to_sfi(struct txgbe_hw *hw,
 	s32 err = 0;
 	u32 value = 0;
 
+	/* Switching to SFI mode clears backplane link mode. */
+	hw->bp_link_mode = 0;
+
 	/* Set the module link speed */
 	hw->mac.set_rate_select_speed(hw, speed);
 	/* 1. Wait xpcs power-up good */
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 9c31b2cfed..5e3403646c 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3025,6 +3025,7 @@ void txgbe_dev_e56_check_bp_event(void *param)
 	u32 __rte_unused an_int = 0;
 	int ret = 0;
 	bool need_link_update = false;
+	bool exchange_done = false;
 
 	if (!hw)
 		return;
@@ -3043,8 +3044,10 @@ void txgbe_dev_e56_check_bp_event(void *param)
 		hw->phy.sfp_type = txgbe_sfp_type_not_present;
 	}
 
-	if (!(txgbe_xpcs_an_enabled(hw)))
+	if (!(txgbe_xpcs_an_enabled(hw))) {
+		BP_LOG("%s %d\n", __func__, __LINE__);
 		return;
+	}
 
 	if (!hw->devarg.auto_neg)
 		return;
@@ -3063,6 +3066,7 @@ void txgbe_dev_e56_check_bp_event(void *param)
 		need_link_update = true;
 		value &= ~VR_AN_INTR_CMPLT;
 		wr32_epcs(hw, VR_AN_INTR, value);
+		txgbe_e56_get_txffe(hw);
 	}
 
 	if (value & VR_AN_INTR_LINK) {
@@ -3080,7 +3084,21 @@ void txgbe_dev_e56_check_bp_event(void *param)
 	}
 
 	if (value & VR_AN_INTR_PG_RCV) {
-		BP_LOG("%d Enter training\n", hw->port_id);
+		BP_LOG("%d 2.1 *** Wait page changed ....\n", hw->port_id);
+		ret = txgbe_e56_exchange_page(hw);
+		if (ret) {
+			BP_LOG("%d 2.2 *** Exchange page failed\n", hw->port_id);
+			goto an_status;
+		} else {
+			BP_LOG("%d 2.2 *** Wait page changed ..done..\n",
+			       hw->port_id);
+			wr32_epcs(hw, 0x100ab, 0);
+			exchange_done = true;
+		}
+	}
+
+	if (exchange_done) {
+		BP_LOG("%d 2.2.2 *** Enter training\n", hw->port_id);
 		ret = txgbe_handle_e56_bkp_an73_flow(hw);
 		if (!AN_TRAINING_MODE) {
 			fsm = rd32_epcs(hw, 0x78010);
@@ -3783,8 +3801,10 @@ txgbe_dev_interrupt_get_status(struct rte_eth_dev *dev,
 	if (eicr & TXGBE_ICRMISC_LSC)
 		intr->flags |= TXGBE_FLAG_NEED_LINK_UPDATE;
 
-	if (eicr & TXGBE_ICRMISC_ANDONE)
+	if (eicr & TXGBE_ICRMISC_ANDONE) {
+		PMD_DRV_LOG(DEBUG, "an int eicr=0x%08x", eicr);
 		intr->flags |= TXGBE_FLAG_NEED_AN_CONFIG;
+	}
 
 	if (eicr & TXGBE_ICRMISC_VFMBX)
 		intr->flags |= TXGBE_FLAG_MAILBOX;
-- 
2.55.0.windows.2


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

* [PATCH v3 15/15] net/txgbe: align link capabilities and DAC classification
       [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
                     ` (13 preceding siblings ...)
  2026-09-08 13:25   ` [PATCH v3 14/15] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
@ 2026-09-08 13:26   ` Zaiyu Wang
  14 siblings, 0 replies; 46+ messages in thread
From: Zaiyu Wang @ 2026-09-08 13:26 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu

An active DAC can be misidentified as a 40G optical module, in which
case the driver reports 40G and enables autoneg for a module that
does not support it; DACs and optical modules are also treated
differently in the FFE, CTLE and capability-report paths.

Rework the AML40/AML link capabilities and DAC classification:

- Port the five-branch capability layout to AML40:
  backplane, DAC (txgbe_is_dac_cable() plus the 10G-only AN-off
  case), multispeed fiber, 40G QSFP and 10G SFP. Modules previously
  misreported as 40G through the fallback now report the correct
  speed and autoneg.
- Add the 40G-active transceiver identification (sfp_type enum and
  identify branch). Like the kernel driver, 40G active cables are
  handled through the optical path, as SFF-8636 byte 131 bit 0
  ("40G Active Cable") also covers active optical cables.
- Unify DAC classification on txgbe_is_dac_cable(), including the
  40G FFE selection in txgbe_e56_tx_ffe_cfg() which still
  open-coded the qsfp_type_40g_cu check; the 10G active cable type
  (da_act_lmt) is no longer treated as an optical module.

Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_aml.c   |  3 +-
 drivers/net/txgbe/base/txgbe_aml40.c | 74 +++++++++++++++++++++++-----
 drivers/net/txgbe/base/txgbe_e56.c   |  9 ++--
 drivers/net/txgbe/base/txgbe_phy.c   |  7 +++
 drivers/net/txgbe/base/txgbe_phy.h   |  1 +
 drivers/net/txgbe/base/txgbe_type.h  |  2 +
 6 files changed, 76 insertions(+), 20 deletions(-)

diff --git a/drivers/net/txgbe/base/txgbe_aml.c b/drivers/net/txgbe/base/txgbe_aml.c
index ac80d85f08..fe4becf198 100644
--- a/drivers/net/txgbe/base/txgbe_aml.c
+++ b/drivers/net/txgbe/base/txgbe_aml.c
@@ -103,8 +103,7 @@ s32 txgbe_get_link_capabilities_aml(struct txgbe_hw *hw,
 		*speed = TXGBE_LINK_SPEED_10GB_FULL |
 			 TXGBE_LINK_SPEED_25GB_FULL;
 		*autoneg = true;
-	} else if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
-		   hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1) {
+	} else if (txgbe_is_dac_cable(hw)) {
 		if (hw->phy.fiber_suppport_speed ==
 		    TXGBE_LINK_SPEED_10GB_FULL) {
 			hw->devarg.auto_neg = false;
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 2d3b32839c..512b8ba331 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -95,27 +95,77 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
 	return 0;
 }
 
+static int txgbe_is_40g_fiber_qsfp(struct txgbe_hw *hw)
+{
+	if (hw->phy.sfp_type == txgbe_qsfp_type_40g_sr_core0 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_sr_core1 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_lr_core0 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_lr_core1 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_active_core0 ||
+	    hw->phy.sfp_type == txgbe_qsfp_type_40g_active_core1)
+		return true;
+
+	return false;
+}
+
+static int txgbe_is_10g_fiber_sfp(struct txgbe_hw *hw)
+{
+	if (hw->phy.sfp_type == txgbe_sfp_type_srlr_core0 ||
+	    hw->phy.sfp_type == txgbe_sfp_type_srlr_core1)
+		return true;
+
+	return false;
+}
+
 s32 txgbe_get_link_capabilities_aml40(struct txgbe_hw *hw,
 				      u32 *speed,
 				      bool *autoneg)
 {
-	if (hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
-	    hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1) {
-		*speed = hw->phy.fiber_suppport_speed;
-		*autoneg = hw->devarg.auto_neg;
-	} else if (txgbe_is_backplane(hw)) {
-		*speed = TXGBE_LINK_SPEED_40GB_FULL |
-			 TXGBE_LINK_SPEED_10GB_FULL;
+	PMD_DRV_LOG(DEBUG, "port[%d]hw->phy.sfp_type = %d",
+		    hw->bus.lan_id, hw->phy.sfp_type);
+
+	/* Backplane */
+	if (txgbe_is_backplane(hw)) {
+		*speed = TXGBE_LINK_SPEED_10GB_FULL |
+			 TXGBE_LINK_SPEED_40GB_FULL;
+		/* Backplane supports autonegotiation */
 		*autoneg = hw->devarg.auto_neg;
+		return 0;
+	}
+
+	/* Fiber or DAC cable */
+	if (txgbe_is_dac_cable(hw)) {
+		/*
+		 * 10G-only DAC cable: legacy build-time AUTO=0/1 default
+		 * mode forces AN off. DPDK equivalent: devarg.auto_neg == 0.
+		 */
+		if (hw->phy.fiber_suppport_speed ==
+		    TXGBE_LINK_SPEED_10GB_FULL &&
+		    hw->devarg.auto_neg == 0) {
+			*autoneg = false;
+		} else {
+			*autoneg = hw->devarg.auto_neg;
+		}
+		*speed = hw->phy.fiber_suppport_speed;
+	} else if (hw->phy.multispeed_fiber) {
+		/* multispeed fiber must come before single-sfp/qsfp fiber */
+		*speed = TXGBE_LINK_SPEED_10GB_FULL |
+			 TXGBE_LINK_SPEED_40GB_FULL;
+		*autoneg = true;
+	} else if (txgbe_is_40g_fiber_qsfp(hw)) {
+		*speed = TXGBE_LINK_SPEED_40GB_FULL;
+		*autoneg = false;
+	} else if (txgbe_is_10g_fiber_sfp(hw)) {
+		*speed = TXGBE_LINK_SPEED_10GB_FULL;
+		*autoneg = false;
 	} else {
 		/*
-		 * Temporary workaround: set speed to 40G even if sfp not present
-		 * to avoid TXGBE_ERR_LINK_SETUP returned by setup_mac_link, but
-		 * a more reasonable solution is don't execute setup_mac_link when
-		 * sfp module not present.
+		 * Unknown / unsupported module: keep 40G default to avoid
+		 * TXGBE_ERR_LINK_SETUP returned by setup_mac_link, mirroring
+		 * the temporary workaround in the previous version.
 		 */
 		*speed = TXGBE_LINK_SPEED_40GB_FULL;
-		*autoneg = true;
+		*autoneg = false;
 	}
 
 	return 0;
diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index 8e986daf96..f996113ab8 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -73,8 +73,7 @@ u32 txgbe_e56_tx_ffe_cfg(struct txgbe_hw *hw, u32 speed)
 		pre2 = S10G_TX_FFE_CFG_PRE2;
 		post = S10G_TX_FFE_CFG_POST;
 	} else if (speed == TXGBE_LINK_SPEED_25GB_FULL) {
-		if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
-		    hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1 ||
+		if (txgbe_is_dac_cable(hw) ||
 		    txgbe_is_backplane(hw)) {
 			ffe_main = S25G_TX_FFE_CFG_DAC_MAIN;
 			pre1 = S25G_TX_FFE_CFG_DAC_PRE1;
@@ -92,8 +91,7 @@ u32 txgbe_e56_tx_ffe_cfg(struct txgbe_hw *hw, u32 speed)
 		pre2 = S10G_TX_FFE_CFG_PRE2;
 		post = S10G_TX_FFE_CFG_POST;
 
-		if (hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
-		    hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1 ||
+		if (txgbe_is_dac_cable(hw) ||
 		    txgbe_is_backplane(hw)) {
 			ffe_main = S40G_TX_FFE_CFG_MAIN;
 			pre1 = S40G_TX_FFE_CFG_PRE1;
@@ -2622,8 +2620,7 @@ txgbe_e56_rxs_calib_adapt_seq(struct txgbe_hw *hw, u32 speed)
 	u32 rdata = 0x0;
 	bool bypass_ctle = true;
 
-	if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
-	    hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1)
+	if (txgbe_is_dac_cable(hw))
 		bypass_ctle = 0;
 
 	if (hw->mac.type == txgbe_mac_aml) {
diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index 10df23afae..e52f1da87d 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1156,6 +1156,13 @@ s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw)
 			else
 				hw->phy.sfp_type = txgbe_qsfp_type_40g_lr_core1;
 		}
+
+		if (transceiver_type & TXGBE_SFF_ETHERNET_40G_ACTIVE) {
+			if (hw->bus.lan_id == 0)
+				hw->phy.sfp_type = txgbe_qsfp_type_40g_active_core0;
+			else
+				hw->phy.sfp_type = txgbe_qsfp_type_40g_active_core1;
+		}
 	}
 
 	hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h
index a06c0eb04e..552fedadab 100644
--- a/drivers/net/txgbe/base/txgbe_phy.h
+++ b/drivers/net/txgbe/base/txgbe_phy.h
@@ -316,6 +316,7 @@
 #define TXGBE_SFF_ETHERNET_40G_CR4		MS(3, 0x1)
 #define TXGBE_SFF_ETHERNET_40G_SR4		MS(2, 0x1)
 #define TXGBE_SFF_ETHERNET_40G_LR4		MS(1, 0x1)
+#define TXGBE_SFF_ETHERNET_40G_ACTIVE		MS(0, 0x1)
 
 #define TXGBE_SFF_SOFT_RS_SELECT_MASK		0x8
 #define TXGBE_SFF_SOFT_RS_SELECT_10G		0x8
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index 39a70746a7..91771b9cbd 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -249,6 +249,8 @@ enum txgbe_sfp_type {
 	txgbe_qsfp_type_40g_sr_core1,
 	txgbe_qsfp_type_40g_lr_core0,
 	txgbe_qsfp_type_40g_lr_core1,
+	txgbe_qsfp_type_40g_active_core0,
+	txgbe_qsfp_type_40g_active_core1,
 	txgbe_sfp_type_not_present = 0xFFFE,
 	txgbe_sfp_type_not_known = 0xFFFF
 };
-- 
2.55.0.windows.2


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

* Re: [PATCH v3 00/15] Wangxun fixes and new features
  2026-09-08 13:25 ` [PATCH v3 00/15] Wangxun fixes and new features Zaiyu Wang
@ 2026-09-08 14:20   ` Stephen Hemminger
  0 siblings, 0 replies; 46+ messages in thread
From: Stephen Hemminger @ 2026-09-08 14:20 UTC (permalink / raw)
  To: Zaiyu Wang; +Cc: dev

On Tue,  8 Sep 2026 21:25:45 +0800
Zaiyu Wang <zaiyuwang@trustnetic.com> wrote:

> This series addresses link-related issues on Wangxun Amber-lite 25G/40G NICs
> (CR/KR training, hot-plug, 10G link state), and additionally refines UDP
> offload handling.
> 
> ---
> v2:
>  - add a new commit to handle 10G config on dual-speed DAC
>  - P02: handle TXGBE_ERR_PHY_INIT_NOT_DONE before the timeout split and leave link_valid untouched.
>  - P07: resolve the inner tunnel type in a local variable instead of rewriting mbuf->ol_flags.
>         check the rte_pktmbuf_read() result for short or mis-annotated packets.
>         use RTE_GENEVE_DEFAULT_PORT instead of the literal 6081.
>         add a Fixes: tag pointing to the commit that introduced the tunnel offload handling.
>  - P10: split into a bug-fix commit and a feature commit.
>         document both devargs in the NIC guide and the release notes.
>  - P11: check the acquire_swfw_sync() result and only touch I2C while the semaphore is held.
>         replace the magic numbers with named constants.
>         add the release notes entry.
>  - P12: drop the stray C99 comment on the AN-config flag assignment that checkpatch rejects.
>  - P13: reword the message to state that 40G active cables are handled through the optical path.
>         use txgbe_is_dac_cable() in the 40G FFE selection to match the 25G path.
> ---
> 
> ---
> Not changed in this revision:
> 
>  - P11: enable_tx_laser() is not gated by laser_off. laser_off only
>    controls whether the Tx laser is brought down on port stop, while
>    enable_tx_laser() is unconditionally called from dev_start() and
>    dev_set_link_up() and must always bring the laser up, otherwise the
>    default (laser_off=0) configuration would never bring the link up.
> 
>  - P11: no extra restore of PMD_CFG0 bit 1 on the DAC path. Bits 19:12
>    are restored by txgbe_e56_set_phy_link_mode() and
>    txgbe_set_link_to_amlite(); bit 1 (PMD enable) is also restored by
>    txgbe_e56_set_phy_link_mode(), which the xpcs AN path calls on link
>    up, so no additional write is required.
> 
>  - P12: no total iteration bound was added to txgbe_e56_exchange_page().
>    The loop is bounded per page and exits when the AN FSM reaches 0x8,
>    so it does not hang in a normal Clause 73 flow. As this is hardware
>    related configuration, we leave the current behaviour unchanged for
>    now.
> ---
> 
> Zaiyu Wang (15):
>   net/txgbe: fix failure to configure 10G on dual-speed DAC
>   net/txgbe: fix e56 PHY configuration error
>   net/txgbe: fix incorrect link state in 10G forced mode
>   net/txgbe: do not force reconfig on link retry
>   net/txgbe: set i2c sda hold time
>   net/txgbe: fix link speed display info for 10G mode
>   net/txgbe: remove stale outer UDP checksum offload flag
>   net/txgbe: add offload support for tunnel type UDP
>   net/txgbe: fix SFP hot-plug when auto-negotiation is on
>   net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation
>   net/txgbe: fix 40G FFE tuning applied to first lane only
>   net/txgbe: add pre2 and backplane capability devargs
>   net/txgbe: add devarg to turn off Tx laser for 40G NIC
>   net/txgbe: fix CR/KR link training and recovery
>   net/txgbe: align link capabilities and DAC classification
> 
>  doc/guides/nics/txgbe.rst              |  18 +++
>  doc/guides/rel_notes/release_26_11.rst |  11 ++
>  drivers/net/txgbe/base/txgbe_aml.c     |   3 +-
>  drivers/net/txgbe/base/txgbe_aml40.c   | 100 +++++++++++++--
>  drivers/net/txgbe/base/txgbe_e56.c     |  14 +--
>  drivers/net/txgbe/base/txgbe_e56.h     |   6 +
>  drivers/net/txgbe/base/txgbe_e56_bp.c  | 161 +++++++++++++++----------
>  drivers/net/txgbe/base/txgbe_e56_bp.h  |   2 +
>  drivers/net/txgbe/base/txgbe_hw.c      |  29 +++++
>  drivers/net/txgbe/base/txgbe_phy.c     |  13 ++
>  drivers/net/txgbe/base/txgbe_phy.h     |   7 ++
>  drivers/net/txgbe/base/txgbe_regs.h    |   3 +
>  drivers/net/txgbe/base/txgbe_type.h    |  17 ++-
>  drivers/net/txgbe/txgbe_ethdev.c       | 120 ++++++++++++++++--
>  drivers/net/txgbe/txgbe_rxtx.c         |  29 ++++-
>  15 files changed, 432 insertions(+), 101 deletions(-)


Looks good, but there are still some leftover items to address.

AI is good at picking out detail but can be wrong. So dont trust it.




Review of "[PATCH v3 00/15] net/txgbe: Amber-Lite link fixes, devargs"

Applied cleanly on d55ccd4 ("pci: remove deprecated catch-all flag").
Reviewed against the post-apply tree.  Build and checkpatch were not
run for this revision.

Closed since the previous revision:

 - The multi-bit speed mask reaching txgbe_set_link_to_amlite() and
   txgbe_e56_tx_ffe_cfg(), which compare with ==.  Patch 01 widens
   allowed_speeds and adds the highest-set-bit reduction ahead of both
   consumers.
 - link_valid set true after TXGBE_ERR_PHY_INIT_NOT_DONE (patch 03).
 - Unchecked rte_pktmbuf_read() and the ol_flags rewrite in
   txgbe_get_tun_len() (patch 08); RTE_GENEVE_DEFAULT_PORT is used and
   the two new TUNNEL_UDP case labels are the right consequence of no
   longer mutating the mbuf.
 - The //aml40-to-do C99 comment.
 - Incomplete txgbe_is_dac_cable() unification (patch 15 converts the
   40G branch of tx_ffe_cfg, rxs_calib_adapt_seq and the aml.c
   capability function as well).
 - Release notes, txgbe.rst entries, named constants for the SFF-8636
   Tx disable byte and PMD_CFG0, and the acquire_swfw_sync return
   checks on the disable path (patches 12 and 13).


Patch 13/15: net/txgbe: add devarg to turn off Tx laser for 40G NIC

Error: the enable path is still not guarded by the devarg.  This was
raised on the previous revision and is unchanged:

  void txgbe_enable_tx_laser_multispeed_fiber(struct txgbe_hw *hw)
  {
      ...
      if (hw->mac.type == txgbe_mac_aml40) {
          wr32m(hw, TXGBE_GPIODIR, TXGBE_GPIOBIT_1, TXGBE_GPIOBIT_1);
          esdp_reg |= TXGBE_GPIOBIT_1;
          if (hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWPHY) == 0) {
              hw->phy.write_i2c_eeprom(hw,
                      TXGBE_SFF_8636_TX_DISABLE, 0x0);

laser_off defaults to 0 and is documented as opt-in, but this I2C
EEPROM write runs on every enable_tx_laser() for every AML40 port
whether or not the user asked for it.

The disable path deliberately branches before touching I2C:

          if (hw->devarg.laser_off) {
                  if (txgbe_is_dac_cable(hw) ||
                      hw->phy.sfp_type == txgbe_sfp_type_unknown) {
                          ... clear PMD_CFG0 19:16, 15:12, bit 1 ...
                  } else if (hw->mac.acquire_swfw_sync(...) == 0) {
                          ... SFF-8636 Tx disable ...

so with laser_off=1 on a DAC cable, down clears those PMD_CFG0 fields
and up writes I2C to a cable that has no EEPROM Tx-disable byte to
write.  Please gate the enable path on hw->devarg.laser_off and mirror
the DAC/QSFP branch.

Warning: the disable path's "no module" case tests

          hw->phy.sfp_type == txgbe_sfp_type_unknown

but patches 09 and 10 in this same series set

          hw->phy.sfp_type = txgbe_sfp_type_not_present;

on module removal.  Those are different enumerators (0 versus 0xFFFE),
so after a pull the disable path falls into the else and issues an I2C
write to an absent module instead of taking the PCS branch.  Test both,
or use one enumerator consistently for "no module".


Patch 14/15: net/txgbe: fix CR/KR link training and recovery

Error: txgbe_e56_exchange_page() can still loop indefinitely.  count2
was added and is incremented on every iteration, but it is only used
in a log message:

          BP_LOG("AN exchange page done in %d ms\n", count2);

The loop bound is still reset from inside the loop body:

          if (rdata & BIT(15)) {
                  wr32_epcs(hw, 0x70016, 0x2001);
                  ...
                  next_page = 1;
                  count = 0; /* reset count to wait next page */
          }

so a link partner that keeps asserting next-page at 0x70019 keeps
resetting count and the loop never terminates.  This revision also
moves the call out of txgbe_handle_e56_bkp_an73_flow() and into
txgbe_dev_e56_check_bp_event(), so it now runs directly in the
interrupt/alarm thread and a wedge there blocks every other alarm in
the process.

count2 is the budget that is needed; it just needs to be enforced:

          if (count2 >= MAX_AN_PAGE_ITERATIONS)
                  return -ETIMEDOUT;

at the top of the loop body would cap the total while still allowing
count to restart per page.

Info (pre-existing, not introduced by this patch): three results in
txgbe_e56_cl72_training() are stored and discarded.  All three lines
are diff context here, so they predate the patch, but the function is
being reworked so they are cheap to fix in passing:

  status = txgbe_set_phy_link_mode(hw, bylinkmode);  /* never read */
  ...
  status = txgbe_e56_get_temp(hw, &temp_data);       /* overwritten */
  ...
  status = txgbe_e56_rxs_adc_adapt_seq(hw, bypass_ctle);

The last one is neither ORed into ret nor returned, so an adc
adaptation failure is silently dropped.

The removal of the early return after txgbe_e56_cl72_training() in
txgbe_handle_e56_bkp_an73_flow() is fine: status is not reassigned
before the return, so a training failure is still propagated and the
idle-detect thresholds are now programmed either way.


Patch 10/15: net/txgbe: fix DAC hot-plug on 40G NIC with autoneg

Warning: the new rearm re-arms without cancelling first, so the poll
chain can be duplicated:

  rearm:
      if (hw->mac.type == txgbe_mac_aml40 && !txgbe_is_backplane(hw) &&
          dev->data->dev_started)
          rte_eal_alarm_set(2000 * 1000, txgbe_dev_detect_sfp, dev);

txgbe_dev_detect_sfp() is also scheduled independently by
txgbe_dev_sfp_event() -- unconditionally on TXGBE_GPIOBIT_2, and again
on TXGBE_GPIOBIT_4 for aml40.  That invocation falls through to rearm
as well and starts a second self-perpetuating 2-second chain, and each
subsequent GPIO event adds another.  Patch 09 handles exactly this for
the other alarm, with the comment "so that only one instance of it is
running at a time":

          rte_eal_alarm_cancel(txgbe_dev_e56_check_bp_event, dev);
          rte_eal_alarm_set(hw->bp_event_interval,
                            txgbe_dev_e56_check_bp_event, dev);

The same cancel is needed before the rearm set.

(The dev_stop path is fine -- rte_eal_alarm_cancel() re-walks the list
in a do/while until nothing matching is executing, so a re-arm issued
by the executing callback is picked up on the next pass.)


Patch 15/15: net/txgbe: align link capabilities and DAC classification

Warning: the *autoneg the patch computes is never read.  All six call
sites of mac.get_link_capabilities pass a local that is not examined
afterwards: txgbe_setup_phy_link_aml40(), txgbe_dev_start(), the two
link alarm handlers in txgbe_ethdev.c, and both FEC ops.  So the new
DAC branch has no effect:

          if (hw->phy.fiber_suppport_speed ==
              TXGBE_LINK_SPEED_10GB_FULL &&
              hw->devarg.auto_neg == 0) {
                  *autoneg = false;
          } else {
                  *autoneg = hw->devarg.auto_neg;
          }

It is also a no-op on its own terms: the guard already requires
hw->devarg.auto_neg == 0, so the else arm yields false anyway and the
whole construct reduces to *autoneg = hw->devarg.auto_neg.

The 25G sibling that this is modelled on writes the field that is
actually consulted:

          if (hw->phy.fiber_suppport_speed ==
              TXGBE_LINK_SPEED_10GB_FULL) {
                  hw->devarg.auto_neg = false;
                  *autoneg = false;

hw->devarg.auto_neg is what txgbe_xpcs_an_enabled() reads.  If the
intent is to force AN off for 10G-only DAC cables on AML40, the aml40
version needs that assignment too; otherwise the comment about the
legacy AUTO=0/1 default does not describe what the code does.

Info: the multispeed_fiber arm is unreachable on this MAC type.
hw->phy.multispeed_fiber is only assigned in
txgbe_identify_sfp_module(), and only under txgbe_mac_aml or the SP
else-branch; txgbe_identify_qsfp_module() never touches it.  So

          } else if (hw->phy.multispeed_fiber) {

never runs on aml40 and the "multispeed fiber must come before
single-sfp/qsfp fiber" ordering comment has nothing to order.


Patch 01/15: net/txgbe: fix failure to configure 10G on dual-speed DAC

Info: the third item in the commit message does not hold.  The message
lists as a blocker that setup_phy_link_aml40() "passed a hardcoded 40
to txgbe_e56_set_phy_link_mode(), ignoring the caller speed", but that
function discards the argument:

  int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
                               u8 bp_link_mode, u32 need_restart)
  {
          ...
          UNREFERENCED_PARAMETER(bp_link_mode);

so replacing 40 with speed changes nothing.  Worth also noting that
the new argument is a bitmask -- TXGBE_LINK_SPEED_40GB_FULL is 0x0040
-- passed into a u8 whose other users in txgbe_e56_bp.c compare it
against 10, 25 and 40.  If the parameter is ever wired up, the value
handed in here will be wrong.  Either drop the hunk and the third
bullet, or convert the speed to a link mode at the call site.


Patch 09/15: net/txgbe: fix SFP hot-plug when auto-negotiation is on

Info: the new module-present sampling is not gated on
!txgbe_is_backplane(hw):

  else if (hw->mac.type == txgbe_mac_aml40)
      value = rd32(hw, TXGBE_GPIOEXT) & TXGBE_SFP1_MOD_PRST_LS;

  if (value != 0 && hw->phy.sfp_type != txgbe_sfp_type_not_present) {
      PMD_DRV_LOG(INFO, "SFP module removed, stop AN73 watchdog.");

On a backplane AML40 port there is no module, so this reports a removal
that never happened and clears sfp_type.  It is harmless for the AN
gate -- txgbe_xpcs_an_enabled() returns true for backplane regardless
of sfp_type -- but the log is misleading.  Patch 10 adds exactly the
!txgbe_is_backplane(hw) guard for its own alarm; the same guard fits
here.


No Reviewed-by on this revision -- the two Errors above are both
carried over unchanged from the previous revision.

Review-Result: ERROR

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

end of thread, other threads:[~2026-09-08 14:21 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20260827114309.10530-1-zaiyuwang@trustnetic.com>
2026-08-27 11:41 ` [PATCH 01/13] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
2026-08-27 11:41 ` [PATCH 02/13] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
2026-08-27 11:41 ` [PATCH 03/13] net/txgbe: do not force reconfig on link retry Zaiyu Wang
2026-08-27 11:41 ` [PATCH 04/13] net/txgbe: set i2c sda hold time Zaiyu Wang
2026-08-27 11:41 ` [PATCH 05/13] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
2026-08-27 11:41 ` [PATCH 06/13] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
2026-08-27 11:41 ` [PATCH 07/13] net/txgbe: add offload support for tunnel type UDP Zaiyu Wang
2026-08-27 11:42 ` [PATCH 08/13] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
2026-08-27 11:42 ` [PATCH 09/13] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
2026-08-27 11:42 ` [PATCH 10/13] net/txgbe: add backplane FFE and capability devargs Zaiyu Wang
2026-08-27 11:42 ` [PATCH 11/13] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
2026-08-27 11:42 ` [PATCH 12/13] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
2026-08-27 11:42 ` [PATCH 13/13] net/txgbe: align link capabilities and DAC classification Zaiyu Wang
2026-09-08 12:38 ` [PATCH v2 00/15] Wangxun fixes and new features Zaiyu Wang
     [not found] ` <20260908124047.2284-1-zaiyuwang@trustnetic.com>
2026-09-08 12:38   ` [PATCH v2 01/15] net/txgbe: fix failure to configure 10G on dual-speed DAC Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 02/15] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 03/15] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 04/15] net/txgbe: do not force reconfig on link retry Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 05/15] net/txgbe: set i2c sda hold time Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 06/15] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 07/15] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 08/15] net/txgbe: add offload support for tunnel type UDP Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 09/15] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 10/15] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 11/15] net/txgbe: fix 40G FFE tuning applied to first lane only Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 12/15] net/txgbe: add pre2 and backplane capability devargs Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 13/15] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
2026-09-08 12:38   ` [PATCH v2 14/15] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
2026-09-08 12:39   ` [PATCH v2 15/15] net/txgbe: align link capabilities and DAC classification Zaiyu Wang
2026-09-08 13:25 ` [PATCH v3 00/15] Wangxun fixes and new features Zaiyu Wang
2026-09-08 14:20   ` Stephen Hemminger
     [not found] ` <20260908132742.2661-1-zaiyuwang@trustnetic.com>
2026-09-08 13:25   ` [PATCH v3 01/15] net/txgbe: fix failure to configure 10G on dual-speed DAC Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 02/15] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 03/15] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 04/15] net/txgbe: do not force reconfig on link retry Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 05/15] net/txgbe: set i2c sda hold time Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 06/15] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 07/15] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 08/15] net/txgbe: add offload support for tunnel type UDP Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 09/15] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 10/15] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 11/15] net/txgbe: fix 40G FFE tuning applied to first lane only Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 12/15] net/txgbe: add pre2 and backplane capability devargs Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 13/15] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
2026-09-08 13:25   ` [PATCH v3 14/15] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
2026-09-08 13:26   ` [PATCH v3 15/15] net/txgbe: align link capabilities and DAC classification Zaiyu Wang

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