After changing speed to 100Mbps as a result of auto-negotiation (AN), some 10/100/1000Mbps SFPs indicate a successful link (no faults or loss of signal), but cannot successfully transmit or receive data. These SFPs required an extra auto-negotiation (AN) after the speed change in order to operate properly. Add a quirk for these SFPs so that if the outcome of the AN actually results in changing to a new speed, re-initiate AN at that new speed.
Signed-off-by: Venkat Kumar Ande <venkatkumar.a...@amd.com> --- drivers/net/axgbe/axgbe_ethdev.h | 1 + drivers/net/axgbe/axgbe_mdio.c | 73 ++++++++++++++++-------------- drivers/net/axgbe/axgbe_phy_impl.c | 5 ++ 3 files changed, 46 insertions(+), 33 deletions(-) diff --git a/drivers/net/axgbe/axgbe_ethdev.h b/drivers/net/axgbe/axgbe_ethdev.h index df5d63c493..924a26ebe3 100644 --- a/drivers/net/axgbe/axgbe_ethdev.h +++ b/drivers/net/axgbe/axgbe_ethdev.h @@ -656,6 +656,7 @@ struct axgbe_port { enum axgbe_an an_state; enum axgbe_rx kr_state; enum axgbe_rx kx_state; + unsigned int an_again; unsigned int an_supported; unsigned int parallel_detect; unsigned int fec_ability; diff --git a/drivers/net/axgbe/axgbe_mdio.c b/drivers/net/axgbe/axgbe_mdio.c index 913ceada0d..0beeb1d0f5 100644 --- a/drivers/net/axgbe/axgbe_mdio.c +++ b/drivers/net/axgbe/axgbe_mdio.c @@ -200,13 +200,14 @@ static void axgbe_switch_mode(struct axgbe_port *pdata) axgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata)); } -static void axgbe_set_mode(struct axgbe_port *pdata, +static bool axgbe_set_mode(struct axgbe_port *pdata, enum axgbe_mode mode) { if (mode == axgbe_cur_mode(pdata)) - return; + return false; axgbe_change_mode(pdata, mode); + return true; } static bool axgbe_use_mode(struct axgbe_port *pdata, @@ -880,21 +881,22 @@ static int axgbe_phy_config_fixed(struct axgbe_port *pdata) return 0; } -static int __axgbe_phy_config_aneg(struct axgbe_port *pdata) +static int __axgbe_phy_config_aneg(struct axgbe_port *pdata, bool set_mode) { int ret; + pthread_mutex_lock(&pdata->an_mutex); rte_bit_relaxed_set32(AXGBE_LINK_INIT, &pdata->dev_state); pdata->link_check = rte_get_timer_cycles(); ret = pdata->phy_if.phy_impl.an_config(pdata); if (ret) - return ret; + goto out; if (pdata->phy.autoneg != AUTONEG_ENABLE) { ret = axgbe_phy_config_fixed(pdata); if (ret || !pdata->kr_redrv) - return ret; + goto out; PMD_DRV_LOG(DEBUG, "AN redriver support\n"); } else { PMD_DRV_LOG(DEBUG, "AN PHY configuration\n"); @@ -904,23 +906,26 @@ static int __axgbe_phy_config_aneg(struct axgbe_port *pdata) rte_intr_disable(pdata->pci_dev->intr_handle); /* Start auto-negotiation in a supported mode */ - if (axgbe_use_mode(pdata, AXGBE_MODE_KR)) { - axgbe_set_mode(pdata, AXGBE_MODE_KR); - } else if (axgbe_use_mode(pdata, AXGBE_MODE_KX_2500)) { - axgbe_set_mode(pdata, AXGBE_MODE_KX_2500); - } else if (axgbe_use_mode(pdata, AXGBE_MODE_KX_1000)) { - axgbe_set_mode(pdata, AXGBE_MODE_KX_1000); - } else if (axgbe_use_mode(pdata, AXGBE_MODE_SFI)) { - axgbe_set_mode(pdata, AXGBE_MODE_SFI); - } else if (axgbe_use_mode(pdata, AXGBE_MODE_X)) { - axgbe_set_mode(pdata, AXGBE_MODE_X); - } else if (axgbe_use_mode(pdata, AXGBE_MODE_SGMII_1000)) { - axgbe_set_mode(pdata, AXGBE_MODE_SGMII_1000); - } else if (axgbe_use_mode(pdata, AXGBE_MODE_SGMII_100)) { - axgbe_set_mode(pdata, AXGBE_MODE_SGMII_100); - } else { - rte_intr_enable(pdata->pci_dev->intr_handle); - return -EINVAL; + if (set_mode) { + if (axgbe_use_mode(pdata, AXGBE_MODE_KR)) { + axgbe_set_mode(pdata, AXGBE_MODE_KR); + } else if (axgbe_use_mode(pdata, AXGBE_MODE_KX_2500)) { + axgbe_set_mode(pdata, AXGBE_MODE_KX_2500); + } else if (axgbe_use_mode(pdata, AXGBE_MODE_KX_1000)) { + axgbe_set_mode(pdata, AXGBE_MODE_KX_1000); + } else if (axgbe_use_mode(pdata, AXGBE_MODE_SFI)) { + axgbe_set_mode(pdata, AXGBE_MODE_SFI); + } else if (axgbe_use_mode(pdata, AXGBE_MODE_X)) { + axgbe_set_mode(pdata, AXGBE_MODE_X); + } else if (axgbe_use_mode(pdata, AXGBE_MODE_SGMII_1000)) { + axgbe_set_mode(pdata, AXGBE_MODE_SGMII_1000); + } else if (axgbe_use_mode(pdata, AXGBE_MODE_SGMII_100)) { + axgbe_set_mode(pdata, AXGBE_MODE_SGMII_100); + } else { + rte_intr_enable(pdata->pci_dev->intr_handle); + ret = -EINVAL; + goto out; + } } /* Disable and stop any in progress auto-negotiation */ @@ -938,16 +943,7 @@ static int __axgbe_phy_config_aneg(struct axgbe_port *pdata) axgbe_an_init(pdata); axgbe_an_restart(pdata); - return 0; -} - -static int axgbe_phy_config_aneg(struct axgbe_port *pdata) -{ - int ret; - - pthread_mutex_lock(&pdata->an_mutex); - - ret = __axgbe_phy_config_aneg(pdata); +out: if (ret) rte_bit_relaxed_set32(AXGBE_LINK_ERR, &pdata->dev_state); else @@ -958,6 +954,16 @@ static int axgbe_phy_config_aneg(struct axgbe_port *pdata) return ret; } +static int axgbe_phy_config_aneg(struct axgbe_port *pdata) +{ + return __axgbe_phy_config_aneg(pdata, true); +} + +static int axgbe_phy_reconfig_aneg(struct axgbe_port *pdata) +{ + return __axgbe_phy_config_aneg(pdata, false); +} + static bool axgbe_phy_aneg_done(struct axgbe_port *pdata) { return pdata->an_result == AXGBE_AN_COMPLETE; @@ -1016,7 +1022,8 @@ static void axgbe_phy_status_result(struct axgbe_port *pdata) pdata->phy.duplex = DUPLEX_FULL; - axgbe_set_mode(pdata, mode); + if (axgbe_set_mode(pdata, mode) && pdata->an_again) + axgbe_phy_reconfig_aneg(pdata); } static int autoneg_time_out(unsigned long autoneg_start_time) diff --git a/drivers/net/axgbe/axgbe_phy_impl.c b/drivers/net/axgbe/axgbe_phy_impl.c index e1b926d48a..5acccf9146 100644 --- a/drivers/net/axgbe/axgbe_phy_impl.c +++ b/drivers/net/axgbe/axgbe_phy_impl.c @@ -560,6 +560,8 @@ static bool axgbe_phy_belfuse_parse_quirks(struct axgbe_port *pdata) if (memcmp(&sfp_eeprom->base[AXGBE_SFP_BASE_VENDOR_NAME], AXGBE_BEL_FUSE_VENDOR, strlen(AXGBE_BEL_FUSE_VENDOR))) return false; + /* For Bel-Fuse, use the extra AN flag */ + pdata->an_again = 1; if (!memcmp(&sfp_eeprom->base[AXGBE_SFP_BASE_VENDOR_PN], AXGBE_BEL_FUSE_PARTNO, strlen(AXGBE_BEL_FUSE_PARTNO))) { @@ -796,6 +798,9 @@ static void axgbe_phy_sfp_detect(struct axgbe_port *pdata) struct axgbe_phy_data *phy_data = pdata->phy_data; int ret; + /* Clear the extra AN flag */ + pdata->an_again = 0; + /* Reset the SFP signals and info */ axgbe_phy_sfp_reset(phy_data); -- 2.34.1