diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0012-amd-xgbe-Improve-SFP-100Mbps-auto-negotiation.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0012-amd-xgbe-Improve-SFP-100Mbps-auto-negotiation.patch | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0012-amd-xgbe-Improve-SFP-100Mbps-auto-negotiation.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0012-amd-xgbe-Improve-SFP-100Mbps-auto-negotiation.patch new file mode 100644 index 00000000..aba4c423 --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0012-amd-xgbe-Improve-SFP-100Mbps-auto-negotiation.patch @@ -0,0 +1,201 @@ +From c02438fa8e23e9752882fb6b783a70fc61b8c1ae Mon Sep 17 00:00:00 2001 +From: Tom Lendacky <thomas.lendacky@amd.com> +Date: Wed, 23 May 2018 11:39:47 -0500 +Subject: [PATCH 12/95] amd-xgbe: Improve SFP 100Mbps auto-negotiation + +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: Tom Lendacky <thomas.lendacky@amd.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Sudheesh Mavila <sudheesh.mavila@amd.com> +--- + drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 77 ++++++++++++++++------------- + drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 6 +++ + drivers/net/ethernet/amd/xgbe/xgbe.h | 1 + + 3 files changed, 50 insertions(+), 34 deletions(-) + +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +index eba757e..8a3a60b 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +@@ -331,13 +331,15 @@ static void xgbe_switch_mode(struct xgbe_prv_data *pdata) + xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata)); + } + +-static void xgbe_set_mode(struct xgbe_prv_data *pdata, ++static bool xgbe_set_mode(struct xgbe_prv_data *pdata, + enum xgbe_mode mode) + { + if (mode == xgbe_cur_mode(pdata)) +- return; ++ return false; + + xgbe_change_mode(pdata, mode); ++ ++ return true; + } + + static bool xgbe_use_mode(struct xgbe_prv_data *pdata, +@@ -1178,21 +1180,23 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) + return 0; + } + +-static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) ++static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode) + { + int ret; + ++ mutex_lock(&pdata->an_mutex); ++ + set_bit(XGBE_LINK_INIT, &pdata->dev_state); + pdata->link_check = jiffies; + + ret = pdata->phy_if.phy_impl.an_config(pdata); + if (ret) +- return ret; ++ goto out; + + if (pdata->phy.autoneg != AUTONEG_ENABLE) { + ret = xgbe_phy_config_fixed(pdata); + if (ret || !pdata->kr_redrv) +- return ret; ++ goto out; + + netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n"); + } else { +@@ -1202,24 +1206,27 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) + /* Disable auto-negotiation interrupt */ + disable_irq(pdata->an_irq); + +- /* Start auto-negotiation in a supported mode */ +- if (xgbe_use_mode(pdata, XGBE_MODE_KR)) { +- xgbe_set_mode(pdata, XGBE_MODE_KR); +- } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) { +- xgbe_set_mode(pdata, XGBE_MODE_KX_2500); +- } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { +- xgbe_set_mode(pdata, XGBE_MODE_KX_1000); +- } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) { +- xgbe_set_mode(pdata, XGBE_MODE_SFI); +- } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) { +- xgbe_set_mode(pdata, XGBE_MODE_X); +- } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) { +- xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000); +- } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) { +- xgbe_set_mode(pdata, XGBE_MODE_SGMII_100); +- } else { +- enable_irq(pdata->an_irq); +- return -EINVAL; ++ if (set_mode) { ++ /* Start auto-negotiation in a supported mode */ ++ if (xgbe_use_mode(pdata, XGBE_MODE_KR)) { ++ xgbe_set_mode(pdata, XGBE_MODE_KR); ++ } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) { ++ xgbe_set_mode(pdata, XGBE_MODE_KX_2500); ++ } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { ++ xgbe_set_mode(pdata, XGBE_MODE_KX_1000); ++ } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) { ++ xgbe_set_mode(pdata, XGBE_MODE_SFI); ++ } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) { ++ xgbe_set_mode(pdata, XGBE_MODE_X); ++ } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) { ++ xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000); ++ } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) { ++ xgbe_set_mode(pdata, XGBE_MODE_SGMII_100); ++ } else { ++ enable_irq(pdata->an_irq); ++ ret = -EINVAL; ++ goto out; ++ } + } + + /* Disable and stop any in progress auto-negotiation */ +@@ -1239,16 +1246,7 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) + xgbe_an_init(pdata); + xgbe_an_restart(pdata); + +- return 0; +-} +- +-static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) +-{ +- int ret; +- +- mutex_lock(&pdata->an_mutex); +- +- ret = __xgbe_phy_config_aneg(pdata); ++out: + if (ret) + set_bit(XGBE_LINK_ERR, &pdata->dev_state); + else +@@ -1259,6 +1257,16 @@ static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) + return ret; + } + ++static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) ++{ ++ return __xgbe_phy_config_aneg(pdata, true); ++} ++ ++static int xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata) ++{ ++ return __xgbe_phy_config_aneg(pdata, false); ++} ++ + static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata) + { + return (pdata->an_result == XGBE_AN_COMPLETE); +@@ -1315,7 +1323,8 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) + + pdata->phy.duplex = DUPLEX_FULL; + +- xgbe_set_mode(pdata, mode); ++ if (xgbe_set_mode(pdata, mode) && pdata->an_again) ++ xgbe_phy_reconfig_aneg(pdata); + } + + static void xgbe_phy_status(struct xgbe_prv_data *pdata) +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +index 194a569..3ceb4f9 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +@@ -902,6 +902,9 @@ static bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata) + XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN)) + return false; + ++ /* For Bel-Fuse, use the extra AN flag */ ++ pdata->an_again = 1; ++ + if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN], + XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN)) + return false; +@@ -978,6 +981,9 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) + if (phy_data->phydev) + return 0; + ++ /* Clear the extra AN flag */ ++ pdata->an_again = 0; ++ + /* Check for the use of an external PHY */ + if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE) + return 0; +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h +index 7a412cf..47bcbcf 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe.h ++++ b/drivers/net/ethernet/amd/xgbe/xgbe.h +@@ -1261,6 +1261,7 @@ struct xgbe_prv_data { + enum xgbe_rx kr_state; + enum xgbe_rx kx_state; + struct work_struct an_work; ++ unsigned int an_again; + unsigned int an_supported; + unsigned int parallel_detect; + unsigned int fec_ability; +-- +2.7.4 + |