Hot-plugging a DAC cable while an Amber-Lite 40G port is running
does not bring the link up.
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(). With an empty cage that poll
reported the absence and cancelled the AN73 watchdog on every pass;
do both only when the cached state changes to not present.
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: [email protected]
Signed-off-by: Zaiyu Wang <[email protected]>
---
drivers/net/txgbe/base/txgbe_aml40.c | 5 +++++
drivers/net/txgbe/base/txgbe_phy.c | 9 +++++++++
drivers/net/txgbe/txgbe_ethdev.c | 30 +++++++++++++++++++++++-----
3 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c
b/drivers/net/txgbe/base/txgbe_aml40.c
index b52702b197..b28eb5f8ff 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -180,6 +180,11 @@ 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: a txgbe_set_link_to_amlite() timeout
+ * leaves it false, and check_phy_link()/check_mac_link() then
+ * keep forcing the link down 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 77e8b9dea7..ececbfb13f 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -1975,6 +1975,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)
@@ -3059,7 +3064,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)
@@ -3071,6 +3076,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) {
@@ -3094,10 +3102,14 @@ txgbe_dev_detect_sfp(void *param)
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);
+ /* The poll runs every two seconds while the cage is empty, so
+ * only the removal itself is reported.
+ */
+ if (hw->phy.sfp_type != txgbe_sfp_type_not_present) {
+ PMD_DRV_LOG(INFO, "SFP not present.");
+ 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);
@@ -3114,6 +3126,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