txgbe_disable_tx_laser_multispeed_fiber() brings the laser down by
driving GPIO bit 1, which holds the SFP module in reset. Some DAC
cables and QSFP modules keep sending after that, so the port reports
link down while the peer still sees a live signal and cannot detect the
loss of signal.
Clear the PMD_CFG0 transmit and receive enables for DAC cables, and
write the SFF-8636 Tx disable bit for QSFP modules. The SFF-8636
register is only written 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.
Re-enabling the transmitter alone does not restore what link-down
disabled for DAC, so run the normal link setup again when the link
comes up. The setup is not gated on the current module classification
because the module may have changed while the port was down.
That setup resets the PHY, and restarts the AN73 negotiation when
auto-negotiation is enabled. That is the cost of bringing the link back
up.
The SFF-8636 Tx disable byte keeps its value while the module stays
powered, so link-up clears it for any module present, including one
left disabled by a previous run.
Fixes: e30e5fba32c4 ("net/txgbe: support Tx laser enable/disable for
Amber-Lite")
Cc: [email protected]
Signed-off-by: Zaiyu Wang <[email protected]>
---
drivers/net/txgbe/base/txgbe_hw.c | 31 ++++++++++++++++++++++++++++++
drivers/net/txgbe/base/txgbe_phy.h | 6 ++++++
drivers/net/txgbe/txgbe_ethdev.c | 17 ++++++++++++++++
3 files changed, 54 insertions(+)
diff --git a/drivers/net/txgbe/base/txgbe_hw.c
b/drivers/net/txgbe/base/txgbe_hw.c
index 2650b8b7f1..eb032eea63 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,28 @@ 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 (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 +3311,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/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0e95643239..9d3e1e4416 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2206,6 +2206,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 */
@@ -2213,6 +2216,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) {
+ 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);
}
--
2.55.0.windows.2