aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0012-amd-xgbe-Improve-SFP-100Mbps-auto-negotiation.patch
diff options
context:
space:
mode:
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.patch201
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
+