summaryrefslogtreecommitdiff
diff options
authorTan, Tee Min <tee.min.tan@intel.com>2022-03-08 14:14:30 +0800
committerPhilip Cox <philip.cox@canonical.com>2022-11-14 14:16:06 -0500
commitd0bb42ad6b726056781f9c8a83f003e0e478017a (patch)
tree73fbb88bb426f7914d60b5a8b2922bd8a0d1bb8a
parent1e3ff292ba12cd983c603f68fbdebba66594cc16 (diff)
net: phy: update in-band AN mode when changing interface by PHY driver
BugLink: https://bugs.launchpad.net/bugs/1982282 Add cur_link_an_mode into phy_device struct for PHY drivers to communicate the in-band AN mode setting with phylink framework. As there is a mechanism in PHY drivers to switch the PHY interface between SGMII and 2500BaseX according to link speed. In this case, the in-band AN mode should be switching based on the PHY interface as well, if the PHY interface has been changed/updated by PHY driver. For e.g., disable in-band AN in 2500BaseX mode, or enable in-band AN back for SGMII mode (10/100/1000Mbps). Signed-off-by: Tan, Tee Min <tee.min.tan@intel.com> (picked from https://github.com/intel/linux-intel-quilt/tree/lts-v5.15.36-linux-220520T033542Z-1/patches/0038-net-phy-update-in-band-AN-mode-when-changing-interfa.patch) Signed-off-by: Philip Cox <philip.cox@canonical.com>
-rw-r--r--drivers/net/phy/marvell10g.c6
-rw-r--r--drivers/net/phy/mxl-gpy.c5
-rw-r--r--drivers/net/phy/phylink.c5
-rw-r--r--include/linux/phy.h4
4 files changed, 20 insertions, 0 deletions
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index ea060aa0dbd1..1bd044fbd584 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -29,6 +29,7 @@
#include <linux/phy.h>
#include <linux/sfp.h>
#include <linux/netdevice.h>
+#include <linux/phylink.h>
#define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe
#define MV_PHY_ALASKA_NBT_QUIRK_REV (MARVELL_PHY_ID_88X3310 | 0xa)
@@ -748,6 +749,9 @@ static void mv3310_update_interface(struct phy_device *phydev)
* xaui / rxaui modes according to the speed.
* Florian suggests setting phydev->interface to communicate this to the
* MAC. Only do this if we are already in one of the above modes.
+ * In-band Auto-negotiation is not supported in 2500BASE-X.
+ * Setting phydev->cur_link_an_mode to communicate this to the
+ * phylink framework.
*/
switch (phydev->speed) {
case SPEED_10000:
@@ -758,11 +762,13 @@ static void mv3310_update_interface(struct phy_device *phydev)
break;
case SPEED_2500:
phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+ phydev->cur_link_an_mode = MLO_AN_PHY;
break;
case SPEED_1000:
case SPEED_100:
case SPEED_10:
phydev->interface = PHY_INTERFACE_MODE_SGMII;
+ phydev->cur_link_an_mode = MLO_AN_INBAND;
break;
default:
break;
diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c
index 5ce1bf03bbd7..e2d714824166 100644
--- a/drivers/net/phy/mxl-gpy.c
+++ b/drivers/net/phy/mxl-gpy.c
@@ -10,6 +10,7 @@
#include <linux/bitfield.h>
#include <linux/phy.h>
#include <linux/netdevice.h>
+#include <linux/phylink.h>
/* PHY ID */
#define PHY_ID_GPYx15B_MASK 0xFFFFFFFC
@@ -266,10 +267,13 @@ static void gpy_update_interface(struct phy_device *phydev)
/* Automatically switch SERDES interface between SGMII and 2500-BaseX
* according to speed. Disable ANEG in 2500-BaseX mode.
+ * Setting phydev->cur_link_an_mode to communicate this to the
+ * phylink framework.
*/
switch (phydev->speed) {
case SPEED_2500:
phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+ phydev->cur_link_an_mode = MLO_AN_PHY;
ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
VSPEC1_SGMII_CTRL_ANEN, 0);
if (ret < 0)
@@ -281,6 +285,7 @@ static void gpy_update_interface(struct phy_device *phydev)
case SPEED_100:
case SPEED_10:
phydev->interface = PHY_INTERFACE_MODE_SGMII;
+ phydev->cur_link_an_mode = MLO_AN_INBAND;
if (gpy_sgmii_aneg_en(phydev))
break;
/* Enable and restart SGMII ANEG for 10/100/1000Mbps link speed
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index fef1416dcee4..5d5c0e5e6ba7 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -963,6 +963,9 @@ static void phylink_phy_change(struct phy_device *phydev, bool up)
pl->phy_state.pause |= MLO_PAUSE_RX;
pl->phy_state.interface = phydev->interface;
pl->phy_state.link = up;
+ /* Update current link AN mode if phy driver has changed it */
+ if (pl->cur_link_an_mode != phydev->cur_link_an_mode)
+ pl->cur_link_an_mode = phydev->cur_link_an_mode;
mutex_unlock(&pl->state_mutex);
phylink_run_resolve(pl);
@@ -1050,6 +1053,8 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
if (phy_interrupt_is_valid(phy))
phy_request_interrupt(phy);
+ pl->phydev->cur_link_an_mode = pl->cur_link_an_mode;
+
return 0;
}
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 946ccec17858..f55604c01f0f 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -676,6 +676,10 @@ struct phy_device {
/* MACsec management functions */
const struct macsec_ops *macsec_ops;
#endif
+ /* Use phydev->cur_link_an_mode to communicate the in-band
+ * AN mode setting with phylink framework.
+ */
+ u8 cur_link_an_mode;
};
static inline struct phy_device *to_phy_device(const struct device *dev)