kernel: phylink: disable autoneg for interfaces that have no inband
authorHauke Mehrtens <hauke@hauke-m.de>
Thu, 1 Jan 2026 18:31:48 +0000 (19:31 +0100)
committerKoen Vandeputte <koen.vandeputte@citymesh.com>
Mon, 5 Jan 2026 13:44:21 +0000 (14:44 +0100)
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 <hauke@hauke-m.de>
13 files changed:
target/linux/airoha/patches-6.12/116-08-net-phylink-add-.pcs_link_down-PCS-OP.patch
target/linux/generic/backport-6.12/605-01-v6.17-net-phy-add-phy_interface_weight.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/605-02-v6.17-net-phylink-provide-phylink_get_inband_type.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/605-03-v6.17-net-phylink-disable-autoneg-for-interfaces-that-have.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/730-03-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch
target/linux/generic/backport-6.12/782-01-v6.16-net-phy-pass-PHY-driver-to-.match_phy_device-OP.patch
target/linux/generic/backport-6.12/782-04-v6.16-net-phy-introduce-genphy_match_phy_device.patch
target/linux/generic/backport-6.12/786-01-v6.18-net-phy-introduce-phy_id_compare_vendor-PHY-ID-helpe.patch
target/linux/generic/pending-6.12/703-phy-add-detach-callback-to-struct-phy_driver.patch
target/linux/generic/pending-6.12/706-net-phy-populate-host_interfaces-when-attaching-PHY.patch
target/linux/layerscape/patches-6.12/702-phy-Add-2.5G-SGMII-interface-mode.patch
target/linux/ramips/patches-6.12/720-NET-no-auto-carrier-off-support.patch
target/linux/realtek/patches-6.12/700-dsa-mdio-increase-max-ports-for-rtl839x-rtl931x.patch

index 7f5dcc7bd3f684bad0726805d64eee74e78edf64..34e8d21ebd83453e48a2ab6a0d66d35621f45cfd 100644 (file)
@@ -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);
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 (file)
index 0000000..3a09a23
--- /dev/null
@@ -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)
+ {
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 (file)
index 0000000..e944f57
--- /dev/null
@@ -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);
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 (file)
index 0000000..0861bb8
--- /dev/null
@@ -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");
index 5563f3dce6797d1008f66b31adf7f451d0bd968b..d30159b377416dc25f8f3f830350bedabce5cd58 100644 (file)
@@ -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 {
index d2b20cc8a52a883887dca0befbf9ff2d4375cce5..2e8ab284f7b0f9a882b28e5029e8385b2c00e9c9 100644 (file)
@@ -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.
         */
index dd24ba23700b3c8e79bc6e08e1dd6a9a1a26b208..190f68c980e5a4916c9622df0ff3f726104235ee 100644 (file)
@@ -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);
  
index cf74512958854439ffd62b806944ae5c8b81e3f4..8172afc40c09ac904c8cdf70e82756745169c869 100644 (file)
@@ -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
  }
  
  /**
index f8bcf6744f7339259641a01f5b224c4d1049a292..4a2b7d0f4e59c6dc25b9bdd7198610db7edb40a3 100644 (file)
@@ -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);
  
index 0af507eed360e8bed6f07c41eb01cf89cd7eb921..dea84c70797904ee8d7dec63fa20bb65eff125cb 100644 (file)
@@ -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;
  
index af14871b59fa93289cb5076cbff53d128b4768a2..20d06924e981d267692dd3de545273d46d6db026 100644 (file)
@@ -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";
index 68c68883328257b027679ddc72ab1167521a030b..25c823931ec3150b0237da8eb4f192fe13267383 100644 (file)
@@ -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;
index f299716abc10233a988bfda63e1fce4bc85973ae..3431715c632afea8a9aa4ffff9b8b3822b101512 100644 (file)
@@ -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 */