From: Hauke Mehrtens Date: Thu, 1 Jan 2026 18:31:48 +0000 (+0100) Subject: kernel: phylink: disable autoneg for interfaces that have no inband X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=69d76e3a144f9ad2b613b2d1e0e376c124ffb39f;p=thirdparty%2Fopenwrt.git 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: 813ecda1f387 ("generic: backport phylink patches for PCS/PHY caps OPs") Link: https://github.com/openwrt/openwrt/pull/21366 Signed-off-by: Hauke Mehrtens --- diff --git a/target/linux/airoha/patches-6.12/116-08-net-phylink-add-.pcs_link_down-PCS-OP.patch b/target/linux/airoha/patches-6.12/116-08-net-phylink-add-.pcs_link_down-PCS-OP.patch index 7f5dcc7bd3f..34e8d21ebd8 100644 --- a/target/linux/airoha/patches-6.12/116-08-net-phylink-add-.pcs_link_down-PCS-OP.patch +++ b/target/linux/airoha/patches-6.12/116-08-net-phylink-add-.pcs_link_down-PCS-OP.patch @@ -35,7 +35,7 @@ Signed-off-by: Christian Marangi 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); diff --git a/target/linux/generic/backport-6.12/605-01-v6.17-net-phy-add-phy_interface_weight.patch b/target/linux/generic/backport-6.12/605-01-v6.17-net-phy-add-phy_interface_weight.patch new file mode 100644 index 00000000000..3a09a237033 --- /dev/null +++ b/target/linux/generic/backport-6.12/605-01-v6.17-net-phy-add-phy_interface_weight.patch @@ -0,0 +1,27 @@ +From 4beb44a2d62dddfe450f310aa1a950901731cb3a Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Sun, 31 Aug 2025 18:34:33 +0100 +Subject: net: phy: add phy_interface_weight() + +Signed-off-by: Russell King (Oracle) +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/E1uslwn-00000001SOx-0a7H@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + 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) + { diff --git a/target/linux/generic/backport-6.12/605-02-v6.17-net-phylink-provide-phylink_get_inband_type.patch b/target/linux/generic/backport-6.12/605-02-v6.17-net-phylink-provide-phylink_get_inband_type.patch new file mode 100644 index 00000000000..e944f573e09 --- /dev/null +++ b/target/linux/generic/backport-6.12/605-02-v6.17-net-phylink-provide-phylink_get_inband_type.patch @@ -0,0 +1,117 @@ +From 1bd905dfea9897eafef532000702e63a66849f54 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +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) +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/E1uslws-00000001SP5-1R2R@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + 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); + diff --git a/target/linux/generic/backport-6.12/605-03-v6.17-net-phylink-disable-autoneg-for-interfaces-that-have.patch b/target/linux/generic/backport-6.12/605-03-v6.17-net-phylink-disable-autoneg-for-interfaces-that-have.patch new file mode 100644 index 00000000000..0861bb820de --- /dev/null +++ b/target/linux/generic/backport-6.12/605-03-v6.17-net-phylink-disable-autoneg-for-interfaces-that-have.patch @@ -0,0 +1,68 @@ +From a21202743f9ce4063e86b99cccaef48ef9813379 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +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 +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) +Tested-by: Vladimir Oltean +Link: https://patch.msgid.link/E1uslwx-00000001SPB-2kiM@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + 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"); diff --git a/target/linux/generic/backport-6.12/730-03-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch b/target/linux/generic/backport-6.12/730-03-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch index 5563f3dce67..d30159b3774 100644 --- a/target/linux/generic/backport-6.12/730-03-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch +++ b/target/linux/generic/backport-6.12/730-03-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch @@ -39,7 +39,7 @@ Signed-off-by: Paolo Abeni 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 { diff --git a/target/linux/generic/backport-6.12/782-01-v6.16-net-phy-pass-PHY-driver-to-.match_phy_device-OP.patch b/target/linux/generic/backport-6.12/782-01-v6.16-net-phy-pass-PHY-driver-to-.match_phy_device-OP.patch index d2b20cc8a52..2e8ab284f7b 100644 --- a/target/linux/generic/backport-6.12/782-01-v6.16-net-phy-pass-PHY-driver-to-.match_phy_device-OP.patch +++ b/target/linux/generic/backport-6.12/782-01-v6.16-net-phy-pass-PHY-driver-to-.match_phy_device-OP.patch @@ -281,7 +281,7 @@ Signed-off-by: Jakub Kicinski } --- 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. */ diff --git a/target/linux/generic/backport-6.12/782-04-v6.16-net-phy-introduce-genphy_match_phy_device.patch b/target/linux/generic/backport-6.12/782-04-v6.16-net-phy-introduce-genphy_match_phy_device.patch index dd24ba23700..190f68c980e 100644 --- a/target/linux/generic/backport-6.12/782-04-v6.16-net-phy-introduce-genphy_match_phy_device.patch +++ b/target/linux/generic/backport-6.12/782-04-v6.16-net-phy-introduce-genphy_match_phy_device.patch @@ -97,7 +97,7 @@ Signed-off-by: Jakub Kicinski 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); diff --git a/target/linux/generic/backport-6.12/786-01-v6.18-net-phy-introduce-phy_id_compare_vendor-PHY-ID-helpe.patch b/target/linux/generic/backport-6.12/786-01-v6.18-net-phy-introduce-phy_id_compare_vendor-PHY-ID-helpe.patch index cf745129588..8172afc40c0 100644 --- a/target/linux/generic/backport-6.12/786-01-v6.18-net-phy-introduce-phy_id_compare_vendor-PHY-ID-helpe.patch +++ b/target/linux/generic/backport-6.12/786-01-v6.18-net-phy-introduce-phy_id_compare_vendor-PHY-ID-helpe.patch @@ -19,7 +19,7 @@ Signed-off-by: Jakub Kicinski --- 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 /** * 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 } /** diff --git a/target/linux/generic/pending-6.12/703-phy-add-detach-callback-to-struct-phy_driver.patch b/target/linux/generic/pending-6.12/703-phy-add-detach-callback-to-struct-phy_driver.patch index f8bcf6744f7..4a2b7d0f4e5 100644 --- a/target/linux/generic/pending-6.12/703-phy-add-detach-callback-to-struct-phy_driver.patch +++ b/target/linux/generic/pending-6.12/703-phy-add-detach-callback-to-struct-phy_driver.patch @@ -23,7 +23,7 @@ Signed-off-by: Gabor Juhos 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); diff --git a/target/linux/generic/pending-6.12/706-net-phy-populate-host_interfaces-when-attaching-PHY.patch b/target/linux/generic/pending-6.12/706-net-phy-populate-host_interfaces-when-attaching-PHY.patch index 0af507eed36..dea84c70797 100644 --- a/target/linux/generic/pending-6.12/706-net-phy-populate-host_interfaces-when-attaching-PHY.patch +++ b/target/linux/generic/pending-6.12/706-net-phy-populate-host_interfaces-when-attaching-PHY.patch @@ -20,7 +20,7 @@ Signed-off-by: Daniel Golle --- 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 /* 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; diff --git a/target/linux/layerscape/patches-6.12/702-phy-Add-2.5G-SGMII-interface-mode.patch b/target/linux/layerscape/patches-6.12/702-phy-Add-2.5G-SGMII-interface-mode.patch index af14871b59f..20d06924e98 100644 --- a/target/linux/layerscape/patches-6.12/702-phy-Add-2.5G-SGMII-interface-mode.patch +++ b/target/linux/layerscape/patches-6.12/702-phy-Add-2.5G-SGMII-interface-mode.patch @@ -62,7 +62,7 @@ Signed-off-by: Bhaskar Upadhaya 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"; diff --git a/target/linux/ramips/patches-6.12/720-NET-no-auto-carrier-off-support.patch b/target/linux/ramips/patches-6.12/720-NET-no-auto-carrier-off-support.patch index 68c68883328..25c823931ec 100644 --- a/target/linux/ramips/patches-6.12/720-NET-no-auto-carrier-off-support.patch +++ b/target/linux/ramips/patches-6.12/720-NET-no-auto-carrier-off-support.patch @@ -21,7 +21,7 @@ Signed-off-by: John Crispin 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; diff --git a/target/linux/realtek/patches-6.12/700-dsa-mdio-increase-max-ports-for-rtl839x-rtl931x.patch b/target/linux/realtek/patches-6.12/700-dsa-mdio-increase-max-ports-for-rtl839x-rtl931x.patch index f299716abc1..3431715c632 100644 --- a/target/linux/realtek/patches-6.12/700-dsa-mdio-increase-max-ports-for-rtl839x-rtl931x.patch +++ b/target/linux/realtek/patches-6.12/700-dsa-mdio-increase-max-ports-for-rtl839x-rtl931x.patch @@ -35,7 +35,7 @@ Signed-off-by: Markus Stockhausen &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 /* 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 */