generic: backport QCA808x possible interfaces fix
authorRobert Marko <robimarko@gmail.com>
Tue, 27 Feb 2024 18:07:42 +0000 (19:07 +0100)
committerRobert Marko <robimarko@gmail.com>
Mon, 24 Jun 2024 07:46:19 +0000 (09:46 +0200)
QCA808x does not currently fill in the possible_interfaces.

This leads to Phylink not being aware that it supports 2500Base-X as well
so in cases where it is connected to a DSA switch like MV88E6393 it will
limit that port to phy-mode set in the DTS.

That means that if SGMII is used you are limited to 1G only while if
2500Base-X was set you are limited to 2.5G only.

Populating the possible_interfaces fixes this, so lets backport the patches
from kernel 6.9.

This also includes a backport of the Phylink PHY validation series from
kernel 6.8 that allows the use of possible_interfaces.

Link: https://github.com/openwrt/openwrt/pull/15765
Signed-off-by: Robert Marko <robimarko@gmail.com>
21 files changed:
target/linux/generic/backport-6.1/895-01-v6.8-net-phy-add-possible-interfaces.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/895-02-v6.8-net-phylink-use-for_each_set_bit.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/895-03-v6.8-net-phylink-split-out-per-interface-validation.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/895-04-v6.8-net-phylink-pass-PHY-into-phylink_validate_one.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/895-05-v6.8-net-phylink-pass-PHY-into-phylink_validate_mask.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/895-06-v6.8-net-phylink-split-out-PHY-validation-from-phylink_br.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/895-07-v6.8-net-phylink-use-the-PHY-s-possible_interfaces-if-pop.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/897-01-v6.9-net-phy-qcom-qca808x-add-helper-for-checking-for-1G-.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/897-02-v6.9-net-phy-qcom-qca808x-fill-in-possible_interfaces.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/895-01-v6.8-net-phy-add-possible-interfaces.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/895-02-v6.8-net-phylink-use-for_each_set_bit.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/895-03-v6.8-net-phylink-split-out-per-interface-validation.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/895-04-v6.8-net-phylink-pass-PHY-into-phylink_validate_one.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/895-05-v6.8-net-phylink-pass-PHY-into-phylink_validate_mask.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/895-06-v6.8-net-phylink-split-out-PHY-validation-from-phylink_br.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/895-07-v6.8-net-phylink-use-the-PHY-s-possible_interfaces-if-pop.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/897-01-v6.9-net-phy-qcom-qca808x-add-helper-for-checking-for-1G-.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/897-02-v6.9-net-phy-qcom-qca808x-fill-in-possible_interfaces.patch [new file with mode: 0644]
target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch
target/linux/generic/pending-6.6/703-phy-add-detach-callback-to-struct-phy_driver.patch
target/linux/generic/pending-6.6/999-net-phy-move-LED-polarity-to-phy_init_hw.patch

diff --git a/target/linux/generic/backport-6.1/895-01-v6.8-net-phy-add-possible-interfaces.patch b/target/linux/generic/backport-6.1/895-01-v6.8-net-phy-add-possible-interfaces.patch
new file mode 100644 (file)
index 0000000..3a9b856
--- /dev/null
@@ -0,0 +1,60 @@
+From 1a7aa058bc92f0edae7a0d1ef1a7b05aec0c643a Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:27:52 +0000
+Subject: [PATCH 1/7] net: phy: add possible interfaces
+
+Add a possible_interfaces member to struct phy_device to indicate which
+interfaces a clause 45 PHY may switch between depending on the media.
+This must be populated by the PHY driver by the time the .config_init()
+method completes according to the PHYs host-side configuration.
+
+For example, the Marvell 88x3310 PHY can switch between 10GBASE-R,
+5GBASE-R, 2500BASE-X, and SGMII on the host side depending on the media
+side speed, so all these interface modes are set in the
+possible_interfaces member.
+
+This allows phylib users (such as phylink) to know in advance which
+interface modes to expect, which allows them to appropriately restrict
+the advertised link modes according to the capabilities of other parts
+of the link.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VHk-00DDLN-I7@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phy_device.c | 2 ++
+ include/linux/phy.h          | 3 +++
+ 2 files changed, 5 insertions(+)
+
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1215,6 +1215,8 @@ int phy_init_hw(struct phy_device *phyde
+       if (ret < 0)
+               return ret;
++      phy_interface_zero(phydev->possible_interfaces);
++
+       if (phydev->drv->config_init) {
+               ret = phydev->drv->config_init(phydev);
+               if (ret < 0)
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -600,6 +600,8 @@ struct macsec_ops;
+  * @irq_rerun: Flag indicating interrupts occurred while PHY was suspended,
+  *             requiring a rerun of the interrupt handler after resume
+  * @interface: enum phy_interface_t value
++ * @possible_interfaces: bitmap if interface modes that the attached PHY
++ *                     will switch between depending on media speed.
+  * @skb: Netlink message for cable diagnostics
+  * @nest: Netlink nest used for cable diagnostics
+  * @ehdr: nNtlink header for cable diagnostics
+@@ -665,6 +667,7 @@ struct phy_device {
+       u32 dev_flags;
+       phy_interface_t interface;
++      DECLARE_PHY_INTERFACE_MASK(possible_interfaces);
+       /*
+        * forced speed & duplex (no autoneg)
diff --git a/target/linux/generic/backport-6.1/895-02-v6.8-net-phylink-use-for_each_set_bit.patch b/target/linux/generic/backport-6.1/895-02-v6.8-net-phylink-use-for_each_set_bit.patch
new file mode 100644 (file)
index 0000000..155ec1c
--- /dev/null
@@ -0,0 +1,46 @@
+From 85631f5b33f2acce7d42dec1d0a062ab40de95b8 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Sun, 19 Nov 2023 21:07:43 +0000
+Subject: [PATCH 2/7] net: phylink: use for_each_set_bit()
+
+Use for_each_set_bit() rather than open coding the for() test_bit()
+loop.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com>
+Link: https://lore.kernel.org/r/E1r4p15-00Cpxe-C7@rmk-PC.armlinux.org.uk
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/phy/phylink.c | 18 ++++++++----------
+ 1 file changed, 8 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -690,18 +690,16 @@ static int phylink_validate_mask(struct
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, };
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(s);
+       struct phylink_link_state t;
+-      int intf;
++      int interface;
+-      for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) {
+-              if (test_bit(intf, interfaces)) {
+-                      linkmode_copy(s, supported);
++      for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) {
++              linkmode_copy(s, supported);
+-                      t = *state;
+-                      t.interface = intf;
+-                      if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
+-                              linkmode_or(all_s, all_s, s);
+-                              linkmode_or(all_adv, all_adv, t.advertising);
+-                      }
++              t = *state;
++              t.interface = interface;
++              if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
++                      linkmode_or(all_s, all_s, s);
++                      linkmode_or(all_adv, all_adv, t.advertising);
+               }
+       }
diff --git a/target/linux/generic/backport-6.1/895-03-v6.8-net-phylink-split-out-per-interface-validation.patch b/target/linux/generic/backport-6.1/895-03-v6.8-net-phylink-split-out-per-interface-validation.patch
new file mode 100644 (file)
index 0000000..163cb95
--- /dev/null
@@ -0,0 +1,76 @@
+From d4788b4383ce5caeb4e68818357c81a02117a3f9 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:28:19 +0000
+Subject: [PATCH 3/7] net: phylink: split out per-interface validation
+
+Split out the internals of phylink_validate_mask() to make the code
+easier to read.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VIB-00DDLr-7g@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 42 ++++++++++++++++++++++++++++-----------
+ 1 file changed, 30 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -682,26 +682,44 @@ static int phylink_validate_mac_and_pcs(
+       return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
+ }
++static void phylink_validate_one(struct phylink *pl,
++                               const unsigned long *supported,
++                               const struct phylink_link_state *state,
++                               phy_interface_t interface,
++                               unsigned long *accum_supported,
++                               unsigned long *accum_advertising)
++{
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp_supported);
++      struct phylink_link_state tmp_state;
++
++      linkmode_copy(tmp_supported, supported);
++
++      tmp_state = *state;
++      tmp_state.interface = interface;
++
++      if (!phylink_validate_mac_and_pcs(pl, tmp_supported, &tmp_state)) {
++              phylink_dbg(pl, " interface %u (%s) rate match %s supports %*pbl\n",
++                          interface, phy_modes(interface),
++                          phy_rate_matching_to_str(tmp_state.rate_matching),
++                          __ETHTOOL_LINK_MODE_MASK_NBITS, tmp_supported);
++
++              linkmode_or(accum_supported, accum_supported, tmp_supported);
++              linkmode_or(accum_advertising, accum_advertising,
++                          tmp_state.advertising);
++      }
++}
++
+ static int phylink_validate_mask(struct phylink *pl, unsigned long *supported,
+                                struct phylink_link_state *state,
+                                const unsigned long *interfaces)
+ {
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, };
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, };
+-      __ETHTOOL_DECLARE_LINK_MODE_MASK(s);
+-      struct phylink_link_state t;
+       int interface;
+-      for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) {
+-              linkmode_copy(s, supported);
+-
+-              t = *state;
+-              t.interface = interface;
+-              if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
+-                      linkmode_or(all_s, all_s, s);
+-                      linkmode_or(all_adv, all_adv, t.advertising);
+-              }
+-      }
++      for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
++              phylink_validate_one(pl, supported, state, interface,
++                                   all_s, all_adv);
+       linkmode_copy(supported, all_s);
+       linkmode_copy(state->advertising, all_adv);
diff --git a/target/linux/generic/backport-6.1/895-04-v6.8-net-phylink-pass-PHY-into-phylink_validate_one.patch b/target/linux/generic/backport-6.1/895-04-v6.8-net-phylink-pass-PHY-into-phylink_validate_one.patch
new file mode 100644 (file)
index 0000000..5012020
--- /dev/null
@@ -0,0 +1,47 @@
+From ce7273c31fadb3143fc80c96a72a42adc19c2757 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:28:24 +0000
+Subject: [PATCH 4/7] net: phylink: pass PHY into phylink_validate_one()
+
+Pass the phy (if any) into phylink_validate_one() so that we can
+validate each interface with its rate matching setting.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VIG-00DDLx-Cb@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -682,7 +682,7 @@ static int phylink_validate_mac_and_pcs(
+       return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
+ }
+-static void phylink_validate_one(struct phylink *pl,
++static void phylink_validate_one(struct phylink *pl, struct phy_device *phy,
+                                const unsigned long *supported,
+                                const struct phylink_link_state *state,
+                                phy_interface_t interface,
+@@ -697,6 +697,9 @@ static void phylink_validate_one(struct
+       tmp_state = *state;
+       tmp_state.interface = interface;
++      if (phy)
++              tmp_state.rate_matching = phy_get_rate_matching(phy, interface);
++
+       if (!phylink_validate_mac_and_pcs(pl, tmp_supported, &tmp_state)) {
+               phylink_dbg(pl, " interface %u (%s) rate match %s supports %*pbl\n",
+                           interface, phy_modes(interface),
+@@ -718,7 +721,7 @@ static int phylink_validate_mask(struct
+       int interface;
+       for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
+-              phylink_validate_one(pl, supported, state, interface,
++              phylink_validate_one(pl, NULL, supported, state, interface,
+                                    all_s, all_adv);
+       linkmode_copy(supported, all_s);
diff --git a/target/linux/generic/backport-6.1/895-05-v6.8-net-phylink-pass-PHY-into-phylink_validate_mask.patch b/target/linux/generic/backport-6.1/895-05-v6.8-net-phylink-pass-PHY-into-phylink_validate_mask.patch
new file mode 100644 (file)
index 0000000..997c743
--- /dev/null
@@ -0,0 +1,58 @@
+From c6fec66d3cd76d797f70b30f1511bed10ba45a96 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:28:29 +0000
+Subject: [PATCH 5/7] net: phylink: pass PHY into phylink_validate_mask()
+
+Pass the phy (if any) into phylink_validate_mask() so that we can
+validate each interface with its rate matching setting.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VIL-00DDM3-HJ@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -712,7 +712,8 @@ static void phylink_validate_one(struct
+       }
+ }
+-static int phylink_validate_mask(struct phylink *pl, unsigned long *supported,
++static int phylink_validate_mask(struct phylink *pl, struct phy_device *phy,
++                               unsigned long *supported,
+                                struct phylink_link_state *state,
+                                const unsigned long *interfaces)
+ {
+@@ -721,7 +722,7 @@ static int phylink_validate_mask(struct
+       int interface;
+       for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
+-              phylink_validate_one(pl, NULL, supported, state, interface,
++              phylink_validate_one(pl, phy, supported, state, interface,
+                                    all_s, all_adv);
+       linkmode_copy(supported, all_s);
+@@ -736,7 +737,8 @@ static int phylink_validate(struct phyli
+       const unsigned long *interfaces = pl->config->supported_interfaces;
+       if (state->interface == PHY_INTERFACE_MODE_NA)
+-              return phylink_validate_mask(pl, supported, state, interfaces);
++              return phylink_validate_mask(pl, NULL, supported, state,
++                                           interfaces);
+       if (!test_bit(state->interface, interfaces))
+               return -EINVAL;
+@@ -3132,7 +3134,8 @@ static int phylink_sfp_config_optical(st
+       /* For all the interfaces that are supported, reduce the sfp_support
+        * mask to only those link modes that can be supported.
+        */
+-      ret = phylink_validate_mask(pl, pl->sfp_support, &config, interfaces);
++      ret = phylink_validate_mask(pl, NULL, pl->sfp_support, &config,
++                                  interfaces);
+       if (ret) {
+               phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n",
+                           __ETHTOOL_LINK_MODE_MASK_NBITS, support);
diff --git a/target/linux/generic/backport-6.1/895-06-v6.8-net-phylink-split-out-PHY-validation-from-phylink_br.patch b/target/linux/generic/backport-6.1/895-06-v6.8-net-phylink-split-out-PHY-validation-from-phylink_br.patch
new file mode 100644 (file)
index 0000000..d3d24c5
--- /dev/null
@@ -0,0 +1,95 @@
+From ee0e0ddb910e7e989b65a19d72b6435baa641fc7 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:28:34 +0000
+Subject: [PATCH 6/7] net: phylink: split out PHY validation from
+ phylink_bringup_phy()
+
+When bringing up a PHY, we need to work out which ethtool link modes it
+should support and advertise. Clause 22 PHYs operate in a single
+interface mode, which can be easily dealt with. However, clause 45 PHYs
+tend to switch interface mode depending on the media. We need more
+flexible validation at this point, so this patch splits out that code
+in preparation to changing it.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VIQ-00DDM9-LK@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 56 ++++++++++++++++++++++-----------------
+ 1 file changed, 31 insertions(+), 25 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1738,6 +1738,35 @@ static void phylink_phy_change(struct ph
+                   phylink_pause_to_str(pl->phy_state.pause));
+ }
++static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy,
++                              unsigned long *supported,
++                              struct phylink_link_state *state)
++{
++      /* Check whether we would use rate matching for the proposed interface
++       * mode.
++       */
++      state->rate_matching = phy_get_rate_matching(phy, state->interface);
++
++      /* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R,
++       * 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching.
++       * For some interface modes (e.g. RXAUI, XAUI and USXGMII) switching
++       * their Serdes is either unnecessary or not reasonable.
++       *
++       * For these which switch interface modes, we really need to know which
++       * interface modes the PHY supports to properly work out which ethtool
++       * linkmodes can be supported. For now, as a work-around, we validate
++       * against all interface modes, which may lead to more ethtool link
++       * modes being advertised than are actually supported.
++       */
++      if (phy->is_c45 && state->rate_matching == RATE_MATCH_NONE &&
++          state->interface != PHY_INTERFACE_MODE_RXAUI &&
++          state->interface != PHY_INTERFACE_MODE_XAUI &&
++          state->interface != PHY_INTERFACE_MODE_USXGMII)
++              state->interface = PHY_INTERFACE_MODE_NA;
++
++      return phylink_validate(pl, supported, state);
++}
++
+ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
+                              phy_interface_t interface)
+ {
+@@ -1758,32 +1787,9 @@ static int phylink_bringup_phy(struct ph
+       memset(&config, 0, sizeof(config));
+       linkmode_copy(supported, phy->supported);
+       linkmode_copy(config.advertising, phy->advertising);
++      config.interface = interface;
+-      /* Check whether we would use rate matching for the proposed interface
+-       * mode.
+-       */
+-      config.rate_matching = phy_get_rate_matching(phy, interface);
+-
+-      /* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R,
+-       * 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching.
+-       * For some interface modes (e.g. RXAUI, XAUI and USXGMII) switching
+-       * their Serdes is either unnecessary or not reasonable.
+-       *
+-       * For these which switch interface modes, we really need to know which
+-       * interface modes the PHY supports to properly work out which ethtool
+-       * linkmodes can be supported. For now, as a work-around, we validate
+-       * against all interface modes, which may lead to more ethtool link
+-       * modes being advertised than are actually supported.
+-       */
+-      if (phy->is_c45 && config.rate_matching == RATE_MATCH_NONE &&
+-          interface != PHY_INTERFACE_MODE_RXAUI &&
+-          interface != PHY_INTERFACE_MODE_XAUI &&
+-          interface != PHY_INTERFACE_MODE_USXGMII)
+-              config.interface = PHY_INTERFACE_MODE_NA;
+-      else
+-              config.interface = interface;
+-
+-      ret = phylink_validate(pl, supported, &config);
++      ret = phylink_validate_phy(pl, phy, supported, &config);
+       if (ret) {
+               phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %pe\n",
+                            phy_modes(config.interface),
diff --git a/target/linux/generic/backport-6.1/895-07-v6.8-net-phylink-use-the-PHY-s-possible_interfaces-if-pop.patch b/target/linux/generic/backport-6.1/895-07-v6.8-net-phylink-use-the-PHY-s-possible_interfaces-if-pop.patch
new file mode 100644 (file)
index 0000000..201afbb
--- /dev/null
@@ -0,0 +1,130 @@
+From 8f7a9799c5949f94ecc3acfd71b36437a7ade73b Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:28:39 +0000
+Subject: [PATCH 7/7] net: phylink: use the PHY's possible_interfaces if
+ populated
+
+Some PHYs such as Aquantia, Broadcom 84881, and Marvell 88X33x0 can
+switch between a set of interface types depending on the negotiated
+media speed, or can use rate adaption for some or all of these
+interface types.
+
+We currently assume that these are Clause 45 PHYs that are configured
+not to use a specific set of interface modes, which has worked so far,
+but is just a work-around. In this workaround, we validate using all
+interfaces that the MAC supports, which can lead to extra modes being
+advertised that can not be supported.
+
+To properly address this, switch to using the newly introduced PHY
+possible_interfaces bitmap which indicates which interface modes will
+be used by the PHY as configured. We calculate the union of the PHY's
+possible interfaces and MACs supported interfaces, checking that is
+non-empty. If the PHY is on a SFP, we further reduce the set by those
+which can be used on a SFP module, again checking that is non-empty.
+Finally, we validate the subset of interfaces, taking account of
+whether rate matching will be used for each individual interface mode.
+
+This becomes independent of whether the PHY is clause 22 or clause 45.
+
+It is encouraged that all PHYs that switch interface modes or use
+rate matching should populate phydev->possible_interfaces.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VIV-00DDMF-Pi@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 67 +++++++++++++++++++++++++++++++--------
+ 1 file changed, 54 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -121,6 +121,19 @@ do {                                                                      \
+ })
+ #endif
++static const phy_interface_t phylink_sfp_interface_preference[] = {
++      PHY_INTERFACE_MODE_25GBASER,
++      PHY_INTERFACE_MODE_USXGMII,
++      PHY_INTERFACE_MODE_10GBASER,
++      PHY_INTERFACE_MODE_5GBASER,
++      PHY_INTERFACE_MODE_2500BASEX,
++      PHY_INTERFACE_MODE_SGMII,
++      PHY_INTERFACE_MODE_1000BASEX,
++      PHY_INTERFACE_MODE_100BASEX,
++};
++
++static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
++
+ /**
+  * phylink_set_port_modes() - set the port type modes in the ethtool mask
+  * @mask: ethtool link mode mask
+@@ -1742,6 +1755,47 @@ static int phylink_validate_phy(struct p
+                               unsigned long *supported,
+                               struct phylink_link_state *state)
+ {
++      DECLARE_PHY_INTERFACE_MASK(interfaces);
++
++      /* If the PHY provides a bitmap of the interfaces it will be using
++       * depending on the negotiated media speeds, use this to validate
++       * which ethtool link modes can be used.
++       */
++      if (!phy_interface_empty(phy->possible_interfaces)) {
++              /* We only care about the union of the PHY's interfaces and
++               * those which the host supports.
++               */
++              phy_interface_and(interfaces, phy->possible_interfaces,
++                                pl->config->supported_interfaces);
++
++              if (phy_interface_empty(interfaces)) {
++                      phylink_err(pl, "PHY has no common interfaces\n");
++                      return -EINVAL;
++              }
++
++              if (phy_on_sfp(phy)) {
++                      /* If the PHY is on a SFP, limit the interfaces to
++                       * those that can be used with a SFP module.
++                       */
++                      phy_interface_and(interfaces, interfaces,
++                                        phylink_sfp_interfaces);
++
++                      if (phy_interface_empty(interfaces)) {
++                              phylink_err(pl, "SFP PHY's possible interfaces becomes empty\n");
++                              return -EINVAL;
++                      }
++              }
++
++              phylink_dbg(pl, "PHY %s uses interfaces %*pbl, validating %*pbl\n",
++                          phydev_name(phy),
++                          (int)PHY_INTERFACE_MODE_MAX,
++                          phy->possible_interfaces,
++                          (int)PHY_INTERFACE_MODE_MAX, interfaces);
++
++              return phylink_validate_mask(pl, phy, supported, state,
++                                           interfaces);
++      }
++
+       /* Check whether we would use rate matching for the proposed interface
+        * mode.
+        */
+@@ -2985,19 +3039,6 @@ static void phylink_sfp_detach(void *ups
+       pl->netdev->sfp_bus = NULL;
+ }
+-static const phy_interface_t phylink_sfp_interface_preference[] = {
+-      PHY_INTERFACE_MODE_25GBASER,
+-      PHY_INTERFACE_MODE_USXGMII,
+-      PHY_INTERFACE_MODE_10GBASER,
+-      PHY_INTERFACE_MODE_5GBASER,
+-      PHY_INTERFACE_MODE_2500BASEX,
+-      PHY_INTERFACE_MODE_SGMII,
+-      PHY_INTERFACE_MODE_1000BASEX,
+-      PHY_INTERFACE_MODE_100BASEX,
+-};
+-
+-static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
+-
+ static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl,
+                                                   const unsigned long *intf)
+ {
diff --git a/target/linux/generic/backport-6.1/897-01-v6.9-net-phy-qcom-qca808x-add-helper-for-checking-for-1G-.patch b/target/linux/generic/backport-6.1/897-01-v6.9-net-phy-qcom-qca808x-add-helper-for-checking-for-1G-.patch
new file mode 100644 (file)
index 0000000..a11e804
--- /dev/null
@@ -0,0 +1,50 @@
+From f058b2dd70b1a5503dff899010aeb53b436091e5 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Wed, 28 Feb 2024 18:24:09 +0100
+Subject: [PATCH 1/2] net: phy: qcom: qca808x: add helper for checking for 1G
+ only model
+
+There are 2 versions of QCA808x, one 2.5G capable and one 1G capable.
+Currently, this matter only in the .get_features call however, it will
+be required for filling supported interface modes so lets add a helper
+that can be reused.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/qcom/qca808x.c | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -156,6 +156,17 @@ static bool qca808x_has_fast_retrain_or_
+       return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
+ }
++static bool qca808x_is_1g_only(struct phy_device *phydev)
++{
++      int ret;
++
++      ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
++      if (ret < 0)
++              return true;
++
++      return !!(QCA808X_PHY_CHIP_TYPE_1G & ret);
++}
++
+ static int qca808x_probe(struct phy_device *phydev)
+ {
+       struct device *dev = &phydev->mdio.dev;
+@@ -350,11 +361,7 @@ static int qca808x_get_features(struct p
+        * existed in the bit0 of MMD1.21, we need to remove it manually if
+        * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.
+        */
+-      ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
+-      if (ret < 0)
+-              return ret;
+-
+-      if (QCA808X_PHY_CHIP_TYPE_1G & ret)
++      if (qca808x_is_1g_only(phydev))
+               linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
+       return 0;
diff --git a/target/linux/generic/backport-6.1/897-02-v6.9-net-phy-qcom-qca808x-fill-in-possible_interfaces.patch b/target/linux/generic/backport-6.1/897-02-v6.9-net-phy-qcom-qca808x-fill-in-possible_interfaces.patch
new file mode 100644 (file)
index 0000000..c162fc7
--- /dev/null
@@ -0,0 +1,44 @@
+From cb28f702960695e26597c332b0e46776e825cc34 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Wed, 28 Feb 2024 18:24:10 +0100
+Subject: [PATCH 2/2] net: phy: qcom: qca808x: fill in possible_interfaces
+
+Currently QCA808x driver does not fill the possible_interfaces.
+2.5G QCA808x support SGMII and 2500Base-X while 1G model only supports
+SGMII, so fill the possible_interfaces accordingly.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/qcom/qca808x.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -167,6 +167,16 @@ static bool qca808x_is_1g_only(struct ph
+       return !!(QCA808X_PHY_CHIP_TYPE_1G & ret);
+ }
++static void qca808x_fill_possible_interfaces(struct phy_device *phydev)
++{
++      unsigned long *possible = phydev->possible_interfaces;
++
++      __set_bit(PHY_INTERFACE_MODE_SGMII, possible);
++
++      if (!qca808x_is_1g_only(phydev))
++              __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible);
++}
++
+ static int qca808x_probe(struct phy_device *phydev)
+ {
+       struct device *dev = &phydev->mdio.dev;
+@@ -231,6 +241,8 @@ static int qca808x_config_init(struct ph
+               }
+       }
++      qca808x_fill_possible_interfaces(phydev);
++
+       /* Configure adc threshold as 100mv for the link 10M */
+       return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
+                                    QCA808X_ADC_THRESHOLD_MASK,
diff --git a/target/linux/generic/backport-6.6/895-01-v6.8-net-phy-add-possible-interfaces.patch b/target/linux/generic/backport-6.6/895-01-v6.8-net-phy-add-possible-interfaces.patch
new file mode 100644 (file)
index 0000000..b86dbea
--- /dev/null
@@ -0,0 +1,60 @@
+From 1a7aa058bc92f0edae7a0d1ef1a7b05aec0c643a Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:27:52 +0000
+Subject: [PATCH 1/7] net: phy: add possible interfaces
+
+Add a possible_interfaces member to struct phy_device to indicate which
+interfaces a clause 45 PHY may switch between depending on the media.
+This must be populated by the PHY driver by the time the .config_init()
+method completes according to the PHYs host-side configuration.
+
+For example, the Marvell 88x3310 PHY can switch between 10GBASE-R,
+5GBASE-R, 2500BASE-X, and SGMII on the host side depending on the media
+side speed, so all these interface modes are set in the
+possible_interfaces member.
+
+This allows phylib users (such as phylink) to know in advance which
+interface modes to expect, which allows them to appropriately restrict
+the advertised link modes according to the capabilities of other parts
+of the link.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VHk-00DDLN-I7@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phy_device.c | 2 ++
+ include/linux/phy.h          | 3 +++
+ 2 files changed, 5 insertions(+)
+
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1247,6 +1247,8 @@ int phy_init_hw(struct phy_device *phyde
+       if (ret < 0)
+               return ret;
++      phy_interface_zero(phydev->possible_interfaces);
++
+       if (phydev->drv->config_init) {
+               ret = phydev->drv->config_init(phydev);
+               if (ret < 0)
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -609,6 +609,8 @@ struct macsec_ops;
+  * @irq_rerun: Flag indicating interrupts occurred while PHY was suspended,
+  *             requiring a rerun of the interrupt handler after resume
+  * @interface: enum phy_interface_t value
++ * @possible_interfaces: bitmap if interface modes that the attached PHY
++ *                     will switch between depending on media speed.
+  * @skb: Netlink message for cable diagnostics
+  * @nest: Netlink nest used for cable diagnostics
+  * @ehdr: nNtlink header for cable diagnostics
+@@ -678,6 +680,7 @@ struct phy_device {
+       u32 dev_flags;
+       phy_interface_t interface;
++      DECLARE_PHY_INTERFACE_MASK(possible_interfaces);
+       /*
+        * forced speed & duplex (no autoneg)
diff --git a/target/linux/generic/backport-6.6/895-02-v6.8-net-phylink-use-for_each_set_bit.patch b/target/linux/generic/backport-6.6/895-02-v6.8-net-phylink-use-for_each_set_bit.patch
new file mode 100644 (file)
index 0000000..397780f
--- /dev/null
@@ -0,0 +1,46 @@
+From 85631f5b33f2acce7d42dec1d0a062ab40de95b8 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Sun, 19 Nov 2023 21:07:43 +0000
+Subject: [PATCH 2/7] net: phylink: use for_each_set_bit()
+
+Use for_each_set_bit() rather than open coding the for() test_bit()
+loop.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com>
+Link: https://lore.kernel.org/r/E1r4p15-00Cpxe-C7@rmk-PC.armlinux.org.uk
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/phy/phylink.c | 18 ++++++++----------
+ 1 file changed, 8 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -712,18 +712,16 @@ static int phylink_validate_mask(struct
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, };
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(s);
+       struct phylink_link_state t;
+-      int intf;
++      int interface;
+-      for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) {
+-              if (test_bit(intf, interfaces)) {
+-                      linkmode_copy(s, supported);
++      for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) {
++              linkmode_copy(s, supported);
+-                      t = *state;
+-                      t.interface = intf;
+-                      if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
+-                              linkmode_or(all_s, all_s, s);
+-                              linkmode_or(all_adv, all_adv, t.advertising);
+-                      }
++              t = *state;
++              t.interface = interface;
++              if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
++                      linkmode_or(all_s, all_s, s);
++                      linkmode_or(all_adv, all_adv, t.advertising);
+               }
+       }
diff --git a/target/linux/generic/backport-6.6/895-03-v6.8-net-phylink-split-out-per-interface-validation.patch b/target/linux/generic/backport-6.6/895-03-v6.8-net-phylink-split-out-per-interface-validation.patch
new file mode 100644 (file)
index 0000000..33f64e8
--- /dev/null
@@ -0,0 +1,76 @@
+From d4788b4383ce5caeb4e68818357c81a02117a3f9 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:28:19 +0000
+Subject: [PATCH 3/7] net: phylink: split out per-interface validation
+
+Split out the internals of phylink_validate_mask() to make the code
+easier to read.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VIB-00DDLr-7g@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 42 ++++++++++++++++++++++++++++-----------
+ 1 file changed, 30 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -704,26 +704,44 @@ static int phylink_validate_mac_and_pcs(
+       return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
+ }
++static void phylink_validate_one(struct phylink *pl,
++                               const unsigned long *supported,
++                               const struct phylink_link_state *state,
++                               phy_interface_t interface,
++                               unsigned long *accum_supported,
++                               unsigned long *accum_advertising)
++{
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp_supported);
++      struct phylink_link_state tmp_state;
++
++      linkmode_copy(tmp_supported, supported);
++
++      tmp_state = *state;
++      tmp_state.interface = interface;
++
++      if (!phylink_validate_mac_and_pcs(pl, tmp_supported, &tmp_state)) {
++              phylink_dbg(pl, " interface %u (%s) rate match %s supports %*pbl\n",
++                          interface, phy_modes(interface),
++                          phy_rate_matching_to_str(tmp_state.rate_matching),
++                          __ETHTOOL_LINK_MODE_MASK_NBITS, tmp_supported);
++
++              linkmode_or(accum_supported, accum_supported, tmp_supported);
++              linkmode_or(accum_advertising, accum_advertising,
++                          tmp_state.advertising);
++      }
++}
++
+ static int phylink_validate_mask(struct phylink *pl, unsigned long *supported,
+                                struct phylink_link_state *state,
+                                const unsigned long *interfaces)
+ {
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, };
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, };
+-      __ETHTOOL_DECLARE_LINK_MODE_MASK(s);
+-      struct phylink_link_state t;
+       int interface;
+-      for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) {
+-              linkmode_copy(s, supported);
+-
+-              t = *state;
+-              t.interface = interface;
+-              if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
+-                      linkmode_or(all_s, all_s, s);
+-                      linkmode_or(all_adv, all_adv, t.advertising);
+-              }
+-      }
++      for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
++              phylink_validate_one(pl, supported, state, interface,
++                                   all_s, all_adv);
+       linkmode_copy(supported, all_s);
+       linkmode_copy(state->advertising, all_adv);
diff --git a/target/linux/generic/backport-6.6/895-04-v6.8-net-phylink-pass-PHY-into-phylink_validate_one.patch b/target/linux/generic/backport-6.6/895-04-v6.8-net-phylink-pass-PHY-into-phylink_validate_one.patch
new file mode 100644 (file)
index 0000000..e3915f0
--- /dev/null
@@ -0,0 +1,47 @@
+From ce7273c31fadb3143fc80c96a72a42adc19c2757 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:28:24 +0000
+Subject: [PATCH 4/7] net: phylink: pass PHY into phylink_validate_one()
+
+Pass the phy (if any) into phylink_validate_one() so that we can
+validate each interface with its rate matching setting.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VIG-00DDLx-Cb@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -704,7 +704,7 @@ static int phylink_validate_mac_and_pcs(
+       return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
+ }
+-static void phylink_validate_one(struct phylink *pl,
++static void phylink_validate_one(struct phylink *pl, struct phy_device *phy,
+                                const unsigned long *supported,
+                                const struct phylink_link_state *state,
+                                phy_interface_t interface,
+@@ -719,6 +719,9 @@ static void phylink_validate_one(struct
+       tmp_state = *state;
+       tmp_state.interface = interface;
++      if (phy)
++              tmp_state.rate_matching = phy_get_rate_matching(phy, interface);
++
+       if (!phylink_validate_mac_and_pcs(pl, tmp_supported, &tmp_state)) {
+               phylink_dbg(pl, " interface %u (%s) rate match %s supports %*pbl\n",
+                           interface, phy_modes(interface),
+@@ -740,7 +743,7 @@ static int phylink_validate_mask(struct
+       int interface;
+       for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
+-              phylink_validate_one(pl, supported, state, interface,
++              phylink_validate_one(pl, NULL, supported, state, interface,
+                                    all_s, all_adv);
+       linkmode_copy(supported, all_s);
diff --git a/target/linux/generic/backport-6.6/895-05-v6.8-net-phylink-pass-PHY-into-phylink_validate_mask.patch b/target/linux/generic/backport-6.6/895-05-v6.8-net-phylink-pass-PHY-into-phylink_validate_mask.patch
new file mode 100644 (file)
index 0000000..5f66869
--- /dev/null
@@ -0,0 +1,58 @@
+From c6fec66d3cd76d797f70b30f1511bed10ba45a96 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:28:29 +0000
+Subject: [PATCH 5/7] net: phylink: pass PHY into phylink_validate_mask()
+
+Pass the phy (if any) into phylink_validate_mask() so that we can
+validate each interface with its rate matching setting.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VIL-00DDM3-HJ@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -734,7 +734,8 @@ static void phylink_validate_one(struct
+       }
+ }
+-static int phylink_validate_mask(struct phylink *pl, unsigned long *supported,
++static int phylink_validate_mask(struct phylink *pl, struct phy_device *phy,
++                               unsigned long *supported,
+                                struct phylink_link_state *state,
+                                const unsigned long *interfaces)
+ {
+@@ -743,7 +744,7 @@ static int phylink_validate_mask(struct
+       int interface;
+       for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
+-              phylink_validate_one(pl, NULL, supported, state, interface,
++              phylink_validate_one(pl, phy, supported, state, interface,
+                                    all_s, all_adv);
+       linkmode_copy(supported, all_s);
+@@ -758,7 +759,8 @@ static int phylink_validate(struct phyli
+       const unsigned long *interfaces = pl->config->supported_interfaces;
+       if (state->interface == PHY_INTERFACE_MODE_NA)
+-              return phylink_validate_mask(pl, supported, state, interfaces);
++              return phylink_validate_mask(pl, NULL, supported, state,
++                                           interfaces);
+       if (!test_bit(state->interface, interfaces))
+               return -EINVAL;
+@@ -3194,7 +3196,8 @@ static int phylink_sfp_config_optical(st
+       /* For all the interfaces that are supported, reduce the sfp_support
+        * mask to only those link modes that can be supported.
+        */
+-      ret = phylink_validate_mask(pl, pl->sfp_support, &config, interfaces);
++      ret = phylink_validate_mask(pl, NULL, pl->sfp_support, &config,
++                                  interfaces);
+       if (ret) {
+               phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n",
+                           __ETHTOOL_LINK_MODE_MASK_NBITS, support);
diff --git a/target/linux/generic/backport-6.6/895-06-v6.8-net-phylink-split-out-PHY-validation-from-phylink_br.patch b/target/linux/generic/backport-6.6/895-06-v6.8-net-phylink-split-out-PHY-validation-from-phylink_br.patch
new file mode 100644 (file)
index 0000000..e295033
--- /dev/null
@@ -0,0 +1,95 @@
+From ee0e0ddb910e7e989b65a19d72b6435baa641fc7 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:28:34 +0000
+Subject: [PATCH 6/7] net: phylink: split out PHY validation from
+ phylink_bringup_phy()
+
+When bringing up a PHY, we need to work out which ethtool link modes it
+should support and advertise. Clause 22 PHYs operate in a single
+interface mode, which can be easily dealt with. However, clause 45 PHYs
+tend to switch interface mode depending on the media. We need more
+flexible validation at this point, so this patch splits out that code
+in preparation to changing it.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VIQ-00DDM9-LK@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 56 ++++++++++++++++++++++-----------------
+ 1 file changed, 31 insertions(+), 25 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1775,6 +1775,35 @@ static void phylink_phy_change(struct ph
+                   phylink_pause_to_str(pl->phy_state.pause));
+ }
++static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy,
++                              unsigned long *supported,
++                              struct phylink_link_state *state)
++{
++      /* Check whether we would use rate matching for the proposed interface
++       * mode.
++       */
++      state->rate_matching = phy_get_rate_matching(phy, state->interface);
++
++      /* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R,
++       * 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching.
++       * For some interface modes (e.g. RXAUI, XAUI and USXGMII) switching
++       * their Serdes is either unnecessary or not reasonable.
++       *
++       * For these which switch interface modes, we really need to know which
++       * interface modes the PHY supports to properly work out which ethtool
++       * linkmodes can be supported. For now, as a work-around, we validate
++       * against all interface modes, which may lead to more ethtool link
++       * modes being advertised than are actually supported.
++       */
++      if (phy->is_c45 && state->rate_matching == RATE_MATCH_NONE &&
++          state->interface != PHY_INTERFACE_MODE_RXAUI &&
++          state->interface != PHY_INTERFACE_MODE_XAUI &&
++          state->interface != PHY_INTERFACE_MODE_USXGMII)
++              state->interface = PHY_INTERFACE_MODE_NA;
++
++      return phylink_validate(pl, supported, state);
++}
++
+ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
+                              phy_interface_t interface)
+ {
+@@ -1795,32 +1824,9 @@ static int phylink_bringup_phy(struct ph
+       memset(&config, 0, sizeof(config));
+       linkmode_copy(supported, phy->supported);
+       linkmode_copy(config.advertising, phy->advertising);
++      config.interface = interface;
+-      /* Check whether we would use rate matching for the proposed interface
+-       * mode.
+-       */
+-      config.rate_matching = phy_get_rate_matching(phy, interface);
+-
+-      /* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R,
+-       * 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching.
+-       * For some interface modes (e.g. RXAUI, XAUI and USXGMII) switching
+-       * their Serdes is either unnecessary or not reasonable.
+-       *
+-       * For these which switch interface modes, we really need to know which
+-       * interface modes the PHY supports to properly work out which ethtool
+-       * linkmodes can be supported. For now, as a work-around, we validate
+-       * against all interface modes, which may lead to more ethtool link
+-       * modes being advertised than are actually supported.
+-       */
+-      if (phy->is_c45 && config.rate_matching == RATE_MATCH_NONE &&
+-          interface != PHY_INTERFACE_MODE_RXAUI &&
+-          interface != PHY_INTERFACE_MODE_XAUI &&
+-          interface != PHY_INTERFACE_MODE_USXGMII)
+-              config.interface = PHY_INTERFACE_MODE_NA;
+-      else
+-              config.interface = interface;
+-
+-      ret = phylink_validate(pl, supported, &config);
++      ret = phylink_validate_phy(pl, phy, supported, &config);
+       if (ret) {
+               phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %pe\n",
+                            phy_modes(config.interface),
diff --git a/target/linux/generic/backport-6.6/895-07-v6.8-net-phylink-use-the-PHY-s-possible_interfaces-if-pop.patch b/target/linux/generic/backport-6.6/895-07-v6.8-net-phylink-use-the-PHY-s-possible_interfaces-if-pop.patch
new file mode 100644 (file)
index 0000000..86ed7a8
--- /dev/null
@@ -0,0 +1,130 @@
+From 8f7a9799c5949f94ecc3acfd71b36437a7ade73b Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 24 Nov 2023 12:28:39 +0000
+Subject: [PATCH 7/7] net: phylink: use the PHY's possible_interfaces if
+ populated
+
+Some PHYs such as Aquantia, Broadcom 84881, and Marvell 88X33x0 can
+switch between a set of interface types depending on the negotiated
+media speed, or can use rate adaption for some or all of these
+interface types.
+
+We currently assume that these are Clause 45 PHYs that are configured
+not to use a specific set of interface modes, which has worked so far,
+but is just a work-around. In this workaround, we validate using all
+interfaces that the MAC supports, which can lead to extra modes being
+advertised that can not be supported.
+
+To properly address this, switch to using the newly introduced PHY
+possible_interfaces bitmap which indicates which interface modes will
+be used by the PHY as configured. We calculate the union of the PHY's
+possible interfaces and MACs supported interfaces, checking that is
+non-empty. If the PHY is on a SFP, we further reduce the set by those
+which can be used on a SFP module, again checking that is non-empty.
+Finally, we validate the subset of interfaces, taking account of
+whether rate matching will be used for each individual interface mode.
+
+This becomes independent of whether the PHY is clause 22 or clause 45.
+
+It is encouraged that all PHYs that switch interface modes or use
+rate matching should populate phydev->possible_interfaces.
+
+Tested-by: Luo Jie <quic_luoj@quicinc.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1r6VIV-00DDMF-Pi@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 67 +++++++++++++++++++++++++++++++--------
+ 1 file changed, 54 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -121,6 +121,19 @@ do {                                                                      \
+ })
+ #endif
++static const phy_interface_t phylink_sfp_interface_preference[] = {
++      PHY_INTERFACE_MODE_25GBASER,
++      PHY_INTERFACE_MODE_USXGMII,
++      PHY_INTERFACE_MODE_10GBASER,
++      PHY_INTERFACE_MODE_5GBASER,
++      PHY_INTERFACE_MODE_2500BASEX,
++      PHY_INTERFACE_MODE_SGMII,
++      PHY_INTERFACE_MODE_1000BASEX,
++      PHY_INTERFACE_MODE_100BASEX,
++};
++
++static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
++
+ /**
+  * phylink_set_port_modes() - set the port type modes in the ethtool mask
+  * @mask: ethtool link mode mask
+@@ -1779,6 +1792,47 @@ static int phylink_validate_phy(struct p
+                               unsigned long *supported,
+                               struct phylink_link_state *state)
+ {
++      DECLARE_PHY_INTERFACE_MASK(interfaces);
++
++      /* If the PHY provides a bitmap of the interfaces it will be using
++       * depending on the negotiated media speeds, use this to validate
++       * which ethtool link modes can be used.
++       */
++      if (!phy_interface_empty(phy->possible_interfaces)) {
++              /* We only care about the union of the PHY's interfaces and
++               * those which the host supports.
++               */
++              phy_interface_and(interfaces, phy->possible_interfaces,
++                                pl->config->supported_interfaces);
++
++              if (phy_interface_empty(interfaces)) {
++                      phylink_err(pl, "PHY has no common interfaces\n");
++                      return -EINVAL;
++              }
++
++              if (phy_on_sfp(phy)) {
++                      /* If the PHY is on a SFP, limit the interfaces to
++                       * those that can be used with a SFP module.
++                       */
++                      phy_interface_and(interfaces, interfaces,
++                                        phylink_sfp_interfaces);
++
++                      if (phy_interface_empty(interfaces)) {
++                              phylink_err(pl, "SFP PHY's possible interfaces becomes empty\n");
++                              return -EINVAL;
++                      }
++              }
++
++              phylink_dbg(pl, "PHY %s uses interfaces %*pbl, validating %*pbl\n",
++                          phydev_name(phy),
++                          (int)PHY_INTERFACE_MODE_MAX,
++                          phy->possible_interfaces,
++                          (int)PHY_INTERFACE_MODE_MAX, interfaces);
++
++              return phylink_validate_mask(pl, phy, supported, state,
++                                           interfaces);
++      }
++
+       /* Check whether we would use rate matching for the proposed interface
+        * mode.
+        */
+@@ -3047,19 +3101,6 @@ static void phylink_sfp_detach(void *ups
+       pl->netdev->sfp_bus = NULL;
+ }
+-static const phy_interface_t phylink_sfp_interface_preference[] = {
+-      PHY_INTERFACE_MODE_25GBASER,
+-      PHY_INTERFACE_MODE_USXGMII,
+-      PHY_INTERFACE_MODE_10GBASER,
+-      PHY_INTERFACE_MODE_5GBASER,
+-      PHY_INTERFACE_MODE_2500BASEX,
+-      PHY_INTERFACE_MODE_SGMII,
+-      PHY_INTERFACE_MODE_1000BASEX,
+-      PHY_INTERFACE_MODE_100BASEX,
+-};
+-
+-static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
+-
+ static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl,
+                                                   const unsigned long *intf)
+ {
diff --git a/target/linux/generic/backport-6.6/897-01-v6.9-net-phy-qcom-qca808x-add-helper-for-checking-for-1G-.patch b/target/linux/generic/backport-6.6/897-01-v6.9-net-phy-qcom-qca808x-add-helper-for-checking-for-1G-.patch
new file mode 100644 (file)
index 0000000..a11e804
--- /dev/null
@@ -0,0 +1,50 @@
+From f058b2dd70b1a5503dff899010aeb53b436091e5 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Wed, 28 Feb 2024 18:24:09 +0100
+Subject: [PATCH 1/2] net: phy: qcom: qca808x: add helper for checking for 1G
+ only model
+
+There are 2 versions of QCA808x, one 2.5G capable and one 1G capable.
+Currently, this matter only in the .get_features call however, it will
+be required for filling supported interface modes so lets add a helper
+that can be reused.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/qcom/qca808x.c | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -156,6 +156,17 @@ static bool qca808x_has_fast_retrain_or_
+       return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
+ }
++static bool qca808x_is_1g_only(struct phy_device *phydev)
++{
++      int ret;
++
++      ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
++      if (ret < 0)
++              return true;
++
++      return !!(QCA808X_PHY_CHIP_TYPE_1G & ret);
++}
++
+ static int qca808x_probe(struct phy_device *phydev)
+ {
+       struct device *dev = &phydev->mdio.dev;
+@@ -350,11 +361,7 @@ static int qca808x_get_features(struct p
+        * existed in the bit0 of MMD1.21, we need to remove it manually if
+        * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.
+        */
+-      ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
+-      if (ret < 0)
+-              return ret;
+-
+-      if (QCA808X_PHY_CHIP_TYPE_1G & ret)
++      if (qca808x_is_1g_only(phydev))
+               linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
+       return 0;
diff --git a/target/linux/generic/backport-6.6/897-02-v6.9-net-phy-qcom-qca808x-fill-in-possible_interfaces.patch b/target/linux/generic/backport-6.6/897-02-v6.9-net-phy-qcom-qca808x-fill-in-possible_interfaces.patch
new file mode 100644 (file)
index 0000000..c162fc7
--- /dev/null
@@ -0,0 +1,44 @@
+From cb28f702960695e26597c332b0e46776e825cc34 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Wed, 28 Feb 2024 18:24:10 +0100
+Subject: [PATCH 2/2] net: phy: qcom: qca808x: fill in possible_interfaces
+
+Currently QCA808x driver does not fill the possible_interfaces.
+2.5G QCA808x support SGMII and 2500Base-X while 1G model only supports
+SGMII, so fill the possible_interfaces accordingly.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/qcom/qca808x.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/net/phy/qcom/qca808x.c
++++ b/drivers/net/phy/qcom/qca808x.c
+@@ -167,6 +167,16 @@ static bool qca808x_is_1g_only(struct ph
+       return !!(QCA808X_PHY_CHIP_TYPE_1G & ret);
+ }
++static void qca808x_fill_possible_interfaces(struct phy_device *phydev)
++{
++      unsigned long *possible = phydev->possible_interfaces;
++
++      __set_bit(PHY_INTERFACE_MODE_SGMII, possible);
++
++      if (!qca808x_is_1g_only(phydev))
++              __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible);
++}
++
+ static int qca808x_probe(struct phy_device *phydev)
+ {
+       struct device *dev = &phydev->mdio.dev;
+@@ -231,6 +241,8 @@ static int qca808x_config_init(struct ph
+               }
+       }
++      qca808x_fill_possible_interfaces(phydev);
++
+       /* Configure adc threshold as 100mv for the link 10M */
+       return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
+                                    QCA808X_ADC_THRESHOLD_MASK,
index e4937a1df1be8ca5040203355ed84ef8dc430219..d50bc9cd4cb6625872d1b3c5b92209cdb3b983d4 100644 (file)
@@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
 
 --- a/drivers/net/phy/phy_device.c
 +++ b/drivers/net/phy/phy_device.c
-@@ -1850,6 +1850,9 @@ void phy_detach(struct phy_device *phyde
+@@ -1852,6 +1852,9 @@ void phy_detach(struct phy_device *phyde
        struct module *ndev_owner = NULL;
        struct mii_bus *bus;
  
@@ -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
-@@ -900,6 +900,12 @@ struct phy_driver {
+@@ -903,6 +903,12 @@ struct phy_driver {
        /** @handle_interrupt: Override default interrupt handling */
        irqreturn_t (*handle_interrupt)(struct phy_device *phydev);
  
index c544a06dfc9215a794f29eb25b01d73b6adaa67d..aa8396826334b50c58cdd8a9c3adcb38e2d5ea72 100644 (file)
@@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
 
 --- a/drivers/net/phy/phy_device.c
 +++ b/drivers/net/phy/phy_device.c
-@@ -1908,6 +1908,9 @@ void phy_detach(struct phy_device *phyde
+@@ -1910,6 +1910,9 @@ void phy_detach(struct phy_device *phyde
        if (phydev->devlink)
                device_link_del(phydev->devlink);
  
@@ -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
-@@ -976,6 +976,12 @@ struct phy_driver {
+@@ -979,6 +979,12 @@ struct phy_driver {
        /** @handle_interrupt: Override default interrupt handling */
        irqreturn_t (*handle_interrupt)(struct phy_device *phydev);
  
index 22c47768279703ea52929ba4422180c323210e26..2cc9a7f5d53833e8e140fda25fb469f77e1eaef2 100644 (file)
@@ -55,7 +55,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
  int phy_init_hw(struct phy_device *phydev)
  {
        int ret = 0;
-@@ -1259,6 +1290,12 @@ int phy_init_hw(struct phy_device *phyde
+@@ -1261,6 +1292,12 @@ int phy_init_hw(struct phy_device *phyde
                        return ret;
        }
  
@@ -68,7 +68,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
        return 0;
  }
  EXPORT_SYMBOL(phy_init_hw);
-@@ -3204,7 +3241,6 @@ static int of_phy_led(struct phy_device
+@@ -3206,7 +3243,6 @@ static int of_phy_led(struct phy_device
        struct device *dev = &phydev->mdio.dev;
        struct led_init_data init_data = {};
        struct led_classdev *cdev;
@@ -76,7 +76,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
        struct phy_led *phyled;
        u32 index;
        int err;
-@@ -3222,21 +3258,6 @@ static int of_phy_led(struct phy_device
+@@ -3224,21 +3260,6 @@ static int of_phy_led(struct phy_device
        if (index > U8_MAX)
                return -EINVAL;