]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
generic: backport phylink patches for PCS/PHY caps OPs 20461/head
authorChristian Marangi <ansuelsmth@gmail.com>
Sun, 19 Oct 2025 23:36:34 +0000 (01:36 +0200)
committerChristian Marangi <ansuelsmth@gmail.com>
Wed, 22 Oct 2025 10:29:41 +0000 (12:29 +0200)
Backport phylink patches for PCS/PHY caps OPs. This makes it easier to
align future generic PCS patch and permit supporting special PHY that
needs specific tune if "in-band" mode is enabled (for example Aeonsemi
PHYs)

This is also mainly using the upstream version of the Mediatek patch
739-net-add-negotiation-of-in-band-capabilities.

All affected patch automatically refreshed.

Link: https://github.com/openwrt/openwrt/pull/20461
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
74 files changed:
target/linux/generic/backport-6.12/600-01-v6.13-net-phylink-move-manual-flow-control-setting.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/600-02-v6.13-net-phylink-move-MLO_AN_FIXED-resolve-handling-to-if.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/600-03-v6.13-net-phylink-move-MLO_AN_PHY-resolve-handling-to-if-s.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/600-04-v6.13-net-phylink-remove-switch-statement-in-resolve-handl.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/600-05-v6.13-net-phylink-clean-up-phylink_resolve.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-01-v6.14-net-phylink-pass-phylink-and-pcs-into-phylink_pcs_ne.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-02-v6.14-net-phylink-split-cur_link_an_mode-into-requested-an.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-03-v6.14-net-phylink-add-debug-for-phylink_major_config.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-04-v6.14-net-phy-add-phy_inband_caps.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-05-v6.14-net-phy-bcm84881-implement-phy_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-06-v6.14-net-phy-marvell-implement-phy_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-07-v6.14-net-phy-add-phy_config_inband.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-08-v6.14-net-phy-marvell-implement-config_inband-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-09-v6.14-net-phylink-add-pcs_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-10-v6.14-net-mvneta-implement-pcs_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-11-v6.14-net-mvpp2-implement-pcs_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-12-v6.14-net-phylink-add-negotiation-of-in-band-capabilities.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/601-13-v6.14-net-phylink-remove-phylink_phy_no_inband.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/602-01-v6.14-net-pcs-pcs-lynx-implement-pcs_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/602-02-v6.14-net-pcs-pcs-mtk-lynxi-implement-pcs_inband_caps-meth.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/602-03-v6.14-net-pcs-xpcs-implement-pcs_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.12/720-09-v6.14-net-phy-Constify-struct-mdio_device_id.patch
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.6/604-01-v6.13-net-phylink-move-manual-flow-control-setting.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/604-02-v6.13-net-phylink-move-MLO_AN_FIXED-resolve-handling-to-if.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/604-03-v6.13-net-phylink-move-MLO_AN_PHY-resolve-handling-to-if-s.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/604-04-v6.13-net-phylink-remove-switch-statement-in-resolve-handl.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/604-05-v6.13-net-phylink-clean-up-phylink_resolve.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/605-v6.8-net-phylink-move-phylink_pcs_neg_mode-into-phylink.c.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-01-v6.14-net-phylink-pass-phylink-and-pcs-into-phylink_pcs_ne.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-02-v6.14-net-phylink-split-cur_link_an_mode-into-requested-an.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-03-v6.14-net-phylink-add-debug-for-phylink_major_config.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-04-v6.14-net-phy-add-phy_inband_caps.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-05-v6.14-net-phy-bcm84881-implement-phy_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-06-v6.14-net-phy-marvell-implement-phy_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-07-v6.14-net-phy-add-phy_config_inband.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-08-v6.14-net-phy-marvell-implement-config_inband-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-09-v6.14-net-phylink-add-pcs_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-10-v6.14-net-mvneta-implement-pcs_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-11-v6.14-net-mvpp2-implement-pcs_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-12-v6.14-net-phylink-add-negotiation-of-in-band-capabilities.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/606-13-v6.14-net-phylink-remove-phylink_phy_no_inband.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/607-01-v6.14-net-pcs-pcs-lynx-implement-pcs_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/607-02-v6.14-net-pcs-pcs-mtk-lynxi-implement-pcs_inband_caps-meth.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/607-03-v6.14-net-pcs-xpcs-implement-pcs_inband_caps-method.patch [new file with mode: 0644]
target/linux/generic/backport-6.6/714-v6.8-02-net-phy-extend-PHY-package-API-to-support-multiple-g.patch
target/linux/generic/backport-6.6/714-v6.8-04-net-phy-add-support-for-PHY-package-MMD-read-write.patch
target/linux/generic/backport-6.6/716-v6.9-03-net-phy-add-devm-of_phy_package_join-helper.patch
target/linux/generic/backport-6.6/716-v6.9-06-net-phy-provide-whether-link-has-changed-in-c37_read.patch
target/linux/generic/backport-6.6/782-01-v6.16-net-phy-pass-PHY-driver-to-.match_phy_device-OP.patch
target/linux/generic/backport-6.6/782-04-v6.16-net-phy-introduce-genphy_match_phy_device.patch
target/linux/generic/backport-6.6/835-v6.9-net-phy-add-support-for-PHY-LEDs-polarity-modes.patch
target/linux/generic/backport-6.6/841-v6.13-net-phy-support-active-high-property-for-PHY-LEDs.patch
target/linux/generic/backport-6.6/895-02-v6.8-net-phylink-use-for_each_set_bit.patch
target/linux/generic/backport-6.6/895-03-v6.8-net-phylink-split-out-per-interface-validation.patch
target/linux/generic/backport-6.6/895-04-v6.8-net-phylink-pass-PHY-into-phylink_validate_one.patch
target/linux/generic/backport-6.6/895-05-v6.8-net-phylink-pass-PHY-into-phylink_validate_mask.patch
target/linux/generic/backport-6.6/895-06-v6.8-net-phylink-split-out-PHY-validation-from-phylink_br.patch
target/linux/generic/backport-6.6/895-07-v6.8-net-phylink-use-the-PHY-s-possible_interfaces-if-pop.patch
target/linux/generic/hack-6.12/750-net-pcs-mtk-lynxi-workaround-2500BaseX-no-an.patch
target/linux/generic/hack-6.6/750-net-pcs-mtk-lynxi-workaround-2500BaseX-no-an.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/generic/pending-6.12/739-03-net-pcs-pcs-mtk-lynxi-add-platform-driver-for-MT7988.patch
target/linux/generic/pending-6.6/703-phy-add-detach-callback-to-struct-phy_driver.patch
target/linux/generic/pending-6.6/706-net-phy-populate-host_interfaces-when-attaching-PHY.patch
target/linux/generic/pending-6.6/739-03-net-pcs-pcs-mtk-lynxi-add-platform-driver-for-MT7988.patch
target/linux/layerscape/patches-6.12/702-phy-Add-2.5G-SGMII-interface-mode.patch
target/linux/layerscape/patches-6.6/702-phy-Add-2.5G-SGMII-interface-mode.patch
target/linux/mediatek/patches-6.12/739-net-add-negotiation-of-in-band-capabilities.patch [deleted file]
target/linux/mvebu/patches-6.12/700-mvneta-tx-queue-workaround.patch
target/linux/siflower/patches-6.6/001-net-phy-c45-add-genphy_c45_pma_read_ext_abilities-fu.patch

diff --git a/target/linux/generic/backport-6.12/600-01-v6.13-net-phylink-move-manual-flow-control-setting.patch b/target/linux/generic/backport-6.12/600-01-v6.13-net-phylink-move-manual-flow-control-setting.patch
new file mode 100644 (file)
index 0000000..a9b86c2
--- /dev/null
@@ -0,0 +1,41 @@
+From 8cc5f4cb94c0b1c7c1ba8013c14fd02ffb1a25f3 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2024 16:01:44 +0000
+Subject: [PATCH 1/5] net: phylink: move manual flow control setting
+
+Move the handling of manual flow control configuration to a common
+location during resolve. We currently evaluate this for all but
+fixed links.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1t9RQe-002Feh-T1@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1484,7 +1484,6 @@ static void phylink_resolve(struct work_
+               switch (pl->cur_link_an_mode) {
+               case MLO_AN_PHY:
+                       link_state = pl->phy_state;
+-                      phylink_apply_manual_flow(pl, &link_state);
+                       mac_config = link_state.link;
+                       break;
+@@ -1545,11 +1544,13 @@ static void phylink_resolve(struct work_
+                               link_state.pause = pl->phy_state.pause;
+                               mac_config = true;
+                       }
+-                      phylink_apply_manual_flow(pl, &link_state);
+                       break;
+               }
+       }
++      if (pl->cur_link_an_mode != MLO_AN_FIXED)
++              phylink_apply_manual_flow(pl, &link_state);
++
+       if (mac_config) {
+               if (link_state.interface != pl->link_config.interface) {
+                       /* The interface has changed, force the link down and
diff --git a/target/linux/generic/backport-6.12/600-02-v6.13-net-phylink-move-MLO_AN_FIXED-resolve-handling-to-if.patch b/target/linux/generic/backport-6.12/600-02-v6.13-net-phylink-move-MLO_AN_FIXED-resolve-handling-to-if.patch
new file mode 100644 (file)
index 0000000..7ff091e
--- /dev/null
@@ -0,0 +1,42 @@
+From 92abfcb4ced482afbe65d18980e6734fe1e62a34 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2024 16:01:50 +0000
+Subject: [PATCH 2/5] net: phylink: move MLO_AN_FIXED resolve handling to if()
+ statement
+
+The switch() statement doesn't sit very well with the preceeding if()
+statements, and results in excessive indentation that spoils code
+readability. Begin cleaning this up by converting the MLO_AN_FIXED case
+to an if() statement.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1t9RQk-002Fen-1A@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1480,6 +1480,9 @@ static void phylink_resolve(struct work_
+       } else if (pl->link_failed) {
+               link_state.link = false;
+               retrigger = true;
++      } else if (pl->cur_link_an_mode == MLO_AN_FIXED) {
++              phylink_get_fixed_state(pl, &link_state);
++              mac_config = link_state.link;
+       } else {
+               switch (pl->cur_link_an_mode) {
+               case MLO_AN_PHY:
+@@ -1487,11 +1490,6 @@ static void phylink_resolve(struct work_
+                       mac_config = link_state.link;
+                       break;
+-              case MLO_AN_FIXED:
+-                      phylink_get_fixed_state(pl, &link_state);
+-                      mac_config = link_state.link;
+-                      break;
+-
+               case MLO_AN_INBAND:
+                       phylink_mac_pcs_get_state(pl, &link_state);
diff --git a/target/linux/generic/backport-6.12/600-03-v6.13-net-phylink-move-MLO_AN_PHY-resolve-handling-to-if-s.patch b/target/linux/generic/backport-6.12/600-03-v6.13-net-phylink-move-MLO_AN_PHY-resolve-handling-to-if-s.patch
new file mode 100644 (file)
index 0000000..76e76fb
--- /dev/null
@@ -0,0 +1,37 @@
+From f0f46c2a3d8ea9d1427298c8103a777d9e616c29 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2024 16:01:55 +0000
+Subject: [PATCH 3/5] net: phylink: move MLO_AN_PHY resolve handling to if()
+ statement
+
+The switch() statement doesn't sit very well with the preceeding if()
+statements, and results in excessive indentation that spoils code
+readability. Continue cleaning this up by converting the MLO_AN_PHY
+case to use an if() statmeent.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1t9RQp-002Fet-5W@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1483,13 +1483,11 @@ static void phylink_resolve(struct work_
+       } else if (pl->cur_link_an_mode == MLO_AN_FIXED) {
+               phylink_get_fixed_state(pl, &link_state);
+               mac_config = link_state.link;
++      } else if (pl->cur_link_an_mode == MLO_AN_PHY) {
++              link_state = pl->phy_state;
++              mac_config = link_state.link;
+       } else {
+               switch (pl->cur_link_an_mode) {
+-              case MLO_AN_PHY:
+-                      link_state = pl->phy_state;
+-                      mac_config = link_state.link;
+-                      break;
+-
+               case MLO_AN_INBAND:
+                       phylink_mac_pcs_get_state(pl, &link_state);
diff --git a/target/linux/generic/backport-6.12/600-04-v6.13-net-phylink-remove-switch-statement-in-resolve-handl.patch b/target/linux/generic/backport-6.12/600-04-v6.13-net-phylink-remove-switch-statement-in-resolve-handl.patch
new file mode 100644 (file)
index 0000000..989fc10
--- /dev/null
@@ -0,0 +1,127 @@
+From d1a16dbbd84e02d2a6dcfcb8d5c4b8b2c0289f00 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2024 16:02:00 +0000
+Subject: [PATCH 4/5] net: phylink: remove switch() statement in resolve
+ handling
+
+The switch() statement doesn't sit very well with the preceeding if()
+statements, so let's just convert everything to if()s. As a result of
+the two preceding commits, there is now only one case in the switch()
+statement. Remove the switch statement and reduce the code indentation.
+Code reformatting will be in the following commit.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1t9RQu-002Fez-AA@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 94 +++++++++++++++++++--------------------
+ 1 file changed, 45 insertions(+), 49 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1487,60 +1487,56 @@ static void phylink_resolve(struct work_
+               link_state = pl->phy_state;
+               mac_config = link_state.link;
+       } else {
+-              switch (pl->cur_link_an_mode) {
+-              case MLO_AN_INBAND:
+-                      phylink_mac_pcs_get_state(pl, &link_state);
+-
+-                      /* The PCS may have a latching link-fail indicator.
+-                       * If the link was up, bring the link down and
+-                       * re-trigger the resolve. Otherwise, re-read the
+-                       * PCS state to get the current status of the link.
++              phylink_mac_pcs_get_state(pl, &link_state);
++
++              /* The PCS may have a latching link-fail indicator.
++               * If the link was up, bring the link down and
++               * re-trigger the resolve. Otherwise, re-read the
++               * PCS state to get the current status of the link.
++               */
++              if (!link_state.link) {
++                      if (cur_link_state)
++                              retrigger = true;
++                      else
++                              phylink_mac_pcs_get_state(pl,
++                                                        &link_state);
++              }
++
++              /* If we have a phy, the "up" state is the union of
++               * both the PHY and the MAC
++               */
++              if (pl->phydev)
++                      link_state.link &= pl->phy_state.link;
++
++              /* Only update if the PHY link is up */
++              if (pl->phydev && pl->phy_state.link) {
++                      /* If the interface has changed, force a
++                       * link down event if the link isn't already
++                       * down, and re-resolve.
+                        */
+-                      if (!link_state.link) {
+-                              if (cur_link_state)
+-                                      retrigger = true;
+-                              else
+-                                      phylink_mac_pcs_get_state(pl,
+-                                                                &link_state);
++                      if (link_state.interface !=
++                          pl->phy_state.interface) {
++                              retrigger = true;
++                              link_state.link = false;
+                       }
++                      link_state.interface = pl->phy_state.interface;
+-                      /* If we have a phy, the "up" state is the union of
+-                       * both the PHY and the MAC
++                      /* If we are doing rate matching, then the
++                       * link speed/duplex comes from the PHY
+                        */
+-                      if (pl->phydev)
+-                              link_state.link &= pl->phy_state.link;
+-
+-                      /* Only update if the PHY link is up */
+-                      if (pl->phydev && pl->phy_state.link) {
+-                              /* If the interface has changed, force a
+-                               * link down event if the link isn't already
+-                               * down, and re-resolve.
+-                               */
+-                              if (link_state.interface !=
+-                                  pl->phy_state.interface) {
+-                                      retrigger = true;
+-                                      link_state.link = false;
+-                              }
+-                              link_state.interface = pl->phy_state.interface;
+-
+-                              /* If we are doing rate matching, then the
+-                               * link speed/duplex comes from the PHY
+-                               */
+-                              if (pl->phy_state.rate_matching) {
+-                                      link_state.rate_matching =
+-                                              pl->phy_state.rate_matching;
+-                                      link_state.speed = pl->phy_state.speed;
+-                                      link_state.duplex =
+-                                              pl->phy_state.duplex;
+-                              }
+-
+-                              /* If we have a PHY, we need to update with
+-                               * the PHY flow control bits.
+-                               */
+-                              link_state.pause = pl->phy_state.pause;
+-                              mac_config = true;
++                      if (pl->phy_state.rate_matching) {
++                              link_state.rate_matching =
++                                      pl->phy_state.rate_matching;
++                              link_state.speed = pl->phy_state.speed;
++                              link_state.duplex =
++                                      pl->phy_state.duplex;
+                       }
+-                      break;
++
++                      /* If we have a PHY, we need to update with
++                       * the PHY flow control bits.
++                       */
++                      link_state.pause = pl->phy_state.pause;
++                      mac_config = true;
+               }
+       }
diff --git a/target/linux/generic/backport-6.12/600-05-v6.13-net-phylink-clean-up-phylink_resolve.patch b/target/linux/generic/backport-6.12/600-05-v6.13-net-phylink-clean-up-phylink_resolve.patch
new file mode 100644 (file)
index 0000000..285eea8
--- /dev/null
@@ -0,0 +1,85 @@
+From bc08ce37d99a3992e975a0f397503cb23404f25a Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2024 16:02:05 +0000
+Subject: [PATCH 5/5] net: phylink: clean up phylink_resolve()
+
+Now that we have reduced the indentation level, clean up the code
+formatting.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1t9RQz-002Ff5-EA@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 35 ++++++++++++++++-------------------
+ 1 file changed, 16 insertions(+), 19 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1489,51 +1489,48 @@ static void phylink_resolve(struct work_
+       } else {
+               phylink_mac_pcs_get_state(pl, &link_state);
+-              /* The PCS may have a latching link-fail indicator.
+-               * If the link was up, bring the link down and
+-               * re-trigger the resolve. Otherwise, re-read the
+-               * PCS state to get the current status of the link.
++              /* The PCS may have a latching link-fail indicator. If the link
++               * was up, bring the link down and re-trigger the resolve.
++               * Otherwise, re-read the PCS state to get the current status
++               * of the link.
+                */
+               if (!link_state.link) {
+                       if (cur_link_state)
+                               retrigger = true;
+                       else
+-                              phylink_mac_pcs_get_state(pl,
+-                                                        &link_state);
++                              phylink_mac_pcs_get_state(pl, &link_state);
+               }
+-              /* If we have a phy, the "up" state is the union of
+-               * both the PHY and the MAC
++              /* If we have a phy, the "up" state is the union of both the
++               * PHY and the MAC
+                */
+               if (pl->phydev)
+                       link_state.link &= pl->phy_state.link;
+               /* Only update if the PHY link is up */
+               if (pl->phydev && pl->phy_state.link) {
+-                      /* If the interface has changed, force a
+-                       * link down event if the link isn't already
+-                       * down, and re-resolve.
++                      /* If the interface has changed, force a link down
++                       * event if the link isn't already down, and re-resolve.
+                        */
+-                      if (link_state.interface !=
+-                          pl->phy_state.interface) {
++                      if (link_state.interface != pl->phy_state.interface) {
+                               retrigger = true;
+                               link_state.link = false;
+                       }
++
+                       link_state.interface = pl->phy_state.interface;
+-                      /* If we are doing rate matching, then the
+-                       * link speed/duplex comes from the PHY
++                      /* If we are doing rate matching, then the link
++                       * speed/duplex comes from the PHY
+                        */
+                       if (pl->phy_state.rate_matching) {
+                               link_state.rate_matching =
+                                       pl->phy_state.rate_matching;
+                               link_state.speed = pl->phy_state.speed;
+-                              link_state.duplex =
+-                                      pl->phy_state.duplex;
++                              link_state.duplex = pl->phy_state.duplex;
+                       }
+-                      /* If we have a PHY, we need to update with
+-                       * the PHY flow control bits.
++                      /* If we have a PHY, we need to update with the PHY
++                       * flow control bits.
+                        */
+                       link_state.pause = pl->phy_state.pause;
+                       mac_config = true;
diff --git a/target/linux/generic/backport-6.12/601-01-v6.14-net-phylink-pass-phylink-and-pcs-into-phylink_pcs_ne.patch b/target/linux/generic/backport-6.12/601-01-v6.14-net-phylink-pass-phylink-and-pcs-into-phylink_pcs_ne.patch
new file mode 100644 (file)
index 0000000..6868cd1
--- /dev/null
@@ -0,0 +1,95 @@
+From 17ed1911f9c8d4f9af8e13b2c95103ee06dadc0f Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:30:47 +0000
+Subject: [PATCH 01/13] net: phylink: pass phylink and pcs into
+ phylink_pcs_neg_mode()
+
+Move the call to phylink_pcs_neg_mode() in phylink_major_config() after
+we have selected the appropriate PCS to allow the PCS to be passed in.
+
+Add struct phylink and struct phylink_pcs pointers to
+phylink_pcs_neg_mode() and pass in the appropriate structures. Set
+pl->pcs_neg_mode before returning, and remove the return value.
+
+This will allow the capabilities of the PCS and any PHY to be used when
+deciding which pcs_neg_mode should be used.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUrP-006ITh-6u@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 26 +++++++++++++-------------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1102,7 +1102,8 @@ static void phylink_pcs_an_restart(struc
+ /**
+  * phylink_pcs_neg_mode() - helper to determine PCS inband mode
+- * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
++ * @pl: a pointer to a &struct phylink returned from phylink_create()
++ * @pcs: a pointer to &struct phylink_pcs
+  * @interface: interface mode to be used
+  * @advertising: adertisement ethtool link mode mask
+  *
+@@ -1119,11 +1120,13 @@ static void phylink_pcs_an_restart(struc
+  * Note: this is for cases where the PCS itself is involved in negotiation
+  * (e.g. Clause 37, SGMII and similar) not Clause 73.
+  */
+-static unsigned int phylink_pcs_neg_mode(unsigned int mode,
+-                                       phy_interface_t interface,
+-                                       const unsigned long *advertising)
++static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs,
++                               phy_interface_t interface,
++                               const unsigned long *advertising)
+ {
+-      unsigned int neg_mode;
++      unsigned int neg_mode, mode;
++
++      mode = pl->cur_link_an_mode;
+       switch (interface) {
+       case PHY_INTERFACE_MODE_SGMII:
+@@ -1164,7 +1167,7 @@ static unsigned int phylink_pcs_neg_mode
+               break;
+       }
+-      return neg_mode;
++      pl->pcs_neg_mode = neg_mode;
+ }
+ static void phylink_major_config(struct phylink *pl, bool restart,
+@@ -1178,10 +1181,6 @@ static void phylink_major_config(struct
+       phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
+-      pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode,
+-                                              state->interface,
+-                                              state->advertising);
+-
+       if (pl->using_mac_select_pcs) {
+               pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
+               if (IS_ERR(pcs)) {
+@@ -1194,6 +1193,8 @@ static void phylink_major_config(struct
+               pcs_changed = pcs && pl->pcs != pcs;
+       }
++      phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising);
++
+       phylink_pcs_poll_stop(pl);
+       if (pl->mac_ops->mac_prepare) {
+@@ -1284,9 +1285,8 @@ static int phylink_change_inband_advert(
+                   pl->link_config.pause);
+       /* Recompute the PCS neg mode */
+-      pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode,
+-                                      pl->link_config.interface,
+-                                      pl->link_config.advertising);
++      phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface,
++                           pl->link_config.advertising);
+       neg_mode = pl->cur_link_an_mode;
+       if (pl->pcs->neg_mode)
diff --git a/target/linux/generic/backport-6.12/601-02-v6.14-net-phylink-split-cur_link_an_mode-into-requested-an.patch b/target/linux/generic/backport-6.12/601-02-v6.14-net-phylink-split-cur_link_an_mode-into-requested-an.patch
new file mode 100644 (file)
index 0000000..76f4d5a
--- /dev/null
@@ -0,0 +1,290 @@
+From 1f92ead7e15003f632b5f138e8138095e0997d3d Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:30:52 +0000
+Subject: [PATCH 02/13] net: phylink: split cur_link_an_mode into requested and
+ active
+
+There is an interdependence between the current link_an_mode and
+pcs_neg_mode that some drivers rely upon to know whether inband or PHY
+mode will be used.
+
+In order to support detection of PCS and PHY inband capabilities
+resulting in automatic selection of inband or PHY mode, we need to
+cater for this, and support changing the MAC link_an_mode. However, we
+end up with an inter-dependency between the current link_an_mode and
+pcs_neg_mode.
+
+To solve this, split the current link_an_mode into the requested
+link_an_mode and active link_an_mode. The requested link_an_mode will
+always be passed to phylink_pcs_neg_mode(), and the active link_an_mode
+will be used for everything else, and only updated during
+phylink_major_config(). This will ensure that phylink_pcs_neg_mode()'s
+link_an_mode will not depend on the active link_an_mode that will,
+in a future patch, depend on pcs_neg_mode.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUrU-006ITn-Ai@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 60 ++++++++++++++++++++-------------------
+ 1 file changed, 31 insertions(+), 29 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -56,7 +56,8 @@ struct phylink {
+       struct phy_device *phydev;
+       phy_interface_t link_interface; /* PHY_INTERFACE_xxx */
+       u8 cfg_link_an_mode;            /* MLO_AN_xxx */
+-      u8 cur_link_an_mode;
++      u8 req_link_an_mode;            /* Requested MLO_AN_xxx mode */
++      u8 act_link_an_mode;            /* Active MLO_AN_xxx mode */
+       u8 link_port;                   /* The current non-phy ethtool port */
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+@@ -1082,13 +1083,13 @@ static void phylink_mac_config(struct ph
+       phylink_dbg(pl,
+                   "%s: mode=%s/%s/%s adv=%*pb pause=%02x\n",
+-                  __func__, phylink_an_mode_str(pl->cur_link_an_mode),
++                  __func__, phylink_an_mode_str(pl->act_link_an_mode),
+                   phy_modes(st.interface),
+                   phy_rate_matching_to_str(st.rate_matching),
+                   __ETHTOOL_LINK_MODE_MASK_NBITS, st.advertising,
+                   st.pause);
+-      pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, &st);
++      pl->mac_ops->mac_config(pl->config, pl->act_link_an_mode, &st);
+ }
+ static void phylink_pcs_an_restart(struct phylink *pl)
+@@ -1096,7 +1097,7 @@ static void phylink_pcs_an_restart(struc
+       if (pl->pcs && linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+                                        pl->link_config.advertising) &&
+           phy_interface_mode_is_8023z(pl->link_config.interface) &&
+-          phylink_autoneg_inband(pl->cur_link_an_mode))
++          phylink_autoneg_inband(pl->act_link_an_mode))
+               pl->pcs->ops->pcs_an_restart(pl->pcs);
+ }
+@@ -1126,7 +1127,7 @@ static void phylink_pcs_neg_mode(struct
+ {
+       unsigned int neg_mode, mode;
+-      mode = pl->cur_link_an_mode;
++      mode = pl->req_link_an_mode;
+       switch (interface) {
+       case PHY_INTERFACE_MODE_SGMII:
+@@ -1168,6 +1169,7 @@ static void phylink_pcs_neg_mode(struct
+       }
+       pl->pcs_neg_mode = neg_mode;
++      pl->act_link_an_mode = mode;
+ }
+ static void phylink_major_config(struct phylink *pl, bool restart,
+@@ -1198,7 +1200,7 @@ static void phylink_major_config(struct
+       phylink_pcs_poll_stop(pl);
+       if (pl->mac_ops->mac_prepare) {
+-              err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode,
++              err = pl->mac_ops->mac_prepare(pl->config, pl->act_link_an_mode,
+                                              state->interface);
+               if (err < 0) {
+                       phylink_err(pl, "mac_prepare failed: %pe\n",
+@@ -1232,7 +1234,7 @@ static void phylink_major_config(struct
+       if (pl->pcs_state == PCS_STATE_STARTING || pcs_changed)
+               phylink_pcs_enable(pl->pcs);
+-      neg_mode = pl->cur_link_an_mode;
++      neg_mode = pl->act_link_an_mode;
+       if (pl->pcs && pl->pcs->neg_mode)
+               neg_mode = pl->pcs_neg_mode;
+@@ -1248,7 +1250,7 @@ static void phylink_major_config(struct
+               phylink_pcs_an_restart(pl);
+       if (pl->mac_ops->mac_finish) {
+-              err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode,
++              err = pl->mac_ops->mac_finish(pl->config, pl->act_link_an_mode,
+                                             state->interface);
+               if (err < 0)
+                       phylink_err(pl, "mac_finish failed: %pe\n",
+@@ -1279,7 +1281,7 @@ static int phylink_change_inband_advert(
+               return 0;
+       phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__,
+-                  phylink_an_mode_str(pl->cur_link_an_mode),
++                  phylink_an_mode_str(pl->req_link_an_mode),
+                   phy_modes(pl->link_config.interface),
+                   __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising,
+                   pl->link_config.pause);
+@@ -1288,7 +1290,7 @@ static int phylink_change_inband_advert(
+       phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface,
+                            pl->link_config.advertising);
+-      neg_mode = pl->cur_link_an_mode;
++      neg_mode = pl->act_link_an_mode;
+       if (pl->pcs->neg_mode)
+               neg_mode = pl->pcs_neg_mode;
+@@ -1353,7 +1355,7 @@ static void phylink_mac_initial_config(s
+ {
+       struct phylink_link_state link_state;
+-      switch (pl->cur_link_an_mode) {
++      switch (pl->req_link_an_mode) {
+       case MLO_AN_PHY:
+               link_state = pl->phy_state;
+               break;
+@@ -1427,14 +1429,14 @@ static void phylink_link_up(struct phyli
+       pl->cur_interface = link_state.interface;
+-      neg_mode = pl->cur_link_an_mode;
++      neg_mode = pl->act_link_an_mode;
+       if (pl->pcs && pl->pcs->neg_mode)
+               neg_mode = pl->pcs_neg_mode;
+       phylink_pcs_link_up(pl->pcs, neg_mode, pl->cur_interface, speed,
+                           duplex);
+-      pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode,
++      pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->act_link_an_mode,
+                                pl->cur_interface, speed, duplex,
+                                !!(link_state.pause & MLO_PAUSE_TX), rx_pause);
+@@ -1454,7 +1456,7 @@ static void phylink_link_down(struct phy
+       if (ndev)
+               netif_carrier_off(ndev);
+-      pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode,
++      pl->mac_ops->mac_link_down(pl->config, pl->act_link_an_mode,
+                                  pl->cur_interface);
+       phylink_info(pl, "Link is Down\n");
+ }
+@@ -1480,10 +1482,10 @@ static void phylink_resolve(struct work_
+       } else if (pl->link_failed) {
+               link_state.link = false;
+               retrigger = true;
+-      } else if (pl->cur_link_an_mode == MLO_AN_FIXED) {
++      } else if (pl->act_link_an_mode == MLO_AN_FIXED) {
+               phylink_get_fixed_state(pl, &link_state);
+               mac_config = link_state.link;
+-      } else if (pl->cur_link_an_mode == MLO_AN_PHY) {
++      } else if (pl->act_link_an_mode == MLO_AN_PHY) {
+               link_state = pl->phy_state;
+               mac_config = link_state.link;
+       } else {
+@@ -1537,7 +1539,7 @@ static void phylink_resolve(struct work_
+               }
+       }
+-      if (pl->cur_link_an_mode != MLO_AN_FIXED)
++      if (pl->act_link_an_mode != MLO_AN_FIXED)
+               phylink_apply_manual_flow(pl, &link_state);
+       if (mac_config) {
+@@ -1661,7 +1663,7 @@ int phylink_set_fixed_link(struct phylin
+       pl->link_config.an_complete = 1;
+       pl->cfg_link_an_mode = MLO_AN_FIXED;
+-      pl->cur_link_an_mode = pl->cfg_link_an_mode;
++      pl->req_link_an_mode = pl->cfg_link_an_mode;
+       return 0;
+ }
+@@ -1756,7 +1758,7 @@ struct phylink *phylink_create(struct ph
+               }
+       }
+-      pl->cur_link_an_mode = pl->cfg_link_an_mode;
++      pl->req_link_an_mode = pl->cfg_link_an_mode;
+       ret = phylink_register_sfp(pl, fwnode);
+       if (ret < 0) {
+@@ -2213,7 +2215,7 @@ void phylink_start(struct phylink *pl)
+       ASSERT_RTNL();
+       phylink_info(pl, "configuring for %s/%s link mode\n",
+-                   phylink_an_mode_str(pl->cur_link_an_mode),
++                   phylink_an_mode_str(pl->req_link_an_mode),
+                    phy_modes(pl->link_config.interface));
+       /* Always set the carrier off */
+@@ -2472,7 +2474,7 @@ int phylink_ethtool_ksettings_get(struct
+       linkmode_copy(kset->link_modes.supported, pl->supported);
+-      switch (pl->cur_link_an_mode) {
++      switch (pl->act_link_an_mode) {
+       case MLO_AN_FIXED:
+               /* We are using fixed settings. Report these as the
+                * current link settings - and note that these also
+@@ -2564,7 +2566,7 @@ int phylink_ethtool_ksettings_set(struct
+               /* If we have a fixed link, refuse to change link parameters.
+                * If the link parameters match, accept them but do nothing.
+                */
+-              if (pl->cur_link_an_mode == MLO_AN_FIXED) {
++              if (pl->req_link_an_mode == MLO_AN_FIXED) {
+                       if (s->speed != pl->link_config.speed ||
+                           s->duplex != pl->link_config.duplex)
+                               return -EINVAL;
+@@ -2580,7 +2582,7 @@ int phylink_ethtool_ksettings_set(struct
+                * is our default case) but do not allow the advertisement to
+                * be changed. If the advertisement matches, simply return.
+                */
+-              if (pl->cur_link_an_mode == MLO_AN_FIXED) {
++              if (pl->req_link_an_mode == MLO_AN_FIXED) {
+                       if (!linkmode_equal(config.advertising,
+                                           pl->link_config.advertising))
+                               return -EINVAL;
+@@ -2620,7 +2622,7 @@ int phylink_ethtool_ksettings_set(struct
+               linkmode_copy(support, pl->supported);
+               if (phylink_validate(pl, support, &config)) {
+                       phylink_err(pl, "validation of %s/%s with support %*pb failed\n",
+-                                  phylink_an_mode_str(pl->cur_link_an_mode),
++                                  phylink_an_mode_str(pl->req_link_an_mode),
+                                   phy_modes(config.interface),
+                                   __ETHTOOL_LINK_MODE_MASK_NBITS, support);
+                       return -EINVAL;
+@@ -2720,7 +2722,7 @@ int phylink_ethtool_set_pauseparam(struc
+       ASSERT_RTNL();
+-      if (pl->cur_link_an_mode == MLO_AN_FIXED)
++      if (pl->req_link_an_mode == MLO_AN_FIXED)
+               return -EOPNOTSUPP;
+       if (!phylink_test(pl->supported, Pause) &&
+@@ -2984,7 +2986,7 @@ static int phylink_mii_read(struct phyli
+       struct phylink_link_state state;
+       int val = 0xffff;
+-      switch (pl->cur_link_an_mode) {
++      switch (pl->act_link_an_mode) {
+       case MLO_AN_FIXED:
+               if (phy_id == 0) {
+                       phylink_get_fixed_state(pl, &state);
+@@ -3009,7 +3011,7 @@ static int phylink_mii_read(struct phyli
+ static int phylink_mii_write(struct phylink *pl, unsigned int phy_id,
+                            unsigned int reg, unsigned int val)
+ {
+-      switch (pl->cur_link_an_mode) {
++      switch (pl->act_link_an_mode) {
+       case MLO_AN_FIXED:
+               break;
+@@ -3199,9 +3201,9 @@ static void phylink_sfp_set_config(struc
+               changed = true;
+       }
+-      if (pl->cur_link_an_mode != mode ||
++      if (pl->req_link_an_mode != mode ||
+           pl->link_config.interface != state->interface) {
+-              pl->cur_link_an_mode = mode;
++              pl->req_link_an_mode = mode;
+               pl->link_config.interface = state->interface;
+               changed = true;
diff --git a/target/linux/generic/backport-6.12/601-03-v6.14-net-phylink-add-debug-for-phylink_major_config.patch b/target/linux/generic/backport-6.12/601-03-v6.14-net-phylink-add-debug-for-phylink_major_config.patch
new file mode 100644 (file)
index 0000000..ee625c7
--- /dev/null
@@ -0,0 +1,66 @@
+From 4e7d000286fe8e12f2d88032711ffab3ab658b12 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:30:57 +0000
+Subject: [PATCH 03/13] net: phylink: add debug for phylink_major_config()
+
+Now that we have a more complexity in phylink_major_config(), augment
+the debugging so we can see what's going on there.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUrZ-006ITt-Fa@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 27 ++++++++++++++++++++++++++-
+ 1 file changed, 26 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -176,6 +176,24 @@ static const char *phylink_an_mode_str(u
+       return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown";
+ }
++static const char *phylink_pcs_mode_str(unsigned int mode)
++{
++      if (!mode)
++              return "none";
++
++      if (mode & PHYLINK_PCS_NEG_OUTBAND)
++              return "outband";
++
++      if (mode & PHYLINK_PCS_NEG_INBAND) {
++              if (mode & PHYLINK_PCS_NEG_ENABLED)
++                      return "inband,an-enabled";
++              else
++                      return "inband,an-disabled";
++      }
++
++      return "unknown";
++}
++
+ static unsigned int phylink_interface_signal_rate(phy_interface_t interface)
+ {
+       switch (interface) {
+@@ -1181,7 +1199,9 @@ static void phylink_major_config(struct
+       unsigned int neg_mode;
+       int err;
+-      phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
++      phylink_dbg(pl, "major config, requested %s/%s\n",
++                  phylink_an_mode_str(pl->req_link_an_mode),
++                  phy_modes(state->interface));
+       if (pl->using_mac_select_pcs) {
+               pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
+@@ -1197,6 +1217,11 @@ static void phylink_major_config(struct
+       phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising);
++      phylink_dbg(pl, "major config, active %s/%s/%s\n",
++                  phylink_an_mode_str(pl->act_link_an_mode),
++                  phylink_pcs_mode_str(pl->pcs_neg_mode),
++                  phy_modes(state->interface));
++
+       phylink_pcs_poll_stop(pl);
+       if (pl->mac_ops->mac_prepare) {
diff --git a/target/linux/generic/backport-6.12/601-04-v6.14-net-phy-add-phy_inband_caps.patch b/target/linux/generic/backport-6.12/601-04-v6.14-net-phy-add-phy_inband_caps.patch
new file mode 100644 (file)
index 0000000..67f4f0b
--- /dev/null
@@ -0,0 +1,118 @@
+From b4c7698dd95f253c6958d8c6ac219098009bf28a Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:02 +0000
+Subject: [PATCH 04/13] net: phy: add phy_inband_caps()
+
+Add a method to query the PHY's in-band capabilities for a PHY
+interface mode.
+
+Where the interface mode does not have in-band capability, or the PHY
+driver has not been updated to return this information, then
+phy_inband_caps() should return zero. Otherwise, PHY drivers will
+return a value consisting of the following flags:
+
+LINK_INBAND_DISABLE indicates that the hardware does not support
+in-band signalling, or can have in-band signalling configured via
+software to be disabled.
+
+LINK_INBAND_ENABLE indicates that the hardware will use in-band
+signalling, or can have in-band signalling configured via software
+to be enabled.
+
+LINK_INBAND_BYPASS indicates that the hardware has the ability to
+bypass in-band signalling when enabled after a timeout if the link
+partner does not respond to its in-band signalling.
+
+This reports the PHY capabilities for the particular interface mode,
+not the current configuration.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUre-006ITz-KF@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phy.c | 21 +++++++++++++++++++++
+ include/linux/phy.h   | 28 ++++++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -1049,6 +1049,27 @@ static int phy_check_link_status(struct
+ }
+ /**
++ * phy_inband_caps - query which in-band signalling modes are supported
++ * @phydev: a pointer to a &struct phy_device
++ * @interface: the interface mode for the PHY
++ *
++ * Returns zero if it is unknown what in-band signalling is supported by the
++ * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise,
++ * returns a bit mask of the LINK_INBAND_* values from
++ * &enum link_inband_signalling to describe which inband modes are supported
++ * by the PHY for this interface mode.
++ */
++unsigned int phy_inband_caps(struct phy_device *phydev,
++                           phy_interface_t interface)
++{
++      if (phydev->drv && phydev->drv->inband_caps)
++              return phydev->drv->inband_caps(phydev, interface);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(phy_inband_caps);
++
++/**
+  * _phy_start_aneg - start auto-negotiation for this PHY device
+  * @phydev: the phy_device struct
+  *
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -816,6 +816,24 @@ struct phy_tdr_config {
+ #define PHY_PAIR_ALL -1
+ /**
++ * enum link_inband_signalling - in-band signalling modes that are supported
++ *
++ * @LINK_INBAND_DISABLE: in-band signalling can be disabled
++ * @LINK_INBAND_ENABLE: in-band signalling can be enabled without bypass
++ * @LINK_INBAND_BYPASS: in-band signalling can be enabled with bypass
++ *
++ * The possible and required bits can only be used if the valid bit is set.
++ * If possible is clear, that means inband signalling can not be used.
++ * Required is only valid when possible is set, and means that inband
++ * signalling must be used.
++ */
++enum link_inband_signalling {
++      LINK_INBAND_DISABLE             = BIT(0),
++      LINK_INBAND_ENABLE              = BIT(1),
++      LINK_INBAND_BYPASS              = BIT(2),
++};
++
++/**
+  * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision
+  * Avoidance) Reconciliation Sublayer.
+  *
+@@ -954,6 +972,14 @@ struct phy_driver {
+       int (*get_features)(struct phy_device *phydev);
+       /**
++       * @inband_caps: query whether in-band is supported for the given PHY
++       * interface mode. Returns a bitmask of bits defined by enum
++       * link_inband_signalling.
++       */
++      unsigned int (*inband_caps)(struct phy_device *phydev,
++                                  phy_interface_t interface);
++
++      /**
+        * @get_rate_matching: Get the supported type of rate matching for a
+        * particular phy interface. This is used by phy consumers to determine
+        * whether to advertise lower-speed modes for that interface. It is
+@@ -1832,6 +1858,8 @@ int phy_config_aneg(struct phy_device *p
+ int _phy_start_aneg(struct phy_device *phydev);
+ int phy_start_aneg(struct phy_device *phydev);
+ int phy_aneg_done(struct phy_device *phydev);
++unsigned int phy_inband_caps(struct phy_device *phydev,
++                           phy_interface_t interface);
+ int phy_speed_down(struct phy_device *phydev, bool sync);
+ int phy_speed_up(struct phy_device *phydev);
+ bool phy_check_valid(int speed, int duplex, unsigned long *features);
diff --git a/target/linux/generic/backport-6.12/601-05-v6.14-net-phy-bcm84881-implement-phy_inband_caps-method.patch b/target/linux/generic/backport-6.12/601-05-v6.14-net-phy-bcm84881-implement-phy_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..0ba3cd2
--- /dev/null
@@ -0,0 +1,41 @@
+From c64c7fa0a774d9da72071a8517e359992baac982 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:07 +0000
+Subject: [PATCH 05/13] net: phy: bcm84881: implement phy_inband_caps() method
+
+BCM84881 has no support for inband signalling, so this is a trivial
+implementation that returns no support for inband.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Acked-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Link: https://patch.msgid.link/E1tIUrj-006IU6-ON@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/bcm84881.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/net/phy/bcm84881.c
++++ b/drivers/net/phy/bcm84881.c
+@@ -235,11 +235,21 @@ static int bcm84881_read_status(struct p
+       return genphy_c45_read_mdix(phydev);
+ }
++/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
++ * or 802.3z control word, so inband will not work.
++ */
++static unsigned int bcm84881_inband_caps(struct phy_device *phydev,
++                                       phy_interface_t interface)
++{
++      return LINK_INBAND_DISABLE;
++}
++
+ static struct phy_driver bcm84881_drivers[] = {
+       {
+               .phy_id         = 0xae025150,
+               .phy_id_mask    = 0xfffffff0,
+               .name           = "Broadcom BCM84881",
++              .inband_caps    = bcm84881_inband_caps,
+               .config_init    = bcm84881_config_init,
+               .probe          = bcm84881_probe,
+               .get_features   = bcm84881_get_features,
diff --git a/target/linux/generic/backport-6.12/601-06-v6.14-net-phy-marvell-implement-phy_inband_caps-method.patch b/target/linux/generic/backport-6.12/601-06-v6.14-net-phy-marvell-implement-phy_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..fb5d9c2
--- /dev/null
@@ -0,0 +1,63 @@
+From 1c86828dff88e28b8ade6bddeee0163a023faf91 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:12 +0000
+Subject: [PATCH 06/13] net: phy: marvell: implement phy_inband_caps() method
+
+Provide an implementation for phy_inband_caps() for Marvell PHYs used
+on SFP modules, so that phylink knows the PHYs capabilities.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUro-006IUC-Rq@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/marvell.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/drivers/net/phy/marvell.c
++++ b/drivers/net/phy/marvell.c
+@@ -716,6 +716,20 @@ static int marvell_config_aneg_fiber(str
+       return genphy_check_and_restart_aneg(phydev, changed);
+ }
++static unsigned int m88e1111_inband_caps(struct phy_device *phydev,
++                                       phy_interface_t interface)
++{
++      /* In 1000base-X and SGMII modes, the inband mode can be changed
++       * through the Fibre page BMCR ANENABLE bit.
++       */
++      if (interface == PHY_INTERFACE_MODE_1000BASEX ||
++          interface == PHY_INTERFACE_MODE_SGMII)
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE |
++                     LINK_INBAND_BYPASS;
++
++      return 0;
++}
++
+ static int m88e1111_config_aneg(struct phy_device *phydev)
+ {
+       int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+@@ -3667,6 +3681,7 @@ static struct phy_driver marvell_drivers
+               .name = "Marvell 88E1112",
+               /* PHY_GBIT_FEATURES */
+               .probe = marvell_probe,
++              .inband_caps = m88e1111_inband_caps,
+               .config_init = m88e1112_config_init,
+               .config_aneg = marvell_config_aneg,
+               .config_intr = marvell_config_intr,
+@@ -3688,6 +3703,7 @@ static struct phy_driver marvell_drivers
+               /* PHY_GBIT_FEATURES */
+               .flags = PHY_POLL_CABLE_TEST,
+               .probe = marvell_probe,
++              .inband_caps = m88e1111_inband_caps,
+               .config_init = m88e1111gbe_config_init,
+               .config_aneg = m88e1111_config_aneg,
+               .read_status = marvell_read_status,
+@@ -3711,6 +3727,7 @@ static struct phy_driver marvell_drivers
+               .name = "Marvell 88E1111 (Finisar)",
+               /* PHY_GBIT_FEATURES */
+               .probe = marvell_probe,
++              .inband_caps = m88e1111_inband_caps,
+               .config_init = m88e1111gbe_config_init,
+               .config_aneg = m88e1111_config_aneg,
+               .read_status = marvell_read_status,
diff --git a/target/linux/generic/backport-6.12/601-07-v6.14-net-phy-add-phy_config_inband.patch b/target/linux/generic/backport-6.12/601-07-v6.14-net-phy-add-phy_config_inband.patch
new file mode 100644 (file)
index 0000000..99f11fe
--- /dev/null
@@ -0,0 +1,79 @@
+From 5d58a890c02770ba8d790b1f3c6e8c0e20514dc2 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:18 +0000
+Subject: [PATCH 07/13] net: phy: add phy_config_inband()
+
+Add a method to configure the PHY's in-band mode.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUru-006IUI-08@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phy.c | 32 ++++++++++++++++++++++++++++++++
+ include/linux/phy.h   |  6 ++++++
+ 2 files changed, 38 insertions(+)
+
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -1070,6 +1070,38 @@ unsigned int phy_inband_caps(struct phy_
+ EXPORT_SYMBOL_GPL(phy_inband_caps);
+ /**
++ * phy_config_inband - configure the desired PHY in-band mode
++ * @phydev: the phy_device struct
++ * @modes: in-band modes to configure
++ *
++ * Description: disables, enables or enables-with-bypass in-band signalling
++ *   between the PHY and host system.
++ *
++ * Returns: zero on success, or negative errno value.
++ */
++int phy_config_inband(struct phy_device *phydev, unsigned int modes)
++{
++      int err;
++
++      if (!!(modes & LINK_INBAND_DISABLE) +
++          !!(modes & LINK_INBAND_ENABLE) +
++          !!(modes & LINK_INBAND_BYPASS) != 1)
++              return -EINVAL;
++
++      mutex_lock(&phydev->lock);
++      if (!phydev->drv)
++              err = -EIO;
++      else if (!phydev->drv->config_inband)
++              err = -EOPNOTSUPP;
++      else
++              err = phydev->drv->config_inband(phydev, modes);
++      mutex_unlock(&phydev->lock);
++
++      return err;
++}
++EXPORT_SYMBOL(phy_config_inband);
++
++/**
+  * _phy_start_aneg - start auto-negotiation for this PHY device
+  * @phydev: the phy_device struct
+  *
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -980,6 +980,11 @@ struct phy_driver {
+                                   phy_interface_t interface);
+       /**
++       * @config_inband: configure in-band mode for the PHY
++       */
++      int (*config_inband)(struct phy_device *phydev, unsigned int modes);
++
++      /**
+        * @get_rate_matching: Get the supported type of rate matching for a
+        * particular phy interface. This is used by phy consumers to determine
+        * whether to advertise lower-speed modes for that interface. It is
+@@ -1860,6 +1865,7 @@ int phy_start_aneg(struct phy_device *ph
+ int phy_aneg_done(struct phy_device *phydev);
+ unsigned int phy_inband_caps(struct phy_device *phydev,
+                            phy_interface_t interface);
++int phy_config_inband(struct phy_device *phydev, unsigned int modes);
+ int phy_speed_down(struct phy_device *phydev, bool sync);
+ int phy_speed_up(struct phy_device *phydev);
+ bool phy_check_valid(int speed, int duplex, unsigned long *features);
diff --git a/target/linux/generic/backport-6.12/601-08-v6.14-net-phy-marvell-implement-config_inband-method.patch b/target/linux/generic/backport-6.12/601-08-v6.14-net-phy-marvell-implement-config_inband-method.patch
new file mode 100644 (file)
index 0000000..00788d4
--- /dev/null
@@ -0,0 +1,77 @@
+From a219912e0fec73c346e64ef47013cb2e152f88fc Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:23 +0000
+Subject: [PATCH 08/13] net: phy: marvell: implement config_inband() method
+
+Implement the config_inband() method for Marvell 88E1112, 88E1111,
+and Finisar's 88E1111 variant.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUrz-006IUO-3r@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/marvell.c | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+--- a/drivers/net/phy/marvell.c
++++ b/drivers/net/phy/marvell.c
+@@ -730,6 +730,34 @@ static unsigned int m88e1111_inband_caps
+       return 0;
+ }
++static int m88e1111_config_inband(struct phy_device *phydev, unsigned int modes)
++{
++      u16 extsr, bmcr;
++      int err;
++
++      if (phydev->interface != PHY_INTERFACE_MODE_1000BASEX &&
++          phydev->interface != PHY_INTERFACE_MODE_SGMII)
++              return -EINVAL;
++
++      if (modes == LINK_INBAND_BYPASS)
++              extsr = MII_M1111_HWCFG_SERIAL_AN_BYPASS;
++      else
++              extsr = 0;
++
++      if (modes == LINK_INBAND_DISABLE)
++              bmcr = 0;
++      else
++              bmcr = BMCR_ANENABLE;
++
++      err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,
++                       MII_M1111_HWCFG_SERIAL_AN_BYPASS, extsr);
++      if (err < 0)
++              return extsr;
++
++      return phy_modify_paged(phydev, MII_MARVELL_FIBER_PAGE, MII_BMCR,
++                              BMCR_ANENABLE, bmcr);
++}
++
+ static int m88e1111_config_aneg(struct phy_device *phydev)
+ {
+       int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+@@ -3682,6 +3710,7 @@ static struct phy_driver marvell_drivers
+               /* PHY_GBIT_FEATURES */
+               .probe = marvell_probe,
+               .inband_caps = m88e1111_inband_caps,
++              .config_inband = m88e1111_config_inband,
+               .config_init = m88e1112_config_init,
+               .config_aneg = marvell_config_aneg,
+               .config_intr = marvell_config_intr,
+@@ -3704,6 +3733,7 @@ static struct phy_driver marvell_drivers
+               .flags = PHY_POLL_CABLE_TEST,
+               .probe = marvell_probe,
+               .inband_caps = m88e1111_inband_caps,
++              .config_inband = m88e1111_config_inband,
+               .config_init = m88e1111gbe_config_init,
+               .config_aneg = m88e1111_config_aneg,
+               .read_status = marvell_read_status,
+@@ -3728,6 +3758,7 @@ static struct phy_driver marvell_drivers
+               /* PHY_GBIT_FEATURES */
+               .probe = marvell_probe,
+               .inband_caps = m88e1111_inband_caps,
++              .config_inband = m88e1111_config_inband,
+               .config_init = m88e1111gbe_config_init,
+               .config_aneg = m88e1111_config_aneg,
+               .read_status = marvell_read_status,
diff --git a/target/linux/generic/backport-6.12/601-09-v6.14-net-phylink-add-pcs_inband_caps-method.patch b/target/linux/generic/backport-6.12/601-09-v6.14-net-phylink-add-pcs_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..4228024
--- /dev/null
@@ -0,0 +1,159 @@
+From df874f9e52c340cc6f0a0014a97b778f67d46849 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:28 +0000
+Subject: [PATCH 09/13] net: phylink: add pcs_inband_caps() method
+
+Add a pcs_inband_caps() method to query the PCS for its inband link
+capabilities, and use this to determine whether link modes used with
+optical SFPs can be supported.
+
+When a PCS does not provide a method, we allow inband negotiation to
+be either on or off, making this a no-op until the pcs_inband_caps()
+method is implemented by a PCS driver.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUs4-006IUU-7K@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 60 +++++++++++++++++++++++++++++++++++++++
+ include/linux/phylink.h   | 17 +++++++++++
+ 2 files changed, 77 insertions(+)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1007,6 +1007,15 @@ static void phylink_resolve_an_pause(str
+       }
+ }
++static unsigned int phylink_pcs_inband_caps(struct phylink_pcs *pcs,
++                                  phy_interface_t interface)
++{
++      if (pcs && pcs->ops->pcs_inband_caps)
++              return pcs->ops->pcs_inband_caps(pcs, interface);
++
++      return 0;
++}
++
+ static void phylink_pcs_pre_config(struct phylink_pcs *pcs,
+                                  phy_interface_t interface)
+ {
+@@ -1060,6 +1069,24 @@ static void phylink_pcs_link_up(struct p
+               pcs->ops->pcs_link_up(pcs, neg_mode, interface, speed, duplex);
+ }
++/* Query inband for a specific interface mode, asking the MAC for the
++ * PCS which will be used to handle the interface mode.
++ */
++static unsigned int phylink_inband_caps(struct phylink *pl,
++                                       phy_interface_t interface)
++{
++      struct phylink_pcs *pcs;
++
++      if (!pl->mac_ops->mac_select_pcs)
++              return 0;
++
++      pcs = pl->mac_ops->mac_select_pcs(pl->config, interface);
++      if (!pcs)
++              return 0;
++
++      return phylink_pcs_inband_caps(pcs, interface);
++}
++
+ static void phylink_pcs_poll_stop(struct phylink *pl)
+ {
+       if (pl->cfg_link_an_mode == MLO_AN_INBAND)
+@@ -2530,6 +2557,26 @@ int phylink_ethtool_ksettings_get(struct
+ }
+ EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get);
++static bool phylink_validate_pcs_inband_autoneg(struct phylink *pl,
++                                              phy_interface_t interface,
++                                              unsigned long *adv)
++{
++      unsigned int inband = phylink_inband_caps(pl, interface);
++      unsigned int mask;
++
++      /* If the PCS doesn't implement inband support, be permissive. */
++      if (!inband)
++              return true;
++
++      if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, adv))
++              mask = LINK_INBAND_ENABLE;
++      else
++              mask = LINK_INBAND_DISABLE;
++
++      /* Check whether the PCS implements the required mode */
++      return !!(inband & mask);
++}
++
+ /**
+  * phylink_ethtool_ksettings_set() - set the link settings
+  * @pl: a pointer to a &struct phylink returned from phylink_create()
+@@ -2665,6 +2712,13 @@ int phylink_ethtool_ksettings_set(struct
+           phylink_is_empty_linkmode(config.advertising))
+               return -EINVAL;
++      /* Validate the autonegotiation state. We don't have a PHY in this
++       * situation, so the PCS is the media-facing entity.
++       */
++      if (!phylink_validate_pcs_inband_autoneg(pl, config.interface,
++                                               config.advertising))
++              return -EINVAL;
++
+       mutex_lock(&pl->state_mutex);
+       pl->link_config.speed = config.speed;
+       pl->link_config.duplex = config.duplex;
+@@ -3349,6 +3403,12 @@ static int phylink_sfp_config_optical(st
+       phylink_dbg(pl, "optical SFP: chosen %s interface\n",
+                   phy_modes(interface));
++      if (!phylink_validate_pcs_inband_autoneg(pl, interface,
++                                               config.advertising)) {
++              phylink_err(pl, "autoneg setting not compatible with PCS");
++              return -EINVAL;
++      }
++
+       config.interface = interface;
+       /* Ignore errors if we're expecting a PHY to attach later */
+--- a/include/linux/phylink.h
++++ b/include/linux/phylink.h
+@@ -419,6 +419,7 @@ struct phylink_pcs {
+ /**
+  * struct phylink_pcs_ops - MAC PCS operations structure.
+  * @pcs_validate: validate the link configuration.
++ * @pcs_inband_caps: query inband support for interface mode.
+  * @pcs_enable: enable the PCS.
+  * @pcs_disable: disable the PCS.
+  * @pcs_pre_config: pre-mac_config method (for errata)
+@@ -434,6 +435,8 @@ struct phylink_pcs {
+ struct phylink_pcs_ops {
+       int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
+                           const struct phylink_link_state *state);
++      unsigned int (*pcs_inband_caps)(struct phylink_pcs *pcs,
++                                      phy_interface_t interface);
+       int (*pcs_enable)(struct phylink_pcs *pcs);
+       void (*pcs_disable)(struct phylink_pcs *pcs);
+       void (*pcs_pre_config)(struct phylink_pcs *pcs,
+@@ -471,6 +474,20 @@ int pcs_validate(struct phylink_pcs *pcs
+                const struct phylink_link_state *state);
+ /**
++ * pcs_inband_caps - query PCS in-band capabilities for interface mode.
++ * @pcs: a pointer to a &struct phylink_pcs.
++ * @interface: interface mode to be queried
++ *
++ * Returns zero if it is unknown what in-band signalling is supported by the
++ * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise,
++ * returns a bit mask of the LINK_INBAND_* values from
++ * &enum link_inband_signalling to describe which inband modes are supported
++ * for this interface mode.
++ */
++unsigned int pcs_inband_caps(struct phylink_pcs *pcs,
++                           phy_interface_t interface);
++
++/**
+  * pcs_enable() - enable the PCS.
+  * @pcs: a pointer to a &struct phylink_pcs.
+  */
diff --git a/target/linux/generic/backport-6.12/601-10-v6.14-net-mvneta-implement-pcs_inband_caps-method.patch b/target/linux/generic/backport-6.12/601-10-v6.14-net-mvneta-implement-pcs_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..0937ad1
--- /dev/null
@@ -0,0 +1,64 @@
+From 513e8fb8fa32035b3325e2e14fb9598f8cb545e9 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:33 +0000
+Subject: [PATCH 10/13] net: mvneta: implement pcs_inband_caps() method
+
+Report the PCS in-band capabilities to phylink for Marvell NETA
+interfaces.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUs9-006IUb-Au@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/ethernet/marvell/mvneta.c | 27 +++++++++++++++++----------
+ 1 file changed, 17 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -3960,20 +3960,27 @@ static struct mvneta_port *mvneta_pcs_to
+       return container_of(pcs, struct mvneta_port, phylink_pcs);
+ }
+-static int mvneta_pcs_validate(struct phylink_pcs *pcs,
+-                             unsigned long *supported,
+-                             const struct phylink_link_state *state)
++static unsigned int mvneta_pcs_inband_caps(struct phylink_pcs *pcs,
++                                         phy_interface_t interface)
+ {
+-      /* We only support QSGMII, SGMII, 802.3z and RGMII modes.
+-       * When in 802.3z mode, we must have AN enabled:
++      /* When operating in an 802.3z mode, we must have AN enabled:
+        * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ...
+        * When <PortType> = 1 (1000BASE-X) this field must be set to 1."
++       * Therefore, inband is "required".
+        */
+-      if (phy_interface_mode_is_8023z(state->interface) &&
+-          !phylink_test(state->advertising, Autoneg))
+-              return -EINVAL;
++      if (phy_interface_mode_is_8023z(interface))
++              return LINK_INBAND_ENABLE;
+-      return 0;
++      /* QSGMII, SGMII and RGMII can be configured to use inband
++       * signalling of the AN result. Indicate these as "possible".
++       */
++      if (interface == PHY_INTERFACE_MODE_SGMII ||
++          interface == PHY_INTERFACE_MODE_QSGMII ||
++          phy_interface_mode_is_rgmii(interface))
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++
++      /* For any other modes, indicate that inband is not supported. */
++      return LINK_INBAND_DISABLE;
+ }
+ static void mvneta_pcs_get_state(struct phylink_pcs *pcs,
+@@ -4071,7 +4078,7 @@ static void mvneta_pcs_an_restart(struct
+ }
+ static const struct phylink_pcs_ops mvneta_phylink_pcs_ops = {
+-      .pcs_validate = mvneta_pcs_validate,
++      .pcs_inband_caps = mvneta_pcs_inband_caps,
+       .pcs_get_state = mvneta_pcs_get_state,
+       .pcs_config = mvneta_pcs_config,
+       .pcs_an_restart = mvneta_pcs_an_restart,
diff --git a/target/linux/generic/backport-6.12/601-11-v6.14-net-mvpp2-implement-pcs_inband_caps-method.patch b/target/linux/generic/backport-6.12/601-11-v6.14-net-mvpp2-implement-pcs_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..846d9df
--- /dev/null
@@ -0,0 +1,62 @@
+From d4169f0c7665afb8d8adb5e1b1df3db88517d0ad Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:38 +0000
+Subject: [PATCH 11/13] net: mvpp2: implement pcs_inband_caps() method
+
+Report the PCS in-band capabilities to phylink for Marvell PP2
+interfaces.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUsE-006IUh-E7@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ .../net/ethernet/marvell/mvpp2/mvpp2_main.c   | 25 ++++++++++++-------
+ 1 file changed, 16 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+@@ -6237,19 +6237,26 @@ static const struct phylink_pcs_ops mvpp
+       .pcs_config = mvpp2_xlg_pcs_config,
+ };
+-static int mvpp2_gmac_pcs_validate(struct phylink_pcs *pcs,
+-                                 unsigned long *supported,
+-                                 const struct phylink_link_state *state)
++static unsigned int mvpp2_gmac_pcs_inband_caps(struct phylink_pcs *pcs,
++                                             phy_interface_t interface)
+ {
+-      /* When in 802.3z mode, we must have AN enabled:
++      /* When operating in an 802.3z mode, we must have AN enabled:
+        * Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ...
+        * When <PortType> = 1 (1000BASE-X) this field must be set to 1.
++       * Therefore, inband is "required".
+        */
+-      if (phy_interface_mode_is_8023z(state->interface) &&
+-          !phylink_test(state->advertising, Autoneg))
+-              return -EINVAL;
++      if (phy_interface_mode_is_8023z(interface))
++              return LINK_INBAND_ENABLE;
+-      return 0;
++      /* SGMII and RGMII can be configured to use inband signalling of the
++       * AN result. Indicate these as "possible".
++       */
++      if (interface == PHY_INTERFACE_MODE_SGMII ||
++          phy_interface_mode_is_rgmii(interface))
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++
++      /* For any other modes, indicate that inband is not supported. */
++      return LINK_INBAND_DISABLE;
+ }
+ static void mvpp2_gmac_pcs_get_state(struct phylink_pcs *pcs,
+@@ -6356,7 +6363,7 @@ static void mvpp2_gmac_pcs_an_restart(st
+ }
+ static const struct phylink_pcs_ops mvpp2_phylink_gmac_pcs_ops = {
+-      .pcs_validate = mvpp2_gmac_pcs_validate,
++      .pcs_inband_caps = mvpp2_gmac_pcs_inband_caps,
+       .pcs_get_state = mvpp2_gmac_pcs_get_state,
+       .pcs_config = mvpp2_gmac_pcs_config,
+       .pcs_an_restart = mvpp2_gmac_pcs_an_restart,
diff --git a/target/linux/generic/backport-6.12/601-12-v6.14-net-phylink-add-negotiation-of-in-band-capabilities.patch b/target/linux/generic/backport-6.12/601-12-v6.14-net-phylink-add-negotiation-of-in-band-capabilities.patch
new file mode 100644 (file)
index 0000000..f629133
--- /dev/null
@@ -0,0 +1,228 @@
+From 5fd0f1a02e750e2db4038dee60edea669ce5aab1 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:43 +0000
+Subject: [PATCH 12/13] net: phylink: add negotiation of in-band capabilities
+
+Support for in-band signalling with Serdes links is uncertain. Some
+PHYs do not support in-band for e.g. SGMII. Some PCS do not support
+in-band for 2500Base-X. Some PCS require in-band for Base-X protocols.
+
+Simply using what is in DT is insufficient when we have hot-pluggable
+PHYs e.g. in the form of SFP modules, which may not provide the
+in-band signalling.
+
+In order to address this, we have introduced phy_inband_caps() and
+pcs_inband_caps() functions to allow phylink to retrieve the
+capabilities from each end of the PCS/PHY link. This commit adds code
+to resolve whether in-band will be used in the various scenarios that
+we have: In-band not being used, PHY present using SGMII or Base-X,
+PHY not present. We also deal with no capabilties provided.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUsJ-006IUn-H3@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 154 +++++++++++++++++++++++++++++++++++---
+ 1 file changed, 144 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -75,6 +75,7 @@ struct phylink {
+       struct mutex state_mutex;
+       struct phylink_link_state phy_state;
++      unsigned int phy_ib_mode;
+       struct work_struct resolve;
+       unsigned int pcs_neg_mode;
+       unsigned int pcs_state;
+@@ -1170,10 +1171,18 @@ static void phylink_pcs_neg_mode(struct
+                                phy_interface_t interface,
+                                const unsigned long *advertising)
+ {
++      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;
++      pl->phy_ib_mode = 0;
++
+       switch (interface) {
+       case PHY_INTERFACE_MODE_SGMII:
+       case PHY_INTERFACE_MODE_QSGMII:
+@@ -1185,10 +1194,7 @@ static void phylink_pcs_neg_mode(struct
+                * inband communication. Note: there exist PHYs that run
+                * with SGMII but do not send the inband data.
+                */
+-              if (!phylink_autoneg_inband(mode))
+-                      neg_mode = PHYLINK_PCS_NEG_OUTBAND;
+-              else
+-                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
++              type = INBAND_CISCO_SGMII;
+               break;
+       case PHY_INTERFACE_MODE_1000BASEX:
+@@ -1199,18 +1205,139 @@ static void phylink_pcs_neg_mode(struct
+                * as well, but drivers may not support this, so may
+                * need to override this.
+                */
+-              if (!phylink_autoneg_inband(mode))
++              type = INBAND_BASEX;
++              break;
++
++      default:
++              pl->pcs_neg_mode = PHYLINK_PCS_NEG_NONE;
++              pl->act_link_an_mode = mode;
++              return;
++      }
++
++      if (pcs)
++              pcs_ib_caps = phylink_pcs_inband_caps(pcs, interface);
++
++      if (pl->phydev)
++              phy_ib_caps = phy_inband_caps(pl->phydev, interface);
++
++      phylink_dbg(pl, "interface %s inband modes: pcs=%02x phy=%02x\n",
++                  phy_modes(interface), pcs_ib_caps, phy_ib_caps);
++
++      if (!phylink_autoneg_inband(mode)) {
++              bool pcs_ib_only = false;
++              bool phy_ib_only = false;
++
++              if (pcs_ib_caps && pcs_ib_caps != LINK_INBAND_DISABLE) {
++                      /* PCS supports reporting in-band capabilities, and
++                       * supports more than disable mode.
++                       */
++                      if (pcs_ib_caps & LINK_INBAND_DISABLE)
++                              neg_mode = PHYLINK_PCS_NEG_OUTBAND;
++                      else if (pcs_ib_caps & LINK_INBAND_ENABLE)
++                              pcs_ib_only = true;
++              }
++
++              if (phy_ib_caps && phy_ib_caps != LINK_INBAND_DISABLE) {
++                      /* PHY supports in-band capabilities, and supports
++                       * more than disable mode.
++                       */
++                      if (phy_ib_caps & LINK_INBAND_DISABLE)
++                              pl->phy_ib_mode = LINK_INBAND_DISABLE;
++                      else if (phy_ib_caps & LINK_INBAND_BYPASS)
++                              pl->phy_ib_mode = LINK_INBAND_BYPASS;
++                      else if (phy_ib_caps & LINK_INBAND_ENABLE)
++                              phy_ib_only = true;
++              }
++
++              /* If either the PCS or PHY requires inband to be enabled,
++               * this is an invalid configuration. Provide a diagnostic
++               * message for this case, but don't try to force the issue.
++               */
++              if (pcs_ib_only || phy_ib_only)
++                      phylink_warn(pl,
++                                   "firmware wants %s mode, but %s%s%s requires inband\n",
++                                   phylink_an_mode_str(mode),
++                                   pcs_ib_only ? "PCS" : "",
++                                   pcs_ib_only && phy_ib_only ? " and " : "",
++                                   phy_ib_only ? "PHY" : "");
++
++              neg_mode = PHYLINK_PCS_NEG_OUTBAND;
++      } else if (type == INBAND_CISCO_SGMII || pl->phydev) {
++              /* For SGMII modes which are designed to be used with PHYs, or
++               * Base-X with a PHY, we try to use in-band mode where-ever
++               * possible. However, there are some PHYs e.g. BCM84881 which
++               * do not support in-band.
++               */
++              const unsigned int inband_ok = LINK_INBAND_ENABLE |
++                                             LINK_INBAND_BYPASS;
++              const unsigned int outband_ok = LINK_INBAND_DISABLE |
++                                              LINK_INBAND_BYPASS;
++              /* PCS  PHY
++               * D E  D E
++               * 0 0  0 0     no information                  inband enabled
++               * 1 0  0 0     pcs doesn't support             outband
++               * 0 1  0 0     pcs required                    inband enabled
++               * 1 1  0 0     pcs optional                    inband enabled
++               * 0 0  1 0     phy doesn't support             outband
++               * 1 0  1 0     pcs+phy doesn't support         outband
++               * 0 1  1 0     pcs required, phy doesn't support, invalid
++               * 1 1  1 0     pcs optional, phy doesn't support, outband
++               * 0 0  0 1     phy required                    inband enabled
++               * 1 0  0 1     pcs doesn't support, phy required, invalid
++               * 0 1  0 1     pcs+phy required                inband enabled
++               * 1 1  0 1     pcs optional, phy required      inband enabled
++               * 0 0  1 1     phy optional                    inband enabled
++               * 1 0  1 1     pcs doesn't support, phy optional, outband
++               * 0 1  1 1     pcs required, phy optional      inband enabled
++               * 1 1  1 1     pcs+phy optional                inband enabled
++               */
++              if ((!pcs_ib_caps || pcs_ib_caps & inband_ok) &&
++                  (!phy_ib_caps || phy_ib_caps & inband_ok)) {
++                      /* In-band supported or unknown at both ends. Enable
++                       * in-band mode with or without bypass at the PHY.
++                       */
++                      if (phy_ib_caps & LINK_INBAND_ENABLE)
++                              pl->phy_ib_mode = LINK_INBAND_ENABLE;
++                      else if (phy_ib_caps & LINK_INBAND_BYPASS)
++                              pl->phy_ib_mode = LINK_INBAND_BYPASS;
++
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
++              } else if ((!pcs_ib_caps || pcs_ib_caps & outband_ok) &&
++                         (!phy_ib_caps || phy_ib_caps & outband_ok)) {
++                      /* Either in-band not supported at at least one end.
++                       * In-band bypass at the other end is possible.
++                       */
++                      if (phy_ib_caps & LINK_INBAND_DISABLE)
++                              pl->phy_ib_mode = LINK_INBAND_DISABLE;
++                      else if (phy_ib_caps & LINK_INBAND_BYPASS)
++                              pl->phy_ib_mode = LINK_INBAND_BYPASS;
++
+                       neg_mode = PHYLINK_PCS_NEG_OUTBAND;
++                      if (pl->phydev)
++                              mode = MLO_AN_PHY;
++              } else {
++                      /* invalid */
++                      phylink_warn(pl, "%s: incompatible in-band capabilities, trying in-band",
++                                   phy_modes(interface));
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
++              }
++      } else {
++              /* For Base-X without a PHY */
++              if (pcs_ib_caps == LINK_INBAND_DISABLE)
++                      /* If the PCS doesn't support inband, then inband must
++                       * be disabled.
++                       */
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
++              else if (pcs_ib_caps == LINK_INBAND_ENABLE)
++                      /* If the PCS requires inband, then inband must always
++                       * be enabled.
++                       */
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
+               else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+                                          advertising))
+                       neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
+               else
+                       neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
+-              break;
+-
+-      default:
+-              neg_mode = PHYLINK_PCS_NEG_NONE;
+-              break;
+       }
+       pl->pcs_neg_mode = neg_mode;
+@@ -1309,6 +1436,13 @@ static void phylink_major_config(struct
+                                   ERR_PTR(err));
+       }
++      if (pl->phydev && pl->phy_ib_mode) {
++              err = phy_config_inband(pl->phydev, pl->phy_ib_mode);
++              if (err < 0)
++                      phylink_err(pl, "phy_config_inband: %pe\n",
++                                  ERR_PTR(err));
++      }
++
+       if (pl->sfp_bus) {
+               rate_kbd = phylink_interface_signal_rate(state->interface);
+               if (rate_kbd)
diff --git a/target/linux/generic/backport-6.12/601-13-v6.14-net-phylink-remove-phylink_phy_no_inband.patch b/target/linux/generic/backport-6.12/601-13-v6.14-net-phylink-remove-phylink_phy_no_inband.patch
new file mode 100644 (file)
index 0000000..8be74a2
--- /dev/null
@@ -0,0 +1,110 @@
+From 77ac9a8b2536e0eaca6c6f21070068458bf55981 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:48 +0000
+Subject: [PATCH 13/13] net: phylink: remove phylink_phy_no_inband()
+
+Remove phylink_phy_no_inband() now that we are handling the lack of
+inband negotiation by querying the capabilities of the PHY and PCS,
+and the BCM84881 PHY driver provides us the information necessary to
+make the decision.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUsO-006IUt-KN@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 27 ++++++---------------------
+ 1 file changed, 6 insertions(+), 21 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -3394,10 +3394,11 @@ static phy_interface_t phylink_choose_sf
+       return interface;
+ }
+-static void phylink_sfp_set_config(struct phylink *pl, u8 mode,
++static void phylink_sfp_set_config(struct phylink *pl,
+                                  unsigned long *supported,
+                                  struct phylink_link_state *state)
+ {
++      u8 mode = MLO_AN_INBAND;
+       bool changed = false;
+       phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
+@@ -3431,8 +3432,7 @@ static void phylink_sfp_set_config(struc
+               phylink_mac_initial_config(pl, false);
+ }
+-static int phylink_sfp_config_phy(struct phylink *pl, u8 mode,
+-                                struct phy_device *phy)
++static int phylink_sfp_config_phy(struct phylink *pl, struct phy_device *phy)
+ {
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(support);
+@@ -3472,7 +3472,7 @@ static int phylink_sfp_config_phy(struct
+       if (ret) {
+               phylink_err(pl,
+                           "validation of %s/%s with support %*pb failed: %pe\n",
+-                          phylink_an_mode_str(mode),
++                          phylink_an_mode_str(pl->req_link_an_mode),
+                           phy_modes(config.interface),
+                           __ETHTOOL_LINK_MODE_MASK_NBITS, support,
+                           ERR_PTR(ret));
+@@ -3481,7 +3481,7 @@ static int phylink_sfp_config_phy(struct
+       pl->link_port = pl->sfp_port;
+-      phylink_sfp_set_config(pl, mode, support, &config);
++      phylink_sfp_set_config(pl, support, &config);
+       return 0;
+ }
+@@ -3556,7 +3556,7 @@ static int phylink_sfp_config_optical(st
+       pl->link_port = pl->sfp_port;
+-      phylink_sfp_set_config(pl, MLO_AN_INBAND, pl->sfp_support, &config);
++      phylink_sfp_set_config(pl, pl->sfp_support, &config);
+       return 0;
+ }
+@@ -3627,20 +3627,10 @@ static void phylink_sfp_link_up(void *up
+       phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_LINK);
+ }
+-/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
+- * or 802.3z control word, so inband will not work.
+- */
+-static bool phylink_phy_no_inband(struct phy_device *phy)
+-{
+-      return phy->is_c45 && phy_id_compare(phy->c45_ids.device_ids[1],
+-                                           0xae025150, 0xfffffff0);
+-}
+-
+ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
+ {
+       struct phylink *pl = upstream;
+       phy_interface_t interface;
+-      u8 mode;
+       int ret;
+       /*
+@@ -3652,17 +3642,12 @@ static int phylink_sfp_connect_phy(void
+        */
+       phy_support_asym_pause(phy);
+-      if (phylink_phy_no_inband(phy))
+-              mode = MLO_AN_PHY;
+-      else
+-              mode = MLO_AN_INBAND;
+-
+       /* Set the PHY's host supported interfaces */
+       phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces,
+                         pl->config->supported_interfaces);
+       /* Do the initial configuration */
+-      ret = phylink_sfp_config_phy(pl, mode, phy);
++      ret = phylink_sfp_config_phy(pl, phy);
+       if (ret < 0)
+               return ret;
diff --git a/target/linux/generic/backport-6.12/602-01-v6.14-net-pcs-pcs-lynx-implement-pcs_inband_caps-method.patch b/target/linux/generic/backport-6.12/602-01-v6.14-net-pcs-pcs-lynx-implement-pcs_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..32ba605
--- /dev/null
@@ -0,0 +1,53 @@
+From 6561f0e547be221f411fda5eddfcc5bd8bb058a5 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Thu, 5 Dec 2024 09:42:24 +0000
+Subject: [PATCH 1/3] net: pcs: pcs-lynx: implement pcs_inband_caps() method
+
+Report the PCS in-band capabilities to phylink for the Lynx PCS.
+
+Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tJ8NM-006L5J-AH@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/pcs/pcs-lynx.c | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+--- a/drivers/net/pcs/pcs-lynx.c
++++ b/drivers/net/pcs/pcs-lynx.c
+@@ -35,6 +35,27 @@ enum sgmii_speed {
+ #define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs)
+ #define lynx_to_phylink_pcs(lynx) (&(lynx)->pcs)
++static unsigned int lynx_pcs_inband_caps(struct phylink_pcs *pcs,
++                                       phy_interface_t interface)
++{
++      switch (interface) {
++      case PHY_INTERFACE_MODE_1000BASEX:
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_QSGMII:
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++
++      case PHY_INTERFACE_MODE_10GBASER:
++      case PHY_INTERFACE_MODE_2500BASEX:
++              return LINK_INBAND_DISABLE;
++
++      case PHY_INTERFACE_MODE_USXGMII:
++              return LINK_INBAND_ENABLE;
++
++      default:
++              return 0;
++      }
++}
++
+ static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs,
+                                      struct phylink_link_state *state)
+ {
+@@ -306,6 +327,7 @@ static void lynx_pcs_link_up(struct phyl
+ }
+ static const struct phylink_pcs_ops lynx_pcs_phylink_ops = {
++      .pcs_inband_caps = lynx_pcs_inband_caps,
+       .pcs_get_state = lynx_pcs_get_state,
+       .pcs_config = lynx_pcs_config,
+       .pcs_an_restart = lynx_pcs_an_restart,
diff --git a/target/linux/generic/backport-6.12/602-02-v6.14-net-pcs-pcs-mtk-lynxi-implement-pcs_inband_caps-meth.patch b/target/linux/generic/backport-6.12/602-02-v6.14-net-pcs-pcs-mtk-lynxi-implement-pcs_inband_caps-meth.patch
new file mode 100644 (file)
index 0000000..1cfd3ba
--- /dev/null
@@ -0,0 +1,47 @@
+From 520d29bdda86915b3caf8c72825a574bff212553 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Thu, 5 Dec 2024 09:42:29 +0000
+Subject: [PATCH 2/3] net: pcs: pcs-mtk-lynxi: implement pcs_inband_caps()
+ method
+
+Report the PCS in-band capabilities to phylink for the LynxI PCS.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tJ8NR-006L5P-E3@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/pcs/pcs-mtk-lynxi.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/net/pcs/pcs-mtk-lynxi.c
++++ b/drivers/net/pcs/pcs-mtk-lynxi.c
+@@ -88,6 +88,21 @@ static struct mtk_pcs_lynxi *pcs_to_mtk_
+       return container_of(pcs, struct mtk_pcs_lynxi, pcs);
+ }
++static unsigned int mtk_pcs_lynxi_inband_caps(struct phylink_pcs *pcs,
++                                            phy_interface_t interface)
++{
++      switch (interface) {
++      case PHY_INTERFACE_MODE_1000BASEX:
++      case PHY_INTERFACE_MODE_2500BASEX:
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_QSGMII:
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++
++      default:
++              return 0;
++      }
++}
++
+ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs,
+                                   struct phylink_link_state *state)
+ {
+@@ -241,6 +256,7 @@ static void mtk_pcs_lynxi_disable(struct
+ }
+ static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = {
++      .pcs_inband_caps = mtk_pcs_lynxi_inband_caps,
+       .pcs_get_state = mtk_pcs_lynxi_get_state,
+       .pcs_config = mtk_pcs_lynxi_config,
+       .pcs_an_restart = mtk_pcs_lynxi_restart_an,
diff --git a/target/linux/generic/backport-6.12/602-03-v6.14-net-pcs-xpcs-implement-pcs_inband_caps-method.patch b/target/linux/generic/backport-6.12/602-03-v6.14-net-pcs-xpcs-implement-pcs_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..8dc495b
--- /dev/null
@@ -0,0 +1,58 @@
+From 484d0170d6c6bbb5213d037664e9a551f793bacd Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Thu, 5 Dec 2024 09:42:34 +0000
+Subject: [PATCH 3/3] net: pcs: xpcs: implement pcs_inband_caps() method
+
+Report the PCS inband capabilities to phylink for XPCS.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tJ8NW-006L5V-I9@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/pcs/pcs-xpcs.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/drivers/net/pcs/pcs-xpcs.c
++++ b/drivers/net/pcs/pcs-xpcs.c
+@@ -608,6 +608,33 @@ static int xpcs_validate(struct phylink_
+       return 0;
+ }
++static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs,
++                                   phy_interface_t interface)
++{
++      struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
++      const struct dw_xpcs_compat *compat;
++
++      compat = xpcs_find_compat(xpcs->desc, interface);
++      if (!compat)
++              return 0;
++
++      switch (compat->an_mode) {
++      case DW_AN_C73:
++              return LINK_INBAND_ENABLE;
++
++      case DW_AN_C37_SGMII:
++      case DW_AN_C37_1000BASEX:
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++
++      case DW_10GBASER:
++      case DW_2500BASEX:
++              return LINK_INBAND_DISABLE;
++
++      default:
++              return 0;
++      }
++}
++
+ void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces)
+ {
+       int i, j;
+@@ -1365,6 +1392,7 @@ static const struct dw_xpcs_desc xpcs_de
+ static const struct phylink_pcs_ops xpcs_phylink_ops = {
+       .pcs_validate = xpcs_validate,
++      .pcs_inband_caps = xpcs_inband_caps,
+       .pcs_config = xpcs_config,
+       .pcs_get_state = xpcs_get_state,
+       .pcs_an_restart = xpcs_an_restart,
index 6b85e59577ab72eb0bb9119fa905812b3ae1bcbd..3a6e0ac80a6ba4dd21ad54eaccd2608a1a8708bf 100644 (file)
@@ -194,7 +194,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
        { PHY_ID_BCM72165, 0xfffffff0, },
 --- a/drivers/net/phy/bcm84881.c
 +++ b/drivers/net/phy/bcm84881.c
-@@ -252,7 +252,7 @@ static struct phy_driver bcm84881_driver
+@@ -262,7 +262,7 @@ static struct phy_driver bcm84881_driver
  module_phy_driver(bcm84881_drivers);
  
  /* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */
@@ -403,7 +403,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  };
 --- a/drivers/net/phy/marvell.c
 +++ b/drivers/net/phy/marvell.c
-@@ -4133,7 +4133,7 @@ static struct phy_driver marvell_drivers
+@@ -4181,7 +4181,7 @@ static struct phy_driver marvell_drivers
  
  module_phy_driver(marvell_drivers);
  
index 9c317606e11373222cd3b0023ff73f5e6cebd73c..5563f3dce6797d1008f66b31adf7f451d0bd968b 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
-@@ -874,8 +874,9 @@ struct phy_plca_status {
+@@ -892,8 +892,9 @@ struct phy_plca_status {
  
  /* Modes for PHY LED configuration */
  enum phy_led_modes {
index cda52269042b1f4cd627c8d5451a9ada8df0b512..d2b20cc8a52a883887dca0befbf9ff2d4375cce5 100644 (file)
@@ -281,7 +281,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  }
 --- a/include/linux/phy.h
 +++ b/include/linux/phy.h
-@@ -1004,7 +1004,8 @@ struct phy_driver {
+@@ -1035,7 +1035,8 @@ struct phy_driver {
         * driver for the given phydev.  If NULL, matching is based on
         * phy_id and phy_id_mask.
         */
index 9e28011b0cc3e65f1c6cb6cc6bf07293dd672b31..dd24ba23700b3c8e79bc6e08e1dd6a9a1a26b208 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
-@@ -1906,6 +1906,9 @@ char *phy_attached_info_irq(struct phy_d
+@@ -1940,6 +1940,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.6/604-01-v6.13-net-phylink-move-manual-flow-control-setting.patch b/target/linux/generic/backport-6.6/604-01-v6.13-net-phylink-move-manual-flow-control-setting.patch
new file mode 100644 (file)
index 0000000..7de4f58
--- /dev/null
@@ -0,0 +1,41 @@
+From 8cc5f4cb94c0b1c7c1ba8013c14fd02ffb1a25f3 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2024 16:01:44 +0000
+Subject: [PATCH 1/5] net: phylink: move manual flow control setting
+
+Move the handling of manual flow control configuration to a common
+location during resolve. We currently evaluate this for all but
+fixed links.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1t9RQe-002Feh-T1@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1433,7 +1433,6 @@ static void phylink_resolve(struct work_
+               switch (pl->cur_link_an_mode) {
+               case MLO_AN_PHY:
+                       link_state = pl->phy_state;
+-                      phylink_apply_manual_flow(pl, &link_state);
+                       mac_config = link_state.link;
+                       break;
+@@ -1494,11 +1493,13 @@ static void phylink_resolve(struct work_
+                               link_state.pause = pl->phy_state.pause;
+                               mac_config = true;
+                       }
+-                      phylink_apply_manual_flow(pl, &link_state);
+                       break;
+               }
+       }
++      if (pl->cur_link_an_mode != MLO_AN_FIXED)
++              phylink_apply_manual_flow(pl, &link_state);
++
+       if (mac_config) {
+               if (link_state.interface != pl->link_config.interface) {
+                       /* The interface has changed, force the link down and
diff --git a/target/linux/generic/backport-6.6/604-02-v6.13-net-phylink-move-MLO_AN_FIXED-resolve-handling-to-if.patch b/target/linux/generic/backport-6.6/604-02-v6.13-net-phylink-move-MLO_AN_FIXED-resolve-handling-to-if.patch
new file mode 100644 (file)
index 0000000..d81ab2a
--- /dev/null
@@ -0,0 +1,42 @@
+From 92abfcb4ced482afbe65d18980e6734fe1e62a34 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2024 16:01:50 +0000
+Subject: [PATCH 2/5] net: phylink: move MLO_AN_FIXED resolve handling to if()
+ statement
+
+The switch() statement doesn't sit very well with the preceeding if()
+statements, and results in excessive indentation that spoils code
+readability. Begin cleaning this up by converting the MLO_AN_FIXED case
+to an if() statement.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1t9RQk-002Fen-1A@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1429,6 +1429,9 @@ static void phylink_resolve(struct work_
+       } else if (pl->mac_link_dropped) {
+               link_state.link = false;
+               retrigger = true;
++      } else if (pl->cur_link_an_mode == MLO_AN_FIXED) {
++              phylink_get_fixed_state(pl, &link_state);
++              mac_config = link_state.link;
+       } else {
+               switch (pl->cur_link_an_mode) {
+               case MLO_AN_PHY:
+@@ -1436,11 +1439,6 @@ static void phylink_resolve(struct work_
+                       mac_config = link_state.link;
+                       break;
+-              case MLO_AN_FIXED:
+-                      phylink_get_fixed_state(pl, &link_state);
+-                      mac_config = link_state.link;
+-                      break;
+-
+               case MLO_AN_INBAND:
+                       phylink_mac_pcs_get_state(pl, &link_state);
diff --git a/target/linux/generic/backport-6.6/604-03-v6.13-net-phylink-move-MLO_AN_PHY-resolve-handling-to-if-s.patch b/target/linux/generic/backport-6.6/604-03-v6.13-net-phylink-move-MLO_AN_PHY-resolve-handling-to-if-s.patch
new file mode 100644 (file)
index 0000000..269c50a
--- /dev/null
@@ -0,0 +1,37 @@
+From f0f46c2a3d8ea9d1427298c8103a777d9e616c29 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2024 16:01:55 +0000
+Subject: [PATCH 3/5] net: phylink: move MLO_AN_PHY resolve handling to if()
+ statement
+
+The switch() statement doesn't sit very well with the preceeding if()
+statements, and results in excessive indentation that spoils code
+readability. Continue cleaning this up by converting the MLO_AN_PHY
+case to use an if() statmeent.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1t9RQp-002Fet-5W@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1432,13 +1432,11 @@ static void phylink_resolve(struct work_
+       } else if (pl->cur_link_an_mode == MLO_AN_FIXED) {
+               phylink_get_fixed_state(pl, &link_state);
+               mac_config = link_state.link;
++      } else if (pl->cur_link_an_mode == MLO_AN_PHY) {
++              link_state = pl->phy_state;
++              mac_config = link_state.link;
+       } else {
+               switch (pl->cur_link_an_mode) {
+-              case MLO_AN_PHY:
+-                      link_state = pl->phy_state;
+-                      mac_config = link_state.link;
+-                      break;
+-
+               case MLO_AN_INBAND:
+                       phylink_mac_pcs_get_state(pl, &link_state);
diff --git a/target/linux/generic/backport-6.6/604-04-v6.13-net-phylink-remove-switch-statement-in-resolve-handl.patch b/target/linux/generic/backport-6.6/604-04-v6.13-net-phylink-remove-switch-statement-in-resolve-handl.patch
new file mode 100644 (file)
index 0000000..521da5f
--- /dev/null
@@ -0,0 +1,127 @@
+From d1a16dbbd84e02d2a6dcfcb8d5c4b8b2c0289f00 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2024 16:02:00 +0000
+Subject: [PATCH 4/5] net: phylink: remove switch() statement in resolve
+ handling
+
+The switch() statement doesn't sit very well with the preceeding if()
+statements, so let's just convert everything to if()s. As a result of
+the two preceding commits, there is now only one case in the switch()
+statement. Remove the switch statement and reduce the code indentation.
+Code reformatting will be in the following commit.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1t9RQu-002Fez-AA@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 94 +++++++++++++++++++--------------------
+ 1 file changed, 45 insertions(+), 49 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1436,60 +1436,56 @@ static void phylink_resolve(struct work_
+               link_state = pl->phy_state;
+               mac_config = link_state.link;
+       } else {
+-              switch (pl->cur_link_an_mode) {
+-              case MLO_AN_INBAND:
+-                      phylink_mac_pcs_get_state(pl, &link_state);
+-
+-                      /* The PCS may have a latching link-fail indicator.
+-                       * If the link was up, bring the link down and
+-                       * re-trigger the resolve. Otherwise, re-read the
+-                       * PCS state to get the current status of the link.
++              phylink_mac_pcs_get_state(pl, &link_state);
++
++              /* The PCS may have a latching link-fail indicator.
++               * If the link was up, bring the link down and
++               * re-trigger the resolve. Otherwise, re-read the
++               * PCS state to get the current status of the link.
++               */
++              if (!link_state.link) {
++                      if (cur_link_state)
++                              retrigger = true;
++                      else
++                              phylink_mac_pcs_get_state(pl,
++                                                        &link_state);
++              }
++
++              /* If we have a phy, the "up" state is the union of
++               * both the PHY and the MAC
++               */
++              if (pl->phydev)
++                      link_state.link &= pl->phy_state.link;
++
++              /* Only update if the PHY link is up */
++              if (pl->phydev && pl->phy_state.link) {
++                      /* If the interface has changed, force a
++                       * link down event if the link isn't already
++                       * down, and re-resolve.
+                        */
+-                      if (!link_state.link) {
+-                              if (cur_link_state)
+-                                      retrigger = true;
+-                              else
+-                                      phylink_mac_pcs_get_state(pl,
+-                                                                &link_state);
++                      if (link_state.interface !=
++                          pl->phy_state.interface) {
++                              retrigger = true;
++                              link_state.link = false;
+                       }
++                      link_state.interface = pl->phy_state.interface;
+-                      /* If we have a phy, the "up" state is the union of
+-                       * both the PHY and the MAC
++                      /* If we are doing rate matching, then the
++                       * link speed/duplex comes from the PHY
+                        */
+-                      if (pl->phydev)
+-                              link_state.link &= pl->phy_state.link;
+-
+-                      /* Only update if the PHY link is up */
+-                      if (pl->phydev && pl->phy_state.link) {
+-                              /* If the interface has changed, force a
+-                               * link down event if the link isn't already
+-                               * down, and re-resolve.
+-                               */
+-                              if (link_state.interface !=
+-                                  pl->phy_state.interface) {
+-                                      retrigger = true;
+-                                      link_state.link = false;
+-                              }
+-                              link_state.interface = pl->phy_state.interface;
+-
+-                              /* If we are doing rate matching, then the
+-                               * link speed/duplex comes from the PHY
+-                               */
+-                              if (pl->phy_state.rate_matching) {
+-                                      link_state.rate_matching =
+-                                              pl->phy_state.rate_matching;
+-                                      link_state.speed = pl->phy_state.speed;
+-                                      link_state.duplex =
+-                                              pl->phy_state.duplex;
+-                              }
+-
+-                              /* If we have a PHY, we need to update with
+-                               * the PHY flow control bits.
+-                               */
+-                              link_state.pause = pl->phy_state.pause;
+-                              mac_config = true;
++                      if (pl->phy_state.rate_matching) {
++                              link_state.rate_matching =
++                                      pl->phy_state.rate_matching;
++                              link_state.speed = pl->phy_state.speed;
++                              link_state.duplex =
++                                      pl->phy_state.duplex;
+                       }
+-                      break;
++
++                      /* If we have a PHY, we need to update with
++                       * the PHY flow control bits.
++                       */
++                      link_state.pause = pl->phy_state.pause;
++                      mac_config = true;
+               }
+       }
diff --git a/target/linux/generic/backport-6.6/604-05-v6.13-net-phylink-clean-up-phylink_resolve.patch b/target/linux/generic/backport-6.6/604-05-v6.13-net-phylink-clean-up-phylink_resolve.patch
new file mode 100644 (file)
index 0000000..e5e2e16
--- /dev/null
@@ -0,0 +1,85 @@
+From bc08ce37d99a3992e975a0f397503cb23404f25a Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2024 16:02:05 +0000
+Subject: [PATCH 5/5] net: phylink: clean up phylink_resolve()
+
+Now that we have reduced the indentation level, clean up the code
+formatting.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1t9RQz-002Ff5-EA@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 35 ++++++++++++++++-------------------
+ 1 file changed, 16 insertions(+), 19 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1438,51 +1438,48 @@ static void phylink_resolve(struct work_
+       } else {
+               phylink_mac_pcs_get_state(pl, &link_state);
+-              /* The PCS may have a latching link-fail indicator.
+-               * If the link was up, bring the link down and
+-               * re-trigger the resolve. Otherwise, re-read the
+-               * PCS state to get the current status of the link.
++              /* The PCS may have a latching link-fail indicator. If the link
++               * was up, bring the link down and re-trigger the resolve.
++               * Otherwise, re-read the PCS state to get the current status
++               * of the link.
+                */
+               if (!link_state.link) {
+                       if (cur_link_state)
+                               retrigger = true;
+                       else
+-                              phylink_mac_pcs_get_state(pl,
+-                                                        &link_state);
++                              phylink_mac_pcs_get_state(pl, &link_state);
+               }
+-              /* If we have a phy, the "up" state is the union of
+-               * both the PHY and the MAC
++              /* If we have a phy, the "up" state is the union of both the
++               * PHY and the MAC
+                */
+               if (pl->phydev)
+                       link_state.link &= pl->phy_state.link;
+               /* Only update if the PHY link is up */
+               if (pl->phydev && pl->phy_state.link) {
+-                      /* If the interface has changed, force a
+-                       * link down event if the link isn't already
+-                       * down, and re-resolve.
++                      /* If the interface has changed, force a link down
++                       * event if the link isn't already down, and re-resolve.
+                        */
+-                      if (link_state.interface !=
+-                          pl->phy_state.interface) {
++                      if (link_state.interface != pl->phy_state.interface) {
+                               retrigger = true;
+                               link_state.link = false;
+                       }
++
+                       link_state.interface = pl->phy_state.interface;
+-                      /* If we are doing rate matching, then the
+-                       * link speed/duplex comes from the PHY
++                      /* If we are doing rate matching, then the link
++                       * speed/duplex comes from the PHY
+                        */
+                       if (pl->phy_state.rate_matching) {
+                               link_state.rate_matching =
+                                       pl->phy_state.rate_matching;
+                               link_state.speed = pl->phy_state.speed;
+-                              link_state.duplex =
+-                                      pl->phy_state.duplex;
++                              link_state.duplex = pl->phy_state.duplex;
+                       }
+-                      /* If we have a PHY, we need to update with
+-                       * the PHY flow control bits.
++                      /* If we have a PHY, we need to update with the PHY
++                       * flow control bits.
+                        */
+                       link_state.pause = pl->phy_state.pause;
+                       mac_config = true;
diff --git a/target/linux/generic/backport-6.6/605-v6.8-net-phylink-move-phylink_pcs_neg_mode-into-phylink.c.patch b/target/linux/generic/backport-6.6/605-v6.8-net-phylink-move-phylink_pcs_neg_mode-into-phylink.c.patch
new file mode 100644 (file)
index 0000000..42715ef
--- /dev/null
@@ -0,0 +1,166 @@
+From 5e5401d6612ef599ad45785b941eebda7effc90f Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Thu, 4 Jan 2024 09:47:36 +0000
+Subject: [PATCH] net: phylink: move phylink_pcs_neg_mode() into phylink.c
+
+Move phylink_pcs_neg_mode() from the header file into the .c file since
+nothing should be using it.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phylink.c | 66 +++++++++++++++++++++++++++++++++++++++
+ include/linux/phylink.h   | 66 ---------------------------------------
+ 2 files changed, 66 insertions(+), 66 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1116,6 +1116,72 @@ static void phylink_pcs_an_restart(struc
+               pl->pcs->ops->pcs_an_restart(pl->pcs);
+ }
++/**
++ * phylink_pcs_neg_mode() - helper to determine PCS inband mode
++ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
++ * @interface: interface mode to be used
++ * @advertising: adertisement ethtool link mode mask
++ *
++ * Determines the negotiation mode to be used by the PCS, and returns
++ * one of:
++ *
++ * - %PHYLINK_PCS_NEG_NONE: interface mode does not support inband
++ * - %PHYLINK_PCS_NEG_OUTBAND: an out of band mode (e.g. reading the PHY)
++ *   will be used.
++ * - %PHYLINK_PCS_NEG_INBAND_DISABLED: inband mode selected but autoneg
++ *   disabled
++ * - %PHYLINK_PCS_NEG_INBAND_ENABLED: inband mode selected and autoneg enabled
++ *
++ * Note: this is for cases where the PCS itself is involved in negotiation
++ * (e.g. Clause 37, SGMII and similar) not Clause 73.
++ */
++static unsigned int phylink_pcs_neg_mode(unsigned int mode,
++                                       phy_interface_t interface,
++                                       const unsigned long *advertising)
++{
++      unsigned int neg_mode;
++
++      switch (interface) {
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_QSGMII:
++      case PHY_INTERFACE_MODE_QUSGMII:
++      case PHY_INTERFACE_MODE_USXGMII:
++              /* 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.
++               */
++              if (!phylink_autoneg_inband(mode))
++                      neg_mode = PHYLINK_PCS_NEG_OUTBAND;
++              else
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
++              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.
++               */
++              if (!phylink_autoneg_inband(mode))
++                      neg_mode = PHYLINK_PCS_NEG_OUTBAND;
++              else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
++                                         advertising))
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
++              else
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
++              break;
++
++      default:
++              neg_mode = PHYLINK_PCS_NEG_NONE;
++              break;
++      }
++
++      return neg_mode;
++}
++
+ static void phylink_major_config(struct phylink *pl, bool restart,
+                                 const struct phylink_link_state *state)
+ {
+--- a/include/linux/phylink.h
++++ b/include/linux/phylink.h
+@@ -99,72 +99,6 @@ static inline bool phylink_autoneg_inban
+ }
+ /**
+- * phylink_pcs_neg_mode() - helper to determine PCS inband mode
+- * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
+- * @interface: interface mode to be used
+- * @advertising: adertisement ethtool link mode mask
+- *
+- * Determines the negotiation mode to be used by the PCS, and returns
+- * one of:
+- *
+- * - %PHYLINK_PCS_NEG_NONE: interface mode does not support inband
+- * - %PHYLINK_PCS_NEG_OUTBAND: an out of band mode (e.g. reading the PHY)
+- *   will be used.
+- * - %PHYLINK_PCS_NEG_INBAND_DISABLED: inband mode selected but autoneg
+- *   disabled
+- * - %PHYLINK_PCS_NEG_INBAND_ENABLED: inband mode selected and autoneg enabled
+- *
+- * Note: this is for cases where the PCS itself is involved in negotiation
+- * (e.g. Clause 37, SGMII and similar) not Clause 73.
+- */
+-static inline unsigned int phylink_pcs_neg_mode(unsigned int mode,
+-                                              phy_interface_t interface,
+-                                              const unsigned long *advertising)
+-{
+-      unsigned int neg_mode;
+-
+-      switch (interface) {
+-      case PHY_INTERFACE_MODE_SGMII:
+-      case PHY_INTERFACE_MODE_QSGMII:
+-      case PHY_INTERFACE_MODE_QUSGMII:
+-      case PHY_INTERFACE_MODE_USXGMII:
+-              /* 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.
+-               */
+-              if (!phylink_autoneg_inband(mode))
+-                      neg_mode = PHYLINK_PCS_NEG_OUTBAND;
+-              else
+-                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
+-              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.
+-               */
+-              if (!phylink_autoneg_inband(mode))
+-                      neg_mode = PHYLINK_PCS_NEG_OUTBAND;
+-              else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+-                                         advertising))
+-                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
+-              else
+-                      neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
+-              break;
+-
+-      default:
+-              neg_mode = PHYLINK_PCS_NEG_NONE;
+-              break;
+-      }
+-
+-      return neg_mode;
+-}
+-
+-/**
+  * struct phylink_link_state - link state structure
+  * @advertising: ethtool bitmask containing advertised link modes
+  * @lp_advertising: ethtool bitmask containing link partner advertised link
diff --git a/target/linux/generic/backport-6.6/606-01-v6.14-net-phylink-pass-phylink-and-pcs-into-phylink_pcs_ne.patch b/target/linux/generic/backport-6.6/606-01-v6.14-net-phylink-pass-phylink-and-pcs-into-phylink_pcs_ne.patch
new file mode 100644 (file)
index 0000000..2150a4a
--- /dev/null
@@ -0,0 +1,95 @@
+From 17ed1911f9c8d4f9af8e13b2c95103ee06dadc0f Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:30:47 +0000
+Subject: [PATCH 01/13] net: phylink: pass phylink and pcs into
+ phylink_pcs_neg_mode()
+
+Move the call to phylink_pcs_neg_mode() in phylink_major_config() after
+we have selected the appropriate PCS to allow the PCS to be passed in.
+
+Add struct phylink and struct phylink_pcs pointers to
+phylink_pcs_neg_mode() and pass in the appropriate structures. Set
+pl->pcs_neg_mode before returning, and remove the return value.
+
+This will allow the capabilities of the PCS and any PHY to be used when
+deciding which pcs_neg_mode should be used.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUrP-006ITh-6u@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 26 +++++++++++++-------------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1118,7 +1118,8 @@ static void phylink_pcs_an_restart(struc
+ /**
+  * phylink_pcs_neg_mode() - helper to determine PCS inband mode
+- * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
++ * @pl: a pointer to a &struct phylink returned from phylink_create()
++ * @pcs: a pointer to &struct phylink_pcs
+  * @interface: interface mode to be used
+  * @advertising: adertisement ethtool link mode mask
+  *
+@@ -1135,11 +1136,13 @@ static void phylink_pcs_an_restart(struc
+  * Note: this is for cases where the PCS itself is involved in negotiation
+  * (e.g. Clause 37, SGMII and similar) not Clause 73.
+  */
+-static unsigned int phylink_pcs_neg_mode(unsigned int mode,
+-                                       phy_interface_t interface,
+-                                       const unsigned long *advertising)
++static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs,
++                               phy_interface_t interface,
++                               const unsigned long *advertising)
+ {
+-      unsigned int neg_mode;
++      unsigned int neg_mode, mode;
++
++      mode = pl->cur_link_an_mode;
+       switch (interface) {
+       case PHY_INTERFACE_MODE_SGMII:
+@@ -1179,7 +1182,7 @@ static unsigned int phylink_pcs_neg_mode
+               break;
+       }
+-      return neg_mode;
++      pl->pcs_neg_mode = neg_mode;
+ }
+ static void phylink_major_config(struct phylink *pl, bool restart,
+@@ -1193,10 +1196,6 @@ static void phylink_major_config(struct
+       phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
+-      pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode,
+-                                              state->interface,
+-                                              state->advertising);
+-
+       if (pl->using_mac_select_pcs) {
+               pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
+               if (IS_ERR(pcs)) {
+@@ -1209,6 +1208,8 @@ static void phylink_major_config(struct
+               pcs_changed = pcs && pl->pcs != pcs;
+       }
++      phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising);
++
+       phylink_pcs_poll_stop(pl);
+       if (pl->mac_ops->mac_prepare) {
+@@ -1299,9 +1300,8 @@ static int phylink_change_inband_advert(
+                   pl->link_config.pause);
+       /* Recompute the PCS neg mode */
+-      pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode,
+-                                      pl->link_config.interface,
+-                                      pl->link_config.advertising);
++      phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface,
++                           pl->link_config.advertising);
+       neg_mode = pl->cur_link_an_mode;
+       if (pl->pcs->neg_mode)
diff --git a/target/linux/generic/backport-6.6/606-02-v6.14-net-phylink-split-cur_link_an_mode-into-requested-an.patch b/target/linux/generic/backport-6.6/606-02-v6.14-net-phylink-split-cur_link_an_mode-into-requested-an.patch
new file mode 100644 (file)
index 0000000..2cc97dd
--- /dev/null
@@ -0,0 +1,281 @@
+From 1f92ead7e15003f632b5f138e8138095e0997d3d Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:30:52 +0000
+Subject: [PATCH 02/13] net: phylink: split cur_link_an_mode into requested and
+ active
+
+There is an interdependence between the current link_an_mode and
+pcs_neg_mode that some drivers rely upon to know whether inband or PHY
+mode will be used.
+
+In order to support detection of PCS and PHY inband capabilities
+resulting in automatic selection of inband or PHY mode, we need to
+cater for this, and support changing the MAC link_an_mode. However, we
+end up with an inter-dependency between the current link_an_mode and
+pcs_neg_mode.
+
+To solve this, split the current link_an_mode into the requested
+link_an_mode and active link_an_mode. The requested link_an_mode will
+always be passed to phylink_pcs_neg_mode(), and the active link_an_mode
+will be used for everything else, and only updated during
+phylink_major_config(). This will ensure that phylink_pcs_neg_mode()'s
+link_an_mode will not depend on the active link_an_mode that will,
+in a future patch, depend on pcs_neg_mode.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUrU-006ITn-Ai@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 60 ++++++++++++++++++++-------------------
+ 1 file changed, 31 insertions(+), 29 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -56,7 +56,8 @@ struct phylink {
+       struct phy_device *phydev;
+       phy_interface_t link_interface; /* PHY_INTERFACE_xxx */
+       u8 cfg_link_an_mode;            /* MLO_AN_xxx */
+-      u8 cur_link_an_mode;
++      u8 req_link_an_mode;            /* Requested MLO_AN_xxx mode */
++      u8 act_link_an_mode;            /* Active MLO_AN_xxx mode */
+       u8 link_port;                   /* The current non-phy ethtool port */
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+@@ -1098,13 +1099,13 @@ static void phylink_mac_config(struct ph
+       phylink_dbg(pl,
+                   "%s: mode=%s/%s/%s adv=%*pb pause=%02x\n",
+-                  __func__, phylink_an_mode_str(pl->cur_link_an_mode),
++                  __func__, phylink_an_mode_str(pl->act_link_an_mode),
+                   phy_modes(st.interface),
+                   phy_rate_matching_to_str(st.rate_matching),
+                   __ETHTOOL_LINK_MODE_MASK_NBITS, st.advertising,
+                   st.pause);
+-      pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, &st);
++      pl->mac_ops->mac_config(pl->config, pl->act_link_an_mode, &st);
+ }
+ static void phylink_pcs_an_restart(struct phylink *pl)
+@@ -1112,7 +1113,7 @@ static void phylink_pcs_an_restart(struc
+       if (pl->pcs && linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+                                        pl->link_config.advertising) &&
+           phy_interface_mode_is_8023z(pl->link_config.interface) &&
+-          phylink_autoneg_inband(pl->cur_link_an_mode))
++          phylink_autoneg_inband(pl->act_link_an_mode))
+               pl->pcs->ops->pcs_an_restart(pl->pcs);
+ }
+@@ -1142,7 +1143,7 @@ static void phylink_pcs_neg_mode(struct
+ {
+       unsigned int neg_mode, mode;
+-      mode = pl->cur_link_an_mode;
++      mode = pl->req_link_an_mode;
+       switch (interface) {
+       case PHY_INTERFACE_MODE_SGMII:
+@@ -1183,6 +1184,7 @@ static void phylink_pcs_neg_mode(struct
+       }
+       pl->pcs_neg_mode = neg_mode;
++      pl->act_link_an_mode = mode;
+ }
+ static void phylink_major_config(struct phylink *pl, bool restart,
+@@ -1213,7 +1215,7 @@ static void phylink_major_config(struct
+       phylink_pcs_poll_stop(pl);
+       if (pl->mac_ops->mac_prepare) {
+-              err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode,
++              err = pl->mac_ops->mac_prepare(pl->config, pl->act_link_an_mode,
+                                              state->interface);
+               if (err < 0) {
+                       phylink_err(pl, "mac_prepare failed: %pe\n",
+@@ -1247,7 +1249,7 @@ static void phylink_major_config(struct
+       if (pl->pcs_state == PCS_STATE_STARTING || pcs_changed)
+               phylink_pcs_enable(pl->pcs);
+-      neg_mode = pl->cur_link_an_mode;
++      neg_mode = pl->act_link_an_mode;
+       if (pl->pcs && pl->pcs->neg_mode)
+               neg_mode = pl->pcs_neg_mode;
+@@ -1263,7 +1265,7 @@ static void phylink_major_config(struct
+               phylink_pcs_an_restart(pl);
+       if (pl->mac_ops->mac_finish) {
+-              err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode,
++              err = pl->mac_ops->mac_finish(pl->config, pl->act_link_an_mode,
+                                             state->interface);
+               if (err < 0)
+                       phylink_err(pl, "mac_finish failed: %pe\n",
+@@ -1294,7 +1296,7 @@ static int phylink_change_inband_advert(
+               return 0;
+       phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__,
+-                  phylink_an_mode_str(pl->cur_link_an_mode),
++                  phylink_an_mode_str(pl->req_link_an_mode),
+                   phy_modes(pl->link_config.interface),
+                   __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising,
+                   pl->link_config.pause);
+@@ -1303,7 +1305,7 @@ static int phylink_change_inband_advert(
+       phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface,
+                            pl->link_config.advertising);
+-      neg_mode = pl->cur_link_an_mode;
++      neg_mode = pl->act_link_an_mode;
+       if (pl->pcs->neg_mode)
+               neg_mode = pl->pcs_neg_mode;
+@@ -1368,7 +1370,7 @@ static void phylink_mac_initial_config(s
+ {
+       struct phylink_link_state link_state;
+-      switch (pl->cur_link_an_mode) {
++      switch (pl->req_link_an_mode) {
+       case MLO_AN_PHY:
+               link_state = pl->phy_state;
+               break;
+@@ -1442,14 +1444,14 @@ static void phylink_link_up(struct phyli
+       pl->cur_interface = link_state.interface;
+-      neg_mode = pl->cur_link_an_mode;
++      neg_mode = pl->act_link_an_mode;
+       if (pl->pcs && pl->pcs->neg_mode)
+               neg_mode = pl->pcs_neg_mode;
+       phylink_pcs_link_up(pl->pcs, neg_mode, pl->cur_interface, speed,
+                           duplex);
+-      pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode,
++      pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->act_link_an_mode,
+                                pl->cur_interface, speed, duplex,
+                                !!(link_state.pause & MLO_PAUSE_TX), rx_pause);
+@@ -1469,7 +1471,7 @@ static void phylink_link_down(struct phy
+       if (ndev)
+               netif_carrier_off(ndev);
+-      pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode,
++      pl->mac_ops->mac_link_down(pl->config, pl->act_link_an_mode,
+                                  pl->cur_interface);
+       phylink_info(pl, "Link is Down\n");
+ }
+@@ -1495,10 +1497,10 @@ static void phylink_resolve(struct work_
+       } else if (pl->mac_link_dropped) {
+               link_state.link = false;
+               retrigger = true;
+-      } else if (pl->cur_link_an_mode == MLO_AN_FIXED) {
++      } else if (pl->act_link_an_mode == MLO_AN_FIXED) {
+               phylink_get_fixed_state(pl, &link_state);
+               mac_config = link_state.link;
+-      } else if (pl->cur_link_an_mode == MLO_AN_PHY) {
++      } else if (pl->act_link_an_mode == MLO_AN_PHY) {
+               link_state = pl->phy_state;
+               mac_config = link_state.link;
+       } else {
+@@ -1552,7 +1554,7 @@ static void phylink_resolve(struct work_
+               }
+       }
+-      if (pl->cur_link_an_mode != MLO_AN_FIXED)
++      if (pl->act_link_an_mode != MLO_AN_FIXED)
+               phylink_apply_manual_flow(pl, &link_state);
+       if (mac_config) {
+@@ -1729,7 +1731,7 @@ struct phylink *phylink_create(struct ph
+               }
+       }
+-      pl->cur_link_an_mode = pl->cfg_link_an_mode;
++      pl->req_link_an_mode = pl->cfg_link_an_mode;
+       ret = phylink_register_sfp(pl, fwnode);
+       if (ret < 0) {
+@@ -2126,7 +2128,7 @@ void phylink_start(struct phylink *pl)
+       ASSERT_RTNL();
+       phylink_info(pl, "configuring for %s/%s link mode\n",
+-                   phylink_an_mode_str(pl->cur_link_an_mode),
++                   phylink_an_mode_str(pl->req_link_an_mode),
+                    phy_modes(pl->link_config.interface));
+       /* Always set the carrier off */
+@@ -2385,7 +2387,7 @@ int phylink_ethtool_ksettings_get(struct
+       linkmode_copy(kset->link_modes.supported, pl->supported);
+-      switch (pl->cur_link_an_mode) {
++      switch (pl->act_link_an_mode) {
+       case MLO_AN_FIXED:
+               /* We are using fixed settings. Report these as the
+                * current link settings - and note that these also
+@@ -2477,7 +2479,7 @@ int phylink_ethtool_ksettings_set(struct
+               /* If we have a fixed link, refuse to change link parameters.
+                * If the link parameters match, accept them but do nothing.
+                */
+-              if (pl->cur_link_an_mode == MLO_AN_FIXED) {
++              if (pl->req_link_an_mode == MLO_AN_FIXED) {
+                       if (s->speed != pl->link_config.speed ||
+                           s->duplex != pl->link_config.duplex)
+                               return -EINVAL;
+@@ -2493,7 +2495,7 @@ int phylink_ethtool_ksettings_set(struct
+                * is our default case) but do not allow the advertisement to
+                * be changed. If the advertisement matches, simply return.
+                */
+-              if (pl->cur_link_an_mode == MLO_AN_FIXED) {
++              if (pl->req_link_an_mode == MLO_AN_FIXED) {
+                       if (!linkmode_equal(config.advertising,
+                                           pl->link_config.advertising))
+                               return -EINVAL;
+@@ -2533,7 +2535,7 @@ int phylink_ethtool_ksettings_set(struct
+               linkmode_copy(support, pl->supported);
+               if (phylink_validate(pl, support, &config)) {
+                       phylink_err(pl, "validation of %s/%s with support %*pb failed\n",
+-                                  phylink_an_mode_str(pl->cur_link_an_mode),
++                                  phylink_an_mode_str(pl->req_link_an_mode),
+                                   phy_modes(config.interface),
+                                   __ETHTOOL_LINK_MODE_MASK_NBITS, support);
+                       return -EINVAL;
+@@ -2633,7 +2635,7 @@ int phylink_ethtool_set_pauseparam(struc
+       ASSERT_RTNL();
+-      if (pl->cur_link_an_mode == MLO_AN_FIXED)
++      if (pl->req_link_an_mode == MLO_AN_FIXED)
+               return -EOPNOTSUPP;
+       if (!phylink_test(pl->supported, Pause) &&
+@@ -2897,7 +2899,7 @@ static int phylink_mii_read(struct phyli
+       struct phylink_link_state state;
+       int val = 0xffff;
+-      switch (pl->cur_link_an_mode) {
++      switch (pl->act_link_an_mode) {
+       case MLO_AN_FIXED:
+               if (phy_id == 0) {
+                       phylink_get_fixed_state(pl, &state);
+@@ -2922,7 +2924,7 @@ static int phylink_mii_read(struct phyli
+ static int phylink_mii_write(struct phylink *pl, unsigned int phy_id,
+                            unsigned int reg, unsigned int val)
+ {
+-      switch (pl->cur_link_an_mode) {
++      switch (pl->act_link_an_mode) {
+       case MLO_AN_FIXED:
+               break;
+@@ -3125,9 +3127,9 @@ static void phylink_sfp_set_config(struc
+               changed = true;
+       }
+-      if (pl->cur_link_an_mode != mode ||
++      if (pl->req_link_an_mode != mode ||
+           pl->link_config.interface != state->interface) {
+-              pl->cur_link_an_mode = mode;
++              pl->req_link_an_mode = mode;
+               pl->link_config.interface = state->interface;
+               changed = true;
diff --git a/target/linux/generic/backport-6.6/606-03-v6.14-net-phylink-add-debug-for-phylink_major_config.patch b/target/linux/generic/backport-6.6/606-03-v6.14-net-phylink-add-debug-for-phylink_major_config.patch
new file mode 100644 (file)
index 0000000..483fe07
--- /dev/null
@@ -0,0 +1,66 @@
+From 4e7d000286fe8e12f2d88032711ffab3ab658b12 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:30:57 +0000
+Subject: [PATCH 03/13] net: phylink: add debug for phylink_major_config()
+
+Now that we have a more complexity in phylink_major_config(), augment
+the debugging so we can see what's going on there.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUrZ-006ITt-Fa@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 27 ++++++++++++++++++++++++++-
+ 1 file changed, 26 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -163,6 +163,24 @@ static const char *phylink_an_mode_str(u
+       return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown";
+ }
++static const char *phylink_pcs_mode_str(unsigned int mode)
++{
++      if (!mode)
++              return "none";
++
++      if (mode & PHYLINK_PCS_NEG_OUTBAND)
++              return "outband";
++
++      if (mode & PHYLINK_PCS_NEG_INBAND) {
++              if (mode & PHYLINK_PCS_NEG_ENABLED)
++                      return "inband,an-enabled";
++              else
++                      return "inband,an-disabled";
++      }
++
++      return "unknown";
++}
++
+ static unsigned int phylink_interface_signal_rate(phy_interface_t interface)
+ {
+       switch (interface) {
+@@ -1196,7 +1214,9 @@ static void phylink_major_config(struct
+       unsigned int neg_mode;
+       int err;
+-      phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
++      phylink_dbg(pl, "major config, requested %s/%s\n",
++                  phylink_an_mode_str(pl->req_link_an_mode),
++                  phy_modes(state->interface));
+       if (pl->using_mac_select_pcs) {
+               pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
+@@ -1212,6 +1232,11 @@ static void phylink_major_config(struct
+       phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising);
++      phylink_dbg(pl, "major config, active %s/%s/%s\n",
++                  phylink_an_mode_str(pl->act_link_an_mode),
++                  phylink_pcs_mode_str(pl->pcs_neg_mode),
++                  phy_modes(state->interface));
++
+       phylink_pcs_poll_stop(pl);
+       if (pl->mac_ops->mac_prepare) {
diff --git a/target/linux/generic/backport-6.6/606-04-v6.14-net-phy-add-phy_inband_caps.patch b/target/linux/generic/backport-6.6/606-04-v6.14-net-phy-add-phy_inband_caps.patch
new file mode 100644 (file)
index 0000000..dcff6b2
--- /dev/null
@@ -0,0 +1,118 @@
+From b4c7698dd95f253c6958d8c6ac219098009bf28a Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:02 +0000
+Subject: [PATCH 04/13] net: phy: add phy_inband_caps()
+
+Add a method to query the PHY's in-band capabilities for a PHY
+interface mode.
+
+Where the interface mode does not have in-band capability, or the PHY
+driver has not been updated to return this information, then
+phy_inband_caps() should return zero. Otherwise, PHY drivers will
+return a value consisting of the following flags:
+
+LINK_INBAND_DISABLE indicates that the hardware does not support
+in-band signalling, or can have in-band signalling configured via
+software to be disabled.
+
+LINK_INBAND_ENABLE indicates that the hardware will use in-band
+signalling, or can have in-band signalling configured via software
+to be enabled.
+
+LINK_INBAND_BYPASS indicates that the hardware has the ability to
+bypass in-band signalling when enabled after a timeout if the link
+partner does not respond to its in-band signalling.
+
+This reports the PHY capabilities for the particular interface mode,
+not the current configuration.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUre-006ITz-KF@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phy.c | 21 +++++++++++++++++++++
+ include/linux/phy.h   | 28 ++++++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -973,6 +973,27 @@ static int phy_check_link_status(struct
+ }
+ /**
++ * phy_inband_caps - query which in-band signalling modes are supported
++ * @phydev: a pointer to a &struct phy_device
++ * @interface: the interface mode for the PHY
++ *
++ * Returns zero if it is unknown what in-band signalling is supported by the
++ * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise,
++ * returns a bit mask of the LINK_INBAND_* values from
++ * &enum link_inband_signalling to describe which inband modes are supported
++ * by the PHY for this interface mode.
++ */
++unsigned int phy_inband_caps(struct phy_device *phydev,
++                           phy_interface_t interface)
++{
++      if (phydev->drv && phydev->drv->inband_caps)
++              return phydev->drv->inband_caps(phydev, interface);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(phy_inband_caps);
++
++/**
+  * _phy_start_aneg - start auto-negotiation for this PHY device
+  * @phydev: the phy_device struct
+  *
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -790,6 +790,24 @@ struct phy_tdr_config {
+ #define PHY_PAIR_ALL -1
+ /**
++ * enum link_inband_signalling - in-band signalling modes that are supported
++ *
++ * @LINK_INBAND_DISABLE: in-band signalling can be disabled
++ * @LINK_INBAND_ENABLE: in-band signalling can be enabled without bypass
++ * @LINK_INBAND_BYPASS: in-band signalling can be enabled with bypass
++ *
++ * The possible and required bits can only be used if the valid bit is set.
++ * If possible is clear, that means inband signalling can not be used.
++ * Required is only valid when possible is set, and means that inband
++ * signalling must be used.
++ */
++enum link_inband_signalling {
++      LINK_INBAND_DISABLE             = BIT(0),
++      LINK_INBAND_ENABLE              = BIT(1),
++      LINK_INBAND_BYPASS              = BIT(2),
++};
++
++/**
+  * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision
+  * Avoidance) Reconciliation Sublayer.
+  *
+@@ -919,6 +937,14 @@ struct phy_driver {
+       int (*get_features)(struct phy_device *phydev);
+       /**
++       * @inband_caps: query whether in-band is supported for the given PHY
++       * interface mode. Returns a bitmask of bits defined by enum
++       * link_inband_signalling.
++       */
++      unsigned int (*inband_caps)(struct phy_device *phydev,
++                                  phy_interface_t interface);
++
++      /**
+        * @get_rate_matching: Get the supported type of rate matching for a
+        * particular phy interface. This is used by phy consumers to determine
+        * whether to advertise lower-speed modes for that interface. It is
+@@ -1735,6 +1761,8 @@ void phy_stop(struct phy_device *phydev)
+ int phy_config_aneg(struct phy_device *phydev);
+ int phy_start_aneg(struct phy_device *phydev);
+ int phy_aneg_done(struct phy_device *phydev);
++unsigned int phy_inband_caps(struct phy_device *phydev,
++                           phy_interface_t interface);
+ int phy_speed_down(struct phy_device *phydev, bool sync);
+ int phy_speed_up(struct phy_device *phydev);
+ bool phy_check_valid(int speed, int duplex, unsigned long *features);
diff --git a/target/linux/generic/backport-6.6/606-05-v6.14-net-phy-bcm84881-implement-phy_inband_caps-method.patch b/target/linux/generic/backport-6.6/606-05-v6.14-net-phy-bcm84881-implement-phy_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..a78fad1
--- /dev/null
@@ -0,0 +1,41 @@
+From c64c7fa0a774d9da72071a8517e359992baac982 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:07 +0000
+Subject: [PATCH 05/13] net: phy: bcm84881: implement phy_inband_caps() method
+
+BCM84881 has no support for inband signalling, so this is a trivial
+implementation that returns no support for inband.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Acked-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Link: https://patch.msgid.link/E1tIUrj-006IU6-ON@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/bcm84881.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/net/phy/bcm84881.c
++++ b/drivers/net/phy/bcm84881.c
+@@ -223,11 +223,21 @@ static int bcm84881_read_status(struct p
+       return genphy_c45_read_mdix(phydev);
+ }
++/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
++ * or 802.3z control word, so inband will not work.
++ */
++static unsigned int bcm84881_inband_caps(struct phy_device *phydev,
++                                       phy_interface_t interface)
++{
++      return LINK_INBAND_DISABLE;
++}
++
+ static struct phy_driver bcm84881_drivers[] = {
+       {
+               .phy_id         = 0xae025150,
+               .phy_id_mask    = 0xfffffff0,
+               .name           = "Broadcom BCM84881",
++              .inband_caps    = bcm84881_inband_caps,
+               .config_init    = bcm84881_config_init,
+               .probe          = bcm84881_probe,
+               .get_features   = bcm84881_get_features,
diff --git a/target/linux/generic/backport-6.6/606-06-v6.14-net-phy-marvell-implement-phy_inband_caps-method.patch b/target/linux/generic/backport-6.6/606-06-v6.14-net-phy-marvell-implement-phy_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..c1f481e
--- /dev/null
@@ -0,0 +1,63 @@
+From 1c86828dff88e28b8ade6bddeee0163a023faf91 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:12 +0000
+Subject: [PATCH 06/13] net: phy: marvell: implement phy_inband_caps() method
+
+Provide an implementation for phy_inband_caps() for Marvell PHYs used
+on SFP modules, so that phylink knows the PHYs capabilities.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUro-006IUC-Rq@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/marvell.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/drivers/net/phy/marvell.c
++++ b/drivers/net/phy/marvell.c
+@@ -673,6 +673,20 @@ static int marvell_config_aneg_fiber(str
+       return genphy_check_and_restart_aneg(phydev, changed);
+ }
++static unsigned int m88e1111_inband_caps(struct phy_device *phydev,
++                                       phy_interface_t interface)
++{
++      /* In 1000base-X and SGMII modes, the inband mode can be changed
++       * through the Fibre page BMCR ANENABLE bit.
++       */
++      if (interface == PHY_INTERFACE_MODE_1000BASEX ||
++          interface == PHY_INTERFACE_MODE_SGMII)
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE |
++                     LINK_INBAND_BYPASS;
++
++      return 0;
++}
++
+ static int m88e1111_config_aneg(struct phy_device *phydev)
+ {
+       int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+@@ -3292,6 +3306,7 @@ static struct phy_driver marvell_drivers
+               .name = "Marvell 88E1112",
+               /* PHY_GBIT_FEATURES */
+               .probe = marvell_probe,
++              .inband_caps = m88e1111_inband_caps,
+               .config_init = m88e1112_config_init,
+               .config_aneg = marvell_config_aneg,
+               .config_intr = marvell_config_intr,
+@@ -3312,6 +3327,7 @@ static struct phy_driver marvell_drivers
+               .name = "Marvell 88E1111",
+               /* PHY_GBIT_FEATURES */
+               .probe = marvell_probe,
++              .inband_caps = m88e1111_inband_caps,
+               .config_init = m88e1111gbe_config_init,
+               .config_aneg = m88e1111_config_aneg,
+               .read_status = marvell_read_status,
+@@ -3333,6 +3349,7 @@ static struct phy_driver marvell_drivers
+               .name = "Marvell 88E1111 (Finisar)",
+               /* PHY_GBIT_FEATURES */
+               .probe = marvell_probe,
++              .inband_caps = m88e1111_inband_caps,
+               .config_init = m88e1111gbe_config_init,
+               .config_aneg = m88e1111_config_aneg,
+               .read_status = marvell_read_status,
diff --git a/target/linux/generic/backport-6.6/606-07-v6.14-net-phy-add-phy_config_inband.patch b/target/linux/generic/backport-6.6/606-07-v6.14-net-phy-add-phy_config_inband.patch
new file mode 100644 (file)
index 0000000..652aaa1
--- /dev/null
@@ -0,0 +1,79 @@
+From 5d58a890c02770ba8d790b1f3c6e8c0e20514dc2 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:18 +0000
+Subject: [PATCH 07/13] net: phy: add phy_config_inband()
+
+Add a method to configure the PHY's in-band mode.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUru-006IUI-08@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phy.c | 32 ++++++++++++++++++++++++++++++++
+ include/linux/phy.h   |  6 ++++++
+ 2 files changed, 38 insertions(+)
+
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -994,6 +994,38 @@ unsigned int phy_inband_caps(struct phy_
+ EXPORT_SYMBOL_GPL(phy_inband_caps);
+ /**
++ * phy_config_inband - configure the desired PHY in-band mode
++ * @phydev: the phy_device struct
++ * @modes: in-band modes to configure
++ *
++ * Description: disables, enables or enables-with-bypass in-band signalling
++ *   between the PHY and host system.
++ *
++ * Returns: zero on success, or negative errno value.
++ */
++int phy_config_inband(struct phy_device *phydev, unsigned int modes)
++{
++      int err;
++
++      if (!!(modes & LINK_INBAND_DISABLE) +
++          !!(modes & LINK_INBAND_ENABLE) +
++          !!(modes & LINK_INBAND_BYPASS) != 1)
++              return -EINVAL;
++
++      mutex_lock(&phydev->lock);
++      if (!phydev->drv)
++              err = -EIO;
++      else if (!phydev->drv->config_inband)
++              err = -EOPNOTSUPP;
++      else
++              err = phydev->drv->config_inband(phydev, modes);
++      mutex_unlock(&phydev->lock);
++
++      return err;
++}
++EXPORT_SYMBOL(phy_config_inband);
++
++/**
+  * _phy_start_aneg - start auto-negotiation for this PHY device
+  * @phydev: the phy_device struct
+  *
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -945,6 +945,11 @@ struct phy_driver {
+                                   phy_interface_t interface);
+       /**
++       * @config_inband: configure in-band mode for the PHY
++       */
++      int (*config_inband)(struct phy_device *phydev, unsigned int modes);
++
++      /**
+        * @get_rate_matching: Get the supported type of rate matching for a
+        * particular phy interface. This is used by phy consumers to determine
+        * whether to advertise lower-speed modes for that interface. It is
+@@ -1763,6 +1768,7 @@ int phy_start_aneg(struct phy_device *ph
+ int phy_aneg_done(struct phy_device *phydev);
+ unsigned int phy_inband_caps(struct phy_device *phydev,
+                            phy_interface_t interface);
++int phy_config_inband(struct phy_device *phydev, unsigned int modes);
+ int phy_speed_down(struct phy_device *phydev, bool sync);
+ int phy_speed_up(struct phy_device *phydev);
+ bool phy_check_valid(int speed, int duplex, unsigned long *features);
diff --git a/target/linux/generic/backport-6.6/606-08-v6.14-net-phy-marvell-implement-config_inband-method.patch b/target/linux/generic/backport-6.6/606-08-v6.14-net-phy-marvell-implement-config_inband-method.patch
new file mode 100644 (file)
index 0000000..30c393d
--- /dev/null
@@ -0,0 +1,77 @@
+From a219912e0fec73c346e64ef47013cb2e152f88fc Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:23 +0000
+Subject: [PATCH 08/13] net: phy: marvell: implement config_inband() method
+
+Implement the config_inband() method for Marvell 88E1112, 88E1111,
+and Finisar's 88E1111 variant.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUrz-006IUO-3r@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/marvell.c | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+--- a/drivers/net/phy/marvell.c
++++ b/drivers/net/phy/marvell.c
+@@ -687,6 +687,34 @@ static unsigned int m88e1111_inband_caps
+       return 0;
+ }
++static int m88e1111_config_inband(struct phy_device *phydev, unsigned int modes)
++{
++      u16 extsr, bmcr;
++      int err;
++
++      if (phydev->interface != PHY_INTERFACE_MODE_1000BASEX &&
++          phydev->interface != PHY_INTERFACE_MODE_SGMII)
++              return -EINVAL;
++
++      if (modes == LINK_INBAND_BYPASS)
++              extsr = MII_M1111_HWCFG_SERIAL_AN_BYPASS;
++      else
++              extsr = 0;
++
++      if (modes == LINK_INBAND_DISABLE)
++              bmcr = 0;
++      else
++              bmcr = BMCR_ANENABLE;
++
++      err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,
++                       MII_M1111_HWCFG_SERIAL_AN_BYPASS, extsr);
++      if (err < 0)
++              return extsr;
++
++      return phy_modify_paged(phydev, MII_MARVELL_FIBER_PAGE, MII_BMCR,
++                              BMCR_ANENABLE, bmcr);
++}
++
+ static int m88e1111_config_aneg(struct phy_device *phydev)
+ {
+       int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+@@ -3307,6 +3335,7 @@ static struct phy_driver marvell_drivers
+               /* PHY_GBIT_FEATURES */
+               .probe = marvell_probe,
+               .inband_caps = m88e1111_inband_caps,
++              .config_inband = m88e1111_config_inband,
+               .config_init = m88e1112_config_init,
+               .config_aneg = marvell_config_aneg,
+               .config_intr = marvell_config_intr,
+@@ -3328,6 +3357,7 @@ static struct phy_driver marvell_drivers
+               /* PHY_GBIT_FEATURES */
+               .probe = marvell_probe,
+               .inband_caps = m88e1111_inband_caps,
++              .config_inband = m88e1111_config_inband,
+               .config_init = m88e1111gbe_config_init,
+               .config_aneg = m88e1111_config_aneg,
+               .read_status = marvell_read_status,
+@@ -3350,6 +3380,7 @@ static struct phy_driver marvell_drivers
+               /* PHY_GBIT_FEATURES */
+               .probe = marvell_probe,
+               .inband_caps = m88e1111_inband_caps,
++              .config_inband = m88e1111_config_inband,
+               .config_init = m88e1111gbe_config_init,
+               .config_aneg = m88e1111_config_aneg,
+               .read_status = marvell_read_status,
diff --git a/target/linux/generic/backport-6.6/606-09-v6.14-net-phylink-add-pcs_inband_caps-method.patch b/target/linux/generic/backport-6.6/606-09-v6.14-net-phylink-add-pcs_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..2ca722b
--- /dev/null
@@ -0,0 +1,159 @@
+From df874f9e52c340cc6f0a0014a97b778f67d46849 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:28 +0000
+Subject: [PATCH 09/13] net: phylink: add pcs_inband_caps() method
+
+Add a pcs_inband_caps() method to query the PCS for its inband link
+capabilities, and use this to determine whether link modes used with
+optical SFPs can be supported.
+
+When a PCS does not provide a method, we allow inband negotiation to
+be either on or off, making this a no-op until the pcs_inband_caps()
+method is implemented by a PCS driver.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUs4-006IUU-7K@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 60 +++++++++++++++++++++++++++++++++++++++
+ include/linux/phylink.h   | 17 +++++++++++
+ 2 files changed, 77 insertions(+)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1038,6 +1038,15 @@ static void phylink_resolve_an_pause(str
+       }
+ }
++static unsigned int phylink_pcs_inband_caps(struct phylink_pcs *pcs,
++                                  phy_interface_t interface)
++{
++      if (pcs && pcs->ops->pcs_inband_caps)
++              return pcs->ops->pcs_inband_caps(pcs, interface);
++
++      return 0;
++}
++
+ static void phylink_pcs_pre_config(struct phylink_pcs *pcs,
+                                  phy_interface_t interface)
+ {
+@@ -1091,6 +1100,24 @@ static void phylink_pcs_link_up(struct p
+               pcs->ops->pcs_link_up(pcs, neg_mode, interface, speed, duplex);
+ }
++/* Query inband for a specific interface mode, asking the MAC for the
++ * PCS which will be used to handle the interface mode.
++ */
++static unsigned int phylink_inband_caps(struct phylink *pl,
++                                       phy_interface_t interface)
++{
++      struct phylink_pcs *pcs;
++
++      if (!pl->mac_ops->mac_select_pcs)
++              return 0;
++
++      pcs = pl->mac_ops->mac_select_pcs(pl->config, interface);
++      if (!pcs)
++              return 0;
++
++      return phylink_pcs_inband_caps(pcs, interface);
++}
++
+ static void phylink_pcs_poll_stop(struct phylink *pl)
+ {
+       if (pl->cfg_link_an_mode == MLO_AN_INBAND)
+@@ -2443,6 +2470,26 @@ int phylink_ethtool_ksettings_get(struct
+ }
+ EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get);
++static bool phylink_validate_pcs_inband_autoneg(struct phylink *pl,
++                                              phy_interface_t interface,
++                                              unsigned long *adv)
++{
++      unsigned int inband = phylink_inband_caps(pl, interface);
++      unsigned int mask;
++
++      /* If the PCS doesn't implement inband support, be permissive. */
++      if (!inband)
++              return true;
++
++      if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, adv))
++              mask = LINK_INBAND_ENABLE;
++      else
++              mask = LINK_INBAND_DISABLE;
++
++      /* Check whether the PCS implements the required mode */
++      return !!(inband & mask);
++}
++
+ /**
+  * phylink_ethtool_ksettings_set() - set the link settings
+  * @pl: a pointer to a &struct phylink returned from phylink_create()
+@@ -2578,6 +2625,13 @@ int phylink_ethtool_ksettings_set(struct
+           phylink_is_empty_linkmode(config.advertising))
+               return -EINVAL;
++      /* Validate the autonegotiation state. We don't have a PHY in this
++       * situation, so the PCS is the media-facing entity.
++       */
++      if (!phylink_validate_pcs_inband_autoneg(pl, config.interface,
++                                               config.advertising))
++              return -EINVAL;
++
+       mutex_lock(&pl->state_mutex);
+       pl->link_config.speed = config.speed;
+       pl->link_config.duplex = config.duplex;
+@@ -3274,6 +3328,12 @@ static int phylink_sfp_config_optical(st
+       phylink_dbg(pl, "optical SFP: chosen %s interface\n",
+                   phy_modes(interface));
++      if (!phylink_validate_pcs_inband_autoneg(pl, interface,
++                                               config.advertising)) {
++              phylink_err(pl, "autoneg setting not compatible with PCS");
++              return -EINVAL;
++      }
++
+       config.interface = interface;
+       /* Ignore errors if we're expecting a PHY to attach later */
+--- a/include/linux/phylink.h
++++ b/include/linux/phylink.h
+@@ -432,6 +432,7 @@ struct phylink_pcs {
+ /**
+  * struct phylink_pcs_ops - MAC PCS operations structure.
+  * @pcs_validate: validate the link configuration.
++ * @pcs_inband_caps: query inband support for interface mode.
+  * @pcs_enable: enable the PCS.
+  * @pcs_disable: disable the PCS.
+  * @pcs_pre_config: pre-mac_config method (for errata)
+@@ -445,6 +446,8 @@ struct phylink_pcs {
+ struct phylink_pcs_ops {
+       int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
+                           const struct phylink_link_state *state);
++      unsigned int (*pcs_inband_caps)(struct phylink_pcs *pcs,
++                                      phy_interface_t interface);
+       int (*pcs_enable)(struct phylink_pcs *pcs);
+       void (*pcs_disable)(struct phylink_pcs *pcs);
+       void (*pcs_pre_config)(struct phylink_pcs *pcs,
+@@ -481,6 +484,20 @@ int pcs_validate(struct phylink_pcs *pcs
+                const struct phylink_link_state *state);
+ /**
++ * pcs_inband_caps - query PCS in-band capabilities for interface mode.
++ * @pcs: a pointer to a &struct phylink_pcs.
++ * @interface: interface mode to be queried
++ *
++ * Returns zero if it is unknown what in-band signalling is supported by the
++ * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise,
++ * returns a bit mask of the LINK_INBAND_* values from
++ * &enum link_inband_signalling to describe which inband modes are supported
++ * for this interface mode.
++ */
++unsigned int pcs_inband_caps(struct phylink_pcs *pcs,
++                           phy_interface_t interface);
++
++/**
+  * pcs_enable() - enable the PCS.
+  * @pcs: a pointer to a &struct phylink_pcs.
+  */
diff --git a/target/linux/generic/backport-6.6/606-10-v6.14-net-mvneta-implement-pcs_inband_caps-method.patch b/target/linux/generic/backport-6.6/606-10-v6.14-net-mvneta-implement-pcs_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..b926312
--- /dev/null
@@ -0,0 +1,64 @@
+From 513e8fb8fa32035b3325e2e14fb9598f8cb545e9 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:33 +0000
+Subject: [PATCH 10/13] net: mvneta: implement pcs_inband_caps() method
+
+Report the PCS in-band capabilities to phylink for Marvell NETA
+interfaces.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUs9-006IUb-Au@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/ethernet/marvell/mvneta.c | 27 +++++++++++++++++----------
+ 1 file changed, 17 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -3959,20 +3959,27 @@ static struct mvneta_port *mvneta_pcs_to
+       return container_of(pcs, struct mvneta_port, phylink_pcs);
+ }
+-static int mvneta_pcs_validate(struct phylink_pcs *pcs,
+-                             unsigned long *supported,
+-                             const struct phylink_link_state *state)
++static unsigned int mvneta_pcs_inband_caps(struct phylink_pcs *pcs,
++                                         phy_interface_t interface)
+ {
+-      /* We only support QSGMII, SGMII, 802.3z and RGMII modes.
+-       * When in 802.3z mode, we must have AN enabled:
++      /* When operating in an 802.3z mode, we must have AN enabled:
+        * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ...
+        * When <PortType> = 1 (1000BASE-X) this field must be set to 1."
++       * Therefore, inband is "required".
+        */
+-      if (phy_interface_mode_is_8023z(state->interface) &&
+-          !phylink_test(state->advertising, Autoneg))
+-              return -EINVAL;
++      if (phy_interface_mode_is_8023z(interface))
++              return LINK_INBAND_ENABLE;
+-      return 0;
++      /* QSGMII, SGMII and RGMII can be configured to use inband
++       * signalling of the AN result. Indicate these as "possible".
++       */
++      if (interface == PHY_INTERFACE_MODE_SGMII ||
++          interface == PHY_INTERFACE_MODE_QSGMII ||
++          phy_interface_mode_is_rgmii(interface))
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++
++      /* For any other modes, indicate that inband is not supported. */
++      return LINK_INBAND_DISABLE;
+ }
+ static void mvneta_pcs_get_state(struct phylink_pcs *pcs,
+@@ -4070,7 +4077,7 @@ static void mvneta_pcs_an_restart(struct
+ }
+ static const struct phylink_pcs_ops mvneta_phylink_pcs_ops = {
+-      .pcs_validate = mvneta_pcs_validate,
++      .pcs_inband_caps = mvneta_pcs_inband_caps,
+       .pcs_get_state = mvneta_pcs_get_state,
+       .pcs_config = mvneta_pcs_config,
+       .pcs_an_restart = mvneta_pcs_an_restart,
diff --git a/target/linux/generic/backport-6.6/606-11-v6.14-net-mvpp2-implement-pcs_inband_caps-method.patch b/target/linux/generic/backport-6.6/606-11-v6.14-net-mvpp2-implement-pcs_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..1ff6035
--- /dev/null
@@ -0,0 +1,62 @@
+From d4169f0c7665afb8d8adb5e1b1df3db88517d0ad Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:38 +0000
+Subject: [PATCH 11/13] net: mvpp2: implement pcs_inband_caps() method
+
+Report the PCS in-band capabilities to phylink for Marvell PP2
+interfaces.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUsE-006IUh-E7@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ .../net/ethernet/marvell/mvpp2/mvpp2_main.c   | 25 ++++++++++++-------
+ 1 file changed, 16 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+@@ -6214,19 +6214,26 @@ static const struct phylink_pcs_ops mvpp
+       .pcs_config = mvpp2_xlg_pcs_config,
+ };
+-static int mvpp2_gmac_pcs_validate(struct phylink_pcs *pcs,
+-                                 unsigned long *supported,
+-                                 const struct phylink_link_state *state)
++static unsigned int mvpp2_gmac_pcs_inband_caps(struct phylink_pcs *pcs,
++                                             phy_interface_t interface)
+ {
+-      /* When in 802.3z mode, we must have AN enabled:
++      /* When operating in an 802.3z mode, we must have AN enabled:
+        * Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ...
+        * When <PortType> = 1 (1000BASE-X) this field must be set to 1.
++       * Therefore, inband is "required".
+        */
+-      if (phy_interface_mode_is_8023z(state->interface) &&
+-          !phylink_test(state->advertising, Autoneg))
+-              return -EINVAL;
++      if (phy_interface_mode_is_8023z(interface))
++              return LINK_INBAND_ENABLE;
+-      return 0;
++      /* SGMII and RGMII can be configured to use inband signalling of the
++       * AN result. Indicate these as "possible".
++       */
++      if (interface == PHY_INTERFACE_MODE_SGMII ||
++          phy_interface_mode_is_rgmii(interface))
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++
++      /* For any other modes, indicate that inband is not supported. */
++      return LINK_INBAND_DISABLE;
+ }
+ static void mvpp2_gmac_pcs_get_state(struct phylink_pcs *pcs,
+@@ -6333,7 +6340,7 @@ static void mvpp2_gmac_pcs_an_restart(st
+ }
+ static const struct phylink_pcs_ops mvpp2_phylink_gmac_pcs_ops = {
+-      .pcs_validate = mvpp2_gmac_pcs_validate,
++      .pcs_inband_caps = mvpp2_gmac_pcs_inband_caps,
+       .pcs_get_state = mvpp2_gmac_pcs_get_state,
+       .pcs_config = mvpp2_gmac_pcs_config,
+       .pcs_an_restart = mvpp2_gmac_pcs_an_restart,
diff --git a/target/linux/generic/backport-6.6/606-12-v6.14-net-phylink-add-negotiation-of-in-band-capabilities.patch b/target/linux/generic/backport-6.6/606-12-v6.14-net-phylink-add-negotiation-of-in-band-capabilities.patch
new file mode 100644 (file)
index 0000000..cf234f8
--- /dev/null
@@ -0,0 +1,228 @@
+From 5fd0f1a02e750e2db4038dee60edea669ce5aab1 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:43 +0000
+Subject: [PATCH 12/13] net: phylink: add negotiation of in-band capabilities
+
+Support for in-band signalling with Serdes links is uncertain. Some
+PHYs do not support in-band for e.g. SGMII. Some PCS do not support
+in-band for 2500Base-X. Some PCS require in-band for Base-X protocols.
+
+Simply using what is in DT is insufficient when we have hot-pluggable
+PHYs e.g. in the form of SFP modules, which may not provide the
+in-band signalling.
+
+In order to address this, we have introduced phy_inband_caps() and
+pcs_inband_caps() functions to allow phylink to retrieve the
+capabilities from each end of the PCS/PHY link. This commit adds code
+to resolve whether in-band will be used in the various scenarios that
+we have: In-band not being used, PHY present using SGMII or Base-X,
+PHY not present. We also deal with no capabilties provided.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUsJ-006IUn-H3@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 154 +++++++++++++++++++++++++++++++++++---
+ 1 file changed, 144 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -75,6 +75,7 @@ struct phylink {
+       struct mutex state_mutex;
+       struct phylink_link_state phy_state;
++      unsigned int phy_ib_mode;
+       struct work_struct resolve;
+       unsigned int pcs_neg_mode;
+       unsigned int pcs_state;
+@@ -1186,10 +1187,18 @@ static void phylink_pcs_neg_mode(struct
+                                phy_interface_t interface,
+                                const unsigned long *advertising)
+ {
++      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;
++      pl->phy_ib_mode = 0;
++
+       switch (interface) {
+       case PHY_INTERFACE_MODE_SGMII:
+       case PHY_INTERFACE_MODE_QSGMII:
+@@ -1200,10 +1209,7 @@ static void phylink_pcs_neg_mode(struct
+                * inband communication. Note: there exist PHYs that run
+                * with SGMII but do not send the inband data.
+                */
+-              if (!phylink_autoneg_inband(mode))
+-                      neg_mode = PHYLINK_PCS_NEG_OUTBAND;
+-              else
+-                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
++              type = INBAND_CISCO_SGMII;
+               break;
+       case PHY_INTERFACE_MODE_1000BASEX:
+@@ -1214,18 +1220,139 @@ static void phylink_pcs_neg_mode(struct
+                * as well, but drivers may not support this, so may
+                * need to override this.
+                */
+-              if (!phylink_autoneg_inband(mode))
++              type = INBAND_BASEX;
++              break;
++
++      default:
++              pl->pcs_neg_mode = PHYLINK_PCS_NEG_NONE;
++              pl->act_link_an_mode = mode;
++              return;
++      }
++
++      if (pcs)
++              pcs_ib_caps = phylink_pcs_inband_caps(pcs, interface);
++
++      if (pl->phydev)
++              phy_ib_caps = phy_inband_caps(pl->phydev, interface);
++
++      phylink_dbg(pl, "interface %s inband modes: pcs=%02x phy=%02x\n",
++                  phy_modes(interface), pcs_ib_caps, phy_ib_caps);
++
++      if (!phylink_autoneg_inband(mode)) {
++              bool pcs_ib_only = false;
++              bool phy_ib_only = false;
++
++              if (pcs_ib_caps && pcs_ib_caps != LINK_INBAND_DISABLE) {
++                      /* PCS supports reporting in-band capabilities, and
++                       * supports more than disable mode.
++                       */
++                      if (pcs_ib_caps & LINK_INBAND_DISABLE)
++                              neg_mode = PHYLINK_PCS_NEG_OUTBAND;
++                      else if (pcs_ib_caps & LINK_INBAND_ENABLE)
++                              pcs_ib_only = true;
++              }
++
++              if (phy_ib_caps && phy_ib_caps != LINK_INBAND_DISABLE) {
++                      /* PHY supports in-band capabilities, and supports
++                       * more than disable mode.
++                       */
++                      if (phy_ib_caps & LINK_INBAND_DISABLE)
++                              pl->phy_ib_mode = LINK_INBAND_DISABLE;
++                      else if (phy_ib_caps & LINK_INBAND_BYPASS)
++                              pl->phy_ib_mode = LINK_INBAND_BYPASS;
++                      else if (phy_ib_caps & LINK_INBAND_ENABLE)
++                              phy_ib_only = true;
++              }
++
++              /* If either the PCS or PHY requires inband to be enabled,
++               * this is an invalid configuration. Provide a diagnostic
++               * message for this case, but don't try to force the issue.
++               */
++              if (pcs_ib_only || phy_ib_only)
++                      phylink_warn(pl,
++                                   "firmware wants %s mode, but %s%s%s requires inband\n",
++                                   phylink_an_mode_str(mode),
++                                   pcs_ib_only ? "PCS" : "",
++                                   pcs_ib_only && phy_ib_only ? " and " : "",
++                                   phy_ib_only ? "PHY" : "");
++
++              neg_mode = PHYLINK_PCS_NEG_OUTBAND;
++      } else if (type == INBAND_CISCO_SGMII || pl->phydev) {
++              /* For SGMII modes which are designed to be used with PHYs, or
++               * Base-X with a PHY, we try to use in-band mode where-ever
++               * possible. However, there are some PHYs e.g. BCM84881 which
++               * do not support in-band.
++               */
++              const unsigned int inband_ok = LINK_INBAND_ENABLE |
++                                             LINK_INBAND_BYPASS;
++              const unsigned int outband_ok = LINK_INBAND_DISABLE |
++                                              LINK_INBAND_BYPASS;
++              /* PCS  PHY
++               * D E  D E
++               * 0 0  0 0     no information                  inband enabled
++               * 1 0  0 0     pcs doesn't support             outband
++               * 0 1  0 0     pcs required                    inband enabled
++               * 1 1  0 0     pcs optional                    inband enabled
++               * 0 0  1 0     phy doesn't support             outband
++               * 1 0  1 0     pcs+phy doesn't support         outband
++               * 0 1  1 0     pcs required, phy doesn't support, invalid
++               * 1 1  1 0     pcs optional, phy doesn't support, outband
++               * 0 0  0 1     phy required                    inband enabled
++               * 1 0  0 1     pcs doesn't support, phy required, invalid
++               * 0 1  0 1     pcs+phy required                inband enabled
++               * 1 1  0 1     pcs optional, phy required      inband enabled
++               * 0 0  1 1     phy optional                    inband enabled
++               * 1 0  1 1     pcs doesn't support, phy optional, outband
++               * 0 1  1 1     pcs required, phy optional      inband enabled
++               * 1 1  1 1     pcs+phy optional                inband enabled
++               */
++              if ((!pcs_ib_caps || pcs_ib_caps & inband_ok) &&
++                  (!phy_ib_caps || phy_ib_caps & inband_ok)) {
++                      /* In-band supported or unknown at both ends. Enable
++                       * in-band mode with or without bypass at the PHY.
++                       */
++                      if (phy_ib_caps & LINK_INBAND_ENABLE)
++                              pl->phy_ib_mode = LINK_INBAND_ENABLE;
++                      else if (phy_ib_caps & LINK_INBAND_BYPASS)
++                              pl->phy_ib_mode = LINK_INBAND_BYPASS;
++
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
++              } else if ((!pcs_ib_caps || pcs_ib_caps & outband_ok) &&
++                         (!phy_ib_caps || phy_ib_caps & outband_ok)) {
++                      /* Either in-band not supported at at least one end.
++                       * In-band bypass at the other end is possible.
++                       */
++                      if (phy_ib_caps & LINK_INBAND_DISABLE)
++                              pl->phy_ib_mode = LINK_INBAND_DISABLE;
++                      else if (phy_ib_caps & LINK_INBAND_BYPASS)
++                              pl->phy_ib_mode = LINK_INBAND_BYPASS;
++
+                       neg_mode = PHYLINK_PCS_NEG_OUTBAND;
++                      if (pl->phydev)
++                              mode = MLO_AN_PHY;
++              } else {
++                      /* invalid */
++                      phylink_warn(pl, "%s: incompatible in-band capabilities, trying in-band",
++                                   phy_modes(interface));
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
++              }
++      } else {
++              /* For Base-X without a PHY */
++              if (pcs_ib_caps == LINK_INBAND_DISABLE)
++                      /* If the PCS doesn't support inband, then inband must
++                       * be disabled.
++                       */
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
++              else if (pcs_ib_caps == LINK_INBAND_ENABLE)
++                      /* If the PCS requires inband, then inband must always
++                       * be enabled.
++                       */
++                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
+               else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+                                          advertising))
+                       neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
+               else
+                       neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
+-              break;
+-
+-      default:
+-              neg_mode = PHYLINK_PCS_NEG_NONE;
+-              break;
+       }
+       pl->pcs_neg_mode = neg_mode;
+@@ -1324,6 +1451,13 @@ static void phylink_major_config(struct
+                                   ERR_PTR(err));
+       }
++      if (pl->phydev && pl->phy_ib_mode) {
++              err = phy_config_inband(pl->phydev, pl->phy_ib_mode);
++              if (err < 0)
++                      phylink_err(pl, "phy_config_inband: %pe\n",
++                                  ERR_PTR(err));
++      }
++
+       if (pl->sfp_bus) {
+               rate_kbd = phylink_interface_signal_rate(state->interface);
+               if (rate_kbd)
diff --git a/target/linux/generic/backport-6.6/606-13-v6.14-net-phylink-remove-phylink_phy_no_inband.patch b/target/linux/generic/backport-6.6/606-13-v6.14-net-phylink-remove-phylink_phy_no_inband.patch
new file mode 100644 (file)
index 0000000..7c5d039
--- /dev/null
@@ -0,0 +1,110 @@
+From 77ac9a8b2536e0eaca6c6f21070068458bf55981 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2024 15:31:48 +0000
+Subject: [PATCH 13/13] net: phylink: remove phylink_phy_no_inband()
+
+Remove phylink_phy_no_inband() now that we are handling the lack of
+inband negotiation by querying the capabilities of the PHY and PCS,
+and the BCM84881 PHY driver provides us the information necessary to
+make the decision.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tIUsO-006IUt-KN@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/phylink.c | 27 ++++++---------------------
+ 1 file changed, 6 insertions(+), 21 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -3320,10 +3320,11 @@ static phy_interface_t phylink_choose_sf
+       return interface;
+ }
+-static void phylink_sfp_set_config(struct phylink *pl, u8 mode,
++static void phylink_sfp_set_config(struct phylink *pl,
+                                  unsigned long *supported,
+                                  struct phylink_link_state *state)
+ {
++      u8 mode = MLO_AN_INBAND;
+       bool changed = false;
+       phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
+@@ -3357,8 +3358,7 @@ static void phylink_sfp_set_config(struc
+               phylink_mac_initial_config(pl, false);
+ }
+-static int phylink_sfp_config_phy(struct phylink *pl, u8 mode,
+-                                struct phy_device *phy)
++static int phylink_sfp_config_phy(struct phylink *pl, struct phy_device *phy)
+ {
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(support);
+@@ -3398,7 +3398,7 @@ static int phylink_sfp_config_phy(struct
+       if (ret) {
+               phylink_err(pl,
+                           "validation of %s/%s with support %*pb failed: %pe\n",
+-                          phylink_an_mode_str(mode),
++                          phylink_an_mode_str(pl->req_link_an_mode),
+                           phy_modes(config.interface),
+                           __ETHTOOL_LINK_MODE_MASK_NBITS, support,
+                           ERR_PTR(ret));
+@@ -3407,7 +3407,7 @@ static int phylink_sfp_config_phy(struct
+       pl->link_port = pl->sfp_port;
+-      phylink_sfp_set_config(pl, mode, support, &config);
++      phylink_sfp_set_config(pl, support, &config);
+       return 0;
+ }
+@@ -3481,7 +3481,7 @@ static int phylink_sfp_config_optical(st
+       pl->link_port = pl->sfp_port;
+-      phylink_sfp_set_config(pl, MLO_AN_INBAND, pl->sfp_support, &config);
++      phylink_sfp_set_config(pl, pl->sfp_support, &config);
+       return 0;
+ }
+@@ -3552,20 +3552,10 @@ static void phylink_sfp_link_up(void *up
+       phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_LINK);
+ }
+-/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
+- * or 802.3z control word, so inband will not work.
+- */
+-static bool phylink_phy_no_inband(struct phy_device *phy)
+-{
+-      return phy->is_c45 && phy_id_compare(phy->c45_ids.device_ids[1],
+-                                           0xae025150, 0xfffffff0);
+-}
+-
+ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
+ {
+       struct phylink *pl = upstream;
+       phy_interface_t interface;
+-      u8 mode;
+       int ret;
+       /*
+@@ -3577,17 +3567,12 @@ static int phylink_sfp_connect_phy(void
+        */
+       phy_support_asym_pause(phy);
+-      if (phylink_phy_no_inband(phy))
+-              mode = MLO_AN_PHY;
+-      else
+-              mode = MLO_AN_INBAND;
+-
+       /* Set the PHY's host supported interfaces */
+       phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces,
+                         pl->config->supported_interfaces);
+       /* Do the initial configuration */
+-      ret = phylink_sfp_config_phy(pl, mode, phy);
++      ret = phylink_sfp_config_phy(pl, phy);
+       if (ret < 0)
+               return ret;
diff --git a/target/linux/generic/backport-6.6/607-01-v6.14-net-pcs-pcs-lynx-implement-pcs_inband_caps-method.patch b/target/linux/generic/backport-6.6/607-01-v6.14-net-pcs-pcs-lynx-implement-pcs_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..d5eb15d
--- /dev/null
@@ -0,0 +1,53 @@
+From 6561f0e547be221f411fda5eddfcc5bd8bb058a5 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Thu, 5 Dec 2024 09:42:24 +0000
+Subject: [PATCH 1/3] net: pcs: pcs-lynx: implement pcs_inband_caps() method
+
+Report the PCS in-band capabilities to phylink for the Lynx PCS.
+
+Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tJ8NM-006L5J-AH@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/pcs/pcs-lynx.c | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+--- a/drivers/net/pcs/pcs-lynx.c
++++ b/drivers/net/pcs/pcs-lynx.c
+@@ -35,6 +35,27 @@ enum sgmii_speed {
+ #define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs)
+ #define lynx_to_phylink_pcs(lynx) (&(lynx)->pcs)
++static unsigned int lynx_pcs_inband_caps(struct phylink_pcs *pcs,
++                                       phy_interface_t interface)
++{
++      switch (interface) {
++      case PHY_INTERFACE_MODE_1000BASEX:
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_QSGMII:
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++
++      case PHY_INTERFACE_MODE_10GBASER:
++      case PHY_INTERFACE_MODE_2500BASEX:
++              return LINK_INBAND_DISABLE;
++
++      case PHY_INTERFACE_MODE_USXGMII:
++              return LINK_INBAND_ENABLE;
++
++      default:
++              return 0;
++      }
++}
++
+ static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs,
+                                      struct phylink_link_state *state)
+ {
+@@ -307,6 +328,7 @@ static void lynx_pcs_link_up(struct phyl
+ }
+ static const struct phylink_pcs_ops lynx_pcs_phylink_ops = {
++      .pcs_inband_caps = lynx_pcs_inband_caps,
+       .pcs_get_state = lynx_pcs_get_state,
+       .pcs_config = lynx_pcs_config,
+       .pcs_an_restart = lynx_pcs_an_restart,
diff --git a/target/linux/generic/backport-6.6/607-02-v6.14-net-pcs-pcs-mtk-lynxi-implement-pcs_inband_caps-meth.patch b/target/linux/generic/backport-6.6/607-02-v6.14-net-pcs-pcs-mtk-lynxi-implement-pcs_inband_caps-meth.patch
new file mode 100644 (file)
index 0000000..1cfd3ba
--- /dev/null
@@ -0,0 +1,47 @@
+From 520d29bdda86915b3caf8c72825a574bff212553 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Thu, 5 Dec 2024 09:42:29 +0000
+Subject: [PATCH 2/3] net: pcs: pcs-mtk-lynxi: implement pcs_inband_caps()
+ method
+
+Report the PCS in-band capabilities to phylink for the LynxI PCS.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tJ8NR-006L5P-E3@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/pcs/pcs-mtk-lynxi.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/net/pcs/pcs-mtk-lynxi.c
++++ b/drivers/net/pcs/pcs-mtk-lynxi.c
+@@ -88,6 +88,21 @@ static struct mtk_pcs_lynxi *pcs_to_mtk_
+       return container_of(pcs, struct mtk_pcs_lynxi, pcs);
+ }
++static unsigned int mtk_pcs_lynxi_inband_caps(struct phylink_pcs *pcs,
++                                            phy_interface_t interface)
++{
++      switch (interface) {
++      case PHY_INTERFACE_MODE_1000BASEX:
++      case PHY_INTERFACE_MODE_2500BASEX:
++      case PHY_INTERFACE_MODE_SGMII:
++      case PHY_INTERFACE_MODE_QSGMII:
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++
++      default:
++              return 0;
++      }
++}
++
+ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs,
+                                   struct phylink_link_state *state)
+ {
+@@ -241,6 +256,7 @@ static void mtk_pcs_lynxi_disable(struct
+ }
+ static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = {
++      .pcs_inband_caps = mtk_pcs_lynxi_inband_caps,
+       .pcs_get_state = mtk_pcs_lynxi_get_state,
+       .pcs_config = mtk_pcs_lynxi_config,
+       .pcs_an_restart = mtk_pcs_lynxi_restart_an,
diff --git a/target/linux/generic/backport-6.6/607-03-v6.14-net-pcs-xpcs-implement-pcs_inband_caps-method.patch b/target/linux/generic/backport-6.6/607-03-v6.14-net-pcs-xpcs-implement-pcs_inband_caps-method.patch
new file mode 100644 (file)
index 0000000..4945f7c
--- /dev/null
@@ -0,0 +1,58 @@
+From 484d0170d6c6bbb5213d037664e9a551f793bacd Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Thu, 5 Dec 2024 09:42:34 +0000
+Subject: [PATCH 3/3] net: pcs: xpcs: implement pcs_inband_caps() method
+
+Report the PCS inband capabilities to phylink for XPCS.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/E1tJ8NW-006L5V-I9@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/pcs/pcs-xpcs.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/drivers/net/pcs/pcs-xpcs.c
++++ b/drivers/net/pcs/pcs-xpcs.c
+@@ -628,6 +628,33 @@ static int xpcs_validate(struct phylink_
+       return 0;
+ }
++static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs,
++                                   phy_interface_t interface)
++{
++      struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
++      const struct xpcs_compat *compat;
++
++      compat = xpcs_find_compat(xpcs->id, interface);
++      if (!compat)
++              return 0;
++
++      switch (compat->an_mode) {
++      case DW_AN_C73:
++              return LINK_INBAND_ENABLE;
++
++      case DW_AN_C37_SGMII:
++      case DW_AN_C37_1000BASEX:
++              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
++
++      case DW_10GBASER:
++      case DW_2500BASEX:
++              return LINK_INBAND_DISABLE;
++
++      default:
++              return 0;
++      }
++}
++
+ void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces)
+ {
+       int i, j;
+@@ -1331,6 +1358,7 @@ static const struct xpcs_id xpcs_id_list
+ static const struct phylink_pcs_ops xpcs_phylink_ops = {
+       .pcs_validate = xpcs_validate,
++      .pcs_inband_caps = xpcs_inband_caps,
+       .pcs_config = xpcs_config,
+       .pcs_get_state = xpcs_get_state,
+       .pcs_an_restart = xpcs_an_restart,
index 514a80b298dfdbbdddeb996daaf9f49b7964a52a..3efeb04d8bc5466a42f085c595b5b0295c8e2f3c 100644 (file)
@@ -242,7 +242,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
        refcount_t refcnt;
        unsigned long flags;
        size_t priv_size;
-@@ -1966,10 +1967,10 @@ int phy_ethtool_get_link_ksettings(struc
+@@ -2000,10 +2001,10 @@ int phy_ethtool_get_link_ksettings(struc
  int phy_ethtool_set_link_ksettings(struct net_device *ndev,
                                   const struct ethtool_link_ksettings *cmd);
  int phy_ethtool_nway_reset(struct net_device *ndev);
@@ -255,7 +255,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
  
  int __init mdio_bus_init(void);
  void mdio_bus_exit(void);
-@@ -1992,46 +1993,65 @@ int __phy_hwtstamp_set(struct phy_device
+@@ -2026,46 +2027,65 @@ int __phy_hwtstamp_set(struct phy_device
                       struct kernel_hwtstamp_config *config,
                       struct netlink_ext_ack *extack);
  
index d42da1b71fef39962f78ec6e8e845eee0b81843c..ae8a43feb17646be4cb84c3f3e9b05d49529ca40 100644 (file)
@@ -171,7 +171,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
   * @regnum: register number to modify
 --- a/include/linux/phy.h
 +++ b/include/linux/phy.h
-@@ -2054,6 +2054,22 @@ static inline int __phy_package_write(st
+@@ -2088,6 +2088,22 @@ static inline int __phy_package_write(st
        return __mdiobus_write(phydev->mdio.bus, addr, regnum, val);
  }
  
index 1fdd91497b26b37c2ff9c01afc5b49d1983d1a75..2fd03e920a0a355dd317ce0ee32a5c833ef960cd 100644 (file)
@@ -170,7 +170,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
        refcount_t refcnt;
        unsigned long flags;
        size_t priv_size;
-@@ -1968,9 +1971,12 @@ int phy_ethtool_set_link_ksettings(struc
+@@ -2002,9 +2005,12 @@ int phy_ethtool_set_link_ksettings(struc
                                   const struct ethtool_link_ksettings *cmd);
  int phy_ethtool_nway_reset(struct net_device *ndev);
  int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size);
index 4bb44b921d45f3c83e75524c9643303ffa37e975..22179d8cc4bcf7717da8d1394511e762866fc622 100644 (file)
@@ -89,7 +89,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
  }
 --- a/include/linux/phy.h
 +++ b/include/linux/phy.h
-@@ -1846,7 +1846,7 @@ int genphy_write_mmd_unsupported(struct
+@@ -1880,7 +1880,7 @@ int genphy_write_mmd_unsupported(struct
  
  /* Clause 37 */
  int genphy_c37_config_aneg(struct phy_device *phydev);
index b8460a2b5e2d8bdaeaaf64a673b92b2ec487221f..b60ce1cfcfcc36cb72f823bd5292cd8fdcfb8078 100644 (file)
@@ -261,7 +261,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  }
 --- a/include/linux/phy.h
 +++ b/include/linux/phy.h
-@@ -972,7 +972,8 @@ struct phy_driver {
+@@ -1003,7 +1003,8 @@ struct phy_driver {
         * driver for the given phydev.  If NULL, matching is based on
         * phy_id and phy_id_mask.
         */
index 1c0b5d836db2a705673e9c8d2f3d0e543a0e5e14..639856fcb83e164168c5cb6e8bca5dfbf62b9cf9 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
-@@ -1812,6 +1812,9 @@ char *phy_attached_info_irq(struct phy_d
+@@ -1846,6 +1846,9 @@ char *phy_attached_info_irq(struct phy_d
        __malloc;
  void phy_attached_info(struct phy_device *phydev);
  
index 4d8742f0e3329e558740d67d9ac4b898413b7e76..bc58e99276a87e4b5cb4a0b542d34d278cebd2b8 100644 (file)
@@ -60,7 +60,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
                cdev->brightness_set_blocking = phy_led_set_brightness;
 --- a/include/linux/phy.h
 +++ b/include/linux/phy.h
-@@ -867,6 +867,15 @@ struct phy_led {
+@@ -885,6 +885,15 @@ struct phy_led {
  
  #define to_phy_led(d) container_of(d, struct phy_led, led_cdev)
  
@@ -76,7 +76,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  /**
   * struct phy_driver - Driver structure for a particular PHY type
   *
-@@ -1144,6 +1153,19 @@ struct phy_driver {
+@@ -1175,6 +1184,19 @@ struct phy_driver {
        int (*led_hw_control_get)(struct phy_device *dev, u8 index,
                                  unsigned long *rules);
  
index 1b979f8662a4844fba78ec55a7dc14fe0b9fd955..aea1046add1e99f0fbb9ec6a777960e1e87a440f 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
-@@ -869,8 +869,9 @@ struct phy_led {
+@@ -887,8 +887,9 @@ struct phy_led {
  
  /* Modes for PHY LED configuration */
  enum phy_led_modes {
index 397780f7fdf73ad6c74cddccf12fec2994bb67bc..c73104522d546dc507670c474641a703295aba61 100644 (file)
@@ -17,7 +17,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
 
 --- a/drivers/net/phy/phylink.c
 +++ b/drivers/net/phy/phylink.c
-@@ -712,18 +712,16 @@ static int phylink_validate_mask(struct
+@@ -732,18 +732,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;
index 33f64e81c20f4a24f3f612a14b6cebd51764e927..ed2f348567237a5eb2e4d64c78c4362604975881 100644 (file)
@@ -17,7 +17,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 
 --- a/drivers/net/phy/phylink.c
 +++ b/drivers/net/phy/phylink.c
-@@ -704,26 +704,44 @@ static int phylink_validate_mac_and_pcs(
+@@ -724,26 +724,44 @@ static int phylink_validate_mac_and_pcs(
        return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
  }
  
index e3915f06091c859dbb89a2913b12b66b290a5c40..9f79748da90066402048937503c895d87f8bd8af 100644 (file)
@@ -17,7 +17,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 
 --- a/drivers/net/phy/phylink.c
 +++ b/drivers/net/phy/phylink.c
-@@ -704,7 +704,7 @@ static int phylink_validate_mac_and_pcs(
+@@ -724,7 +724,7 @@ static int phylink_validate_mac_and_pcs(
        return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
  }
  
@@ -26,7 +26,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
                                 const unsigned long *supported,
                                 const struct phylink_link_state *state,
                                 phy_interface_t interface,
-@@ -719,6 +719,9 @@ static void phylink_validate_one(struct
+@@ -739,6 +739,9 @@ static void phylink_validate_one(struct
        tmp_state = *state;
        tmp_state.interface = interface;
  
@@ -36,7 +36,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
        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
+@@ -760,7 +763,7 @@ static int phylink_validate_mask(struct
        int interface;
  
        for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
index 5f66869ef374ccbc899c57b74c303d9ab5496f08..6e04ebeda4cf23d5e1ebea4d779b9ea973cbde47 100644 (file)
@@ -17,7 +17,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 
 --- a/drivers/net/phy/phylink.c
 +++ b/drivers/net/phy/phylink.c
-@@ -734,7 +734,8 @@ static void phylink_validate_one(struct
+@@ -754,7 +754,8 @@ static void phylink_validate_one(struct
        }
  }
  
@@ -27,7 +27,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
                                 struct phylink_link_state *state,
                                 const unsigned long *interfaces)
  {
-@@ -743,7 +744,7 @@ static int phylink_validate_mask(struct
+@@ -763,7 +764,7 @@ static int phylink_validate_mask(struct
        int interface;
  
        for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
@@ -36,7 +36,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
                                     all_s, all_adv);
  
        linkmode_copy(supported, all_s);
-@@ -758,7 +759,8 @@ static int phylink_validate(struct phyli
+@@ -778,7 +779,8 @@ static int phylink_validate(struct phyli
        const unsigned long *interfaces = pl->config->supported_interfaces;
  
        if (state->interface == PHY_INTERFACE_MODE_NA)
@@ -46,7 +46,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  
        if (!test_bit(state->interface, interfaces))
                return -EINVAL;
-@@ -3194,7 +3196,8 @@ static int phylink_sfp_config_optical(st
+@@ -3465,7 +3467,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.
         */
index e29503398e0d6a6553414a60c0e51d9e55df320b..a02677d9a4140321ffedb3ca1e155d39ed69ef6d 100644 (file)
@@ -22,7 +22,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 
 --- a/drivers/net/phy/phylink.c
 +++ b/drivers/net/phy/phylink.c
-@@ -1775,6 +1775,35 @@ static void phylink_phy_change(struct ph
+@@ -2019,6 +2019,35 @@ static void phylink_phy_change(struct ph
                    phylink_pause_to_str(pl->phy_state.pause));
  }
  
@@ -58,7 +58,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  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
+@@ -2039,32 +2068,9 @@ static int phylink_bringup_phy(struct ph
        memset(&config, 0, sizeof(config));
        linkmode_copy(supported, phy->supported);
        linkmode_copy(config.advertising, phy->advertising);
index 86ed7a868ecdaf0c82a0e745838a35358c055d4a..1d98dd1de0c5dfd23d3a55686f5f628440d3a767 100644 (file)
@@ -40,7 +40,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 
 --- a/drivers/net/phy/phylink.c
 +++ b/drivers/net/phy/phylink.c
-@@ -121,6 +121,19 @@ do {                                                                      \
+@@ -123,6 +123,19 @@ do {                                                                      \
  })
  #endif
  
@@ -60,7 +60,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  /**
   * 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
+@@ -2023,6 +2036,47 @@ static int phylink_validate_phy(struct p
                                unsigned long *supported,
                                struct phylink_link_state *state)
  {
@@ -108,7 +108,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
        /* Check whether we would use rate matching for the proposed interface
         * mode.
         */
-@@ -3047,19 +3101,6 @@ static void phylink_sfp_detach(void *ups
+@@ -3318,19 +3372,6 @@ static void phylink_sfp_detach(void *ups
        pl->netdev->sfp_bus = NULL;
  }
  
index 30a502a237c7f37544073f73e72da2510be64e98..bf26a2f6ec1ccaac1242c0221b876737e0ae39c1 100644 (file)
@@ -13,7 +13,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
 
 --- a/drivers/net/pcs/pcs-mtk-lynxi.c
 +++ b/drivers/net/pcs/pcs-mtk-lynxi.c
-@@ -114,14 +114,23 @@ static void mtk_pcs_lynxi_get_state(stru
+@@ -129,14 +129,23 @@ static void mtk_pcs_lynxi_get_state(stru
                                    struct phylink_link_state *state)
  {
        struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
@@ -41,7 +41,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  }
  
  static void mtk_sgmii_reset(struct mtk_pcs_lynxi *mpcs)
-@@ -142,7 +151,7 @@ static int mtk_pcs_lynxi_config(struct p
+@@ -157,7 +166,7 @@ static int mtk_pcs_lynxi_config(struct p
  {
        struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
        bool mode_changed = false, changed;
@@ -50,7 +50,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
        int advertise, link_timer;
  
        advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
-@@ -165,9 +174,8 @@ static int mtk_pcs_lynxi_config(struct p
+@@ -180,9 +189,8 @@ static int mtk_pcs_lynxi_config(struct p
        if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
                if (interface == PHY_INTERFACE_MODE_SGMII)
                        sgm_mode |= SGMII_SPEED_DUPLEX_AN;
index 30a502a237c7f37544073f73e72da2510be64e98..bf26a2f6ec1ccaac1242c0221b876737e0ae39c1 100644 (file)
@@ -13,7 +13,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
 
 --- a/drivers/net/pcs/pcs-mtk-lynxi.c
 +++ b/drivers/net/pcs/pcs-mtk-lynxi.c
-@@ -114,14 +114,23 @@ static void mtk_pcs_lynxi_get_state(stru
+@@ -129,14 +129,23 @@ static void mtk_pcs_lynxi_get_state(stru
                                    struct phylink_link_state *state)
  {
        struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
@@ -41,7 +41,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  }
  
  static void mtk_sgmii_reset(struct mtk_pcs_lynxi *mpcs)
-@@ -142,7 +151,7 @@ static int mtk_pcs_lynxi_config(struct p
+@@ -157,7 +166,7 @@ static int mtk_pcs_lynxi_config(struct p
  {
        struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
        bool mode_changed = false, changed;
@@ -50,7 +50,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
        int advertise, link_timer;
  
        advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
-@@ -165,9 +174,8 @@ static int mtk_pcs_lynxi_config(struct p
+@@ -180,9 +189,8 @@ static int mtk_pcs_lynxi_config(struct p
        if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
                if (interface == PHY_INTERFACE_MODE_SGMII)
                        sgm_mode |= SGMII_SPEED_DUPLEX_AN;
index ed6c9070b24bca71c454d8f2eeb45e78c15b1490..f8bcf6744f7339259641a01f5b224c4d1049a292 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
-@@ -996,6 +996,12 @@ struct phy_driver {
+@@ -1027,6 +1027,12 @@ struct phy_driver {
        /** @handle_interrupt: Override default interrupt handling */
        irqreturn_t (*handle_interrupt)(struct phy_device *phydev);
  
index 6b2b016881da8b1c0ab0f0e60bd2e4764a7b8a8a..0af507eed360e8bed6f07c41eb01cf89cd7eb921 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
-@@ -2086,7 +2086,7 @@ int phylink_fwnode_phy_connect(struct ph
+@@ -2264,7 +2264,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 ||
-@@ -2116,6 +2116,25 @@ int phylink_fwnode_phy_connect(struct ph
+@@ -2294,6 +2294,25 @@ int phylink_fwnode_phy_connect(struct ph
        if (pl->config->mac_requires_rxc)
                flags |= PHY_F_RXC_ALWAYS_ON;
  
index 8eb9d35b5800eb526c1a03c1a40f4e68f85af1be..0e4a63ec7fbe960dbbdcacb56713038447a09ae0 100644 (file)
@@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs)
  {
        return container_of(pcs, struct mtk_pcs_lynxi, pcs);
-@@ -102,6 +124,17 @@ static void mtk_pcs_lynxi_get_state(stru
+@@ -117,6 +139,17 @@ static void mtk_pcs_lynxi_get_state(stru
                                         FIELD_GET(SGMII_LPA, adv));
  }
  
@@ -97,7 +97,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
                                phy_interface_t interface,
                                const unsigned long *advertising,
-@@ -147,6 +180,7 @@ static int mtk_pcs_lynxi_config(struct p
+@@ -162,6 +195,7 @@ static int mtk_pcs_lynxi_config(struct p
                                SGMII_PHYA_PWD);
  
                /* Reset SGMII PCS state */
@@ -105,7 +105,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
                regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0,
                                SGMII_SW_RESET);
  
-@@ -233,10 +267,29 @@ static void mtk_pcs_lynxi_link_up(struct
+@@ -248,10 +282,29 @@ static void mtk_pcs_lynxi_link_up(struct
        }
  }
  
@@ -135,7 +135,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
        mpcs->interface = PHY_INTERFACE_MODE_NA;
  }
  
-@@ -246,11 +299,12 @@ static const struct phylink_pcs_ops mtk_
+@@ -262,11 +315,12 @@ static const struct phylink_pcs_ops mtk_
        .pcs_an_restart = mtk_pcs_lynxi_restart_an,
        .pcs_link_up = mtk_pcs_lynxi_link_up,
        .pcs_disable = mtk_pcs_lynxi_disable,
@@ -151,7 +151,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  {
        struct mtk_pcs_lynxi *mpcs;
        u32 id, ver;
-@@ -258,29 +312,33 @@ struct phylink_pcs *mtk_pcs_lynxi_create
+@@ -274,29 +328,33 @@ struct phylink_pcs *mtk_pcs_lynxi_create
  
        ret = regmap_read(regmap, SGMSYS_PCS_DEVICE_ID, &id);
        if (ret < 0)
@@ -192,7 +192,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  
        mpcs->ana_rgc3 = ana_rgc3;
        mpcs->regmap = regmap;
-@@ -291,6 +349,13 @@ struct phylink_pcs *mtk_pcs_lynxi_create
+@@ -307,6 +365,13 @@ struct phylink_pcs *mtk_pcs_lynxi_create
        mpcs->interface = PHY_INTERFACE_MODE_NA;
  
        return &mpcs->pcs;
@@ -206,7 +206,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  }
  EXPORT_SYMBOL(mtk_pcs_lynxi_create);
  
-@@ -303,5 +368,142 @@ void mtk_pcs_lynxi_destroy(struct phylin
+@@ -319,5 +384,142 @@ void mtk_pcs_lynxi_destroy(struct phylin
  }
  EXPORT_SYMBOL(mtk_pcs_lynxi_destroy);
  
index efa76572f86e74f5f7c2138c4f81c77007c83af5..3fe618ab9c1aa2cedc200e8340f6f698c63ae0c2 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
-@@ -977,6 +977,12 @@ struct phy_driver {
+@@ -1008,6 +1008,12 @@ struct phy_driver {
        /** @handle_interrupt: Override default interrupt handling */
        irqreturn_t (*handle_interrupt)(struct phy_device *phydev);
  
index 78e0049f05243fe7512301ca4a134184ef5d4e96..968fea4431f5ca9dfa038e12f1003da460ccd9cf 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
-@@ -2017,7 +2017,7 @@ int phylink_fwnode_phy_connect(struct ph
+@@ -2261,7 +2261,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 ||
-@@ -2044,6 +2044,25 @@ int phylink_fwnode_phy_connect(struct ph
+@@ -2288,6 +2288,25 @@ int phylink_fwnode_phy_connect(struct ph
                pl->link_config.interface = pl->link_interface;
        }
  
index faa7624307dfed9fc432c8af91a1561b9395f8dc..11cb53428fb0181c528184cf4d8bcc585427b64c 100644 (file)
@@ -79,7 +79,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs)
  {
        return container_of(pcs, struct mtk_pcs_lynxi, pcs);
-@@ -102,6 +124,17 @@ static void mtk_pcs_lynxi_get_state(stru
+@@ -117,6 +139,17 @@ static void mtk_pcs_lynxi_get_state(stru
                                         FIELD_GET(SGMII_LPA, adv));
  }
  
@@ -97,7 +97,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
                                phy_interface_t interface,
                                const unsigned long *advertising,
-@@ -147,6 +180,7 @@ static int mtk_pcs_lynxi_config(struct p
+@@ -162,6 +195,7 @@ static int mtk_pcs_lynxi_config(struct p
                                SGMII_PHYA_PWD);
  
                /* Reset SGMII PCS state */
@@ -105,7 +105,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
                regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0,
                                SGMII_SW_RESET);
  
-@@ -233,10 +267,29 @@ static void mtk_pcs_lynxi_link_up(struct
+@@ -248,10 +282,29 @@ static void mtk_pcs_lynxi_link_up(struct
        }
  }
  
@@ -135,7 +135,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
        mpcs->interface = PHY_INTERFACE_MODE_NA;
  }
  
-@@ -246,11 +299,12 @@ static const struct phylink_pcs_ops mtk_
+@@ -262,11 +315,12 @@ static const struct phylink_pcs_ops mtk_
        .pcs_an_restart = mtk_pcs_lynxi_restart_an,
        .pcs_link_up = mtk_pcs_lynxi_link_up,
        .pcs_disable = mtk_pcs_lynxi_disable,
@@ -151,7 +151,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  {
        struct mtk_pcs_lynxi *mpcs;
        u32 id, ver;
-@@ -258,29 +312,33 @@ struct phylink_pcs *mtk_pcs_lynxi_create
+@@ -274,29 +328,33 @@ struct phylink_pcs *mtk_pcs_lynxi_create
  
        ret = regmap_read(regmap, SGMSYS_PCS_DEVICE_ID, &id);
        if (ret < 0)
@@ -192,7 +192,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  
        mpcs->ana_rgc3 = ana_rgc3;
        mpcs->regmap = regmap;
-@@ -291,6 +349,13 @@ struct phylink_pcs *mtk_pcs_lynxi_create
+@@ -307,6 +365,13 @@ struct phylink_pcs *mtk_pcs_lynxi_create
        mpcs->interface = PHY_INTERFACE_MODE_NA;
  
        return &mpcs->pcs;
@@ -206,7 +206,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  }
  EXPORT_SYMBOL(mtk_pcs_lynxi_create);
  
-@@ -303,4 +368,142 @@ void mtk_pcs_lynxi_destroy(struct phylin
+@@ -319,4 +384,142 @@ void mtk_pcs_lynxi_destroy(struct phylin
  }
  EXPORT_SYMBOL(mtk_pcs_lynxi_destroy);
  
index 92e71276bf84a8bda4146adc5bc7d7981dcb3743..af14871b59fa93289cb5076cbff53d128b4768a2 100644 (file)
@@ -36,7 +36,7 @@ Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
        case PHY_INTERFACE_MODE_QUSGMII:
 --- a/drivers/net/phy/phylink.c
 +++ b/drivers/net/phy/phylink.c
-@@ -230,6 +230,7 @@ static int phylink_interface_max_speed(p
+@@ -250,6 +250,7 @@ static int phylink_interface_max_speed(p
        case PHY_INTERFACE_MODE_GMII:
                return SPEED_1000;
  
@@ -44,7 +44,7 @@ Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
        case PHY_INTERFACE_MODE_2500BASEX:
        case PHY_INTERFACE_MODE_10G_QXGMII:
                return SPEED_2500;
-@@ -544,6 +545,7 @@ static unsigned long phylink_get_capabil
+@@ -564,6 +565,7 @@ static unsigned long phylink_get_capabil
                break;
  
        case PHY_INTERFACE_MODE_2500BASEX:
index b4e527214e85d9a8e968192212307d6d6b3224d1..975288871ebbf6c521a7b6bc3d23c745e5e41378 100644 (file)
@@ -25,7 +25,7 @@ Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
        case PHY_INTERFACE_MODE_QUSGMII:
 --- a/drivers/net/phy/phylink.c
 +++ b/drivers/net/phy/phylink.c
-@@ -231,6 +231,7 @@ static int phylink_interface_max_speed(p
+@@ -251,6 +251,7 @@ static int phylink_interface_max_speed(p
                return SPEED_1000;
  
        case PHY_INTERFACE_MODE_2500BASEX:
@@ -33,7 +33,7 @@ Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
                return SPEED_2500;
  
        case PHY_INTERFACE_MODE_5GBASER:
-@@ -539,6 +540,7 @@ unsigned long phylink_get_capabilities(p
+@@ -559,6 +560,7 @@ unsigned long phylink_get_capabilities(p
                break;
  
        case PHY_INTERFACE_MODE_2500BASEX:
diff --git a/target/linux/mediatek/patches-6.12/739-net-add-negotiation-of-in-band-capabilities.patch b/target/linux/mediatek/patches-6.12/739-net-add-negotiation-of-in-band-capabilities.patch
deleted file mode 100644 (file)
index 1263897..0000000
+++ /dev/null
@@ -1,1242 +0,0 @@
-From: "Russell King (Oracle)" <linux@armlinux.org.uk>
-To: Andrew Lunn <andrew@lunn.ch>, Heiner Kallweit <hkallweit1@gmail.com>
-Cc: Alexander Couzens <lynxis@fe80.eu>,
-       Andrew Lunn <andrew+netdev@lunn.ch>,
-       AngeloGioacchino Del Regno
-       <angelogioacchino.delregno@collabora.com>,
-       Broadcom internal kernel review list
-       <bcm-kernel-feedback-list@broadcom.com>,
-       Daniel Golle <daniel@makrotopia.org>,
-       "David S. Miller" <davem@davemloft.net>,
-       Eric Dumazet <edumazet@google.com>,
-       Florian Fainelli <florian.fainelli@broadcom.com>,
-       Ioana Ciornei <ioana.ciornei@nxp.com>,
-       Jakub Kicinski <kuba@kernel.org>,
-       Jose Abreu <Jose.Abreu@synopsys.com>,
-       linux-arm-kernel@lists.infradead.org,
-       linux-mediatek@lists.infradead.org,
-       Marcin Wojtas <marcin.s.wojtas@gmail.com>,
-       Matthias Brugger <matthias.bgg@gmail.com>,
-       netdev@vger.kernel.org, Paolo Abeni <pabeni@redhat.com>
-Subject: [PATCH RFC net-next 00/16] net: add negotiation of in-band capabilities
-Date: Tue, 26 Nov 2024 09:23:48 +0000  [thread overview]
-Message-ID: <Z0WTpE8wkpjMiv_J@shell.armlinux.org.uk> (raw)
-
-Hi,
-
-Yes, this is one patch over the limit of 15 for netdev - but I think it's
-important to include the last patch to head off review comments like "why
-don't you remove phylink_phy_no_inband() in this series?"
-
-Phylink's handling of in-band has been deficient for a long time, and
-people keep hitting problems with it. Notably, situations with the way-
-to-late standardized 2500Base-X and whether that should or should not
-have in-band enabled. We have also been carrying a hack in the form of
-phylink_phy_no_inband() for a PHY that has been used on a SFP module,
-but has no in-band capabilities, not even for SGMII.
-
-When phylink is trying to operate in in-band mode, this series will look
-at the capabilities of the MAC-side PCS and PHY, and work out whether
-in-band can or should be used, programming the PHY as appropriate. This
-includes in-band bypass mode at the PHY.
-
-We don't... yet... support that on the MAC side PCS, because that
-requires yet more complexity.
-
-Patch 1 passes struct phylink and struct phylink_pcs into
-phylink_pcs_neg_mode() so we can look at more state in this function in
-a future patch.
-
-Patch 2 splits "cur_link_an_mode" (the MLO_AN_* mode) into two separate
-purposes - a requested and an active mode. The active mode is the one
-we will be using for the MAC, which becomes dependent on the result of
-in-band negotiation.
-
-Patch 3 adds debug to phylink_major_config() so we can see what is going
-on with the requested and active AN modes.
-
-Patch 4 adds to phylib a method to get the in-band capabilities of the
-PHY from phylib. Patches 5 and 6 add implementations for BCM84881 and
-some Marvell PHYs found on SFPs.
-
-Patch 7 adds to phylib a method to configure the PHY in-band signalling,
-and patch 8 implements it for those Marvell PHYs that support the method
-in patch 4.
-
-Patch 9 does the same as patch 4 but for the MAC-side PCS, with patches
-10 through 14 adding support to several PCS.
-
-Patch 15 adds the code to phylink_pcs_neg_mode() which looks at the
-capabilities, and works out whether to use in-band or out-band mode for
-driving the link between the MAC PCS and PHY.
-
-Patch 16 removes the phylink_phy_no_inband() hack now that we are
-publishing the in-band capabilities from the BCM84881 PHY driver.
-
- drivers/net/ethernet/marvell/mvneta.c           |  27 +-
- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c |  25 +-
- drivers/net/pcs/pcs-lynx.c                      |  22 ++
- drivers/net/pcs/pcs-mtk-lynxi.c                 |  16 ++
- drivers/net/pcs/pcs-xpcs.c                      |  28 ++
- drivers/net/phy/bcm84881.c                      |  10 +
- drivers/net/phy/marvell.c                       |  48 ++++
- drivers/net/phy/phy.c                           |  52 ++++
- drivers/net/phy/phylink.c                       | 352 +++++++++++++++++++-----
- include/linux/phy.h                             |  34 +++
- include/linux/phylink.h                         |  17 ++
- 11 files changed, 539 insertions(+), 92 deletions(-)
-
---- a/drivers/net/phy/phylink.c
-+++ b/drivers/net/phy/phylink.c
-@@ -56,7 +56,8 @@ struct phylink {
-       struct phy_device *phydev;
-       phy_interface_t link_interface; /* PHY_INTERFACE_xxx */
-       u8 cfg_link_an_mode;            /* MLO_AN_xxx */
--      u8 cur_link_an_mode;
-+      u8 req_link_an_mode;            /* Requested MLO_AN_xxx mode */
-+      u8 act_link_an_mode;            /* Active MLO_AN_xxx mode */
-       u8 link_port;                   /* The current non-phy ethtool port */
-       __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
-@@ -74,6 +75,7 @@ struct phylink {
-       struct mutex state_mutex;
-       struct phylink_link_state phy_state;
-+      unsigned int phy_ib_mode;
-       struct work_struct resolve;
-       unsigned int pcs_neg_mode;
-       unsigned int pcs_state;
-@@ -175,6 +177,24 @@ static const char *phylink_an_mode_str(u
-       return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown";
- }
-+static const char *phylink_pcs_mode_str(unsigned int mode)
-+{
-+      if (!mode)
-+              return "none";
-+
-+      if (mode & PHYLINK_PCS_NEG_OUTBAND)
-+              return "outband";
-+
-+      if (mode & PHYLINK_PCS_NEG_INBAND) {
-+              if (mode & PHYLINK_PCS_NEG_ENABLED)
-+                      return "inband,an-enabled";
-+              else
-+                      return "inband,an-disabled";
-+      }
-+
-+      return "unknown";
-+}
-+
- static unsigned int phylink_interface_signal_rate(phy_interface_t interface)
- {
-       switch (interface) {
-@@ -988,6 +1008,15 @@ static void phylink_resolve_an_pause(str
-       }
- }
-+static unsigned int phylink_pcs_inband_caps(struct phylink_pcs *pcs,
-+                                  phy_interface_t interface)
-+{
-+      if (pcs && pcs->ops->pcs_inband_caps)
-+              return pcs->ops->pcs_inband_caps(pcs, interface);
-+
-+      return 0;
-+}
-+
- static void phylink_pcs_pre_config(struct phylink_pcs *pcs,
-                                  phy_interface_t interface)
- {
-@@ -1041,6 +1070,24 @@ static void phylink_pcs_link_up(struct p
-               pcs->ops->pcs_link_up(pcs, neg_mode, interface, speed, duplex);
- }
-+/* Query inband for a specific interface mode, asking the MAC for the
-+ * PCS which will be used to handle the interface mode.
-+ */
-+static unsigned int phylink_inband_caps(struct phylink *pl,
-+                                       phy_interface_t interface)
-+{
-+      struct phylink_pcs *pcs;
-+
-+      if (!pl->mac_ops->mac_select_pcs)
-+              return 0;
-+
-+      pcs = pl->mac_ops->mac_select_pcs(pl->config, interface);
-+      if (!pcs)
-+              return 0;
-+
-+      return phylink_pcs_inband_caps(pcs, interface);
-+}
-+
- static void phylink_pcs_poll_stop(struct phylink *pl)
- {
-       if (pl->cfg_link_an_mode == MLO_AN_INBAND)
-@@ -1082,13 +1129,13 @@ static void phylink_mac_config(struct ph
-       phylink_dbg(pl,
-                   "%s: mode=%s/%s/%s adv=%*pb pause=%02x\n",
--                  __func__, phylink_an_mode_str(pl->cur_link_an_mode),
-+                  __func__, phylink_an_mode_str(pl->act_link_an_mode),
-                   phy_modes(st.interface),
-                   phy_rate_matching_to_str(st.rate_matching),
-                   __ETHTOOL_LINK_MODE_MASK_NBITS, st.advertising,
-                   st.pause);
--      pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, &st);
-+      pl->mac_ops->mac_config(pl->config, pl->act_link_an_mode, &st);
- }
- static void phylink_pcs_an_restart(struct phylink *pl)
-@@ -1096,13 +1143,14 @@ static void phylink_pcs_an_restart(struc
-       if (pl->pcs && linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
-                                        pl->link_config.advertising) &&
-           phy_interface_mode_is_8023z(pl->link_config.interface) &&
--          phylink_autoneg_inband(pl->cur_link_an_mode))
-+          phylink_autoneg_inband(pl->act_link_an_mode))
-               pl->pcs->ops->pcs_an_restart(pl->pcs);
- }
- /**
-  * phylink_pcs_neg_mode() - helper to determine PCS inband mode
-- * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
-+ * @pl: a pointer to a &struct phylink returned from phylink_create()
-+ * @pcs: a pointer to &struct phylink_pcs
-  * @interface: interface mode to be used
-  * @advertising: adertisement ethtool link mode mask
-  *
-@@ -1119,11 +1167,21 @@ static void phylink_pcs_an_restart(struc
-  * Note: this is for cases where the PCS itself is involved in negotiation
-  * (e.g. Clause 37, SGMII and similar) not Clause 73.
-  */
--static unsigned int phylink_pcs_neg_mode(unsigned int mode,
--                                       phy_interface_t interface,
--                                       const unsigned long *advertising)
-+static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs,
-+                               phy_interface_t interface,
-+                               const unsigned long *advertising)
- {
--      unsigned int neg_mode;
-+      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;
-+
-+      pl->phy_ib_mode = 0;
-       switch (interface) {
-       case PHY_INTERFACE_MODE_SGMII:
-@@ -1136,10 +1194,7 @@ static unsigned int phylink_pcs_neg_mode
-                * inband communication. Note: there exist PHYs that run
-                * with SGMII but do not send the inband data.
-                */
--              if (!phylink_autoneg_inband(mode))
--                      neg_mode = PHYLINK_PCS_NEG_OUTBAND;
--              else
--                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-+              type = INBAND_CISCO_SGMII;
-               break;
-       case PHY_INTERFACE_MODE_1000BASEX:
-@@ -1150,21 +1205,143 @@ static unsigned int phylink_pcs_neg_mode
-                * as well, but drivers may not support this, so may
-                * need to override this.
-                */
--              if (!phylink_autoneg_inband(mode))
-+              type = INBAND_BASEX;
-+              break;
-+
-+      default:
-+              pl->pcs_neg_mode = PHYLINK_PCS_NEG_NONE;
-+              pl->act_link_an_mode = mode;
-+              return;
-+      }
-+
-+      if (pcs)
-+              pcs_ib_caps = phylink_pcs_inband_caps(pcs, interface);
-+
-+      if (pl->phydev)
-+              phy_ib_caps = phy_inband_caps(pl->phydev, interface);
-+
-+      phylink_dbg(pl, "interface %s inband modes: pcs=%02x phy=%02x\n",
-+                  phy_modes(interface), pcs_ib_caps, phy_ib_caps);
-+
-+      if (!phylink_autoneg_inband(mode)) {
-+              bool pcs_ib_only = false;
-+              bool phy_ib_only = false;
-+
-+              if (pcs_ib_caps && pcs_ib_caps != LINK_INBAND_DISABLE) {
-+                      /* PCS supports reporting in-band capabilities, and
-+                       * supports more than disable mode.
-+                       */
-+                      if (pcs_ib_caps & LINK_INBAND_DISABLE)
-+                              neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-+                      else if (pcs_ib_caps & LINK_INBAND_ENABLE)
-+                              pcs_ib_only = true;
-+              }
-+
-+              if (phy_ib_caps && phy_ib_caps != LINK_INBAND_DISABLE) {
-+                      /* PHY supports in-band capabilities, and supports
-+                       * more than disable mode.
-+                       */
-+                      if (phy_ib_caps & LINK_INBAND_DISABLE)
-+                              pl->phy_ib_mode = LINK_INBAND_DISABLE;
-+                      else if (phy_ib_caps & LINK_INBAND_BYPASS)
-+                              pl->phy_ib_mode = LINK_INBAND_BYPASS;
-+                      else if (phy_ib_caps & LINK_INBAND_ENABLE)
-+                              phy_ib_only = true;
-+              }
-+
-+              /* If either the PCS or PHY requires inband to be enabled,
-+               * this is an invalid configuration. Provide a diagnostic
-+               * message for this case, but don't try to force the issue.
-+               */
-+              if (pcs_ib_only || phy_ib_only)
-+                      phylink_warn(pl,
-+                                   "firmware wants %s mode, but %s%s%s requires inband\n",
-+                                   phylink_an_mode_str(mode),
-+                                   pcs_ib_only ? "PCS" : "",
-+                                   pcs_ib_only && phy_ib_only ? " and " : "",
-+                                   phy_ib_only ? "PHY" : "");
-+
-+              neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-+      } else if (type == INBAND_CISCO_SGMII || pl->phydev) {
-+              /* For SGMII modes which are designed to be used with PHYs, or
-+               * Base-X with a PHY, we try to use in-band mode where-ever
-+               * possible. However, there are some PHYs e.g. BCM84881 which
-+               * do not support in-band.
-+               */
-+              const unsigned int inband_ok = LINK_INBAND_ENABLE |
-+                                             LINK_INBAND_BYPASS;
-+              const unsigned int outband_ok = LINK_INBAND_DISABLE |
-+                                              LINK_INBAND_BYPASS;
-+              /* PCS  PHY
-+               * D E  D E
-+               * 0 0  0 0     no information                  inband enabled
-+               * 1 0  0 0     pcs doesn't support             outband
-+               * 0 1  0 0     pcs required                    inband enabled
-+               * 1 1  0 0     pcs optional                    inband enabled
-+               * 0 0  1 0     phy doesn't support             outband
-+               * 1 0  1 0     pcs+phy doesn't support         outband
-+               * 0 1  1 0     pcs required, phy doesn't support, invalid
-+               * 1 1  1 0     pcs optional, phy doesn't support, outband
-+               * 0 0  0 1     phy required                    inband enabled
-+               * 1 0  0 1     pcs doesn't support, phy required, invalid
-+               * 0 1  0 1     pcs+phy required                inband enabled
-+               * 1 1  0 1     pcs optional, phy required      inband enabled
-+               * 0 0  1 1     phy optional                    inband enabled
-+               * 1 0  1 1     pcs doesn't support, phy optional, outband
-+               * 0 1  1 1     pcs required, phy optional      inband enabled
-+               * 1 1  1 1     pcs+phy optional                inband enabled
-+               */
-+              if ((!pcs_ib_caps || pcs_ib_caps & inband_ok) &&
-+                  (!phy_ib_caps || phy_ib_caps & inband_ok)) {
-+                      /* In-band supported or unknown at both ends. Enable
-+                       * in-band mode with or without bypass at the PHY.
-+                       */
-+                      if (phy_ib_caps & LINK_INBAND_ENABLE)
-+                              pl->phy_ib_mode = LINK_INBAND_ENABLE;
-+                      else if (phy_ib_caps & LINK_INBAND_BYPASS)
-+                              pl->phy_ib_mode = LINK_INBAND_BYPASS;
-+
-+                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-+              } else if ((!pcs_ib_caps || pcs_ib_caps & outband_ok) &&
-+                         (!phy_ib_caps || phy_ib_caps & outband_ok)) {
-+                      /* Either in-band not supported at at least one end.
-+                       * In-band bypass at the other end is possible.
-+                       */
-+                      if (phy_ib_caps & LINK_INBAND_DISABLE)
-+                              pl->phy_ib_mode = LINK_INBAND_DISABLE;
-+                      else if (phy_ib_caps & LINK_INBAND_BYPASS)
-+                              pl->phy_ib_mode = LINK_INBAND_BYPASS;
-+
-                       neg_mode = PHYLINK_PCS_NEG_OUTBAND;
-+                      if (pl->phydev)
-+                              mode = MLO_AN_PHY;
-+              } else {
-+                      /* invalid */
-+                      phylink_warn(pl, "%s: incompatible in-band capabilities, trying in-band",
-+                                   phy_modes(interface));
-+                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-+              }
-+      } else {
-+              /* For Base-X without a PHY */
-+              if (pcs_ib_caps == LINK_INBAND_DISABLE)
-+                      /* If the PCS doesn't support inband, then inband must
-+                       * be disabled.
-+                       */
-+                      neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
-+              else if (pcs_ib_caps == LINK_INBAND_ENABLE)
-+                      /* If the PCS requires inband, then inband must always
-+                       * be enabled.
-+                       */
-+                      neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-               else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
-                                          advertising))
-                       neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
-               else
-                       neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
--              break;
--
--      default:
--              neg_mode = PHYLINK_PCS_NEG_NONE;
--              break;
-       }
--      return neg_mode;
-+      pl->pcs_neg_mode = neg_mode;
-+      pl->act_link_an_mode = mode;
- }
- static void phylink_major_config(struct phylink *pl, bool restart,
-@@ -1176,11 +1353,9 @@ static void phylink_major_config(struct
-       unsigned int neg_mode;
-       int err;
--      phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
--
--      pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode,
--                                              state->interface,
--                                              state->advertising);
-+      phylink_dbg(pl, "major config, requested %s/%s\n",
-+                  phylink_an_mode_str(pl->req_link_an_mode),
-+                  phy_modes(state->interface));
-       if (pl->using_mac_select_pcs) {
-               pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
-@@ -1194,10 +1369,17 @@ static void phylink_major_config(struct
-               pcs_changed = pcs && pl->pcs != pcs;
-       }
-+      phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising);
-+
-+      phylink_dbg(pl, "major config, active %s/%s/%s\n",
-+                  phylink_an_mode_str(pl->act_link_an_mode),
-+                  phylink_pcs_mode_str(pl->pcs_neg_mode),
-+                  phy_modes(state->interface));
-+
-       phylink_pcs_poll_stop(pl);
-       if (pl->mac_ops->mac_prepare) {
--              err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode,
-+              err = pl->mac_ops->mac_prepare(pl->config, pl->act_link_an_mode,
-                                              state->interface);
-               if (err < 0) {
-                       phylink_err(pl, "mac_prepare failed: %pe\n",
-@@ -1231,7 +1413,7 @@ static void phylink_major_config(struct
-       if (pl->pcs_state == PCS_STATE_STARTING || pcs_changed)
-               phylink_pcs_enable(pl->pcs);
--      neg_mode = pl->cur_link_an_mode;
-+      neg_mode = pl->act_link_an_mode;
-       if (pl->pcs && pl->pcs->neg_mode)
-               neg_mode = pl->pcs_neg_mode;
-@@ -1247,13 +1429,20 @@ static void phylink_major_config(struct
-               phylink_pcs_an_restart(pl);
-       if (pl->mac_ops->mac_finish) {
--              err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode,
-+              err = pl->mac_ops->mac_finish(pl->config, pl->act_link_an_mode,
-                                             state->interface);
-               if (err < 0)
-                       phylink_err(pl, "mac_finish failed: %pe\n",
-                                   ERR_PTR(err));
-       }
-+      if (pl->phydev && pl->phy_ib_mode) {
-+              err = phy_config_inband(pl->phydev, pl->phy_ib_mode);
-+              if (err < 0)
-+                      phylink_err(pl, "phy_config_inband: %pe\n",
-+                                  ERR_PTR(err));
-+      }
-+
-       if (pl->sfp_bus) {
-               rate_kbd = phylink_interface_signal_rate(state->interface);
-               if (rate_kbd)
-@@ -1278,17 +1467,16 @@ static int phylink_change_inband_advert(
-               return 0;
-       phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__,
--                  phylink_an_mode_str(pl->cur_link_an_mode),
-+                  phylink_an_mode_str(pl->req_link_an_mode),
-                   phy_modes(pl->link_config.interface),
-                   __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising,
-                   pl->link_config.pause);
-       /* Recompute the PCS neg mode */
--      pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode,
--                                      pl->link_config.interface,
--                                      pl->link_config.advertising);
-+      phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface,
-+                           pl->link_config.advertising);
--      neg_mode = pl->cur_link_an_mode;
-+      neg_mode = pl->act_link_an_mode;
-       if (pl->pcs->neg_mode)
-               neg_mode = pl->pcs_neg_mode;
-@@ -1353,7 +1541,7 @@ static void phylink_mac_initial_config(s
- {
-       struct phylink_link_state link_state;
--      switch (pl->cur_link_an_mode) {
-+      switch (pl->req_link_an_mode) {
-       case MLO_AN_PHY:
-               link_state = pl->phy_state;
-               break;
-@@ -1427,14 +1615,14 @@ static void phylink_link_up(struct phyli
-       pl->cur_interface = link_state.interface;
--      neg_mode = pl->cur_link_an_mode;
-+      neg_mode = pl->act_link_an_mode;
-       if (pl->pcs && pl->pcs->neg_mode)
-               neg_mode = pl->pcs_neg_mode;
-       phylink_pcs_link_up(pl->pcs, neg_mode, pl->cur_interface, speed,
-                           duplex);
--      pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode,
-+      pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->act_link_an_mode,
-                                pl->cur_interface, speed, duplex,
-                                !!(link_state.pause & MLO_PAUSE_TX), rx_pause);
-@@ -1454,7 +1642,7 @@ static void phylink_link_down(struct phy
-       if (ndev)
-               netif_carrier_off(ndev);
--      pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode,
-+      pl->mac_ops->mac_link_down(pl->config, pl->act_link_an_mode,
-                                  pl->cur_interface);
-       phylink_info(pl, "Link is Down\n");
- }
-@@ -1481,7 +1669,7 @@ static void phylink_resolve(struct work_
-               link_state.link = false;
-               retrigger = true;
-       } else {
--              switch (pl->cur_link_an_mode) {
-+              switch (pl->act_link_an_mode) {
-               case MLO_AN_PHY:
-                       link_state = pl->phy_state;
-                       phylink_apply_manual_flow(pl, &link_state);
-@@ -1671,7 +1859,7 @@ int phylink_set_fixed_link(struct phylin
-       pl->link_config.an_complete = 1;
-       pl->cfg_link_an_mode = MLO_AN_FIXED;
--      pl->cur_link_an_mode = pl->cfg_link_an_mode;
-+      pl->req_link_an_mode = pl->cfg_link_an_mode;
-       return 0;
- }
-@@ -1766,7 +1954,7 @@ struct phylink *phylink_create(struct ph
-               }
-       }
--      pl->cur_link_an_mode = pl->cfg_link_an_mode;
-+      pl->req_link_an_mode = pl->cfg_link_an_mode;
-       ret = phylink_register_sfp(pl, fwnode);
-       if (ret < 0) {
-@@ -2242,7 +2430,7 @@ void phylink_start(struct phylink *pl)
-       ASSERT_RTNL();
-       phylink_info(pl, "configuring for %s/%s link mode\n",
--                   phylink_an_mode_str(pl->cur_link_an_mode),
-+                   phylink_an_mode_str(pl->req_link_an_mode),
-                    phy_modes(pl->link_config.interface));
-       /* Always set the carrier off */
-@@ -2501,7 +2689,7 @@ int phylink_ethtool_ksettings_get(struct
-       linkmode_copy(kset->link_modes.supported, pl->supported);
--      switch (pl->cur_link_an_mode) {
-+      switch (pl->act_link_an_mode) {
-       case MLO_AN_FIXED:
-               /* We are using fixed settings. Report these as the
-                * current link settings - and note that these also
-@@ -2532,6 +2720,26 @@ int phylink_ethtool_ksettings_get(struct
- }
- EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get);
-+static bool phylink_validate_pcs_inband_autoneg(struct phylink *pl,
-+                                              phy_interface_t interface,
-+                                              unsigned long *adv)
-+{
-+      unsigned int inband = phylink_inband_caps(pl, interface);
-+      unsigned int mask;
-+
-+      /* If the PCS doesn't implement inband support, be permissive. */
-+      if (!inband)
-+              return true;
-+
-+      if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, adv))
-+              mask = LINK_INBAND_ENABLE;
-+      else
-+              mask = LINK_INBAND_DISABLE;
-+
-+      /* Check whether the PCS implements the required mode */
-+      return !!(inband & mask);
-+}
-+
- /**
-  * phylink_ethtool_ksettings_set() - set the link settings
-  * @pl: a pointer to a &struct phylink returned from phylink_create()
-@@ -2593,7 +2801,7 @@ int phylink_ethtool_ksettings_set(struct
-               /* If we have a fixed link, refuse to change link parameters.
-                * If the link parameters match, accept them but do nothing.
-                */
--              if (pl->cur_link_an_mode == MLO_AN_FIXED) {
-+              if (pl->req_link_an_mode == MLO_AN_FIXED) {
-                       if (s->speed != pl->link_config.speed ||
-                           s->duplex != pl->link_config.duplex)
-                               return -EINVAL;
-@@ -2609,7 +2817,7 @@ int phylink_ethtool_ksettings_set(struct
-                * is our default case) but do not allow the advertisement to
-                * be changed. If the advertisement matches, simply return.
-                */
--              if (pl->cur_link_an_mode == MLO_AN_FIXED) {
-+              if (pl->req_link_an_mode == MLO_AN_FIXED) {
-                       if (!linkmode_equal(config.advertising,
-                                           pl->link_config.advertising))
-                               return -EINVAL;
-@@ -2649,7 +2857,7 @@ int phylink_ethtool_ksettings_set(struct
-               linkmode_copy(support, pl->supported);
-               if (phylink_validate(pl, support, &config)) {
-                       phylink_err(pl, "validation of %s/%s with support %*pb failed\n",
--                                  phylink_an_mode_str(pl->cur_link_an_mode),
-+                                  phylink_an_mode_str(pl->req_link_an_mode),
-                                   phy_modes(config.interface),
-                                   __ETHTOOL_LINK_MODE_MASK_NBITS, support);
-                       return -EINVAL;
-@@ -2667,6 +2875,13 @@ int phylink_ethtool_ksettings_set(struct
-           phylink_is_empty_linkmode(config.advertising))
-               return -EINVAL;
-+      /* Validate the autonegotiation state. We don't have a PHY in this
-+       * situation, so the PCS is the media-facing entity.
-+       */
-+      if (!phylink_validate_pcs_inband_autoneg(pl, config.interface,
-+                                               config.advertising))
-+              return -EINVAL;
-+
-       mutex_lock(&pl->state_mutex);
-       pl->link_config.speed = config.speed;
-       pl->link_config.duplex = config.duplex;
-@@ -2749,7 +2964,7 @@ int phylink_ethtool_set_pauseparam(struc
-       ASSERT_RTNL();
--      if (pl->cur_link_an_mode == MLO_AN_FIXED)
-+      if (pl->req_link_an_mode == MLO_AN_FIXED)
-               return -EOPNOTSUPP;
-       if (!phylink_test(pl->supported, Pause) &&
-@@ -3013,7 +3228,7 @@ static int phylink_mii_read(struct phyli
-       struct phylink_link_state state;
-       int val = 0xffff;
--      switch (pl->cur_link_an_mode) {
-+      switch (pl->act_link_an_mode) {
-       case MLO_AN_FIXED:
-               if (phy_id == 0) {
-                       phylink_get_fixed_state(pl, &state);
-@@ -3038,7 +3253,7 @@ static int phylink_mii_read(struct phyli
- static int phylink_mii_write(struct phylink *pl, unsigned int phy_id,
-                            unsigned int reg, unsigned int val)
- {
--      switch (pl->cur_link_an_mode) {
-+      switch (pl->act_link_an_mode) {
-       case MLO_AN_FIXED:
-               break;
-@@ -3208,10 +3423,11 @@ static phy_interface_t phylink_choose_sf
-       return interface;
- }
--static void phylink_sfp_set_config(struct phylink *pl, u8 mode,
-+static void phylink_sfp_set_config(struct phylink *pl,
-                                  unsigned long *supported,
-                                  struct phylink_link_state *state)
- {
-+      u8 mode = MLO_AN_INBAND;
-       bool changed = false;
-       phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
-@@ -3228,9 +3444,9 @@ static void phylink_sfp_set_config(struc
-               changed = true;
-       }
--      if (pl->cur_link_an_mode != mode ||
-+      if (pl->req_link_an_mode != mode ||
-           pl->link_config.interface != state->interface) {
--              pl->cur_link_an_mode = mode;
-+              pl->req_link_an_mode = mode;
-               pl->link_config.interface = state->interface;
-               changed = true;
-@@ -3245,8 +3461,7 @@ static void phylink_sfp_set_config(struc
-               phylink_mac_initial_config(pl, false);
- }
--static int phylink_sfp_config_phy(struct phylink *pl, u8 mode,
--                                struct phy_device *phy)
-+static int phylink_sfp_config_phy(struct phylink *pl, struct phy_device *phy)
- {
-       __ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
-       __ETHTOOL_DECLARE_LINK_MODE_MASK(support);
-@@ -3285,8 +3500,7 @@ static int phylink_sfp_config_phy(struct
-       ret = phylink_validate(pl, support1, &config);
-       if (ret) {
-               phylink_err(pl,
--                          "validation of %s/%s with support %*pb failed: %pe\n",
--                          phylink_an_mode_str(mode),
-+                          "validation of %s with support %*pb failed: %pe\n",
-                           phy_modes(config.interface),
-                           __ETHTOOL_LINK_MODE_MASK_NBITS, support,
-                           ERR_PTR(ret));
-@@ -3295,7 +3509,7 @@ static int phylink_sfp_config_phy(struct
-       pl->link_port = pl->sfp_port;
--      phylink_sfp_set_config(pl, mode, support, &config);
-+      phylink_sfp_set_config(pl, support, &config);
-       return 0;
- }
-@@ -3351,6 +3565,12 @@ static int phylink_sfp_config_optical(st
-       phylink_dbg(pl, "optical SFP: chosen %s interface\n",
-                   phy_modes(interface));
-+      if (!phylink_validate_pcs_inband_autoneg(pl, interface,
-+                                               config.advertising)) {
-+              phylink_err(pl, "autoneg setting not compatible with PCS");
-+              return -EINVAL;
-+      }
-+
-       config.interface = interface;
-       /* Ignore errors if we're expecting a PHY to attach later */
-@@ -3364,7 +3584,7 @@ static int phylink_sfp_config_optical(st
-       pl->link_port = pl->sfp_port;
--      phylink_sfp_set_config(pl, MLO_AN_INBAND, pl->sfp_support, &config);
-+      phylink_sfp_set_config(pl, pl->sfp_support, &config);
-       return 0;
- }
-@@ -3435,20 +3655,10 @@ static void phylink_sfp_link_up(void *up
-       phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_LINK);
- }
--/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
-- * or 802.3z control word, so inband will not work.
-- */
--static bool phylink_phy_no_inband(struct phy_device *phy)
--{
--      return phy->is_c45 && phy_id_compare(phy->c45_ids.device_ids[1],
--                                           0xae025150, 0xfffffff0);
--}
--
- static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
- {
-       struct phylink *pl = upstream;
-       phy_interface_t interface;
--      u8 mode;
-       int ret;
-       /*
-@@ -3460,17 +3670,12 @@ static int phylink_sfp_connect_phy(void
-        */
-       phy_support_asym_pause(phy);
--      if (phylink_phy_no_inband(phy))
--              mode = MLO_AN_PHY;
--      else
--              mode = MLO_AN_INBAND;
--
-       /* Set the PHY's host supported interfaces */
-       phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces,
-                         pl->config->supported_interfaces);
-       /* Do the initial configuration */
--      ret = phylink_sfp_config_phy(pl, mode, phy);
-+      ret = phylink_sfp_config_phy(pl, phy);
-       if (ret < 0)
-               return ret;
---- a/drivers/net/phy/phy.c
-+++ b/drivers/net/phy/phy.c
-@@ -1049,6 +1049,58 @@ static int phy_check_link_status(struct
- }
- /**
-+ * phy_inband_caps - query which in-band signalling modes are supported
-+ * @phydev: a pointer to a &struct phy_device
-+ * @interface: the interface mode for the PHY
-+ *
-+ * Returns zero if it is unknown what in-band signalling is supported by the
-+ * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise,
-+ * returns a bit mask of the LINK_INBAND_* values from
-+ * &enum link_inband_signalling to describe which inband modes are supported
-+ * by the PHY for this interface mode.
-+ */
-+unsigned int phy_inband_caps(struct phy_device *phydev,
-+                           phy_interface_t interface)
-+{
-+      if (phydev->drv && phydev->drv->inband_caps)
-+              return phydev->drv->inband_caps(phydev, interface);
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL_GPL(phy_inband_caps);
-+
-+/**
-+ * phy_config_inband - configure the desired PHY in-band mode
-+ * @phydev: the phy_device struct
-+ * @modes: in-band modes to configure
-+ *
-+ * Description: disables, enables or enables-with-bypass in-band signalling
-+ *   between the PHY and host system.
-+ *
-+ * Returns: zero on success, or negative errno value.
-+ */
-+int phy_config_inband(struct phy_device *phydev, unsigned int modes)
-+{
-+      int err;
-+
-+      if (!!(modes & LINK_INBAND_DISABLE) +
-+          !!(modes & LINK_INBAND_ENABLE) +
-+          !!(modes & LINK_INBAND_BYPASS) != 1)
-+              return -EINVAL;
-+
-+      mutex_lock(&phydev->lock);
-+      if (!phydev->drv)
-+              err = -EIO;
-+      else if (!phydev->drv->config_inband)
-+              err = -EOPNOTSUPP;
-+      else
-+              err = phydev->drv->config_inband(phydev, modes);
-+      mutex_unlock(&phydev->lock);
-+
-+      return err;
-+}
-+
-+/**
-  * _phy_start_aneg - start auto-negotiation for this PHY device
-  * @phydev: the phy_device struct
-  *
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -816,6 +816,24 @@ struct phy_tdr_config {
- #define PHY_PAIR_ALL -1
- /**
-+ * enum link_inband_signalling - in-band signalling modes that are supported
-+ *
-+ * @LINK_INBAND_DISABLE: in-band signalling can be disabled
-+ * @LINK_INBAND_ENABLE: in-band signalling can be enabled without bypass
-+ * @LINK_INBAND_BYPASS: in-band signalling can be enabled with bypass
-+ *
-+ * The possible and required bits can only be used if the valid bit is set.
-+ * If possible is clear, that means inband signalling can not be used.
-+ * Required is only valid when possible is set, and means that inband
-+ * signalling must be used.
-+ */
-+enum link_inband_signalling {
-+      LINK_INBAND_DISABLE             = BIT(0),
-+      LINK_INBAND_ENABLE              = BIT(1),
-+      LINK_INBAND_BYPASS              = BIT(2),
-+};
-+
-+/**
-  * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision
-  * Avoidance) Reconciliation Sublayer.
-  *
-@@ -955,6 +973,19 @@ struct phy_driver {
-       int (*get_features)(struct phy_device *phydev);
-       /**
-+       * @inband_caps: query whether in-band is supported for the given PHY
-+       * interface mode. Returns a bitmask of bits defined by enum
-+       * link_inband_signalling.
-+       */
-+      unsigned int (*inband_caps)(struct phy_device *phydev,
-+                                  phy_interface_t interface);
-+
-+      /**
-+       * @config_inband: configure in-band mode for the PHY
-+       */
-+      int (*config_inband)(struct phy_device *phydev, unsigned int modes);
-+
-+      /**
-        * @get_rate_matching: Get the supported type of rate matching for a
-        * particular phy interface. This is used by phy consumers to determine
-        * whether to advertise lower-speed modes for that interface. It is
-@@ -1840,6 +1871,9 @@ int phy_config_aneg(struct phy_device *p
- int _phy_start_aneg(struct phy_device *phydev);
- int phy_start_aneg(struct phy_device *phydev);
- int phy_aneg_done(struct phy_device *phydev);
-+unsigned int phy_inband_caps(struct phy_device *phydev,
-+                           phy_interface_t interface);
-+int phy_config_inband(struct phy_device *phydev, unsigned int modes);
- int phy_speed_down(struct phy_device *phydev, bool sync);
- int phy_speed_up(struct phy_device *phydev);
- bool phy_check_valid(int speed, int duplex, unsigned long *features);
---- a/drivers/net/phy/bcm84881.c
-+++ b/drivers/net/phy/bcm84881.c
-@@ -235,11 +235,21 @@ static int bcm84881_read_status(struct p
-       return genphy_c45_read_mdix(phydev);
- }
-+/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
-+ * or 802.3z control word, so inband will not work.
-+ */
-+static unsigned int bcm84881_inband_caps(struct phy_device *phydev,
-+                                       phy_interface_t interface)
-+{
-+      return LINK_INBAND_DISABLE;
-+}
-+
- static struct phy_driver bcm84881_drivers[] = {
-       {
-               .phy_id         = 0xae025150,
-               .phy_id_mask    = 0xfffffff0,
-               .name           = "Broadcom BCM84881",
-+              .inband_caps    = bcm84881_inband_caps,
-               .config_init    = bcm84881_config_init,
-               .probe          = bcm84881_probe,
-               .get_features   = bcm84881_get_features,
---- a/drivers/net/phy/marvell.c
-+++ b/drivers/net/phy/marvell.c
-@@ -716,6 +716,48 @@ static int marvell_config_aneg_fiber(str
-       return genphy_check_and_restart_aneg(phydev, changed);
- }
-+static unsigned int m88e1111_inband_caps(struct phy_device *phydev,
-+                                       phy_interface_t interface)
-+{
-+      /* In 1000base-X and SGMII modes, the inband mode can be changed
-+       * through the Fibre page BMCR ANENABLE bit.
-+       */
-+      if (interface == PHY_INTERFACE_MODE_1000BASEX ||
-+          interface == PHY_INTERFACE_MODE_SGMII)
-+              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE |
-+                     LINK_INBAND_BYPASS;
-+
-+      return 0;
-+}
-+
-+static int m88e1111_config_inband(struct phy_device *phydev, unsigned int modes)
-+{
-+      u16 extsr, bmcr;
-+      int err;
-+
-+      if (phydev->interface != PHY_INTERFACE_MODE_1000BASEX &&
-+          phydev->interface != PHY_INTERFACE_MODE_SGMII)
-+              return -EINVAL;
-+
-+      if (modes == LINK_INBAND_BYPASS)
-+              extsr = MII_M1111_HWCFG_SERIAL_AN_BYPASS;
-+      else
-+              extsr = 0;
-+
-+      if (modes == LINK_INBAND_DISABLE)
-+              bmcr = 0;
-+      else
-+              bmcr = BMCR_ANENABLE;
-+
-+      err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,
-+                       MII_M1111_HWCFG_SERIAL_AN_BYPASS, extsr);
-+      if (err < 0)
-+              return extsr;
-+
-+      return phy_modify_paged(phydev, MII_MARVELL_FIBER_PAGE, MII_BMCR,
-+                              BMCR_ANENABLE, bmcr);
-+}
-+
- static int m88e1111_config_aneg(struct phy_device *phydev)
- {
-       int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);
-@@ -3667,6 +3709,8 @@ static struct phy_driver marvell_drivers
-               .name = "Marvell 88E1112",
-               /* PHY_GBIT_FEATURES */
-               .probe = marvell_probe,
-+              .inband_caps = m88e1111_inband_caps,
-+              .config_inband = m88e1111_config_inband,
-               .config_init = m88e1112_config_init,
-               .config_aneg = marvell_config_aneg,
-               .config_intr = marvell_config_intr,
-@@ -3688,6 +3732,8 @@ static struct phy_driver marvell_drivers
-               /* PHY_GBIT_FEATURES */
-               .flags = PHY_POLL_CABLE_TEST,
-               .probe = marvell_probe,
-+              .inband_caps = m88e1111_inband_caps,
-+              .config_inband = m88e1111_config_inband,
-               .config_init = m88e1111gbe_config_init,
-               .config_aneg = m88e1111_config_aneg,
-               .read_status = marvell_read_status,
-@@ -3711,6 +3757,8 @@ static struct phy_driver marvell_drivers
-               .name = "Marvell 88E1111 (Finisar)",
-               /* PHY_GBIT_FEATURES */
-               .probe = marvell_probe,
-+              .inband_caps = m88e1111_inband_caps,
-+              .config_inband = m88e1111_config_inband,
-               .config_init = m88e1111gbe_config_init,
-               .config_aneg = m88e1111_config_aneg,
-               .read_status = marvell_read_status,
---- a/include/linux/phylink.h
-+++ b/include/linux/phylink.h
-@@ -419,6 +419,7 @@ struct phylink_pcs {
- /**
-  * struct phylink_pcs_ops - MAC PCS operations structure.
-  * @pcs_validate: validate the link configuration.
-+ * @pcs_inband_caps: query inband support for interface mode.
-  * @pcs_enable: enable the PCS.
-  * @pcs_disable: disable the PCS.
-  * @pcs_pre_config: pre-mac_config method (for errata)
-@@ -434,6 +435,8 @@ struct phylink_pcs {
- struct phylink_pcs_ops {
-       int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
-                           const struct phylink_link_state *state);
-+      unsigned int (*pcs_inband_caps)(struct phylink_pcs *pcs,
-+                                      phy_interface_t interface);
-       int (*pcs_enable)(struct phylink_pcs *pcs);
-       void (*pcs_disable)(struct phylink_pcs *pcs);
-       void (*pcs_pre_config)(struct phylink_pcs *pcs,
-@@ -471,6 +474,20 @@ int pcs_validate(struct phylink_pcs *pcs
-                const struct phylink_link_state *state);
- /**
-+ * pcs_inband_caps - query PCS in-band capabilities for interface mode.
-+ * @pcs: a pointer to a &struct phylink_pcs.
-+ * @interface: interface mode to be queried
-+ *
-+ * Returns zero if it is unknown what in-band signalling is supported by the
-+ * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise,
-+ * returns a bit mask of the LINK_INBAND_* values from
-+ * &enum link_inband_signalling to describe which inband modes are supported
-+ * for this interface mode.
-+ */
-+unsigned int pcs_inband_caps(struct phylink_pcs *pcs,
-+                           phy_interface_t interface);
-+
-+/**
-  * pcs_enable() - enable the PCS.
-  * @pcs: a pointer to a &struct phylink_pcs.
-  */
---- a/drivers/net/ethernet/marvell/mvneta.c
-+++ b/drivers/net/ethernet/marvell/mvneta.c
-@@ -3960,20 +3960,27 @@ static struct mvneta_port *mvneta_pcs_to
-       return container_of(pcs, struct mvneta_port, phylink_pcs);
- }
--static int mvneta_pcs_validate(struct phylink_pcs *pcs,
--                             unsigned long *supported,
--                             const struct phylink_link_state *state)
-+static unsigned int mvneta_pcs_inband_caps(struct phylink_pcs *pcs,
-+                                         phy_interface_t interface)
- {
--      /* We only support QSGMII, SGMII, 802.3z and RGMII modes.
--       * When in 802.3z mode, we must have AN enabled:
-+      /* When operating in an 802.3z mode, we must have AN enabled:
-        * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ...
-        * When <PortType> = 1 (1000BASE-X) this field must be set to 1."
-+       * Therefore, inband is "required".
-        */
--      if (phy_interface_mode_is_8023z(state->interface) &&
--          !phylink_test(state->advertising, Autoneg))
--              return -EINVAL;
-+      if (phy_interface_mode_is_8023z(interface))
-+              return LINK_INBAND_ENABLE;
--      return 0;
-+      /* QSGMII, SGMII and RGMII can be configured to use inband
-+       * signalling of the AN result. Indicate these as "possible".
-+       */
-+      if (interface == PHY_INTERFACE_MODE_SGMII ||
-+          interface == PHY_INTERFACE_MODE_QSGMII ||
-+          phy_interface_mode_is_rgmii(interface))
-+              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
-+
-+      /* For any other modes, indicate that inband is not supported. */
-+      return LINK_INBAND_DISABLE;
- }
- static void mvneta_pcs_get_state(struct phylink_pcs *pcs,
-@@ -4071,7 +4078,7 @@ static void mvneta_pcs_an_restart(struct
- }
- static const struct phylink_pcs_ops mvneta_phylink_pcs_ops = {
--      .pcs_validate = mvneta_pcs_validate,
-+      .pcs_inband_caps = mvneta_pcs_inband_caps,
-       .pcs_get_state = mvneta_pcs_get_state,
-       .pcs_config = mvneta_pcs_config,
-       .pcs_an_restart = mvneta_pcs_an_restart,
---- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
-+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
-@@ -6237,19 +6237,26 @@ static const struct phylink_pcs_ops mvpp
-       .pcs_config = mvpp2_xlg_pcs_config,
- };
--static int mvpp2_gmac_pcs_validate(struct phylink_pcs *pcs,
--                                 unsigned long *supported,
--                                 const struct phylink_link_state *state)
-+static unsigned int mvpp2_gmac_pcs_inband_caps(struct phylink_pcs *pcs,
-+                                             phy_interface_t interface)
- {
--      /* When in 802.3z mode, we must have AN enabled:
-+      /* When operating in an 802.3z mode, we must have AN enabled:
-        * Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ...
-        * When <PortType> = 1 (1000BASE-X) this field must be set to 1.
-+       * Therefore, inband is "required".
-        */
--      if (phy_interface_mode_is_8023z(state->interface) &&
--          !phylink_test(state->advertising, Autoneg))
--              return -EINVAL;
-+      if (phy_interface_mode_is_8023z(interface))
-+              return LINK_INBAND_ENABLE;
--      return 0;
-+      /* SGMII and RGMII can be configured to use inband signalling of the
-+       * AN result. Indicate these as "possible".
-+       */
-+      if (interface == PHY_INTERFACE_MODE_SGMII ||
-+          phy_interface_mode_is_rgmii(interface))
-+              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
-+
-+      /* For any other modes, indicate that inband is not supported. */
-+      return LINK_INBAND_DISABLE;
- }
- static void mvpp2_gmac_pcs_get_state(struct phylink_pcs *pcs,
-@@ -6356,7 +6363,7 @@ static void mvpp2_gmac_pcs_an_restart(st
- }
- static const struct phylink_pcs_ops mvpp2_phylink_gmac_pcs_ops = {
--      .pcs_validate = mvpp2_gmac_pcs_validate,
-+      .pcs_inband_caps = mvpp2_gmac_pcs_inband_caps,
-       .pcs_get_state = mvpp2_gmac_pcs_get_state,
-       .pcs_config = mvpp2_gmac_pcs_config,
-       .pcs_an_restart = mvpp2_gmac_pcs_an_restart,
---- a/drivers/net/pcs/pcs-lynx.c
-+++ b/drivers/net/pcs/pcs-lynx.c
-@@ -35,6 +35,27 @@ enum sgmii_speed {
- #define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs)
- #define lynx_to_phylink_pcs(lynx) (&(lynx)->pcs)
-+static unsigned int lynx_pcs_inband_caps(struct phylink_pcs *pcs,
-+                                       phy_interface_t interface)
-+{
-+      switch (interface) {
-+      case PHY_INTERFACE_MODE_1000BASEX:
-+      case PHY_INTERFACE_MODE_SGMII:
-+      case PHY_INTERFACE_MODE_QSGMII:
-+              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
-+
-+      case PHY_INTERFACE_MODE_10GBASER:
-+      case PHY_INTERFACE_MODE_2500BASEX:
-+              return LINK_INBAND_DISABLE;
-+
-+      case PHY_INTERFACE_MODE_USXGMII:
-+              return LINK_INBAND_ENABLE;
-+
-+      default:
-+              return 0;
-+      }
-+}
-+
- static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs,
-                                      struct phylink_link_state *state)
- {
-@@ -306,6 +327,7 @@ static void lynx_pcs_link_up(struct phyl
- }
- static const struct phylink_pcs_ops lynx_pcs_phylink_ops = {
-+      .pcs_inband_caps = lynx_pcs_inband_caps,
-       .pcs_get_state = lynx_pcs_get_state,
-       .pcs_config = lynx_pcs_config,
-       .pcs_an_restart = lynx_pcs_an_restart,
---- a/drivers/net/pcs/pcs-mtk-lynxi.c
-+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
-@@ -110,6 +110,21 @@ static struct mtk_pcs_lynxi *pcs_to_mtk_
-       return container_of(pcs, struct mtk_pcs_lynxi, pcs);
- }
-+static unsigned int mtk_pcs_lynxi_inband_caps(struct phylink_pcs *pcs,
-+                                            phy_interface_t interface)
-+{
-+      switch (interface) {
-+      case PHY_INTERFACE_MODE_1000BASEX:
-+      case PHY_INTERFACE_MODE_2500BASEX:
-+      case PHY_INTERFACE_MODE_SGMII:
-+      case PHY_INTERFACE_MODE_QSGMII:
-+              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
-+
-+      default:
-+              return 0;
-+      }
-+}
-+
- static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs,
-                                   struct phylink_link_state *state)
- {
-@@ -302,6 +317,7 @@ static void mtk_pcs_lynxi_disable(struct
- }
- static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = {
-+      .pcs_inband_caps = mtk_pcs_lynxi_inband_caps,
-       .pcs_get_state = mtk_pcs_lynxi_get_state,
-       .pcs_config = mtk_pcs_lynxi_config,
-       .pcs_an_restart = mtk_pcs_lynxi_restart_an,
---- a/drivers/net/pcs/pcs-xpcs.c
-+++ b/drivers/net/pcs/pcs-xpcs.c
-@@ -608,6 +608,33 @@ static int xpcs_validate(struct phylink_
-       return 0;
- }
-+static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs,
-+                                   phy_interface_t interface)
-+{
-+      struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
-+      const struct dw_xpcs_compat *compat;
-+
-+      compat = xpcs_find_compat(xpcs, interface);
-+      if (!compat)
-+              return 0;
-+
-+      switch (compat->an_mode) {
-+      case DW_AN_C73:
-+              return LINK_INBAND_ENABLE;
-+
-+      case DW_AN_C37_SGMII:
-+      case DW_AN_C37_1000BASEX:
-+              return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
-+
-+      case DW_10GBASER:
-+      case DW_2500BASEX:
-+              return LINK_INBAND_DISABLE;
-+
-+      default:
-+              return 0;
-+      }
-+}
-+
- void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces)
- {
-       int i, j;
-@@ -1365,6 +1392,7 @@ static const struct dw_xpcs_desc xpcs_de
- static const struct phylink_pcs_ops xpcs_phylink_ops = {
-       .pcs_validate = xpcs_validate,
-+      .pcs_inband_caps = xpcs_inband_caps,
-       .pcs_config = xpcs_config,
-       .pcs_get_state = xpcs_get_state,
-       .pcs_an_restart = xpcs_an_restart,
index 28aadad1ffe4f02007b795ccd9ea984a645d552a..39112f23bb19e1e634132332aa08e1fb87d1d33f 100644 (file)
@@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 ---
 --- a/drivers/net/ethernet/marvell/mvneta.c
 +++ b/drivers/net/ethernet/marvell/mvneta.c
-@@ -5296,6 +5296,16 @@ static int mvneta_setup_tc(struct net_de
+@@ -5303,6 +5303,16 @@ static int mvneta_setup_tc(struct net_de
        }
  }
  
@@ -31,7 +31,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  static const struct net_device_ops mvneta_netdev_ops = {
        .ndo_open            = mvneta_open,
        .ndo_stop            = mvneta_stop,
-@@ -5306,6 +5316,9 @@ static const struct net_device_ops mvnet
+@@ -5313,6 +5323,9 @@ static const struct net_device_ops mvnet
        .ndo_fix_features    = mvneta_fix_features,
        .ndo_get_stats64     = mvneta_get_stats64,
        .ndo_eth_ioctl        = mvneta_ioctl,
index 98a6f07de80d9f80ba54021175dbb5f8e79cd4da..e693e95cb0fd0965c59bfb13637dd2a9f97a2fae 100644 (file)
@@ -170,7 +170,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
        /* This is optional functionality. If not supported, we may get an error
 --- a/include/linux/phy.h
 +++ b/include/linux/phy.h
-@@ -1897,6 +1897,7 @@ int genphy_c45_an_config_aneg(struct phy
+@@ -1931,6 +1931,7 @@ int genphy_c45_an_config_aneg(struct phy
  int genphy_c45_an_disable_aneg(struct phy_device *phydev);
  int genphy_c45_read_mdix(struct phy_device *phydev);
  int genphy_c45_pma_read_abilities(struct phy_device *phydev);