mirror of
https://git.openwrt.org/openwrt/openwrt.git
synced 2026-03-14 12:39:45 +01:00
kernel: phylink: disable autoneg for interfaces that have no inband
This patch fixes a bug in a patch we backported.
This patch was cherry picked from upstream Linux because it references a
patch we backported in the fixes tag.
The first two patches are providing function needed by the last patch.
Fixes: 813ecda1f3 ("generic: backport phylink patches for PCS/PHY caps OPs")
Link: https://github.com/openwrt/openwrt/pull/21366
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
parent
2c7241b209
commit
69d76e3a14
13 changed files with 225 additions and 13 deletions
|
|
@ -35,7 +35,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
|||
static void phylink_pcs_poll_stop(struct phylink *pl)
|
||||
{
|
||||
if (pl->cfg_link_an_mode == MLO_AN_INBAND)
|
||||
@@ -1642,6 +1648,8 @@ static void phylink_link_down(struct phy
|
||||
@@ -1651,6 +1657,8 @@ static void phylink_link_down(struct phy
|
||||
|
||||
if (ndev)
|
||||
netif_carrier_off(ndev);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
From 4beb44a2d62dddfe450f310aa1a950901731cb3a Mon Sep 17 00:00:00 2001
|
||||
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
|
||||
Date: Sun, 31 Aug 2025 18:34:33 +0100
|
||||
Subject: net: phy: add phy_interface_weight()
|
||||
|
||||
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Link: https://patch.msgid.link/E1uslwn-00000001SOx-0a7H@rmk-PC.armlinux.org.uk
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
include/linux/phy.h | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -187,6 +187,11 @@ static inline bool phy_interface_empty(c
|
||||
return bitmap_empty(intf, PHY_INTERFACE_MODE_MAX);
|
||||
}
|
||||
|
||||
+static inline unsigned int phy_interface_weight(const unsigned long *intf)
|
||||
+{
|
||||
+ return bitmap_weight(intf, PHY_INTERFACE_MODE_MAX);
|
||||
+}
|
||||
+
|
||||
static inline void phy_interface_and(unsigned long *dst, const unsigned long *a,
|
||||
const unsigned long *b)
|
||||
{
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
From 1bd905dfea9897eafef532000702e63a66849f54 Mon Sep 17 00:00:00 2001
|
||||
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
|
||||
Date: Sun, 31 Aug 2025 18:34:38 +0100
|
||||
Subject: net: phylink: provide phylink_get_inband_type()
|
||||
|
||||
Provide a function to get the type of the inband signalling used for
|
||||
a PHY interface type. This will be used in the subsequent patch to
|
||||
address problems with 10G optical modules.
|
||||
|
||||
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Link: https://patch.msgid.link/E1uslws-00000001SP5-1R2R@rmk-PC.armlinux.org.uk
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 79 ++++++++++++++++++++++-----------------
|
||||
1 file changed, 44 insertions(+), 35 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -1147,6 +1147,42 @@ static void phylink_pcs_an_restart(struc
|
||||
pl->pcs->ops->pcs_an_restart(pl->pcs);
|
||||
}
|
||||
|
||||
+enum inband_type {
|
||||
+ INBAND_NONE,
|
||||
+ INBAND_CISCO_SGMII,
|
||||
+ INBAND_BASEX,
|
||||
+};
|
||||
+
|
||||
+static enum inband_type phylink_get_inband_type(phy_interface_t interface)
|
||||
+{
|
||||
+ switch (interface) {
|
||||
+ case PHY_INTERFACE_MODE_SGMII:
|
||||
+ case PHY_INTERFACE_MODE_QSGMII:
|
||||
+ case PHY_INTERFACE_MODE_QUSGMII:
|
||||
+ case PHY_INTERFACE_MODE_USXGMII:
|
||||
+ case PHY_INTERFACE_MODE_10G_QXGMII:
|
||||
+ /* These protocols are designed for use with a PHY which
|
||||
+ * communicates its negotiation result back to the MAC via
|
||||
+ * inband communication. Note: there exist PHYs that run
|
||||
+ * with SGMII but do not send the inband data.
|
||||
+ */
|
||||
+ return INBAND_CISCO_SGMII;
|
||||
+
|
||||
+ case PHY_INTERFACE_MODE_1000BASEX:
|
||||
+ case PHY_INTERFACE_MODE_2500BASEX:
|
||||
+ /* 1000base-X is designed for use media-side for Fibre
|
||||
+ * connections, and thus the Autoneg bit needs to be
|
||||
+ * taken into account. We also do this for 2500base-X
|
||||
+ * as well, but drivers may not support this, so may
|
||||
+ * need to override this.
|
||||
+ */
|
||||
+ return INBAND_BASEX;
|
||||
+
|
||||
+ default:
|
||||
+ return INBAND_NONE;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* phylink_pcs_neg_mode() - helper to determine PCS inband mode
|
||||
* @pl: a pointer to a &struct phylink returned from phylink_create()
|
||||
@@ -1174,46 +1210,19 @@ static void phylink_pcs_neg_mode(struct
|
||||
unsigned int pcs_ib_caps = 0;
|
||||
unsigned int phy_ib_caps = 0;
|
||||
unsigned int neg_mode, mode;
|
||||
- enum {
|
||||
- INBAND_CISCO_SGMII,
|
||||
- INBAND_BASEX,
|
||||
- } type;
|
||||
-
|
||||
- mode = pl->req_link_an_mode;
|
||||
+ enum inband_type type;
|
||||
|
||||
- pl->phy_ib_mode = 0;
|
||||
-
|
||||
- switch (interface) {
|
||||
- case PHY_INTERFACE_MODE_SGMII:
|
||||
- case PHY_INTERFACE_MODE_QSGMII:
|
||||
- case PHY_INTERFACE_MODE_QUSGMII:
|
||||
- case PHY_INTERFACE_MODE_USXGMII:
|
||||
- case PHY_INTERFACE_MODE_10G_QXGMII:
|
||||
- /* These protocols are designed for use with a PHY which
|
||||
- * communicates its negotiation result back to the MAC via
|
||||
- * inband communication. Note: there exist PHYs that run
|
||||
- * with SGMII but do not send the inband data.
|
||||
- */
|
||||
- type = INBAND_CISCO_SGMII;
|
||||
- break;
|
||||
-
|
||||
- case PHY_INTERFACE_MODE_1000BASEX:
|
||||
- case PHY_INTERFACE_MODE_2500BASEX:
|
||||
- /* 1000base-X is designed for use media-side for Fibre
|
||||
- * connections, and thus the Autoneg bit needs to be
|
||||
- * taken into account. We also do this for 2500base-X
|
||||
- * as well, but drivers may not support this, so may
|
||||
- * need to override this.
|
||||
- */
|
||||
- type = INBAND_BASEX;
|
||||
- break;
|
||||
-
|
||||
- default:
|
||||
+ type = phylink_get_inband_type(interface);
|
||||
+ if (type == INBAND_NONE) {
|
||||
pl->pcs_neg_mode = PHYLINK_PCS_NEG_NONE;
|
||||
- pl->act_link_an_mode = mode;
|
||||
+ pl->act_link_an_mode = pl->req_link_an_mode;
|
||||
return;
|
||||
}
|
||||
|
||||
+ mode = pl->req_link_an_mode;
|
||||
+
|
||||
+ pl->phy_ib_mode = 0;
|
||||
+
|
||||
if (pcs)
|
||||
pcs_ib_caps = phylink_pcs_inband_caps(pcs, interface);
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
From a21202743f9ce4063e86b99cccaef48ef9813379 Mon Sep 17 00:00:00 2001
|
||||
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
|
||||
Date: Sun, 31 Aug 2025 18:34:43 +0100
|
||||
Subject: net: phylink: disable autoneg for interfaces that have no inband
|
||||
|
||||
Mathew reports that as a result of commit 6561f0e547be ("net: pcs:
|
||||
pcs-lynx: implement pcs_inband_caps() method"), 10G SFP modules no
|
||||
longer work with the Lynx PCS.
|
||||
|
||||
This problem is not specific to the Lynx PCS, but is caused by commit
|
||||
df874f9e52c3 ("net: phylink: add pcs_inband_caps() method") which added
|
||||
validation of the autoneg state to the optical SFP configuration path.
|
||||
|
||||
Fix this by handling interface modes that fundamentally have no
|
||||
inband negotiation more correctly - if we only have a single interface
|
||||
mode, clear the Autoneg support bit and the advertising mask. If the
|
||||
module can operate with several different interface modes, autoneg may
|
||||
be supported for other modes, so leave the support mask alone and just
|
||||
clear the Autoneg bit in the advertising mask.
|
||||
|
||||
This restores 10G optical module functionality with PCS that supply
|
||||
their inband support, and makes ethtool output look sane.
|
||||
|
||||
Reported-by: Mathew McBride <matt@traverse.com.au>
|
||||
Closes: https://lore.kernel.org/r/025c0ebe-5537-4fa3-b05a-8b835e5ad317@app.fastmail.com
|
||||
Fixes: df874f9e52c3 ("net: phylink: add pcs_inband_caps() method")
|
||||
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
|
||||
Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Link: https://patch.msgid.link/E1uslwx-00000001SPB-2kiM@rmk-PC.armlinux.org.uk
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 18 ++++++++++++++++++
|
||||
1 file changed, 18 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -3500,6 +3500,7 @@ static int phylink_sfp_config_optical(st
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(support);
|
||||
DECLARE_PHY_INTERFACE_MASK(interfaces);
|
||||
struct phylink_link_state config;
|
||||
+ enum inband_type inband_type;
|
||||
phy_interface_t interface;
|
||||
int ret;
|
||||
|
||||
@@ -3546,6 +3547,23 @@ static int phylink_sfp_config_optical(st
|
||||
phylink_dbg(pl, "optical SFP: chosen %s interface\n",
|
||||
phy_modes(interface));
|
||||
|
||||
+ inband_type = phylink_get_inband_type(interface);
|
||||
+ if (inband_type == INBAND_NONE) {
|
||||
+ /* If this is the sole interface, and there is no inband
|
||||
+ * support, clear the advertising mask and Autoneg bit in
|
||||
+ * the support mask. Otherwise, just clear the Autoneg bit
|
||||
+ * in the advertising mask.
|
||||
+ */
|
||||
+ if (phy_interface_weight(pl->sfp_interfaces) == 1) {
|
||||
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
|
||||
+ pl->sfp_support);
|
||||
+ linkmode_zero(config.advertising);
|
||||
+ } else {
|
||||
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
|
||||
+ config.advertising);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (!phylink_validate_pcs_inband_autoneg(pl, interface,
|
||||
config.advertising)) {
|
||||
phylink_err(pl, "autoneg setting not compatible with PCS");
|
||||
|
|
@ -39,7 +39,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
|||
if (!phydev->drv->led_polarity_set)
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -892,8 +892,9 @@ struct phy_plca_status {
|
||||
@@ -897,8 +897,9 @@ struct phy_plca_status {
|
||||
|
||||
/* Modes for PHY LED configuration */
|
||||
enum phy_led_modes {
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|||
}
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -1035,7 +1035,8 @@ struct phy_driver {
|
||||
@@ -1040,7 +1040,8 @@ struct phy_driver {
|
||||
* driver for the given phydev. If NULL, matching is based on
|
||||
* phy_id and phy_id_mask.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|||
static ssize_t
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -1940,6 +1940,9 @@ char *phy_attached_info_irq(struct phy_d
|
||||
@@ -1945,6 +1945,9 @@ char *phy_attached_info_irq(struct phy_d
|
||||
__malloc;
|
||||
void phy_attached_info(struct phy_device *phydev);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|||
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -1256,9 +1256,13 @@ struct phy_driver {
|
||||
@@ -1261,9 +1261,13 @@ struct phy_driver {
|
||||
#define PHY_ANY_ID "MATCH ANY PHY"
|
||||
#define PHY_ANY_UID 0xffffffff
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|||
|
||||
/**
|
||||
* phy_id_compare - compare @id1 with @id2 taking account of @mask
|
||||
@@ -1275,6 +1279,19 @@ static inline bool phy_id_compare(u32 id
|
||||
@@ -1280,6 +1284,19 @@ static inline bool phy_id_compare(u32 id
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
|||
sysfs_remove_link(&dev->dev.kobj, "phydev");
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -1027,6 +1027,12 @@ struct phy_driver {
|
||||
@@ -1032,6 +1032,12 @@ struct phy_driver {
|
||||
/** @handle_interrupt: Override default interrupt handling */
|
||||
irqreturn_t (*handle_interrupt)(struct phy_device *phydev);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -2264,7 +2264,7 @@ int phylink_fwnode_phy_connect(struct ph
|
||||
@@ -2273,7 +2273,7 @@ int phylink_fwnode_phy_connect(struct ph
|
||||
{
|
||||
struct fwnode_handle *phy_fwnode;
|
||||
struct phy_device *phy_dev;
|
||||
|
|
@ -29,7 +29,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|||
|
||||
/* Fixed links and 802.3z are handled without needing a PHY */
|
||||
if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
|
||||
@@ -2294,6 +2294,25 @@ int phylink_fwnode_phy_connect(struct ph
|
||||
@@ -2303,6 +2303,25 @@ int phylink_fwnode_phy_connect(struct ph
|
||||
if (pl->config->mac_requires_rxc)
|
||||
flags |= PHY_F_RXC_ALWAYS_ON;
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
|
|||
PHY_INTERFACE_MODE_MAX,
|
||||
} phy_interface_t;
|
||||
|
||||
@@ -235,6 +236,8 @@ static inline const char *phy_modes(phy_
|
||||
@@ -240,6 +241,8 @@ static inline const char *phy_modes(phy_
|
||||
return "gmii";
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
return "sgmii";
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
|
|||
if (phydev->mii_ts && phydev->mii_ts->link_state)
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -675,6 +675,7 @@ struct phy_device {
|
||||
@@ -680,6 +680,7 @@ struct phy_device {
|
||||
unsigned downshifted_rate:1;
|
||||
unsigned is_on_sfp_module:1;
|
||||
unsigned mac_managed_pm:1;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
|||
&phy->mdio.reset_assert_delay);
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -301,7 +301,7 @@ static inline const char *phy_modes(phy_
|
||||
@@ -306,7 +306,7 @@ static inline const char *phy_modes(phy_
|
||||
#define PHY_INIT_TIMEOUT 100000
|
||||
#define PHY_FORCE_TIMEOUT 10
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
|||
|
||||
/* Used when trying to connect to a specific phy (mii bus id:phy device id) */
|
||||
#define PHY_ID_FMT "%s:%02x"
|
||||
@@ -421,10 +421,10 @@ struct mii_bus {
|
||||
@@ -426,10 +426,10 @@ struct mii_bus {
|
||||
struct mdio_device *mdio_map[PHY_MAX_ADDR];
|
||||
|
||||
/** @phy_mask: PHY addresses to be ignored when probing */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue