* [PATCH v8 01/16] net/txgbe: fix failure to configure 10G on dual-speed DAC
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 02/16] net/txgbe: use the requested speed in E56 AN setup Zaiyu Wang
` (14 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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.
Two 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.
Remove both 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 | 15 +++++++++++----
drivers/net/txgbe/txgbe_ethdev.c | 2 +-
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 1098efe5e6..7c72b53f64 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
@@ -176,6 +177,12 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
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 0734a1c63c..d4c635dc2f 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -1848,7 +1848,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] 21+ messages in thread* [PATCH v8 02/16] net/txgbe: use the requested speed in E56 AN setup
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
2026-10-12 10:56 ` [PATCH v8 01/16] net/txgbe: fix failure to configure 10G on dual-speed DAC Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 03/16] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
` (13 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
txgbe_e56_set_phy_link_mode() takes the speeds to advertise, but the
port does not use the argument: it is passed to
UNREFERENCED_PARAMETER(), and the AN base page is built from the
device id and from hw->phy.fiber_suppport_speed instead. The caller
therefore cannot narrow what is advertised, which is what kept a
10G request from reaching the base page on a 10G/40G part even
after the capability mask had been opened up.
Take the argument as a speed bitmask, as the base layer of the
out-of-tree driver does: gate the 10G, 25G, and 40G advertisement on
the requested speed and use speed rather than
hw->phy.fiber_suppport_speed on the fiber/DAC path.
Both Amber-Lite MACs support 10GBASE-KR in addition to their nominal
speed: the capability masks already report 10G|25G for the 25G MAC
and 10G|40G for the 40G MAC, while the AN base page advertised
exactly one speed picked from the device id. With automatic speed
selection asking for 10G|40G on the 40G MAC as it already did 10G|25G
on the 25G MAC, the base page advertises 10GBASE-KR together with
25GBASE-KR/CR on the 25G MAC and together with 40GBASE-KR4/CR4 on the
40G MAC. Explicit speed requests advertise only the requested modes.
The AN restart paths also have no record of the caller speed to
re-apply. Record it in hw->phy.autoneg_advertised before setup_link(),
as the base layer does, and pass it from the watchdog and
training-restart paths instead of the hardcoded 10. The two readers
of that field keep their existing fallback to get_link_capabilities()
when it is zero.
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_aml40.c | 2 +-
drivers/net/txgbe/base/txgbe_e56_bp.c | 23 +++++++++++------------
drivers/net/txgbe/base/txgbe_e56_bp.h | 2 +-
drivers/net/txgbe/txgbe_ethdev.c | 25 +++++++++++++++++++++----
4 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 7c72b53f64..7476759d4d 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -172,7 +172,7 @@ 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;
}
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.c b/drivers/net/txgbe/base/txgbe_e56_bp.c
index d376d918df..760101a05e 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.c
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.c
@@ -2091,13 +2091,11 @@ static int txgbe_set_phy_link_mode(struct txgbe_hw *hw,
}
int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
- u8 bp_link_mode, u32 need_restart)
+ u32 speed, u32 need_restart)
{
int status = 0;
u32 rdata;
- UNREFERENCED_PARAMETER(bp_link_mode);
-
hw->an_done = false;
if (hw->curbp_link_mode == 10 && !need_restart)
return 0;
@@ -2130,14 +2128,18 @@ int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
/* backplane 10G/25G/40G */
/* 10GKR:7-25KR:14/15-40GKR:8-40GCR:9 */
/* default all speed */
- if ((hw->device_id & 0xFF) == 0x10) {
+ if (speed & TXGBE_LINK_SPEED_10GB_FULL) {
backplane_mode |= BIT(7);
fec_advertise |= TXGBE_10G_FEC_ABL;
- } else if ((hw->device_id & 0xFF) == 0x25) {
+ }
+
+ if (speed & TXGBE_LINK_SPEED_25GB_FULL) {
backplane_mode |= BIT(14) | BIT(15);
fec_advertise |= TXGBE_25G_RS_FEC_REQ |
TXGBE_25G_BASE_FEC_REQ;
- } else if ((hw->device_id & 0xFF) == 0x40) {
+ }
+
+ if (speed & TXGBE_LINK_SPEED_40GB_FULL) {
if (hw->phy.bp_capa == 0)
/* original configure: KR4 + CR4 */
backplane_mode |= BIT(9) | BIT(8);
@@ -2151,21 +2153,18 @@ int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
BP_LOG("Advertised abilities: %d\n", backplane_mode);
}
} else {
- if ((hw->phy.fiber_suppport_speed & TXGBE_LINK_SPEED_10GB_FULL)
- == TXGBE_LINK_SPEED_10GB_FULL) {
+ if (speed & TXGBE_LINK_SPEED_10GB_FULL) {
backplane_mode |= 0x80;
fec_advertise |= TXGBE_10G_FEC_ABL;
}
- if ((hw->phy.fiber_suppport_speed & TXGBE_LINK_SPEED_25GB_FULL)
- == TXGBE_LINK_SPEED_25GB_FULL) {
+ if (speed & TXGBE_LINK_SPEED_25GB_FULL) {
backplane_mode |= 0xc000;
fec_advertise |= TXGBE_25G_RS_FEC_REQ |
TXGBE_25G_BASE_FEC_REQ;
}
- if ((hw->phy.fiber_suppport_speed & TXGBE_LINK_SPEED_40GB_FULL)
- == TXGBE_LINK_SPEED_40GB_FULL) {
+ if (speed & TXGBE_LINK_SPEED_40GB_FULL) {
backplane_mode |= BIT(9) | BIT(8);
fec_advertise |= TXGBE_10G_FEC_ABL;
}
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.h b/drivers/net/txgbe/base/txgbe_e56_bp.h
index d2c49c2fce..8089e5b971 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.h
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.h
@@ -277,6 +277,6 @@ typedef union {
#define E56PHY_CMS_ANA_OVRDVAL_7_ANA_LCPLL_LF_LPF_SETCODE_CALIB_I 8, 4
int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
- u8 bp_link_mode, u32 need_restart);
+ u32 speed, u32 need_restart);
int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw);
#endif
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index d4c635dc2f..2f59b0794f 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -1864,7 +1864,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_10GB_FULL |
+ TXGBE_LINK_SPEED_40GB_FULL;
} else if (hw->mac.type == txgbe_mac_aml) {
speed = (TXGBE_LINK_SPEED_10GB_FULL |
TXGBE_LINK_SPEED_25GB_FULL);
@@ -1888,6 +1889,20 @@ txgbe_dev_start(struct rte_eth_dev *dev)
hw->autoneg = false;
}
+ /* Record the caller speed before setup_link so that the AN
+ * restart paths can re-apply the same configuration.
+ */
+ hw->phy.autoneg_advertised = 0;
+
+ if (speed & TXGBE_LINK_SPEED_40GB_FULL)
+ hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_40GB_FULL;
+
+ if (speed & TXGBE_LINK_SPEED_25GB_FULL)
+ hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_25GB_FULL;
+
+ if (speed & TXGBE_LINK_SPEED_10GB_FULL)
+ hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_10GB_FULL;
+
err = hw->mac.setup_link(hw, speed, link_up);
if (err)
goto error;
@@ -2951,7 +2966,7 @@ void txgbe_dev_e56_check_bp_event(void *param)
value &= ~TXGBE_E56_AN_TXDIS;
wr32_epcs(hw, VR_AN_INTR, value);
rte_spinlock_lock(&hw->phy_lock);
- txgbe_e56_set_phy_link_mode(hw, 10, hw->bypass_ctle);
+ txgbe_e56_set_phy_link_mode(hw, hw->phy.autoneg_advertised, hw->bypass_ctle);
rte_spinlock_unlock(&hw->phy_lock);
goto an_status;
}
@@ -2966,7 +2981,8 @@ void txgbe_dev_e56_check_bp_event(void *param)
if (ret) {
BP_LOG("Training FAILED, do reset\n");
rte_spinlock_lock(&hw->phy_lock);
- txgbe_e56_set_phy_link_mode(hw, 10, hw->bypass_ctle);
+ txgbe_e56_set_phy_link_mode(hw, hw->phy.autoneg_advertised,
+ hw->bypass_ctle);
rte_spinlock_unlock(&hw->phy_lock);
} else {
BP_LOG("ALL SUCCEEDED\n");
@@ -2975,7 +2991,8 @@ void txgbe_dev_e56_check_bp_event(void *param)
if (ret) {
BP_LOG("Training FAILED, do reset\n");
rte_spinlock_lock(&hw->phy_lock);
- txgbe_e56_set_phy_link_mode(hw, 10, hw->bypass_ctle);
+ txgbe_e56_set_phy_link_mode(hw, hw->phy.autoneg_advertised,
+ hw->bypass_ctle);
rte_spinlock_unlock(&hw->phy_lock);
} else {
hw->an_done = true;
--
2.55.0.windows.2
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH v8 03/16] net/txgbe: fix e56 PHY configuration error
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
2026-10-12 10:56 ` [PATCH v8 01/16] net/txgbe: fix failure to configure 10G on dual-speed DAC Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 02/16] net/txgbe: use the requested speed in E56 AN setup Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 04/16] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
` (12 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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] 21+ messages in thread* [PATCH v8 04/16] net/txgbe: fix incorrect link state in 10G forced mode
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (2 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 03/16] net/txgbe: fix e56 PHY configuration error Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 05/16] net/txgbe: do not force reconfig on link retry Zaiyu Wang
` (11 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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] 21+ messages in thread* [PATCH v8 05/16] net/txgbe: do not force reconfig on link retry
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (3 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 04/16] net/txgbe: fix incorrect link state in 10G forced mode Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 06/16] net/txgbe: set i2c sda hold time Zaiyu Wang
` (10 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
The link alarm retry calls mac.setup_link() with
autoneg_wait_to_complete = false. On the AN73/xpcs path, this skips
reconfiguration once the link is up and AN is complete. Passing true
from the retry path instead resets an established AN73 link, which
then drops and may not recover after DAC hot-plug.
The setup flag is also passed to txgbe_e56_set_phy_link_mode() as its
need_restart argument. Passing false unchanged would make a retry a
no-op while the link is down or AN is incomplete if the PHY is already
in 10G mode. Derive need_restart from the current link and AN state so
retries recover an incomplete setup without reconfiguring an
established link.
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_aml.c | 5 ++++-
drivers/net/txgbe/base/txgbe_aml40.c | 5 ++++-
drivers/net/txgbe/txgbe_ethdev.c | 2 +-
3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_aml.c b/drivers/net/txgbe/base/txgbe_aml.c
index ac80d85f08..7a0839a7d1 100644
--- a/drivers/net/txgbe/base/txgbe_aml.c
+++ b/drivers/net/txgbe/base/txgbe_aml.c
@@ -213,6 +213,7 @@ s32 txgbe_setup_phy_link_aml(struct txgbe_hw *hw,
s32 ret_status = 0;
u32 link_speed = TXGBE_LINK_SPEED_UNKNOWN;
bool link_up = false;
+ bool need_restart;
int i;
u32 link_capabilities = TXGBE_LINK_SPEED_UNKNOWN;
u32 value;
@@ -246,8 +247,10 @@ s32 txgbe_setup_phy_link_aml(struct txgbe_hw *hw,
txgbe_e56_check_phy_link(hw, &link_speed, &link_up);
if (link_up && hw->an_done && !autoneg_wait_to_complete)
return status;
+
+ need_restart = autoneg_wait_to_complete || !link_up || !hw->an_done;
rte_spinlock_lock(&hw->phy_lock);
- txgbe_e56_set_phy_link_mode(hw, speed, autoneg_wait_to_complete);
+ txgbe_e56_set_phy_link_mode(hw, speed, need_restart);
rte_spinlock_unlock(&hw->phy_lock);
return 0;
}
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 5fa7c6a243..892dddd373 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -148,6 +148,7 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
s32 ret_status = 0;
u32 link_speed = TXGBE_LINK_SPEED_UNKNOWN;
bool link_up = false;
+ bool need_restart;
int i;
u32 link_capabilities = TXGBE_LINK_SPEED_UNKNOWN;
u32 value;
@@ -171,8 +172,10 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
txgbe_e56_check_phy_link(hw, &link_speed, &link_up);
if (link_up && hw->an_done && !autoneg_wait_to_complete)
return status;
+
+ need_restart = autoneg_wait_to_complete || !link_up || !hw->an_done;
rte_spinlock_lock(&hw->phy_lock);
- txgbe_e56_set_phy_link_mode(hw, speed, autoneg_wait_to_complete);
+ txgbe_e56_set_phy_link_mode(hw, speed, need_restart);
rte_spinlock_unlock(&hw->phy_lock);
return status;
}
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 2f59b0794f..a5ef0b3e54 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3237,7 +3237,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] 21+ messages in thread* [PATCH v8 06/16] net/txgbe: set i2c sda hold time
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (4 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 05/16] net/txgbe: do not force reconfig on link retry Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 07/16] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
` (9 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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] 21+ messages in thread* [PATCH v8 07/16] net/txgbe: fix link speed display info for 10G mode
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (5 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 06/16] net/txgbe: set i2c sda hold time Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 08/16] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
` (8 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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, so a 10G link is reported
as 10G.
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 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 892dddd373..b52702b197 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;
}
--
2.55.0.windows.2
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH v8 08/16] net/txgbe: remove stale outer UDP checksum offload flag
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (6 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 07/16] net/txgbe: fix link speed display info for 10G mode Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 09/16] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
` (7 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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] 21+ messages in thread* [PATCH v8 09/16] net/txgbe: fix SFP hot-plug when auto-negotiation is on
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (7 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 08/16] net/txgbe: remove stale outer UDP checksum offload flag Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 10/16] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
` (6 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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.
The SFP detection alarm and the AN73 watchdog are gated on a per-port
flag that txgbe_dev_start() sets before the alarms are armed and
txgbe_dev_stop() clears before it cancels anything, so a handler
already running on the alarm thread can neither re-arm itself nor arm
the other one on a port that is being stopped. The flag goes low
before the cancels because hw->adapter_stopped is only set at the end
of txgbe_dev_stop().
The link thread can arm the AML link alarm while txgbe_dev_stop()
waits for it, so cancel that alarm again after the thread has been
joined.
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 | 61 ++++++++++++++++++++++++++++++--
drivers/net/txgbe/txgbe_ethdev.h | 2 ++
2 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index a5ef0b3e54..83ef9d8bfc 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -1695,6 +1695,7 @@ txgbe_set_vf_rate_limit(struct rte_eth_dev *dev, uint16_t vf,
static int
txgbe_dev_start(struct rte_eth_dev *dev)
{
+ struct txgbe_adapter *adapter = TXGBE_DEV_ADAPTER(dev);
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
struct txgbe_hw_stats *hw_stats = TXGBE_DEV_STATS(dev);
struct txgbe_vf_info *vfinfo = *TXGBE_DEV_VFDATA(dev);
@@ -1970,6 +1971,8 @@ txgbe_dev_start(struct rte_eth_dev *dev)
txgbe_dev_rxq_interrupt_setup(dev);
/* enable uio/vfio intr/eventfd mapping */
+ rte_atomic_store_explicit(&adapter->sfp_an_alarm_enabled, 1,
+ rte_memory_order_release);
rte_intr_enable(intr_handle);
/* resume enabled intr since hw reset */
@@ -2027,15 +2030,22 @@ txgbe_dev_stop(struct rte_eth_dev *dev)
PMD_INIT_FUNC_TRACE();
+ rte_atomic_store_explicit(&adapter->sfp_an_alarm_enabled, 0,
+ rte_memory_order_release);
+
+ /* Stop the producer before the watchdog it can arm. */
+ rte_eal_alarm_cancel(txgbe_dev_detect_sfp, dev);
+
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_cancel(txgbe_dev_check_aml_temp_event, dev);
rte_eal_alarm_cancel(txgbe_dev_setup_link_alarm_handler_aml, hw);
}
- rte_eal_alarm_cancel(txgbe_dev_detect_sfp, dev);
rte_eal_alarm_cancel(txgbe_tx_queue_clear_error, dev);
txgbe_dev_wait_setup_link_complete(dev, 0);
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40)
+ rte_eal_alarm_cancel(txgbe_dev_setup_link_alarm_handler_aml, hw);
/* disable interrupts */
txgbe_disable_intr(hw);
@@ -2926,6 +2936,7 @@ void txgbe_dev_check_aml_temp_event(void *param)
void txgbe_dev_e56_check_bp_event(void *param)
{
struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+ struct txgbe_adapter *adapter = TXGBE_DEV_ADAPTER(dev);
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
u32 an_int1 = 0, value = 0, fsm = 0;
u32 __rte_unused an_int = 0;
@@ -2935,6 +2946,27 @@ void txgbe_dev_e56_check_bp_event(void *param)
if (!hw)
return;
+ if (rte_atomic_load_explicit(&adapter->sfp_an_alarm_enabled,
+ rte_memory_order_acquire) == 0)
+ 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 (!txgbe_is_backplane(hw)) {
+ 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;
@@ -3022,7 +3054,10 @@ void txgbe_dev_e56_check_bp_event(void *param)
hw->bp_event_interval = 2000 * 1000;
out:
- if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40)
+ if (rte_atomic_load_explicit(&adapter->sfp_an_alarm_enabled,
+ rte_memory_order_acquire) != 0 &&
+ (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);
}
@@ -3030,10 +3065,15 @@ static void
txgbe_dev_detect_sfp(void *param)
{
struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+ struct txgbe_adapter *adapter = TXGBE_DEV_ADAPTER(dev);
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
u32 value = 0;
s32 err;
+ if (rte_atomic_load_explicit(&adapter->sfp_an_alarm_enabled,
+ rte_memory_order_acquire) == 0)
+ return;
+
if (hw->mac.type == txgbe_mac_aml40) {
value = rd32(hw, TXGBE_GPIOEXT);
if (value & TXGBE_SFP1_MOD_PRST_LS) {
@@ -3056,14 +3096,31 @@ txgbe_dev_detect_sfp(void *param)
err = hw->phy.identify_sfp(hw);
out:
+ if (rte_atomic_load_explicit(&adapter->sfp_an_alarm_enabled,
+ rte_memory_order_acquire) == 0)
+ return;
+
if (err == TXGBE_ERR_SFP_NOT_SUPPORTED) {
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->adapter_stopped &&
+ (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);
}
}
diff --git a/drivers/net/txgbe/txgbe_ethdev.h b/drivers/net/txgbe/txgbe_ethdev.h
index a617b70e3c..08f41e628d 100644
--- a/drivers/net/txgbe/txgbe_ethdev.h
+++ b/drivers/net/txgbe/txgbe_ethdev.h
@@ -368,6 +368,8 @@ struct txgbe_adapter {
uint8_t rss_reta_updated;
RTE_ATOMIC(uint32_t) link_thread_running;
+ /* SFP detection and AN73 watchdog alarm state. */
+ RTE_ATOMIC(uint32_t) sfp_an_alarm_enabled;
rte_thread_t link_thread_tid;
};
--
2.55.0.windows.2
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH v8 10/16] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (8 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 09/16] net/txgbe: fix SFP hot-plug when auto-negotiation is on Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 11/16] net/txgbe: fix 40G FFE tuning applied to first lane only Zaiyu Wang
` (5 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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. Three 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. Identification is
attempted only when the cached module state is not present, and the
poll re-arms itself only while the SFP/AN73 alarm gate is set, so that
it cannot survive txgbe_dev_stop().
Second, on AML40, an unsupported QSFP identifier, or a QSFP module
with no supported capability bit, previously left the cached state as
not present. The poll then repeated the delay and I2C reads
indefinitely, and the latter case also repeated module and link setup.
Record these modules as unknown and return not supported so polling
resumes only after an observed removal.
Third, 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/base/txgbe_phy.c | 9 +++++++++
drivers/net/txgbe/txgbe_ethdev.c | 18 +++++++++++++++++-
3 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index b52702b197..cee2f2880a 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -180,6 +180,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, need_restart);
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/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index 8b653f0aeb..a50fa986b9 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1125,6 +1125,8 @@ s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw)
PMD_INIT_LOG(ERR, "port[%d] QSFP module not supported, identifier = 0x%x",
hw->bus.lan_id, identifier);
hw->phy.type = txgbe_phy_sfp_unsupported;
+ if (hw->mac.type == txgbe_mac_aml40)
+ hw->phy.sfp_type = txgbe_sfp_type_unknown;
err = TXGBE_ERR_SFP_NOT_SUPPORTED;
} else {
err = hw->phy.read_i2c_sff8636(hw, 0,
@@ -1158,6 +1160,13 @@ s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw)
}
}
+ if (err == 0 && hw->mac.type == txgbe_mac_aml40 &&
+ hw->phy.sfp_type == txgbe_sfp_type_not_present) {
+ hw->phy.type = txgbe_phy_sfp_unsupported;
+ hw->phy.sfp_type = txgbe_sfp_type_unknown;
+ err = TXGBE_ERR_SFP_NOT_SUPPORTED;
+ }
+
hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
return err;
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 83ef9d8bfc..8e2adb245e 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -1984,6 +1984,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)
@@ -3068,7 +3073,7 @@ txgbe_dev_detect_sfp(void *param)
struct txgbe_adapter *adapter = TXGBE_DEV_ADAPTER(dev);
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
u32 value = 0;
- s32 err;
+ s32 err = 0;
if (rte_atomic_load_explicit(&adapter->sfp_an_alarm_enabled,
rte_memory_order_acquire) == 0)
@@ -3080,6 +3085,9 @@ txgbe_dev_detect_sfp(void *param)
err = TXGBE_ERR_SFP_NOT_PRESENT;
goto out;
}
+ /* Re-identification is only attempted from the not-present state. */
+ if (hw->phy.sfp_type != txgbe_sfp_type_not_present)
+ goto rearm;
}
if (hw->mac.type == txgbe_mac_aml) {
@@ -3123,6 +3131,14 @@ txgbe_dev_detect_sfp(void *param)
}
txgbe_dev_link_update(dev, 0);
}
+
+rearm:
+ if (hw->mac.type == txgbe_mac_aml40 && !txgbe_is_backplane(hw) &&
+ rte_atomic_load_explicit(&adapter->sfp_an_alarm_enabled,
+ rte_memory_order_acquire) != 0) {
+ rte_eal_alarm_cancel(txgbe_dev_detect_sfp, dev);
+ rte_eal_alarm_set(2000 * 1000, txgbe_dev_detect_sfp, dev);
+ }
}
static void
--
2.55.0.windows.2
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH v8 11/16] net/txgbe: fix 40G FFE tuning applied to first lane only
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (9 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 10/16] net/txgbe: fix DAC hot-plug on 40G NIC with auto-negotiation Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 12/16] net/txgbe: add pre2 FFE tap and backplane capability devargs Zaiyu Wang
` (4 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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 5c16c4f07e..60298800ee 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 8e2adb245e..25a65f6a6d 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -483,6 +483,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 */
u16 pballoc = 0;
@@ -492,6 +493,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;
@@ -540,6 +550,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;
}
@@ -642,7 +660,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) {
@@ -650,6 +667,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] 21+ messages in thread* [PATCH v8 12/16] net/txgbe: add pre2 FFE tap and backplane capability devargs
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (10 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 11/16] net/txgbe: fix 40G FFE tuning applied to first lane only Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 13/16] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
` (3 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, Jiawen Wu
The Amber-Lite E56 PHY has per-MAC FFE defaults that differ from the
Sapphire defaults. In particular, the second pre-cursor tap defaults
to zero, but callers need a devarg to override it when ffe_set is
enabled.
Add ffe_pre2 for the E56 second pre-cursor tap, and bp_capa for the
40G backplane advertisement selection. The latter supports the
existing default of both KR4 and CR4, or either capability alone.
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
doc/guides/nics/txgbe.rst | 18 +++++++++++++++---
doc/guides/rel_notes/release_26_11.rst | 9 +++++++++
drivers/net/txgbe/base/txgbe_type.h | 6 +++++-
drivers/net/txgbe/txgbe_ethdev.c | 23 +++++++++++++++++++----
4 files changed, 48 insertions(+), 8 deletions(-)
diff --git a/doc/guides/nics/txgbe.rst b/doc/guides/nics/txgbe.rst
index 90c55141f1..61766cc4ac 100644
--- a/doc/guides/nics/txgbe.rst
+++ b/doc/guides/nics/txgbe.rst
@@ -132,17 +132,23 @@ Please note that following ``devargs`` are only set for backplane NICs.
If disabled, the FFE parameters will not take effect. Otherwise, set 1
for SFI mode, set 2 for KR mode, set 3 for KX4 mode, set 4 for KX mode.
-- ``ffe_main`` (default **27**)
+- ``ffe_main`` (default **42** on the 25G Amber-Lite, **43** on the 40G
+ Amber-Lite, **27** otherwise)
PHY parameter used for user debugging. Setting other values to
take effect requires setting the ``ffe_set``.
-- ``ffe_pre`` (default **8**)
+- ``ffe_pre`` (default **3** on Amber-Lite, **8** otherwise)
PHY parameter used for user debugging. Setting other values to
take effect requires setting the ``ffe_set``.
-- ``ffe_post`` (default **44**)
+- ``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 **17** on Amber-Lite, **44** otherwise)
PHY parameter used for user debugging. Setting other values to
take effect requires setting the ``ffe_set``.
@@ -177,6 +183,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 e282fa5581..f40f9e7da3 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -142,6 +142,14 @@ New Features
* Added VF support on AMD Solarflare X45xx adapters.
+* **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).
+
* **Updated ZTE zxdh ethernet driver.**
* Added a fast single-segment Rx path (``zxdh_recv_single_pkts``)
@@ -164,6 +172,7 @@ New Features
for a specific queue, complementing the existing device-level statistics API.
+
Removed Items
-------------
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index 60298800ee..d65a50530f 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 25a65f6a6d..07b6d13ce1 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -492,13 +492,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;
}
@@ -523,6 +530,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,
@@ -535,6 +544,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:
@@ -548,7 +559,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) {
@@ -6479,12 +6492,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] 21+ messages in thread* [PATCH v8 13/16] net/txgbe: add devarg to turn off Tx laser for 40G NIC
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (11 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 12/16] net/txgbe: add pre2 FFE tap and backplane capability devargs Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 14/16] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
` (2 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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, for
example for link-state tracking at the peer.
Add a laser_off devarg: when enabled, bring the Tx laser down on port
link-down -- 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).
For AML40, rerun normal link setup when link is brought up with
laser_off enabled. Re-enabling the transmitter alone does not restore
the configuration disabled for DAC on link-down. The setup is not
gated on the current module classification because the module may have
changed while the port was down.
Restoring the Tx enable state is deliberately not gated on laser_off
in txgbe_enable_tx_laser_multispeed_fiber(). The SFF-8636 Tx disable
byte keeps its value while the module stays powered, so a module left
with Tx disabled by a run that exited with laser_off=1 is still
disabled when the driver next starts with laser_off=0. Nothing else
clears that byte when the link comes up, so gating this write would
leave the laser off for good.
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
doc/guides/nics/txgbe.rst | 7 ++++++
doc/guides/rel_notes/release_26_11.rst | 4 +++-
drivers/net/txgbe/base/txgbe_hw.c | 33 ++++++++++++++++++++++++++
drivers/net/txgbe/base/txgbe_phy.h | 6 +++++
drivers/net/txgbe/base/txgbe_type.h | 3 +++
drivers/net/txgbe/txgbe_ethdev.c | 24 ++++++++++++++++++-
6 files changed, 75 insertions(+), 2 deletions(-)
diff --git a/doc/guides/nics/txgbe.rst b/doc/guides/nics/txgbe.rst
index 61766cc4ac..6aa6d4597f 100644
--- a/doc/guides/nics/txgbe.rst
+++ b/doc/guides/nics/txgbe.rst
@@ -189,6 +189,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 f40f9e7da3..d62f787747 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -149,6 +149,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 ZTE zxdh ethernet driver.**
@@ -172,7 +175,6 @@ New Features
for a specific queue, complementing the existing device-level statistics API.
-
Removed Items
-------------
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 2650b8b7f1..cbf859c54f 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,30 @@ 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 ||
+ hw->phy.sfp_type == txgbe_sfp_type_not_present) {
+ 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 +3313,14 @@ 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_is_dac_cable(hw) &&
+ hw->phy.sfp_type != txgbe_sfp_type_unknown &&
+ hw->phy.sfp_type != txgbe_sfp_type_not_present &&
+ 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 d65a50530f..33e306ac70 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 07b6d13ce1..ae3dbf076e 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -493,6 +493,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.
@@ -546,6 +547,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:
@@ -556,6 +559,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;
@@ -2158,6 +2162,9 @@ static int
txgbe_dev_set_link_up(struct rte_eth_dev *dev)
{
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+ bool autoneg = false;
+ u32 speed;
+ int err;
if (hw->phy.media_type == txgbe_media_type_copper) {
/* Turn on the copper */
@@ -2165,6 +2172,20 @@ txgbe_dev_set_link_up(struct rte_eth_dev *dev)
} else {
/* Turn on the laser */
hw->mac.enable_tx_laser(hw);
+
+ if (hw->mac.type == txgbe_mac_aml40 && hw->devarg.laser_off) {
+ speed = hw->phy.autoneg_advertised;
+ if (speed == 0) {
+ err = hw->mac.get_link_capabilities(hw, &speed, &autoneg);
+ if (err != 0)
+ return -EIO;
+ }
+
+ err = hw->mac.setup_link(hw, speed, true);
+ if (err != 0)
+ return -EIO;
+ }
+
hw->dev_start = true;
txgbe_dev_link_update(dev, 0);
}
@@ -6499,7 +6520,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] 21+ messages in thread* [PATCH v8 14/16] net/txgbe: fix CR/KR link training and recovery
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (12 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 13/16] net/txgbe: add devarg to turn off Tx laser for 40G NIC Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 15/16] net/txgbe: align link capabilities and DAC classification Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 16/16] net/txgbe: respect manual link-down on Amber-Lite Zaiyu Wang
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 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) for CL72 completion until bits 0 and 3
are set, ((rdata & 0x9) == 0x9), with a 1 ms step and a 400 ms
budget. This replaces 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 (1 ms
step, 50 ms per exchange round, 200 ms total, 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.
- Avoid register reads that are only used by disabled BP debug logs,
and drop a leftover debug line in the watchdog.
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 | 173 ++++++++++++++++----------
drivers/net/txgbe/base/txgbe_e56_bp.h | 2 +
drivers/net/txgbe/base/txgbe_osdep.h | 12 +-
drivers/net/txgbe/base/txgbe_phy.c | 3 +
drivers/net/txgbe/txgbe_ethdev.c | 24 +++-
7 files changed, 146 insertions(+), 72 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 760101a05e..7656da5cd0 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");
@@ -2121,6 +2122,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);
@@ -2350,24 +2352,35 @@ static int chk_bkp_ability(struct txgbe_hw *hw,
return 0;
}
-static int txgbe_e56_exchange_page(struct txgbe_hw *hw)
+#define AN_PAGE_EXCHANGE_TIMEOUT_MS 200
+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++) {
+ /* Allow up to 50 ms per page-exchange round, with a 200 ms total budget. */
+ 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++;
+ if (count2 >= AN_PAGE_EXCHANGE_TIMEOUT_MS) {
+ BP_LOG("Wait for next page timeout after %d ms\n",
+ count2);
+ return -ETIMEDOUT;
+ }
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) {
@@ -2382,31 +2395,87 @@ 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)
+{
+ u32 rdata = 0, pmd_ctrl = 0, lane_idx = 0, lane_num = 0, txffe = 0;
+
+ if (!rte_log_can_log(RTE_LOGTYPE_TXGBE_BP, RTE_LOG_DEBUG))
+ return;
+
+ /* 21. read txffe to check kr training status */
+ 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 TRAINING 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;
@@ -2436,6 +2505,7 @@ static int txgbe_e56_cl72_training(struct txgbe_hw *hw)
BP_LOG("2.3 Wait %dG KR phy mode init ....\n", bylinkmode);
status = txgbe_set_phy_link_mode(hw, bylinkmode);
+ ret |= status;
/* 13. set phy an status to 1 - AN_CFG[0]: 4-7 lane0-lane3 */
rdata = rd32_ephy(hw, 0x1434);
@@ -2462,51 +2532,49 @@ 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);
+ ret |= status;
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);
+ ret |= status;
+
+ BP_LOG("2.8 ===end ret : %d.... fsm:%x, an_int: %x\n",
+ ret, rd32_epcs(hw, 0x78010),
+ rd32_epcs(hw, 0x78002));
return ret;
}
@@ -2516,27 +2584,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);
@@ -2582,11 +2630,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 8089e5b971..f667a052ec 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,
u32 speed, 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_osdep.h b/drivers/net/txgbe/base/txgbe_osdep.h
index da069e94f6..83fee14d12 100644
--- a/drivers/net/txgbe/base/txgbe_osdep.h
+++ b/drivers/net/txgbe/base/txgbe_osdep.h
@@ -31,10 +31,14 @@
extern int txgbe_logtype_bp;
#define RTE_LOGTYPE_TXGBE_BP txgbe_logtype_bp
#define BP_LOG(fmt, ...) \
- RTE_LOG(DEBUG, TXGBE_BP, \
- "[%"PRIu64".%"PRIu64"]%s(%d): " fmt, \
- usec_stamp() / 1000000, usec_stamp() % 1000000, \
- __func__, __LINE__, ## __VA_ARGS__)
+ do { \
+ if (rte_log_can_log(RTE_LOGTYPE_TXGBE_BP, RTE_LOG_DEBUG)) \
+ RTE_LOG(DEBUG, TXGBE_BP, \
+ "[%"PRIu64".%"PRIu64"]%s(%d): " fmt, \
+ usec_stamp() / 1000000, \
+ usec_stamp() % 1000000, \
+ __func__, __LINE__, ## __VA_ARGS__); \
+ } while (0)
#define ASSERT(x) do { \
if (!(x)) \
diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index a50fa986b9..decfcbadd6 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1956,6 +1956,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 ae3dbf076e..f87fca5b19 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3001,6 +3001,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;
@@ -3026,7 +3027,7 @@ void txgbe_dev_e56_check_bp_event(void *param)
}
}
- if (!(txgbe_xpcs_an_enabled(hw)))
+ if (!txgbe_xpcs_an_enabled(hw))
return;
if (!hw->devarg.auto_neg)
@@ -3046,6 +3047,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) {
@@ -3063,7 +3065,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);
@@ -3782,8 +3798,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] 21+ messages in thread* [PATCH v8 15/16] net/txgbe: align link capabilities and DAC classification
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (13 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 14/16] net/txgbe: fix CR/KR link training and recovery Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
2026-10-12 10:56 ` [PATCH v8 16/16] net/txgbe: respect manual link-down on Amber-Lite Zaiyu Wang
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
A 10G active-limiting DAC on an Amber-Lite 25G NIC has no
fiber_suppport_speed value, so the capability path rejects it. A
10G-only passive DAC can also retain a stale 25G bit after hot-plug.
DACs and optical modules are additionally treated differently in the
FFE, CTLE and capability-report paths.
Rework the AML40/AML link capabilities and DAC classification:
- Use the detected DAC speed in the capability paths. Assign 10G for
passive 10G-only and active-limiting DACs instead of preserving a
speed value left by the previously installed module.
- Keep the bp_auto devarg unchanged when a 10G-only DAC disables AN.
The XPCS AN gate queries the current link capabilities, so a
subsequently hot-plugged AN-capable DAC is re-evaluated and can
enable AN73 again.
- 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.
- Remove the AML40 10G SFP capability branch. AML40 identifies QSFP
modules and cannot produce the SFP SR/LR types tested by that
branch.
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 | 4 +--
drivers/net/txgbe/base/txgbe_aml40.c | 52 +++++++++++++++++++++-------
drivers/net/txgbe/base/txgbe_e56.c | 9 ++---
drivers/net/txgbe/base/txgbe_phy.c | 23 ++++++++++--
drivers/net/txgbe/base/txgbe_phy.h | 1 +
drivers/net/txgbe/base/txgbe_type.h | 2 ++
6 files changed, 68 insertions(+), 23 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_aml.c b/drivers/net/txgbe/base/txgbe_aml.c
index 7a0839a7d1..ae5c7d7f0d 100644
--- a/drivers/net/txgbe/base/txgbe_aml.c
+++ b/drivers/net/txgbe/base/txgbe_aml.c
@@ -103,11 +103,9 @@ 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;
*autoneg = false;
} else {
*autoneg = true;
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index cee2f2880a..4080302ce7 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -95,27 +95,55 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
return 0;
}
+static bool 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;
+}
+
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;
+ DEBUGOUT("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)) {
+ if (hw->phy.fiber_suppport_speed ==
+ TXGBE_LINK_SPEED_10GB_FULL) {
+ *autoneg = false;
+ } else {
+ *autoneg = hw->devarg.auto_neg;
+ }
+ *speed = hw->phy.fiber_suppport_speed;
+ } else if (txgbe_is_40g_fiber_qsfp(hw)) {
+ *speed = TXGBE_LINK_SPEED_40GB_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 decfcbadd6..896fe7eecf 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -917,7 +917,7 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
TXGBE_LINK_SPEED_25GB_FULL |
TXGBE_LINK_SPEED_10GB_FULL;
} else {
- hw->phy.fiber_suppport_speed |=
+ hw->phy.fiber_suppport_speed =
TXGBE_LINK_SPEED_10GB_FULL;
}
} else if (comp_codes_25g == TXGBE_SFF_25GAUI_C2M_AOC_BER_5 ||
@@ -938,6 +938,8 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
hw->phy.sfp_type = (hw->bus.lan_id == 0
? txgbe_sfp_type_da_act_lmt_core0
: txgbe_sfp_type_da_act_lmt_core1);
+ hw->phy.fiber_suppport_speed =
+ TXGBE_LINK_SPEED_10GB_FULL;
} else {
hw->phy.sfp_type = txgbe_sfp_type_unknown;
}
@@ -1158,6 +1160,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;
+ }
}
if (err == 0 && hw->mac.type == txgbe_mac_aml40 &&
@@ -2430,10 +2439,20 @@ int txgbe_is_dac_cable(struct txgbe_hw *hw)
int txgbe_xpcs_an_enabled(struct txgbe_hw *hw)
{
+ u32 speed;
+ bool autoneg;
+
if (!(txgbe_is_dac_cable(hw) || txgbe_is_backplane(hw)))
return false;
- return hw->devarg.auto_neg ? true : false;
+ if (!hw->devarg.auto_neg)
+ return false;
+
+ /* Re-evaluate AN support for the currently detected module. */
+ if (hw->mac.get_link_capabilities(hw, &speed, &autoneg) != 0)
+ return false;
+
+ return autoneg;
}
/**
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 33e306ac70..a1ce78623b 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] 21+ messages in thread* [PATCH v8 16/16] net/txgbe: respect manual link-down on Amber-Lite
[not found] ` <20261012110518.1911-1-zaiyuwang@trustnetic.com>
` (14 preceding siblings ...)
2026-10-12 10:56 ` [PATCH v8 15/16] net/txgbe: align link capabilities and DAC classification Zaiyu Wang
@ 2026-10-12 10:56 ` Zaiyu Wang
15 siblings, 0 replies; 21+ messages in thread
From: Zaiyu Wang @ 2026-10-12 10:56 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
txgbe_dev_set_link_down() clears hw->dev_start, but the Amber-Lite
AN73 watchdog treats a down link as a recovery condition and can start
negotiation again. The setup-link alarm handler can likewise configure
the PHY after a link update or a previous setup retry.
As a result, a port brought down through rte_eth_dev_set_link_down()
can link up again without a matching rte_eth_dev_set_link_up() call.
Use hw->dev_start as the administrative link gate. Keep the AN73
watchdog armed so that monitoring resumes after link-up, but skip link
recovery while the port is administratively down. Also make the
setup-link alarm handler return before it configures the PHY in that
state.
This keeps the link down until rte_eth_dev_set_link_up() explicitly
re-enables it. The link-up path then restores the required PHY
configuration.
Fixes: 234ce0d1fa9d ("net/txgbe: fix link stability for Amber-Lite backplane mode")
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 | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index f87fca5b19..e733514826 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3033,8 +3033,8 @@ void txgbe_dev_e56_check_bp_event(void *param)
if (!hw->devarg.auto_neg)
return;
- /* only continue if link is down */
- if (dev->data->dev_link.link_status)
+ /* Continue only for an administratively up port with link down. */
+ if (!hw->dev_start || dev->data->dev_link.link_status)
goto out;
value = rd32_epcs(hw, VR_AN_INTR);
@@ -3362,6 +3362,9 @@ txgbe_dev_setup_link_alarm_handler_aml(void *param)
if (!hw)
return;
+ if (!hw->dev_start)
+ return;
+
struct rte_eth_dev *dev = (struct rte_eth_dev *)hw->dev_back;
struct txgbe_interrupt *intr = TXGBE_DEV_INTR(dev);
u32 speed;
--
2.55.0.windows.2
^ permalink raw reply related [flat|nested] 21+ messages in thread