diff --git a/NEWS b/NEWS index 4533070d7a3aa6547aa5ffbd993532c6385dca4c..215aee40617c3a7c1d17feee6bdf4969f1b0e641 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ 7.0.1 ----- +🚀 New Features + • Backport support for more SFP modules from mainline kernel + 📌 Updates • ethtool: Update to 6.6 • iproute2: Update to 6.7.0 diff --git a/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-5.15-Backport-SFP-changes-from-upstream.patch b/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-5.15-Backport-SFP-changes-from-upstream.patch new file mode 100644 index 0000000000000000000000000000000000000000..c6c28683c2e49920ea6efefc1074e4809ee42c6e --- /dev/null +++ b/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-5.15-Backport-SFP-changes-from-upstream.patch @@ -0,0 +1,8526 @@ +From ea2ce87cc28cab1eba8236425d3604314e3aebdb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> +Date: Tue, 23 Apr 2024 12:45:24 +0200 +Subject: [PATCH] mvebu: 5.15: Backport SFP changes from upstream + +--- + .../790-SFP-GE-T-ignore-TX_FAULT.patch | 65 --- + ...rtl8221-allow-to-configure-SERDES-mo.patch | 101 ----- + target/linux/mvebu/config-5.15 | 2 + + ...t-phylink-use-pe-for-printing-errors.patch | 68 +++ + ...2-net-sfp-use-pe-for-printing-errors.patch | 165 +++++++ + ...ability-to-validate-a-set-of-interfa.patch | 60 +++ + ...SFP-parsing-with-phy_interface_t-bit.patch | 322 +++++++++++++ + ...phy_interface_t-bitmaps-for-optical-.patch | 238 ++++++++++ + ...et-phylink-rename-phylink_sfp_config.patch | 51 +++ + ...-supported-host-PHY-interface-modes-.patch | 83 ++++ + ...0g-Use-tabs-instead-of-spaces-for-in.patch | 44 ++ + ...0g-select-host-interface-configurati.patch | 216 +++++++++ + ...w-attaching-phy-for-SFP-modules-on-8.patch | 41 ++ + ...use-macros-for-SFP-quirks-definition.patch | 85 ++++ + ...estroy-I2C-mdiobus-before-PHY-probe-.patch | 171 +++++++ + ...-support-I2C-MDIO-protocol-for-RollB.patch | 421 +++++++++++++++++ + ...ort-for-multigig-RollBall-transceive.patch | 152 +++++++ + ...o-5gbase-r-and-25gbase-r-modes-in-sf.patch | 44 ++ + ...fp-check-firmware-provided-max-power.patch | 57 +++ + ...ower-level-2-prior-to-SFF-8472-Rev-1.patch | 27 ++ + ...ower-level-3-prior-to-SFF-8472-Rev-1.patch | 28 ++ + ...a-definition-for-the-power-level-sel.patch | 42 ++ + ...5-5-net-sfp-add-sfp_modify_u8-helper.patch | 61 +++ + ...of-DM7052-hack-when-enabling-high-po.patch | 53 +++ + ...register-indexes-from-hex-to-decimal.patch | 234 ++++++++++ + ...ld-definitions-along-side-register-i.patch | 83 ++++ + ...6-07-1-net-sfp-add-A2h-presence-flag.patch | 100 +++++ + ...e-soft-polling-if-we-have-A2h-access.patch | 28 ++ + ...ate-loss-when-updating-state_hw_mask.patch | 41 ++ + ...w-SFP-quirks-to-override-Autoneg-and.patch | 43 ++ + ...et-sfp-add-quirk-for-2.5G-copper-SFP.patch | 51 +++ + ...k-enabling-2500Base-x-for-HG-MXPD-48.patch | 34 ++ + ...oid-EEPROM-read-of-absent-SFP-module.patch | 36 ++ + ...p-add-helper-to-modify-signal-states.patch | 64 +++ + ...ove-rtnl-lock-to-cover-reading-state.patch | 42 ++ + ...wap-order-of-rtnl-and-st_mutex-locks.patch | 36 ++ + ...p-move-sm_mutex-into-sfp_check_state.patch | 66 +++ + ...12-5-net-sfp-change-st_mutex-locking.patch | 182 ++++++++ + ...-support-for-setting-signalling-rate.patch | 142 ++++++ + ...t-sfp-add-support-for-rate-selection.patch | 422 ++++++++++++++++++ + ...ort-for-a-couple-of-copper-multi-rat.patch | 93 ++++ + ...ort-for-HXSX-ATRI-1-copper-SFP-modul.patch | 30 ++ + ...king-PHY-on-SFP-module-into-SFP-code.patch | 39 ++ + ...uirk-for-Fiberstone-GPON-ONU-34-20BI.patch | 29 ++ + ...p-add-quirk-for-FS-s-2.5G-copper-SFP.patch | 26 ++ + ...ment-ignoring-the-hardware-TX_FAULT-.patch | 82 ++++ + ...net-sfp-improve-Nokia-GPON-sfp-fixup.patch | 54 +++ + ...et-linkmode-add-linkmode_fill-helper.patch | 26 ++ + ...6-19-2-net-phylink-use-linkmode_fill.patch | 31 ++ + ...se-linkmode_-rather-than-open-coding.patch | 23 + + ...rework-the-RollBall-PHY-waiting-code.patch | 131 ++++++ + ...HY-discovery-for-FS-SFP-10G-T-module.patch | 82 ++++ + ...bus-fix-SFP-mode-detect-from-bitrate.patch | 43 ++ + ...ell10g-add-downshift-tunable-support.patch | 212 +++++++++ + ...-02-net-phylink-use-for_each_set_bit.patch | 43 ++ + ...ort-disabling-autonegotiation-for-PC.patch | 79 ++++ + ...4-net-phy-Introduce-QUSGMII-PHY-mode.patch | 117 +++++ + ...t-phy-Add-1000BASE-KX-interface-mode.patch | 80 ++++ + ...et-phylink-Document-MAC_-A-SYM_PAUSE.patch | 66 +++ + ...ink-Export-phylink_caps_to_linkmodes.patch | 62 +++ + ...rate-caps-and-convert-to-linkmodes-s.patch | 113 +++++ + ...et-phy-Add-support-for-rate-matching.patch | 284 ++++++++++++ + ...st-link-settings-based-on-rate-match.patch | 256 +++++++++++ + ...st-advertisement-based-on-rate-match.patch | 187 ++++++++ + ...07-1-net-phy-add-possible-interfaces.patch | 56 +++ + ...rvell10g-table-driven-mactype-decode.patch | 295 ++++++++++++ + ...rvell10g-fill-in-possible_interfaces.patch | 47 ++ + ...bcm84881-fill-in-possible_interfaces.patch | 44 ++ + ...g-and-5g-related-PMA-speed-constants.patch | 27 ++ + ...y-realtek-use-generic-MDIO-constants.patch | 90 ++++ + ...add-5Gbps-support-to-rtl822x_config_.patch | 39 ++ + ...use-generic-MDIO-helpers-to-simplify.patch | 49 ++ + ...configure-SerDes-mode-for-rtl822xb-P.patch | 206 +++++++++ + ...add-get_rate_matching-for-rtl822xb-P.patch | 74 +++ + ...Add-driver-instances-for-rtl8221b-vi.patch | 215 +++++++++ + ...Change-rtlgen_get_speed-to-rtlgen_de.patch | 122 +++++ + ...add-rtl822x_c45_get_features-to-set-.patch | 45 ++ + ...k-for-another-multigig-RollBall-tran.patch | 27 ++ + ...pdate-comment-for-FS-SFP-10G-T-quirk.patch | 30 ++ + ...quirk-for-Fibrestore-2.5G-copper-SFP.patch | 71 +++ + ...k-for-ATS-SFP-GE-T-1000Base-TX-modul.patch | 30 ++ + 81 files changed, 7690 insertions(+), 166 deletions(-) + delete mode 100644 target/linux/generic/hack-5.15/790-SFP-GE-T-ignore-TX_FAULT.patch + delete mode 100644 target/linux/generic/pending-5.15/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-01-1-net-phylink-use-pe-for-printing-errors.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-01-2-net-sfp-use-pe-for-printing-errors.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-01-net-phylink-add-ability-to-validate-a-set-of-interfa.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-02-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-03-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-04-net-phylink-rename-phylink_sfp_config.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-05-net-phylink-pass-supported-host-PHY-interface-modes-.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-06-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-07-net-phy-marvell10g-select-host-interface-configurati.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-08-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-09-net-sfp-Add-and-use-macros-for-SFP-quirks-definition.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-10-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-11-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-03-12-net-sfp-add-support-for-multigig-RollBall-transceive.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-04-net-sfp-fill-also-5gbase-r-and-25gbase-r-modes-in-sf.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-05-1-net-sfp-check-firmware-provided-max-power.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-05-2-net-sfp-ignore-power-level-2-prior-to-SFF-8472-Rev-1.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-05-3-net-sfp-ignore-power-level-3-prior-to-SFF-8472-Rev-1.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-05-4-net-sfp-provide-a-definition-for-the-power-level-sel.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-05-5-net-sfp-add-sfp_modify_u8-helper.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-05-6-net-sfp-get-rid-of-DM7052-hack-when-enabling-high-po.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-06-1-net-sfp-convert-register-indexes-from-hex-to-decimal.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-06-2-net-sfp-move-field-definitions-along-side-register-i.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-07-1-net-sfp-add-A2h-presence-flag.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-07-2-net-sfp-only-use-soft-polling-if-we-have-A2h-access.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-08-net-sfp-fix-state-loss-when-updating-state_hw_mask.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-09-1-net-sfp-bus-allow-SFP-quirks-to-override-Autoneg-and.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-09-2-net-sfp-add-quirk-for-2.5G-copper-SFP.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-10-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-11-net-sfp-avoid-EEPROM-read-of-absent-SFP-module.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-12-1-net-sfp-add-helper-to-modify-signal-states.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-12-2-net-sfp-move-rtnl-lock-to-cover-reading-state.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-12-3-net-sfp-swap-order-of-rtnl-and-st_mutex-locks.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-12-4-net-sfp-move-sm_mutex-into-sfp_check_state.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-12-5-net-sfp-change-st_mutex-locking.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-12-6-net-sfp-add-support-for-setting-signalling-rate.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-12-7-net-sfp-add-support-for-rate-selection.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-13-net-sfp-add-support-for-a-couple-of-copper-multi-rat.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-14-net-sfp-add-support-for-HXSX-ATRI-1-copper-SFP-modul.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-15-net-phy-move-marking-PHY-on-SFP-module-into-SFP-code.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-16-net-sfp-add-quirk-for-Fiberstone-GPON-ONU-34-20BI.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-17-net-sfp-add-quirk-for-FS-s-2.5G-copper-SFP.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-18-1-net-sfp-re-implement-ignoring-the-hardware-TX_FAULT-.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-18-2-net-sfp-improve-Nokia-GPON-sfp-fixup.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-19-1-net-linkmode-add-linkmode_fill-helper.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-19-2-net-phylink-use-linkmode_fill.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-19-3-net-sfp-use-linkmode_-rather-than-open-coding.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-20-net-sfp-rework-the-RollBall-PHY-waiting-code.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-21-net-sfp-fix-PHY-discovery-for-FS-SFP-10G-T-module.patch + create mode 100644 target/linux/mvebu/patches-5.15/706-22-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-01-net-phy-marvell10g-add-downshift-tunable-support.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-02-net-phylink-use-for_each_set_bit.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-03-net-phylink-Support-disabling-autonegotiation-for-PC.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-04-net-phy-Introduce-QUSGMII-PHY-mode.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-05-net-phy-Add-1000BASE-KX-interface-mode.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-06-1-net-phylink-Document-MAC_-A-SYM_PAUSE.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-06-2-net-phylink-Export-phylink_caps_to_linkmodes.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-06-3-net-phylink-Generate-caps-and-convert-to-linkmodes-s.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-06-4-net-phy-Add-support-for-rate-matching.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-06-5-net-phylink-Adjust-link-settings-based-on-rate-match.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-06-6-net-phylink-Adjust-advertisement-based-on-rate-match.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-07-1-net-phy-add-possible-interfaces.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-07-2-net-phy-marvell10g-table-driven-mactype-decode.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-07-3-net-phy-marvell10g-fill-in-possible_interfaces.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-07-4-net-phy-bcm84881-fill-in-possible_interfaces.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-08-1-net-mdio-add-2.5g-and-5g-related-PMA-speed-constants.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-08-2-net-phy-realtek-use-generic-MDIO-constants.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-08-3-net-phy-realtek-add-5Gbps-support-to-rtl822x_config_.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-09-net-phy-realtek-use-generic-MDIO-helpers-to-simplify.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-10-1-net-phy-realtek-configure-SerDes-mode-for-rtl822xb-P.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-10-2-net-phy-realtek-add-get_rate_matching-for-rtl822xb-P.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-10-3-net-phy-realtek-Add-driver-instances-for-rtl8221b-vi.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-10-4-net-phy-realtek-Change-rtlgen_get_speed-to-rtlgen_de.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-10-5-net-phy-realtek-add-rtl822x_c45_get_features-to-set-.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-10-6-net-sfp-add-quirk-for-another-multigig-RollBall-tran.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-11-1-net-sfp-update-comment-for-FS-SFP-10G-T-quirk.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-11-2-net-sfp-enhance-quirk-for-Fibrestore-2.5G-copper-SFP.patch + create mode 100644 target/linux/mvebu/patches-5.15/707-12-net-sfp-add-quirk-for-ATS-SFP-GE-T-1000Base-TX-modul.patch + +diff --git a/target/linux/generic/hack-5.15/790-SFP-GE-T-ignore-TX_FAULT.patch b/target/linux/generic/hack-5.15/790-SFP-GE-T-ignore-TX_FAULT.patch +deleted file mode 100644 +index 83b2c304e2..0000000000 +--- a/target/linux/generic/hack-5.15/790-SFP-GE-T-ignore-TX_FAULT.patch ++++ /dev/null +@@ -1,65 +0,0 @@ +-From 7cc39a6bedbd85f3ff7e16845f310e4ce8d9833f Mon Sep 17 00:00:00 2001 +-From: Daniel Golle <daniel@makrotopia.org> +-Date: Tue, 6 Sep 2022 00:31:19 +0100 +-Subject: [PATCH] net: sfp: add quirk for ATS SFP-GE-T 1000Base-TX module +-To: netdev@vger.kernel.org, +- linux-kernel@vger.kernel.org, +- Russell King <linux@armlinux.org.uk>, +- Andrew Lunn <andrew@lunn.ch>, +- Heiner Kallweit <hkallweit1@gmail.com> +-Cc: David S. Miller <davem@davemloft.net>, +- Eric Dumazet <edumazet@google.com>, +- Jakub Kicinski <kuba@kernel.org>, +- Paolo Abeni <pabeni@redhat.com>, +- Josef Schlehofer <pepe.schlehofer@gmail.com> +- +-This copper module comes with broken TX_FAULT indicator which must be +-ignored for it to work. Implement ignoring TX_FAULT state bit also +-during reset/insertion and mute the warning telling the user that the +-module indicates TX_FAULT. +- +-Co-authored-by: Josef Schlehofer <pepe.schlehofer@gmail.com> +-Signed-off-by: Daniel Golle <daniel@makrotopia.org> +---- +- drivers/net/phy/sfp.c | 14 +++++++++++--- +- 1 file changed, 11 insertions(+), 3 deletions(-) +- +---- a/drivers/net/phy/sfp.c +-+++ b/drivers/net/phy/sfp.c +-@@ -373,6 +373,11 @@ static const struct sfp_quirk sfp_quirks +- .modes = sfp_quirk_2500basex, +- .fixup = sfp_fixup_ignore_tx_fault, +- }, { +-+ // OEM SFP-GE-T is 1000Base-T module +-+ .vendor = "OEM", +-+ .part = "SFP-GE-T", +-+ .fixup = sfp_fixup_ignore_tx_fault, +-+ }, { +- // Lantech 8330-262D-E can operate at 2500base-X, but +- // incorrectly report 2500MBd NRZ in their EEPROM +- .vendor = "Lantech", +-@@ -2306,7 +2311,8 @@ static void sfp_sm_main(struct sfp *sfp, +- * or t_start_up, so assume there is a fault. +- */ +- sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, +-- sfp->sm_fault_retries == N_FAULT_INIT); +-+ !sfp->tx_fault_ignore && +-+ (sfp->sm_fault_retries == N_FAULT_INIT)); +- } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { +- init_done: +- sfp->sm_phy_retries = R_PHY_RETRY; +-@@ -2529,10 +2535,12 @@ static void sfp_check_state(struct sfp * +- mutex_lock(&sfp->st_mutex); +- state = sfp_get_state(sfp); +- changed = state ^ sfp->state; +-- if (sfp->tx_fault_ignore) +-+ if (sfp->tx_fault_ignore) { +- changed &= SFP_F_PRESENT | SFP_F_LOS; +-- else +-+ state &= ~SFP_F_TX_FAULT; +-+ } else { +- changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT; +-+ } +- +- for (i = 0; i < GPIO_MAX; i++) +- if (changed & BIT(i)) +diff --git a/target/linux/generic/pending-5.15/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch b/target/linux/generic/pending-5.15/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch +deleted file mode 100644 +index 703a0b8b72..0000000000 +--- a/target/linux/generic/pending-5.15/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch ++++ /dev/null +@@ -1,101 +0,0 @@ +-From ace6abaa0f9203083fe4c0a6a74da2d96410b625 Mon Sep 17 00:00:00 2001 +-From: Alexander Couzens <lynxis@fe80.eu> +-Date: Sat, 13 Aug 2022 12:49:33 +0200 +-Subject: [PATCH 01/10] net: phy: realtek: rtl8221: allow to configure SERDES +- mode +- +-The rtl8221 supports multiple SERDES modes: +-- SGMII +-- 2500base-x +-- HiSGMII +- +-Further it supports rate adaption on SERDES links to allow +-slow ethernet speeds (10/100/1000mbit) to work on 2500base-x/HiSGMII +-links without reducing the SERDES speed. +- +-When operating without rate adapters the SERDES link will follow the +-ethernet speed. +- +-Signed-off-by: Alexander Couzens <lynxis@fe80.eu> +---- +- drivers/net/phy/realtek.c | 48 +++++++++++++++++++++++++++++++++++++++ +- 1 file changed, 48 insertions(+) +- +---- a/drivers/net/phy/realtek.c +-+++ b/drivers/net/phy/realtek.c +-@@ -53,6 +53,15 @@ +- RTL8201F_ISR_LINK) +- #define RTL8201F_IER 0x13 +- +-+#define RTL8221B_MMD_SERDES_CTRL MDIO_MMD_VEND1 +-+#define RTL8221B_MMD_PHY_CTRL MDIO_MMD_VEND2 +-+#define RTL8221B_SERDES_OPTION 0x697a +-+#define RTL8221B_SERDES_OPTION_MODE_MASK GENMASK(5, 0) +-+#define RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII 0 +-+#define RTL8221B_SERDES_OPTION_MODE_HISGMII_SGMII 1 +-+#define RTL8221B_SERDES_OPTION_MODE_2500BASEX 2 +-+#define RTL8221B_SERDES_OPTION_MODE_HISGMII 3 +-+ +- #define RTL8366RB_POWER_SAVE 0x15 +- #define RTL8366RB_POWER_SAVE_ON BIT(12) +- +-@@ -841,6 +850,43 @@ static irqreturn_t rtl9000a_handle_inter +- return IRQ_HANDLED; +- } +- +-+static int rtl8221b_config_init(struct phy_device *phydev) +-+{ +-+ u16 option_mode; +-+ +-+ switch (phydev->interface) { +-+ case PHY_INTERFACE_MODE_SGMII: +-+ case PHY_INTERFACE_MODE_2500BASEX: +-+ option_mode = RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII; +-+ break; +-+ default: +-+ return 0; +-+ } +-+ +-+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, +-+ 0x75f3, 0); +-+ +-+ phy_modify_mmd_changed(phydev, RTL8221B_MMD_SERDES_CTRL, +-+ RTL8221B_SERDES_OPTION, +-+ RTL8221B_SERDES_OPTION_MODE_MASK, option_mode); +-+ switch (option_mode) { +-+ case RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII: +-+ case RTL8221B_SERDES_OPTION_MODE_2500BASEX: +-+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6a04, 0x0503); +-+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f10, 0xd455); +-+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f11, 0x8020); +-+ break; +-+ case RTL8221B_SERDES_OPTION_MODE_HISGMII_SGMII: +-+ case RTL8221B_SERDES_OPTION_MODE_HISGMII: +-+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6a04, 0x0503); +-+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f10, 0xd433); +-+ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f11, 0x8020); +-+ break; +-+ } +-+ +-+ return 0; +-+} +-+ +- static struct phy_driver realtek_drvs[] = { +- { +- PHY_ID_MATCH_EXACT(0x00008201), +-@@ -981,6 +1027,7 @@ static struct phy_driver realtek_drvs[] +- PHY_ID_MATCH_EXACT(0x001cc849), +- .name = "RTL8221B-VB-CG 2.5Gbps PHY", +- .get_features = rtl822x_get_features, +-+ .config_init = rtl8221b_config_init, +- .config_aneg = rtl822x_config_aneg, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +-@@ -992,6 +1039,7 @@ static struct phy_driver realtek_drvs[] +- .name = "RTL8221B-VM-CG 2.5Gbps PHY", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +-+ .config_init = rtl8221b_config_init, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +diff --git a/target/linux/mvebu/config-5.15 b/target/linux/mvebu/config-5.15 +index bf432cd183..42351e6ff2 100644 +--- a/target/linux/mvebu/config-5.15 ++++ b/target/linux/mvebu/config-5.15 +@@ -241,6 +241,7 @@ CONFIG_MACH_MVEBU_V7=y + CONFIG_MAGIC_SYSRQ=y + CONFIG_MANGLE_BOOTARGS=y + CONFIG_MARVELL_PHY=y ++CONFIG_MARVELL_10G_PHY=y + CONFIG_MDIO_BUS=y + CONFIG_MDIO_DEVICE=y + CONFIG_MDIO_DEVRES=y +@@ -347,6 +348,7 @@ CONFIG_PTP_1588_CLOCK_OPTIONAL=y + CONFIG_PWM=y + CONFIG_PWM_SYSFS=y + CONFIG_RATIONAL=y ++CONFIG_REALTEK_PHY=y + CONFIG_REGMAP=y + CONFIG_REGMAP_I2C=y + CONFIG_REGMAP_MMIO=y +diff --git a/target/linux/mvebu/patches-5.15/706-01-1-net-phylink-use-pe-for-printing-errors.patch b/target/linux/mvebu/patches-5.15/706-01-1-net-phylink-use-pe-for-printing-errors.patch +new file mode 100644 +index 0000000000..50fddcf6e8 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-01-1-net-phylink-use-pe-for-printing-errors.patch +@@ -0,0 +1,68 @@ ++From ab1198e5a1dc02970a4ba490d4ec3c80d4d027f2 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Tue, 1 Mar 2022 08:51:34 +0000 ++Subject: [PATCH] net: phylink: use %pe for printing errors ++ ++Convert phylink to use %pe for printing error codes, which can print ++them as errno symbols rather than numbers. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Link: https://lore.kernel.org/r/E1nOyEI-00Buu8-K9@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -1176,9 +1176,8 @@ static int phylink_register_sfp(struct p ++ ++ bus = sfp_bus_find_fwnode(fwnode); ++ if (IS_ERR(bus)) { ++- ret = PTR_ERR(bus); ++- phylink_err(pl, "unable to attach SFP bus: %d\n", ret); ++- return ret; +++ phylink_err(pl, "unable to attach SFP bus: %pe\n", bus); +++ return PTR_ERR(bus); ++ } ++ ++ pl->sfp_bus = bus; ++@@ -1405,11 +1404,11 @@ static int phylink_bringup_phy(struct ph ++ ++ ret = phylink_validate(pl, supported, &config); ++ if (ret) { ++- phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %d\n", +++ phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %pe\n", ++ phy_modes(config.interface), ++ __ETHTOOL_LINK_MODE_MASK_NBITS, phy->supported, ++ __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising, ++- ret); +++ ERR_PTR(ret)); ++ return ret; ++ } ++ ++@@ -2603,8 +2602,9 @@ static int phylink_sfp_config(struct phy ++ /* Ignore errors if we're expecting a PHY to attach later */ ++ ret = phylink_validate(pl, support, &config); ++ if (ret) { ++- phylink_err(pl, "validation with support %*pb failed: %d\n", ++- __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); +++ phylink_err(pl, "validation with support %*pb failed: %pe\n", +++ __ETHTOOL_LINK_MODE_MASK_NBITS, support, +++ ERR_PTR(ret)); ++ return ret; ++ } ++ ++@@ -2620,10 +2620,12 @@ static int phylink_sfp_config(struct phy ++ linkmode_copy(support1, support); ++ ret = phylink_validate(pl, support1, &config); ++ if (ret) { ++- phylink_err(pl, "validation of %s/%s with support %*pb failed: %d\n", +++ phylink_err(pl, +++ "validation of %s/%s with support %*pb failed: %pe\n", ++ phylink_an_mode_str(mode), ++ phy_modes(config.interface), ++- __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); +++ __ETHTOOL_LINK_MODE_MASK_NBITS, support, +++ ERR_PTR(ret)); ++ return ret; ++ } ++ +diff --git a/target/linux/mvebu/patches-5.15/706-01-2-net-sfp-use-pe-for-printing-errors.patch b/target/linux/mvebu/patches-5.15/706-01-2-net-sfp-use-pe-for-printing-errors.patch +new file mode 100644 +index 0000000000..4237130e35 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-01-2-net-sfp-use-pe-for-printing-errors.patch +@@ -0,0 +1,165 @@ ++From 9ae1ef4b1634547d7ab7d15a9ffd48df8ce6883c Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Tue, 1 Mar 2022 08:51:39 +0000 ++Subject: [PATCH] net: sfp: use %pe for printing errors ++ ++Convert sfp to use %pe for printing error codes, which can print them ++as errno symbols rather than numbers. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Link: https://lore.kernel.org/r/E1nOyEN-00BuuE-OB@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -595,8 +595,8 @@ static unsigned int sfp_soft_get_state(s ++ state |= SFP_F_TX_FAULT; ++ } else { ++ dev_err_ratelimited(sfp->dev, ++- "failed to read SFP soft status: %d\n", ++- ret); +++ "failed to read SFP soft status: %pe\n", +++ ERR_PTR(ret)); ++ /* Preserve the current state */ ++ state = sfp->state; ++ } ++@@ -1437,7 +1437,8 @@ static void sfp_hwmon_probe(struct work_ ++ mod_delayed_work(system_wq, &sfp->hwmon_probe, ++ T_PROBE_RETRY_SLOW); ++ } else { ++- dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); +++ dev_warn(sfp->dev, "hwmon probe failed: %pe\n", +++ ERR_PTR(err)); ++ } ++ return; ++ } ++@@ -1642,14 +1643,15 @@ static int sfp_sm_probe_phy(struct sfp * ++ if (phy == ERR_PTR(-ENODEV)) ++ return PTR_ERR(phy); ++ if (IS_ERR(phy)) { ++- dev_err(sfp->dev, "mdiobus scan returned %ld\n", PTR_ERR(phy)); +++ dev_err(sfp->dev, "mdiobus scan returned %pe\n", phy); ++ return PTR_ERR(phy); ++ } ++ ++ err = phy_device_register(phy); ++ if (err) { ++ phy_device_free(phy); ++- dev_err(sfp->dev, "phy_device_register failed: %d\n", err); +++ dev_err(sfp->dev, "phy_device_register failed: %pe\n", +++ ERR_PTR(err)); ++ return err; ++ } ++ ++@@ -1657,7 +1659,7 @@ static int sfp_sm_probe_phy(struct sfp * ++ if (err) { ++ phy_device_remove(phy); ++ phy_device_free(phy); ++- dev_err(sfp->dev, "sfp_add_phy failed: %d\n", err); +++ dev_err(sfp->dev, "sfp_add_phy failed: %pe\n", ERR_PTR(err)); ++ return err; ++ } ++ ++@@ -1834,7 +1836,7 @@ static int sfp_sm_mod_hpower(struct sfp ++ ++ err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); ++ if (err != sizeof(val)) { ++- dev_err(sfp->dev, "Failed to read EEPROM: %d\n", err); +++ dev_err(sfp->dev, "Failed to read EEPROM: %pe\n", ERR_PTR(err)); ++ return -EAGAIN; ++ } ++ ++@@ -1852,7 +1854,8 @@ static int sfp_sm_mod_hpower(struct sfp ++ ++ err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); ++ if (err != sizeof(val)) { ++- dev_err(sfp->dev, "Failed to write EEPROM: %d\n", err); +++ dev_err(sfp->dev, "Failed to write EEPROM: %pe\n", +++ ERR_PTR(err)); ++ return -EAGAIN; ++ } ++ ++@@ -1904,7 +1907,9 @@ static int sfp_cotsworks_fixup_check(str ++ id->base.connector = SFF8024_CONNECTOR_LC; ++ err = sfp_write(sfp, false, SFP_PHYS_ID, &id->base, 3); ++ if (err != 3) { ++- dev_err(sfp->dev, "Failed to rewrite module EEPROM: %d\n", err); +++ dev_err(sfp->dev, +++ "Failed to rewrite module EEPROM: %pe\n", +++ ERR_PTR(err)); ++ return err; ++ } ++ ++@@ -1915,7 +1920,9 @@ static int sfp_cotsworks_fixup_check(str ++ check = sfp_check(&id->base, sizeof(id->base) - 1); ++ err = sfp_write(sfp, false, SFP_CC_BASE, &check, 1); ++ if (err != 1) { ++- dev_err(sfp->dev, "Failed to update base structure checksum in fiber module EEPROM: %d\n", err); +++ dev_err(sfp->dev, +++ "Failed to update base structure checksum in fiber module EEPROM: %pe\n", +++ ERR_PTR(err)); ++ return err; ++ } ++ } ++@@ -1936,12 +1943,13 @@ static int sfp_sm_mod_probe(struct sfp * ++ ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base)); ++ if (ret < 0) { ++ if (report) ++- dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret); +++ dev_err(sfp->dev, "failed to read EEPROM: %pe\n", +++ ERR_PTR(ret)); ++ return -EAGAIN; ++ } ++ ++ if (ret != sizeof(id.base)) { ++- dev_err(sfp->dev, "EEPROM short read: %d\n", ret); +++ dev_err(sfp->dev, "EEPROM short read: %pe\n", ERR_PTR(ret)); ++ return -EAGAIN; ++ } ++ ++@@ -1961,13 +1969,15 @@ static int sfp_sm_mod_probe(struct sfp * ++ ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base)); ++ if (ret < 0) { ++ if (report) ++- dev_err(sfp->dev, "failed to read EEPROM: %d\n", ++- ret); +++ dev_err(sfp->dev, +++ "failed to read EEPROM: %pe\n", +++ ERR_PTR(ret)); ++ return -EAGAIN; ++ } ++ ++ if (ret != sizeof(id.base)) { ++- dev_err(sfp->dev, "EEPROM short read: %d\n", ret); +++ dev_err(sfp->dev, "EEPROM short read: %pe\n", +++ ERR_PTR(ret)); ++ return -EAGAIN; ++ } ++ } ++@@ -2009,12 +2019,13 @@ static int sfp_sm_mod_probe(struct sfp * ++ ret = sfp_read(sfp, false, SFP_CC_BASE + 1, &id.ext, sizeof(id.ext)); ++ if (ret < 0) { ++ if (report) ++- dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret); +++ dev_err(sfp->dev, "failed to read EEPROM: %pe\n", +++ ERR_PTR(ret)); ++ return -EAGAIN; ++ } ++ ++ if (ret != sizeof(id.ext)) { ++- dev_err(sfp->dev, "EEPROM short read: %d\n", ret); +++ dev_err(sfp->dev, "EEPROM short read: %pe\n", ERR_PTR(ret)); ++ return -EAGAIN; ++ } ++ ++@@ -2179,7 +2190,8 @@ static void sfp_sm_module(struct sfp *sf ++ ++ err = sfp_hwmon_insert(sfp); ++ if (err) ++- dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); +++ dev_warn(sfp->dev, "hwmon probe failed: %pe\n", +++ ERR_PTR(err)); ++ ++ sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0); ++ fallthrough; +diff --git a/target/linux/mvebu/patches-5.15/706-03-01-net-phylink-add-ability-to-validate-a-set-of-interfa.patch b/target/linux/mvebu/patches-5.15/706-03-01-net-phylink-add-ability-to-validate-a-set-of-interfa.patch +new file mode 100644 +index 0000000000..6d730934a1 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-01-net-phylink-add-ability-to-validate-a-set-of-interfa.patch +@@ -0,0 +1,60 @@ ++From 1645f44dd5b846a473d7789fe622c278eb880d48 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 30 Sep 2022 16:20:59 +0200 ++Subject: [PATCH] net: phylink: add ability to validate a set of interface ++ modes ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Rather than having the ability to validate all supported interface ++modes or a single interface mode, introduce the ability to validate ++a subset of supported modes. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++[ rebased on current net-next ] ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -467,8 +467,9 @@ void phylink_generic_validate(struct phy ++ } ++ EXPORT_SYMBOL_GPL(phylink_generic_validate); ++ ++-static int phylink_validate_any(struct phylink *pl, unsigned long *supported, ++- struct phylink_link_state *state) +++static int phylink_validate_mask(struct phylink *pl, unsigned long *supported, +++ struct phylink_link_state *state, +++ const unsigned long *interfaces) ++ { ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, }; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, }; ++@@ -477,7 +478,7 @@ static int phylink_validate_any(struct p ++ int intf; ++ ++ for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) { ++- if (test_bit(intf, pl->config->supported_interfaces)) { +++ if (test_bit(intf, interfaces)) { ++ linkmode_copy(s, supported); ++ ++ t = *state; ++@@ -498,12 +499,14 @@ static int phylink_validate_any(struct p ++ static int phylink_validate(struct phylink *pl, unsigned long *supported, ++ struct phylink_link_state *state) ++ { ++- if (!phy_interface_empty(pl->config->supported_interfaces)) { +++ const unsigned long *interfaces = pl->config->supported_interfaces; +++ +++ if (!phy_interface_empty(interfaces)) { ++ if (state->interface == PHY_INTERFACE_MODE_NA) ++- return phylink_validate_any(pl, supported, state); +++ return phylink_validate_mask(pl, supported, state, +++ interfaces); ++ ++- if (!test_bit(state->interface, ++- pl->config->supported_interfaces)) +++ if (!test_bit(state->interface, interfaces)) ++ return -EINVAL; ++ } ++ +diff --git a/target/linux/mvebu/patches-5.15/706-03-02-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch b/target/linux/mvebu/patches-5.15/706-03-02-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch +new file mode 100644 +index 0000000000..9ff137d7b1 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-02-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch +@@ -0,0 +1,322 @@ ++From fd580c9830316edad6f8b1d9f542563730658efe Mon Sep 17 00:00:00 2001 ++From: Russell King <rmk+kernel@armlinux.org.uk> ++Date: Fri, 30 Sep 2022 16:21:00 +0200 ++Subject: [PATCH] net: sfp: augment SFP parsing with phy_interface_t bitmap ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++We currently parse the SFP EEPROM to a bitmap of ethtool link modes, ++and then attempt to convert the link modes to a PHY interface mode. ++While this works at present, there are cases where this is sub-optimal. ++For example, where a module can operate with several different PHY ++interface modes. ++ ++To start addressing this, arrange for the SFP EEPROM parsing to also ++provide a bitmap of the possible PHY interface modes. ++ ++Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++[ backported to 5.15 ] ++ ++--- a/drivers/net/phy/marvell-88x2222.c +++++ b/drivers/net/phy/marvell-88x2222.c ++@@ -478,6 +478,7 @@ static int mv2222_config_init(struct phy ++ ++ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) ++ { +++ DECLARE_PHY_INTERFACE_MASK(interfaces); ++ struct phy_device *phydev = upstream; ++ phy_interface_t sfp_interface; ++ struct mv2222_data *priv; ++@@ -489,7 +490,7 @@ static int mv2222_sfp_insert(void *upstr ++ priv = (struct mv2222_data *)phydev->priv; ++ dev = &phydev->mdio.dev; ++ ++- sfp_parse_support(phydev->sfp_bus, id, sfp_supported); +++ sfp_parse_support(phydev->sfp_bus, id, sfp_supported, interfaces); ++ sfp_interface = sfp_select_interface(phydev->sfp_bus, sfp_supported); ++ ++ dev_info(dev, "%s SFP module inserted\n", phy_modes(sfp_interface)); ++--- a/drivers/net/phy/marvell.c +++++ b/drivers/net/phy/marvell.c ++@@ -2808,6 +2808,7 @@ static int marvell_probe(struct phy_devi ++ ++ static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) ++ { +++ DECLARE_PHY_INTERFACE_MASK(interfaces); ++ struct phy_device *phydev = upstream; ++ phy_interface_t interface; ++ struct device *dev; ++@@ -2819,7 +2820,7 @@ static int m88e1510_sfp_insert(void *ups ++ ++ dev = &phydev->mdio.dev; ++ ++- sfp_parse_support(phydev->sfp_bus, id, supported); +++ sfp_parse_support(phydev->sfp_bus, id, supported, interfaces); ++ interface = sfp_select_interface(phydev->sfp_bus, supported); ++ ++ dev_info(dev, "%s SFP module inserted\n", phy_modes(interface)); ++--- a/drivers/net/phy/marvell10g.c +++++ b/drivers/net/phy/marvell10g.c ++@@ -394,9 +394,10 @@ static int mv3310_sfp_insert(void *upstr ++ { ++ struct phy_device *phydev = upstream; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; +++ DECLARE_PHY_INTERFACE_MASK(interfaces); ++ phy_interface_t iface; ++ ++- sfp_parse_support(phydev->sfp_bus, id, support); +++ sfp_parse_support(phydev->sfp_bus, id, support, interfaces); ++ iface = sfp_select_interface(phydev->sfp_bus, support); ++ ++ if (iface != PHY_INTERFACE_MODE_10GBASER) { ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -78,6 +78,7 @@ struct phylink { ++ ++ struct sfp_bus *sfp_bus; ++ bool sfp_may_have_phy; +++ DECLARE_PHY_INTERFACE_MASK(sfp_interfaces); ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); ++ u8 sfp_port; ++ }; ++@@ -2677,7 +2678,8 @@ static int phylink_sfp_module_insert(voi ++ ASSERT_RTNL(); ++ ++ linkmode_zero(support); ++- sfp_parse_support(pl->sfp_bus, id, support); +++ phy_interface_zero(pl->sfp_interfaces); +++ sfp_parse_support(pl->sfp_bus, id, support, pl->sfp_interfaces); ++ pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support); ++ ++ /* If this module may have a PHY connecting later, defer until later */ ++--- a/drivers/net/phy/sfp-bus.c +++++ b/drivers/net/phy/sfp-bus.c ++@@ -139,12 +139,14 @@ EXPORT_SYMBOL_GPL(sfp_may_have_phy); ++ * @bus: a pointer to the &struct sfp_bus structure for the sfp module ++ * @id: a pointer to the module's &struct sfp_eeprom_id ++ * @support: pointer to an array of unsigned long for the ethtool support mask +++ * @interfaces: pointer to an array of unsigned long for phy interface modes +++ * mask ++ * ++ * Parse the EEPROM identification information and derive the supported ++ * ethtool link modes for the module. ++ */ ++ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, ++- unsigned long *support) +++ unsigned long *support, unsigned long *interfaces) ++ { ++ unsigned int br_min, br_nom, br_max; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, }; ++@@ -171,54 +173,81 @@ void sfp_parse_support(struct sfp_bus *b ++ } ++ ++ /* Set ethtool support from the compliance fields. */ ++- if (id->base.e10g_base_sr) +++ if (id->base.e10g_base_sr) { ++ phylink_set(modes, 10000baseSR_Full); ++- if (id->base.e10g_base_lr) +++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); +++ } +++ if (id->base.e10g_base_lr) { ++ phylink_set(modes, 10000baseLR_Full); ++- if (id->base.e10g_base_lrm) +++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); +++ } +++ if (id->base.e10g_base_lrm) { ++ phylink_set(modes, 10000baseLRM_Full); ++- if (id->base.e10g_base_er) +++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); +++ } +++ if (id->base.e10g_base_er) { ++ phylink_set(modes, 10000baseER_Full); +++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); +++ } ++ if (id->base.e1000_base_sx || ++ id->base.e1000_base_lx || ++- id->base.e1000_base_cx) +++ id->base.e1000_base_cx) { ++ phylink_set(modes, 1000baseX_Full); +++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); +++ } ++ if (id->base.e1000_base_t) { ++ phylink_set(modes, 1000baseT_Half); ++ phylink_set(modes, 1000baseT_Full); +++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); +++ __set_bit(PHY_INTERFACE_MODE_SGMII, interfaces); ++ } ++ ++ /* 1000Base-PX or 1000Base-BX10 */ ++ if ((id->base.e_base_px || id->base.e_base_bx10) && ++- br_min <= 1300 && br_max >= 1200) +++ br_min <= 1300 && br_max >= 1200) { ++ phylink_set(modes, 1000baseX_Full); +++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); +++ } ++ ++ /* 100Base-FX, 100Base-LX, 100Base-PX, 100Base-BX10 */ ++- if (id->base.e100_base_fx || id->base.e100_base_lx) +++ if (id->base.e100_base_fx || id->base.e100_base_lx) { ++ phylink_set(modes, 100baseFX_Full); ++- if ((id->base.e_base_px || id->base.e_base_bx10) && br_nom == 100) +++ __set_bit(PHY_INTERFACE_MODE_100BASEX, interfaces); +++ } +++ if ((id->base.e_base_px || id->base.e_base_bx10) && br_nom == 100) { ++ phylink_set(modes, 100baseFX_Full); +++ __set_bit(PHY_INTERFACE_MODE_100BASEX, interfaces); +++ } ++ ++ /* For active or passive cables, select the link modes ++ * based on the bit rates and the cable compliance bytes. ++ */ ++ if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) { ++ /* This may look odd, but some manufacturers use 12000MBd */ ++- if (br_min <= 12000 && br_max >= 10300) +++ if (br_min <= 12000 && br_max >= 10300) { ++ phylink_set(modes, 10000baseCR_Full); ++- if (br_min <= 3200 && br_max >= 3100) +++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); +++ } +++ if (br_min <= 3200 && br_max >= 3100) { ++ phylink_set(modes, 2500baseX_Full); ++- if (br_min <= 1300 && br_max >= 1200) +++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); +++ } +++ if (br_min <= 1300 && br_max >= 1200) { ++ phylink_set(modes, 1000baseX_Full); +++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); +++ } ++ } ++ if (id->base.sfp_ct_passive) { ++- if (id->base.passive.sff8431_app_e) +++ if (id->base.passive.sff8431_app_e) { ++ phylink_set(modes, 10000baseCR_Full); +++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); +++ } ++ } ++ if (id->base.sfp_ct_active) { ++ if (id->base.active.sff8431_app_e || ++ id->base.active.sff8431_lim) { ++ phylink_set(modes, 10000baseCR_Full); +++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); ++ } ++ } ++ ++@@ -243,12 +272,14 @@ void sfp_parse_support(struct sfp_bus *b ++ case SFF8024_ECC_10GBASE_T_SFI: ++ case SFF8024_ECC_10GBASE_T_SR: ++ phylink_set(modes, 10000baseT_Full); +++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); ++ break; ++ case SFF8024_ECC_5GBASE_T: ++ phylink_set(modes, 5000baseT_Full); ++ break; ++ case SFF8024_ECC_2_5GBASE_T: ++ phylink_set(modes, 2500baseT_Full); +++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); ++ break; ++ default: ++ dev_warn(bus->sfp_dev, ++@@ -261,10 +292,14 @@ void sfp_parse_support(struct sfp_bus *b ++ if (id->base.fc_speed_100 || ++ id->base.fc_speed_200 || ++ id->base.fc_speed_400) { ++- if (id->base.br_nominal >= 31) +++ if (id->base.br_nominal >= 31) { ++ phylink_set(modes, 2500baseX_Full); ++- if (id->base.br_nominal >= 12) +++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); +++ } +++ if (id->base.br_nominal >= 12) { ++ phylink_set(modes, 1000baseX_Full); +++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); +++ } ++ } ++ ++ /* If we haven't discovered any modes that this module supports, try ++@@ -277,14 +312,18 @@ void sfp_parse_support(struct sfp_bus *b ++ * 2500BASE-X, so we allow some slack here. ++ */ ++ if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS) && br_nom) { ++- if (br_min <= 1300 && br_max >= 1200) +++ if (br_min <= 1300 && br_max >= 1200) { ++ phylink_set(modes, 1000baseX_Full); ++- if (br_min <= 3200 && br_max >= 2500) +++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); +++ } +++ if (br_min <= 3200 && br_max >= 2500) { ++ phylink_set(modes, 2500baseX_Full); +++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); +++ } ++ } ++ ++ if (bus->sfp_quirk && bus->sfp_quirk->modes) ++- bus->sfp_quirk->modes(id, modes); +++ bus->sfp_quirk->modes(id, modes, interfaces); ++ ++ linkmode_or(support, support, modes); ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -337,13 +337,16 @@ static void sfp_fixup_halny_gsfp(struct ++ } ++ ++ static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, ++- unsigned long *modes) +++ unsigned long *modes, +++ unsigned long *interfaces) ++ { ++ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, modes); +++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); ++ } ++ ++ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, ++- unsigned long *modes) +++ unsigned long *modes, +++ unsigned long *interfaces) ++ { ++ /* Ubiquiti U-Fiber Instant module claims that support all transceiver ++ * types including 10G Ethernet which is not truth. So clear all claimed ++@@ -351,6 +354,7 @@ static void sfp_quirk_ubnt_uf_instant(co ++ */ ++ linkmode_zero(modes); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, modes); +++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); ++ } ++ ++ static const struct sfp_quirk sfp_quirks[] = { ++--- a/drivers/net/phy/sfp.h +++++ b/drivers/net/phy/sfp.h ++@@ -9,7 +9,8 @@ struct sfp; ++ struct sfp_quirk { ++ const char *vendor; ++ const char *part; ++- void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes); +++ void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes, +++ unsigned long *interfaces); ++ void (*fixup)(struct sfp *sfp); ++ }; ++ ++--- a/include/linux/sfp.h +++++ b/include/linux/sfp.h ++@@ -535,7 +535,7 @@ int sfp_parse_port(struct sfp_bus *bus, ++ unsigned long *support); ++ bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id); ++ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, ++- unsigned long *support); +++ unsigned long *support, unsigned long *interfaces); ++ phy_interface_t sfp_select_interface(struct sfp_bus *bus, ++ unsigned long *link_modes); ++ ++@@ -568,7 +568,8 @@ static inline bool sfp_may_have_phy(stru ++ ++ static inline void sfp_parse_support(struct sfp_bus *bus, ++ const struct sfp_eeprom_id *id, ++- unsigned long *support) +++ unsigned long *support, +++ unsigned long *interfaces) ++ { ++ } ++ +diff --git a/target/linux/mvebu/patches-5.15/706-03-03-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch b/target/linux/mvebu/patches-5.15/706-03-03-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch +new file mode 100644 +index 0000000000..89eb65d350 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-03-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch +@@ -0,0 +1,238 @@ ++From f81fa96d8a6c7a7723b7cfa2ef8f6e514843d577 Mon Sep 17 00:00:00 2001 ++From: Russell King <rmk+kernel@armlinux.org.uk> ++Date: Fri, 30 Sep 2022 16:21:01 +0200 ++Subject: [PATCH] net: phylink: use phy_interface_t bitmaps for optical modules ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Where a MAC provides a phy_interface_t bitmap, use these bitmaps to ++select the operating interface mode for optical SFP modules, rather ++than using the linkmode bitmaps. ++ ++Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -2582,6 +2582,70 @@ static void phylink_sfp_detach(void *ups ++ pl->netdev->sfp_bus = NULL; ++ } ++ +++static const phy_interface_t phylink_sfp_interface_preference[] = { +++ PHY_INTERFACE_MODE_25GBASER, +++ PHY_INTERFACE_MODE_USXGMII, +++ PHY_INTERFACE_MODE_10GBASER, +++ PHY_INTERFACE_MODE_5GBASER, +++ PHY_INTERFACE_MODE_2500BASEX, +++ PHY_INTERFACE_MODE_SGMII, +++ PHY_INTERFACE_MODE_1000BASEX, +++ PHY_INTERFACE_MODE_100BASEX, +++}; +++ +++static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl, +++ const unsigned long *intf) +++{ +++ phy_interface_t interface; +++ size_t i; +++ +++ interface = PHY_INTERFACE_MODE_NA; +++ for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++) +++ if (test_bit(phylink_sfp_interface_preference[i], intf)) { +++ interface = phylink_sfp_interface_preference[i]; +++ break; +++ } +++ +++ return interface; +++} +++ +++static void phylink_sfp_set_config(struct phylink *pl, u8 mode, +++ unsigned long *supported, +++ struct phylink_link_state *state) +++{ +++ bool changed = false; +++ +++ phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n", +++ phylink_an_mode_str(mode), phy_modes(state->interface), +++ __ETHTOOL_LINK_MODE_MASK_NBITS, supported); +++ +++ if (!linkmode_equal(pl->supported, supported)) { +++ linkmode_copy(pl->supported, supported); +++ changed = true; +++ } +++ +++ if (!linkmode_equal(pl->link_config.advertising, state->advertising)) { +++ linkmode_copy(pl->link_config.advertising, state->advertising); +++ changed = true; +++ } +++ +++ if (pl->cur_link_an_mode != mode || +++ pl->link_config.interface != state->interface) { +++ pl->cur_link_an_mode = mode; +++ pl->link_config.interface = state->interface; +++ +++ changed = true; +++ +++ phylink_info(pl, "switched to %s/%s link mode\n", +++ phylink_an_mode_str(mode), +++ phy_modes(state->interface)); +++ } +++ +++ if (changed && !test_bit(PHYLINK_DISABLE_STOPPED, +++ &pl->phylink_disable_state)) +++ phylink_mac_initial_config(pl, false); +++} +++ ++ static int phylink_sfp_config(struct phylink *pl, u8 mode, ++ const unsigned long *supported, ++ const unsigned long *advertising) ++@@ -2590,7 +2654,6 @@ static int phylink_sfp_config(struct phy ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(support); ++ struct phylink_link_state config; ++ phy_interface_t iface; ++- bool changed; ++ int ret; ++ ++ linkmode_copy(support, supported); ++@@ -2633,61 +2696,103 @@ static int phylink_sfp_config(struct phy ++ return ret; ++ } ++ ++- phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n", ++- phylink_an_mode_str(mode), phy_modes(config.interface), ++- __ETHTOOL_LINK_MODE_MASK_NBITS, support); ++- ++ if (phy_interface_mode_is_8023z(iface) && pl->phydev) ++ return -EINVAL; ++ ++- changed = !linkmode_equal(pl->supported, support) || ++- !linkmode_equal(pl->link_config.advertising, ++- config.advertising); ++- if (changed) { ++- linkmode_copy(pl->supported, support); ++- linkmode_copy(pl->link_config.advertising, config.advertising); +++ pl->link_port = pl->sfp_port; +++ +++ phylink_sfp_set_config(pl, mode, support, &config); +++ +++ return 0; +++} +++ +++static int phylink_sfp_config_optical(struct phylink *pl) +++{ +++ __ETHTOOL_DECLARE_LINK_MODE_MASK(support); +++ DECLARE_PHY_INTERFACE_MASK(interfaces); +++ struct phylink_link_state config; +++ phy_interface_t interface; +++ int ret; +++ +++ phylink_dbg(pl, "optical SFP: interfaces=[mac=%*pbl, sfp=%*pbl]\n", +++ (int)PHY_INTERFACE_MODE_MAX, +++ pl->config->supported_interfaces, +++ (int)PHY_INTERFACE_MODE_MAX, +++ pl->sfp_interfaces); +++ +++ /* Find the union of the supported interfaces by the PCS/MAC and +++ * the SFP module. +++ */ +++ phy_interface_and(interfaces, pl->config->supported_interfaces, +++ pl->sfp_interfaces); +++ if (phy_interface_empty(interfaces)) { +++ phylink_err(pl, "unsupported SFP module: no common interface modes\n"); +++ return -EINVAL; ++ } ++ ++- if (pl->cur_link_an_mode != mode || ++- pl->link_config.interface != config.interface) { ++- pl->link_config.interface = config.interface; ++- pl->cur_link_an_mode = mode; +++ memset(&config, 0, sizeof(config)); +++ linkmode_copy(support, pl->sfp_support); +++ linkmode_copy(config.advertising, pl->sfp_support); +++ config.speed = SPEED_UNKNOWN; +++ config.duplex = DUPLEX_UNKNOWN; +++ config.pause = MLO_PAUSE_AN; +++ config.an_enabled = true; ++ ++- changed = true; +++ /* For all the interfaces that are supported, reduce the sfp_support +++ * mask to only those link modes that can be supported. +++ */ +++ ret = phylink_validate_mask(pl, pl->sfp_support, &config, interfaces); +++ if (ret) { +++ phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n", +++ __ETHTOOL_LINK_MODE_MASK_NBITS, support); +++ return ret; +++ } ++ ++- phylink_info(pl, "switched to %s/%s link mode\n", ++- phylink_an_mode_str(mode), ++- phy_modes(config.interface)); +++ interface = phylink_choose_sfp_interface(pl, interfaces); +++ if (interface == PHY_INTERFACE_MODE_NA) { +++ phylink_err(pl, "failed to select SFP interface\n"); +++ return -EINVAL; +++ } +++ +++ phylink_dbg(pl, "optical SFP: chosen %s interface\n", +++ phy_modes(interface)); +++ +++ config.interface = interface; +++ +++ /* Ignore errors if we're expecting a PHY to attach later */ +++ ret = phylink_validate(pl, support, &config); +++ if (ret) { +++ phylink_err(pl, "validation with support %*pb failed: %pe\n", +++ __ETHTOOL_LINK_MODE_MASK_NBITS, support, +++ ERR_PTR(ret)); +++ return ret; ++ } ++ ++ pl->link_port = pl->sfp_port; ++ ++- if (changed && !test_bit(PHYLINK_DISABLE_STOPPED, ++- &pl->phylink_disable_state)) ++- phylink_mac_initial_config(pl, false); +++ phylink_sfp_set_config(pl, MLO_AN_INBAND, pl->sfp_support, &config); ++ ++- return ret; +++ return 0; ++ } ++ ++ static int phylink_sfp_module_insert(void *upstream, ++ const struct sfp_eeprom_id *id) ++ { ++ struct phylink *pl = upstream; ++- unsigned long *support = pl->sfp_support; ++ ++ ASSERT_RTNL(); ++ ++- linkmode_zero(support); +++ linkmode_zero(pl->sfp_support); ++ phy_interface_zero(pl->sfp_interfaces); ++- sfp_parse_support(pl->sfp_bus, id, support, pl->sfp_interfaces); ++- pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support); +++ sfp_parse_support(pl->sfp_bus, id, pl->sfp_support, pl->sfp_interfaces); +++ pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, pl->sfp_support); ++ ++ /* If this module may have a PHY connecting later, defer until later */ ++ pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id); ++ if (pl->sfp_may_have_phy) ++ return 0; ++ ++- return phylink_sfp_config(pl, MLO_AN_INBAND, support, support); +++ return phylink_sfp_config_optical(pl); ++ } ++ ++ static int phylink_sfp_module_start(void *upstream) ++@@ -2706,8 +2811,7 @@ static int phylink_sfp_module_start(void ++ if (!pl->sfp_may_have_phy) ++ return 0; ++ ++- return phylink_sfp_config(pl, MLO_AN_INBAND, ++- pl->sfp_support, pl->sfp_support); +++ return phylink_sfp_config_optical(pl); ++ } ++ ++ static void phylink_sfp_module_stop(void *upstream) +diff --git a/target/linux/mvebu/patches-5.15/706-03-04-net-phylink-rename-phylink_sfp_config.patch b/target/linux/mvebu/patches-5.15/706-03-04-net-phylink-rename-phylink_sfp_config.patch +new file mode 100644 +index 0000000000..459fb57704 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-04-net-phylink-rename-phylink_sfp_config.patch +@@ -0,0 +1,51 @@ ++From e60846370ca96a042d0e203782b84ed9558a8546 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 30 Sep 2022 16:21:02 +0200 ++Subject: [PATCH] net: phylink: rename phylink_sfp_config() ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++phylink_sfp_config() now only deals with configuring the MAC for a ++SFP containing a PHY. Rename it to be specific. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -2646,9 +2646,8 @@ static void phylink_sfp_set_config(struc ++ phylink_mac_initial_config(pl, false); ++ } ++ ++-static int phylink_sfp_config(struct phylink *pl, u8 mode, ++- const unsigned long *supported, ++- const unsigned long *advertising) +++static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, +++ struct phy_device *phy) ++ { ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(support1); ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(support); ++@@ -2656,10 +2655,10 @@ static int phylink_sfp_config(struct phy ++ phy_interface_t iface; ++ int ret; ++ ++- linkmode_copy(support, supported); +++ linkmode_copy(support, phy->supported); ++ ++ memset(&config, 0, sizeof(config)); ++- linkmode_copy(config.advertising, advertising); +++ linkmode_copy(config.advertising, phy->advertising); ++ config.interface = PHY_INTERFACE_MODE_NA; ++ config.speed = SPEED_UNKNOWN; ++ config.duplex = DUPLEX_UNKNOWN; ++@@ -2872,7 +2871,7 @@ static int phylink_sfp_connect_phy(void ++ mode = MLO_AN_INBAND; ++ ++ /* Do the initial configuration */ ++- ret = phylink_sfp_config(pl, mode, phy->supported, phy->advertising); +++ ret = phylink_sfp_config_phy(pl, mode, phy); ++ if (ret < 0) ++ return ret; ++ +diff --git a/target/linux/mvebu/patches-5.15/706-03-05-net-phylink-pass-supported-host-PHY-interface-modes-.patch b/target/linux/mvebu/patches-5.15/706-03-05-net-phylink-pass-supported-host-PHY-interface-modes-.patch +new file mode 100644 +index 0000000000..5e9c007c8a +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-05-net-phylink-pass-supported-host-PHY-interface-modes-.patch +@@ -0,0 +1,83 @@ ++From eca68a3c7d05b38b4e728cead0c49718f2bc1d5a Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Fri, 30 Sep 2022 16:21:03 +0200 ++Subject: [PATCH] net: phylink: pass supported host PHY interface modes to ++ phylib for SFP's PHYs ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Pass the supported PHY interface types to phylib if the PHY we are ++connecting is inside a SFP, so that the PHY driver can select an ++appropriate host configuration mode for their interface according to ++the host capabilities. ++ ++For example the Marvell 88X3310 PHY inside RollBall SFP modules ++defaults to 10gbase-r mode on host's side, and the marvell10g ++driver currently does not change this setting. But a host may not ++support 10gbase-r. For example Turris Omnia only supports sgmii, ++1000base-x and 2500base-x modes. The PHY can be configured to use ++those modes, but in order for the PHY driver to do that, it needs ++to know which modes are supported. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -2593,6 +2593,8 @@ static const phy_interface_t phylink_sfp ++ PHY_INTERFACE_MODE_100BASEX, ++ }; ++ +++static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces); +++ ++ static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl, ++ const unsigned long *intf) ++ { ++@@ -2870,6 +2872,10 @@ static int phylink_sfp_connect_phy(void ++ 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); ++ if (ret < 0) ++@@ -3253,4 +3259,15 @@ void phylink_mii_c45_pcs_get_state(struc ++ } ++ EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state); ++ +++static int __init phylink_init(void) +++{ +++ for (int i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); ++i) +++ __set_bit(phylink_sfp_interface_preference[i], +++ phylink_sfp_interfaces); +++ +++ return 0; +++} +++ +++module_init(phylink_init); +++ ++ MODULE_LICENSE("GPL v2"); ++--- a/include/linux/phy.h +++++ b/include/linux/phy.h ++@@ -563,6 +563,7 @@ struct macsec_ops; ++ * @advertising: Currently advertised linkmodes ++ * @adv_old: Saved advertised while power saving for WoL ++ * @lp_advertising: Current link partner advertised linkmodes +++ * @host_interfaces: PHY interface modes supported by host ++ * @eee_broken_modes: Energy efficient ethernet modes which should be prohibited ++ * @autoneg: Flag autoneg being used ++ * @link: Current link state ++@@ -658,6 +659,9 @@ struct phy_device { ++ /* used with phy_speed_down */ ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); ++ +++ /* Host supported PHY interface types. Should be ignored if empty. */ +++ DECLARE_PHY_INTERFACE_MASK(host_interfaces); +++ ++ /* Energy efficient ethernet modes which should be prohibited */ ++ u32 eee_broken_modes; ++ +diff --git a/target/linux/mvebu/patches-5.15/706-03-06-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch b/target/linux/mvebu/patches-5.15/706-03-06-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch +new file mode 100644 +index 0000000000..2c327f2e28 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-06-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch +@@ -0,0 +1,44 @@ ++From 3891569b2fc378e7fb882f5dbdc001ee8f78f024 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Fri, 30 Sep 2022 16:21:04 +0200 ++Subject: [PATCH] net: phy: marvell10g: Use tabs instead of spaces for ++ indentation ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Some register definitions were defined with spaces used for indentation. ++Change them to tabs. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/marvell10g.c +++++ b/drivers/net/phy/marvell10g.c ++@@ -105,16 +105,16 @@ enum { ++ MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN = 0x5, ++ MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6, ++ MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII = 0x7, ++- MV_V2_PORT_INTR_STS = 0xf040, ++- MV_V2_PORT_INTR_MASK = 0xf043, ++- MV_V2_PORT_INTR_STS_WOL_EN = BIT(8), ++- MV_V2_MAGIC_PKT_WORD0 = 0xf06b, ++- MV_V2_MAGIC_PKT_WORD1 = 0xf06c, ++- MV_V2_MAGIC_PKT_WORD2 = 0xf06d, +++ MV_V2_PORT_INTR_STS = 0xf040, +++ MV_V2_PORT_INTR_MASK = 0xf043, +++ MV_V2_PORT_INTR_STS_WOL_EN = BIT(8), +++ MV_V2_MAGIC_PKT_WORD0 = 0xf06b, +++ MV_V2_MAGIC_PKT_WORD1 = 0xf06c, +++ MV_V2_MAGIC_PKT_WORD2 = 0xf06d, ++ /* Wake on LAN registers */ ++- MV_V2_WOL_CTRL = 0xf06e, ++- MV_V2_WOL_CTRL_CLEAR_STS = BIT(15), ++- MV_V2_WOL_CTRL_MAGIC_PKT_EN = BIT(0), +++ MV_V2_WOL_CTRL = 0xf06e, +++ MV_V2_WOL_CTRL_CLEAR_STS = BIT(15), +++ MV_V2_WOL_CTRL_MAGIC_PKT_EN = BIT(0), ++ /* Temperature control/read registers (88X3310 only) */ ++ MV_V2_TEMP_CTRL = 0xf08a, ++ MV_V2_TEMP_CTRL_MASK = 0xc000, +diff --git a/target/linux/mvebu/patches-5.15/706-03-07-net-phy-marvell10g-select-host-interface-configurati.patch b/target/linux/mvebu/patches-5.15/706-03-07-net-phy-marvell10g-select-host-interface-configurati.patch +new file mode 100644 +index 0000000000..575f3f967b +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-07-net-phy-marvell10g-select-host-interface-configurati.patch +@@ -0,0 +1,216 @@ ++From d6d29292640d3f778a28a74c53ae1733c023392f Mon Sep 17 00:00:00 2001 ++From: Russell King <rmk+kernel@armlinux.org.uk> ++Date: Fri, 30 Sep 2022 16:21:05 +0200 ++Subject: [PATCH] net: phy: marvell10g: select host interface configuration ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Select the host interface configuration according to the capabilities of ++the host if the host provided them. This is currently provided only when ++connecting PHY that is inside a SFP. ++ ++The PHY supports several configurations of host communication: ++- always communicate with host in 10gbase-r, even if copper speed is ++ lower (rate matching mode), ++- the same as above but use xaui/rxaui instead of 10gbase-r, ++- switch host SerDes mode between 10gbase-r, 5gbase-r, 2500base-x and ++ sgmii according to copper speed, ++- the same as above but use xaui/rxaui instead of 10gbase-r. ++ ++This mode of host communication, called MACTYPE, is by default selected ++by strapping pins, but it can be changed in software. ++ ++This adds support for selecting this mode according to which modes are ++supported by the host. ++ ++This allows the kernel to: ++- support SFP modules with 88X33X0 or 88E21X0 inside them ++ ++Note: we use mv3310_select_mactype() for both 88X3310 and 88X3340, ++although 88X3340 does not support XAUI. This is not a problem because ++88X3340 does not declare XAUI in it's supported_interfaces, and so this ++function will never choose that MACTYPE. ++ ++Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> ++[ rebase, updated, also added support for 88E21X0 ] ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/marvell10g.c +++++ b/drivers/net/phy/marvell10g.c ++@@ -84,6 +84,11 @@ enum { ++ MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380, ++ MV_PCS_PORT_INFO_NPORTS_SHIFT = 7, ++ +++ /* SerDes reinitialization 88E21X0 */ +++ MV_AN_21X0_SERDES_CTRL2 = 0x800f, +++ MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS = BIT(13), +++ MV_AN_21X0_SERDES_CTRL2_RUN_INIT = BIT(15), +++ ++ /* These registers appear at 0x800X and 0xa00X - the 0xa00X control ++ * registers appear to set themselves to the 0x800X when AN is ++ * restarted, but status registers appear readable from either. ++@@ -127,6 +132,8 @@ enum { ++ struct mv3310_chip { ++ void (*init_supported_interfaces)(unsigned long *mask); ++ int (*get_mactype)(struct phy_device *phydev); +++ int (*set_mactype)(struct phy_device *phydev, int mactype); +++ int (*select_mactype)(unsigned long *interfaces); ++ int (*init_interface)(struct phy_device *phydev, int mactype); ++ ++ #ifdef CONFIG_HWMON ++@@ -519,6 +526,49 @@ static int mv2110_get_mactype(struct phy ++ return mactype & MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK; ++ } ++ +++static int mv2110_set_mactype(struct phy_device *phydev, int mactype) +++{ +++ int err, val; +++ +++ mactype &= MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK; +++ err = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_21X0_PORT_CTRL, +++ MV_PMA_21X0_PORT_CTRL_SWRST | +++ MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK, +++ MV_PMA_21X0_PORT_CTRL_SWRST | mactype); +++ if (err) +++ return err; +++ +++ err = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2, +++ MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS | +++ MV_AN_21X0_SERDES_CTRL2_RUN_INIT); +++ if (err) +++ return err; +++ +++ err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_AN, +++ MV_AN_21X0_SERDES_CTRL2, val, +++ !(val & +++ MV_AN_21X0_SERDES_CTRL2_RUN_INIT), +++ 5000, 100000, true); +++ if (err) +++ return err; +++ +++ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2, +++ MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS); +++} +++ +++static int mv2110_select_mactype(unsigned long *interfaces) +++{ +++ if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces)) +++ return MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII; +++ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) && +++ !test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces)) +++ return MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER; +++ else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces)) +++ return MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH; +++ else +++ return -1; +++} +++ ++ static int mv3310_get_mactype(struct phy_device *phydev) ++ { ++ int mactype; ++@@ -530,6 +580,46 @@ static int mv3310_get_mactype(struct phy ++ return mactype & MV_V2_33X0_PORT_CTRL_MACTYPE_MASK; ++ } ++ +++static int mv3310_set_mactype(struct phy_device *phydev, int mactype) +++{ +++ int ret; +++ +++ mactype &= MV_V2_33X0_PORT_CTRL_MACTYPE_MASK; +++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, +++ MV_V2_33X0_PORT_CTRL_MACTYPE_MASK, +++ mactype); +++ if (ret <= 0) +++ return ret; +++ +++ return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, +++ MV_V2_33X0_PORT_CTRL_SWRST); +++} +++ +++static int mv3310_select_mactype(unsigned long *interfaces) +++{ +++ if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces)) +++ return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII; +++ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) && +++ test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces)) +++ return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER; +++ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) && +++ test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces)) +++ return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI; +++ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) && +++ test_bit(PHY_INTERFACE_MODE_XAUI, interfaces)) +++ return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI; +++ else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces)) +++ return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH; +++ else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces)) +++ return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH; +++ else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces)) +++ return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH; +++ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces)) +++ return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER; +++ else +++ return -1; +++} +++ ++ static int mv2110_init_interface(struct phy_device *phydev, int mactype) ++ { ++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++@@ -613,6 +703,20 @@ static int mv3310_config_init(struct phy ++ if (err) ++ return err; ++ +++ /* If host provided host supported interface modes, try to select the +++ * best one +++ */ +++ if (!phy_interface_empty(phydev->host_interfaces)) { +++ mactype = chip->select_mactype(phydev->host_interfaces); +++ if (mactype >= 0) { +++ phydev_info(phydev, "Changing MACTYPE to %i\n", +++ mactype); +++ err = chip->set_mactype(phydev, mactype); +++ if (err) +++ return err; +++ } +++ } +++ ++ mactype = chip->get_mactype(phydev); ++ if (mactype < 0) ++ return mactype; ++@@ -953,6 +1057,8 @@ static void mv2111_init_supported_interf ++ static const struct mv3310_chip mv3310_type = { ++ .init_supported_interfaces = mv3310_init_supported_interfaces, ++ .get_mactype = mv3310_get_mactype, +++ .set_mactype = mv3310_set_mactype, +++ .select_mactype = mv3310_select_mactype, ++ .init_interface = mv3310_init_interface, ++ ++ #ifdef CONFIG_HWMON ++@@ -963,6 +1069,8 @@ static const struct mv3310_chip mv3310_t ++ static const struct mv3310_chip mv3340_type = { ++ .init_supported_interfaces = mv3340_init_supported_interfaces, ++ .get_mactype = mv3310_get_mactype, +++ .set_mactype = mv3310_set_mactype, +++ .select_mactype = mv3310_select_mactype, ++ .init_interface = mv3340_init_interface, ++ ++ #ifdef CONFIG_HWMON ++@@ -973,6 +1081,8 @@ static const struct mv3310_chip mv3340_t ++ static const struct mv3310_chip mv2110_type = { ++ .init_supported_interfaces = mv2110_init_supported_interfaces, ++ .get_mactype = mv2110_get_mactype, +++ .set_mactype = mv2110_set_mactype, +++ .select_mactype = mv2110_select_mactype, ++ .init_interface = mv2110_init_interface, ++ ++ #ifdef CONFIG_HWMON ++@@ -983,6 +1093,8 @@ static const struct mv3310_chip mv2110_t ++ static const struct mv3310_chip mv2111_type = { ++ .init_supported_interfaces = mv2111_init_supported_interfaces, ++ .get_mactype = mv2110_get_mactype, +++ .set_mactype = mv2110_set_mactype, +++ .select_mactype = mv2110_select_mactype, ++ .init_interface = mv2110_init_interface, ++ ++ #ifdef CONFIG_HWMON +diff --git a/target/linux/mvebu/patches-5.15/706-03-08-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch b/target/linux/mvebu/patches-5.15/706-03-08-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch +new file mode 100644 +index 0000000000..84404d6839 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-08-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch +@@ -0,0 +1,41 @@ ++From 31eb8907aa5b9e9be1a63f2ac574973715172ab4 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Fri, 30 Sep 2022 16:21:06 +0200 ++Subject: [PATCH] net: phylink: allow attaching phy for SFP modules on 802.3z ++ mode ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Some SFPs may contain an internal PHY which may in some cases want to ++connect with the host interface in 1000base-x/2500base-x mode. ++Do not fail if such PHY is being attached in one of these PHY interface ++modes. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Reviewed-by: Russell King <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Pali Rohár <pali@kernel.org> ++Cc: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -1459,7 +1459,7 @@ static int phylink_attach_phy(struct phy ++ { ++ if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED || ++ (pl->cfg_link_an_mode == MLO_AN_INBAND && ++- phy_interface_mode_is_8023z(interface)))) +++ phy_interface_mode_is_8023z(interface) && !pl->sfp_bus))) ++ return -EINVAL; ++ ++ if (pl->phydev) ++@@ -2697,9 +2697,6 @@ static int phylink_sfp_config_phy(struct ++ return ret; ++ } ++ ++- if (phy_interface_mode_is_8023z(iface) && pl->phydev) ++- return -EINVAL; ++- ++ pl->link_port = pl->sfp_port; ++ ++ phylink_sfp_set_config(pl, mode, support, &config); +diff --git a/target/linux/mvebu/patches-5.15/706-03-09-net-sfp-Add-and-use-macros-for-SFP-quirks-definition.patch b/target/linux/mvebu/patches-5.15/706-03-09-net-sfp-Add-and-use-macros-for-SFP-quirks-definition.patch +new file mode 100644 +index 0000000000..afd627c460 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-09-net-sfp-Add-and-use-macros-for-SFP-quirks-definition.patch +@@ -0,0 +1,85 @@ ++From 13c8adcf221f1ff407115d3269e0fb57e8cecf82 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Fri, 30 Sep 2022 16:21:07 +0200 ++Subject: [PATCH] net: sfp: Add and use macros for SFP quirks definitions ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Add macros SFP_QUIRK(), SFP_QUIRK_M() and SFP_QUIRK_F() for defining SFP ++quirk table entries. Use them to deduplicate the code a little bit. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -357,42 +357,33 @@ static void sfp_quirk_ubnt_uf_instant(co ++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); ++ } ++ +++#define SFP_QUIRK(_v, _p, _m, _f) \ +++ { .vendor = _v, .part = _p, .modes = _m, .fixup = _f, } +++#define SFP_QUIRK_M(_v, _p, _m) SFP_QUIRK(_v, _p, _m, NULL) +++#define SFP_QUIRK_F(_v, _p, _f) SFP_QUIRK(_v, _p, NULL, _f) +++ ++ static const struct sfp_quirk sfp_quirks[] = { ++- { ++- // Alcatel Lucent G-010S-P can operate at 2500base-X, but ++- // incorrectly report 2500MBd NRZ in their EEPROM ++- .vendor = "ALCATELLUCENT", ++- .part = "G010SP", ++- .modes = sfp_quirk_2500basex, ++- }, { ++- // Alcatel Lucent G-010S-A can operate at 2500base-X, but ++- // report 3.2GBd NRZ in their EEPROM ++- .vendor = "ALCATELLUCENT", ++- .part = "3FE46541AA", ++- .modes = sfp_quirk_2500basex, ++- .fixup = sfp_fixup_long_startup, ++- }, { ++- .vendor = "HALNy", ++- .part = "HL-GSFP", ++- .fixup = sfp_fixup_halny_gsfp, ++- }, { ++- // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd ++- // NRZ in their EEPROM ++- .vendor = "HUAWEI", ++- .part = "MA5671A", ++- .modes = sfp_quirk_2500basex, ++- .fixup = sfp_fixup_ignore_tx_fault, ++- }, { ++- // Lantech 8330-262D-E can operate at 2500base-X, but ++- // incorrectly report 2500MBd NRZ in their EEPROM ++- .vendor = "Lantech", ++- .part = "8330-262D-E", ++- .modes = sfp_quirk_2500basex, ++- }, { ++- .vendor = "UBNT", ++- .part = "UF-INSTANT", ++- .modes = sfp_quirk_ubnt_uf_instant, ++- } +++ // Alcatel Lucent G-010S-P can operate at 2500base-X, but incorrectly +++ // report 2500MBd NRZ in their EEPROM +++ SFP_QUIRK_M("ALCATELLUCENT", "G010SP", sfp_quirk_2500basex), +++ +++ // Alcatel Lucent G-010S-A can operate at 2500base-X, but report 3.2GBd +++ // NRZ in their EEPROM +++ SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex, +++ sfp_fixup_long_startup), +++ +++ SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp), +++ +++ // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in +++ // their EEPROM +++ SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex, +++ sfp_fixup_ignore_tx_fault), +++ +++ // Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report +++ // 2500MBd NRZ in their EEPROM +++ SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex), +++ +++ SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant), ++ }; ++ ++ static size_t sfp_strlen(const char *str, size_t maxlen) +diff --git a/target/linux/mvebu/patches-5.15/706-03-10-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch b/target/linux/mvebu/patches-5.15/706-03-10-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch +new file mode 100644 +index 0000000000..235f5d4b10 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-10-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch +@@ -0,0 +1,171 @@ ++From e85b1347ace677c3822c12d9332dfaaffe594da6 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Fri, 30 Sep 2022 16:21:08 +0200 ++Subject: [PATCH] net: sfp: create/destroy I2C mdiobus before PHY probe/after ++ PHY release ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Instead of configuring the I2C mdiobus when SFP driver is probed, ++create/destroy the mdiobus before the PHY is probed for/after it is ++released. ++ ++This way we can tell the mdio-i2c code which protocol to use for each ++SFP transceiver. ++ ++Move the code that determines MDIO I2C protocol from ++sfp_sm_probe_for_phy() to sfp_sm_mod_probe(), where most of the SFP ID ++parsing is done. Don't allocate I2C bus if no PHY is expected. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -224,6 +224,7 @@ struct sfp { ++ struct i2c_adapter *i2c; ++ struct mii_bus *i2c_mii; ++ struct sfp_bus *sfp_bus; +++ enum mdio_i2c_proto mdio_protocol; ++ struct phy_device *mod_phy; ++ const struct sff_data *type; ++ size_t i2c_block_size; ++@@ -537,9 +538,6 @@ static int sfp_i2c_write(struct sfp *sfp ++ ++ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) ++ { ++- struct mii_bus *i2c_mii; ++- int ret; ++- ++ if (!i2c_check_functionality(i2c, I2C_FUNC_I2C)) ++ return -EINVAL; ++ ++@@ -547,7 +545,15 @@ static int sfp_i2c_configure(struct sfp ++ sfp->read = sfp_i2c_read; ++ sfp->write = sfp_i2c_write; ++ ++- i2c_mii = mdio_i2c_alloc(sfp->dev, i2c); +++ return 0; +++} +++ +++static int sfp_i2c_mdiobus_create(struct sfp *sfp) +++{ +++ struct mii_bus *i2c_mii; +++ int ret; +++ +++ i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c); ++ if (IS_ERR(i2c_mii)) ++ return PTR_ERR(i2c_mii); ++ ++@@ -565,6 +571,12 @@ static int sfp_i2c_configure(struct sfp ++ return 0; ++ } ++ +++static void sfp_i2c_mdiobus_destroy(struct sfp *sfp) +++{ +++ mdiobus_unregister(sfp->i2c_mii); +++ sfp->i2c_mii = NULL; +++} +++ ++ /* Interface */ ++ static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) ++ { ++@@ -1730,6 +1742,14 @@ static void sfp_sm_fault(struct sfp *sfp ++ } ++ } ++ +++static int sfp_sm_add_mdio_bus(struct sfp *sfp) +++{ +++ if (sfp->mdio_protocol != MDIO_I2C_NONE) +++ return sfp_i2c_mdiobus_create(sfp); +++ +++ return 0; +++} +++ ++ /* Probe a SFP for a PHY device if the module supports copper - the PHY ++ * normally sits at I2C bus address 0x56, and may either be a clause 22 ++ * or clause 45 PHY. ++@@ -1745,19 +1765,19 @@ static int sfp_sm_probe_for_phy(struct s ++ { ++ int err = 0; ++ ++- switch (sfp->id.base.extended_cc) { ++- case SFF8024_ECC_10GBASE_T_SFI: ++- case SFF8024_ECC_10GBASE_T_SR: ++- case SFF8024_ECC_5GBASE_T: ++- case SFF8024_ECC_2_5GBASE_T: ++- err = sfp_sm_probe_phy(sfp, true); +++ switch (sfp->mdio_protocol) { +++ case MDIO_I2C_NONE: ++ break; ++ ++- default: ++- if (sfp->id.base.e1000_base_t) ++- err = sfp_sm_probe_phy(sfp, false); +++ case MDIO_I2C_MARVELL_C22: +++ err = sfp_sm_probe_phy(sfp, false); +++ break; +++ +++ case MDIO_I2C_C45: +++ err = sfp_sm_probe_phy(sfp, true); ++ break; ++ } +++ ++ return err; ++ } ++ ++@@ -2080,6 +2100,16 @@ static int sfp_sm_mod_probe(struct sfp * ++ ++ sfp->tx_fault_ignore = false; ++ +++ if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI || +++ sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR || +++ sfp->id.base.extended_cc == SFF8024_ECC_5GBASE_T || +++ sfp->id.base.extended_cc == SFF8024_ECC_2_5GBASE_T) +++ sfp->mdio_protocol = MDIO_I2C_C45; +++ else if (sfp->id.base.e1000_base_t) +++ sfp->mdio_protocol = MDIO_I2C_MARVELL_C22; +++ else +++ sfp->mdio_protocol = MDIO_I2C_NONE; +++ ++ sfp->quirk = sfp_lookup_quirk(&id); ++ if (sfp->quirk && sfp->quirk->fixup) ++ sfp->quirk->fixup(sfp); ++@@ -2256,6 +2286,8 @@ static void sfp_sm_main(struct sfp *sfp, ++ sfp_module_stop(sfp->sfp_bus); ++ if (sfp->mod_phy) ++ sfp_sm_phy_detach(sfp); +++ if (sfp->i2c_mii) +++ sfp_i2c_mdiobus_destroy(sfp); ++ sfp_module_tx_disable(sfp); ++ sfp_soft_stop_poll(sfp); ++ sfp_sm_next(sfp, SFP_S_DOWN, 0); ++@@ -2318,6 +2350,12 @@ static void sfp_sm_main(struct sfp *sfp, ++ sfp->sm_fault_retries == N_FAULT_INIT); ++ } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { ++ init_done: +++ /* Create mdiobus and start trying for PHY */ +++ ret = sfp_sm_add_mdio_bus(sfp); +++ if (ret < 0) { +++ sfp_sm_next(sfp, SFP_S_FAIL, 0); +++ break; +++ } ++ sfp->sm_phy_retries = R_PHY_RETRY; ++ goto phy_probe; ++ } ++--- a/include/linux/mdio/mdio-i2c.h +++++ b/include/linux/mdio/mdio-i2c.h ++@@ -11,6 +11,12 @@ struct device; ++ struct i2c_adapter; ++ struct mii_bus; ++ +++enum mdio_i2c_proto { +++ MDIO_I2C_NONE, +++ MDIO_I2C_MARVELL_C22, +++ MDIO_I2C_C45, +++}; +++ ++ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c); ++ ++ #endif +diff --git a/target/linux/mvebu/patches-5.15/706-03-11-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch b/target/linux/mvebu/patches-5.15/706-03-11-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch +new file mode 100644 +index 0000000000..865f107a78 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-11-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch +@@ -0,0 +1,421 @@ ++From 09bbedac72d5a9267088c15d1a71c8c3a8fb47e7 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Fri, 30 Sep 2022 16:21:09 +0200 ++Subject: [PATCH] net: phy: mdio-i2c: support I2C MDIO protocol for RollBall ++ SFP modules ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Some multigig SFPs from RollBall and Hilink do not expose functional ++MDIO access to the internal PHY of the SFP via I2C address 0x56 ++(although there seems to be read-only clause 22 access on this address). ++ ++Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced ++Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be ++selected to 3 and the password must be filled with 0xff bytes for this ++PHY communication to work. ++ ++This extends the mdio-i2c driver to support this protocol by adding a ++special parameter to mdio_i2c_alloc function via which this RollBall ++protocol can be selected. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Cc: Andrew Lunn <andrew@lunn.ch> ++Cc: Russell King <rmk+kernel@armlinux.org.uk> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/mdio/mdio-i2c.c +++++ b/drivers/net/mdio/mdio-i2c.c ++@@ -3,6 +3,7 @@ ++ * MDIO I2C bridge ++ * ++ * Copyright (C) 2015-2016 Russell King +++ * Copyright (C) 2021 Marek Behun ++ * ++ * Network PHYs can appear on I2C buses when they are part of SFP module. ++ * This driver exposes these PHYs to the networking PHY code, allowing ++@@ -12,6 +13,7 @@ ++ #include <linux/i2c.h> ++ #include <linux/mdio/mdio-i2c.h> ++ #include <linux/phy.h> +++#include <linux/sfp.h> ++ ++ /* ++ * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is ++@@ -28,7 +30,7 @@ static unsigned int i2c_mii_phy_addr(int ++ return phy_id + 0x40; ++ } ++ ++-static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg) +++static int i2c_mii_read_default(struct mii_bus *bus, int phy_id, int reg) ++ { ++ struct i2c_adapter *i2c = bus->priv; ++ struct i2c_msg msgs[2]; ++@@ -62,7 +64,8 @@ static int i2c_mii_read(struct mii_bus * ++ return data[0] << 8 | data[1]; ++ } ++ ++-static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val) +++static int i2c_mii_write_default(struct mii_bus *bus, int phy_id, int reg, +++ u16 val) ++ { ++ struct i2c_adapter *i2c = bus->priv; ++ struct i2c_msg msg; ++@@ -91,9 +94,288 @@ static int i2c_mii_write(struct mii_bus ++ return ret < 0 ? ret : 0; ++ } ++ ++-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c) +++/* RollBall SFPs do not access internal PHY via I2C address 0x56, but +++ * instead via address 0x51, when SFP page is set to 0x03 and password to +++ * 0xffffffff. +++ * +++ * address size contents description +++ * ------- ---- -------- ----------- +++ * 0x80 1 CMD 0x01/0x02/0x04 for write/read/done +++ * 0x81 1 DEV Clause 45 device +++ * 0x82 2 REG Clause 45 register +++ * 0x84 2 VAL Register value +++ */ +++#define ROLLBALL_PHY_I2C_ADDR 0x51 +++ +++#define ROLLBALL_PASSWORD (SFP_VSL + 3) +++ +++#define ROLLBALL_CMD_ADDR 0x80 +++#define ROLLBALL_DATA_ADDR 0x81 +++ +++#define ROLLBALL_CMD_WRITE 0x01 +++#define ROLLBALL_CMD_READ 0x02 +++#define ROLLBALL_CMD_DONE 0x04 +++ +++#define SFP_PAGE_ROLLBALL_MDIO 3 +++ +++static int __i2c_transfer_err(struct i2c_adapter *i2c, struct i2c_msg *msgs, +++ int num) +++{ +++ int ret; +++ +++ ret = __i2c_transfer(i2c, msgs, num); +++ if (ret < 0) +++ return ret; +++ else if (ret != num) +++ return -EIO; +++ else +++ return 0; +++} +++ +++static int __i2c_rollball_get_page(struct i2c_adapter *i2c, int bus_addr, +++ u8 *page) +++{ +++ struct i2c_msg msgs[2]; +++ u8 addr = SFP_PAGE; +++ +++ msgs[0].addr = bus_addr; +++ msgs[0].flags = 0; +++ msgs[0].len = 1; +++ msgs[0].buf = &addr; +++ +++ msgs[1].addr = bus_addr; +++ msgs[1].flags = I2C_M_RD; +++ msgs[1].len = 1; +++ msgs[1].buf = page; +++ +++ return __i2c_transfer_err(i2c, msgs, 2); +++} +++ +++static int __i2c_rollball_set_page(struct i2c_adapter *i2c, int bus_addr, +++ u8 page) +++{ +++ struct i2c_msg msg; +++ u8 buf[2]; +++ +++ buf[0] = SFP_PAGE; +++ buf[1] = page; +++ +++ msg.addr = bus_addr; +++ msg.flags = 0; +++ msg.len = 2; +++ msg.buf = buf; +++ +++ return __i2c_transfer_err(i2c, &msg, 1); +++} +++ +++/* In order to not interfere with other SFP code (which possibly may manipulate +++ * SFP_PAGE), for every transfer we do this: +++ * 1. lock the bus +++ * 2. save content of SFP_PAGE +++ * 3. set SFP_PAGE to 3 +++ * 4. do the transfer +++ * 5. restore original SFP_PAGE +++ * 6. unlock the bus +++ * Note that one might think that steps 2 to 5 could be theoretically done all +++ * in one call to i2c_transfer (by constructing msgs array in such a way), but +++ * unfortunately tests show that this does not work :-( Changed SFP_PAGE does +++ * not take into account until i2c_transfer() is done. +++ */ +++static int i2c_transfer_rollball(struct i2c_adapter *i2c, +++ struct i2c_msg *msgs, int num) +++{ +++ int ret, main_err = 0; +++ u8 saved_page; +++ +++ i2c_lock_bus(i2c, I2C_LOCK_SEGMENT); +++ +++ /* save original page */ +++ ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page); +++ if (ret) +++ goto unlock; +++ +++ /* change to RollBall MDIO page */ +++ ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO); +++ if (ret) +++ goto unlock; +++ +++ /* do the transfer; we try to restore original page if this fails */ +++ ret = __i2c_transfer_err(i2c, msgs, num); +++ if (ret) +++ main_err = ret; +++ +++ /* restore original page */ +++ ret = __i2c_rollball_set_page(i2c, msgs->addr, saved_page); +++ +++unlock: +++ i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT); +++ +++ return main_err ? : ret; +++} +++ +++static int i2c_rollball_mii_poll(struct mii_bus *bus, int bus_addr, u8 *buf, +++ size_t len) +++{ +++ struct i2c_adapter *i2c = bus->priv; +++ struct i2c_msg msgs[2]; +++ u8 cmd_addr, tmp, *res; +++ int i, ret; +++ +++ cmd_addr = ROLLBALL_CMD_ADDR; +++ +++ res = buf ? buf : &tmp; +++ len = buf ? len : 1; +++ +++ msgs[0].addr = bus_addr; +++ msgs[0].flags = 0; +++ msgs[0].len = 1; +++ msgs[0].buf = &cmd_addr; +++ +++ msgs[1].addr = bus_addr; +++ msgs[1].flags = I2C_M_RD; +++ msgs[1].len = len; +++ msgs[1].buf = res; +++ +++ /* By experiment it takes up to 70 ms to access a register for these +++ * SFPs. Sleep 20ms between iterations and try 10 times. +++ */ +++ i = 10; +++ do { +++ msleep(20); +++ +++ ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); +++ if (ret) +++ return ret; +++ +++ if (*res == ROLLBALL_CMD_DONE) +++ return 0; +++ } while (i-- > 0); +++ +++ dev_dbg(&bus->dev, "poll timed out\n"); +++ +++ return -ETIMEDOUT; +++} +++ +++static int i2c_rollball_mii_cmd(struct mii_bus *bus, int bus_addr, u8 cmd, +++ u8 *data, size_t len) +++{ +++ struct i2c_adapter *i2c = bus->priv; +++ struct i2c_msg msgs[2]; +++ u8 cmdbuf[2]; +++ +++ cmdbuf[0] = ROLLBALL_CMD_ADDR; +++ cmdbuf[1] = cmd; +++ +++ msgs[0].addr = bus_addr; +++ msgs[0].flags = 0; +++ msgs[0].len = len; +++ msgs[0].buf = data; +++ +++ msgs[1].addr = bus_addr; +++ msgs[1].flags = 0; +++ msgs[1].len = sizeof(cmdbuf); +++ msgs[1].buf = cmdbuf; +++ +++ return i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); +++} +++ +++static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int reg) +++{ +++ u8 buf[4], res[6]; +++ int bus_addr, ret; +++ u16 val; +++ +++ if (!(reg & MII_ADDR_C45)) +++ return -EOPNOTSUPP; +++ +++ bus_addr = i2c_mii_phy_addr(phy_id); +++ if (bus_addr != ROLLBALL_PHY_I2C_ADDR) +++ return 0xffff; +++ +++ buf[0] = ROLLBALL_DATA_ADDR; +++ buf[1] = (reg >> 16) & 0x1f; +++ buf[2] = (reg >> 8) & 0xff; +++ buf[3] = reg & 0xff; +++ +++ ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_READ, buf, +++ sizeof(buf)); +++ if (ret < 0) +++ return ret; +++ +++ ret = i2c_rollball_mii_poll(bus, bus_addr, res, sizeof(res)); +++ if (ret == -ETIMEDOUT) +++ return 0xffff; +++ else if (ret < 0) +++ return ret; +++ +++ val = res[4] << 8 | res[5]; +++ +++ return val; +++} +++ +++static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int reg, +++ u16 val) +++{ +++ int bus_addr, ret; +++ u8 buf[6]; +++ +++ if (!(reg & MII_ADDR_C45)) +++ return -EOPNOTSUPP; +++ +++ bus_addr = i2c_mii_phy_addr(phy_id); +++ if (bus_addr != ROLLBALL_PHY_I2C_ADDR) +++ return 0; +++ +++ buf[0] = ROLLBALL_DATA_ADDR; +++ buf[1] = (reg >> 16) & 0x1f; +++ buf[2] = (reg >> 8) & 0xff; +++ buf[3] = reg & 0xff; +++ buf[4] = val >> 8; +++ buf[5] = val & 0xff; +++ +++ ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_WRITE, buf, +++ sizeof(buf)); +++ if (ret < 0) +++ return ret; +++ +++ ret = i2c_rollball_mii_poll(bus, bus_addr, NULL, 0); +++ if (ret < 0) +++ return ret; +++ +++ return 0; +++} +++ +++static int i2c_mii_init_rollball(struct i2c_adapter *i2c) +++{ +++ struct i2c_msg msg; +++ u8 pw[5]; +++ int ret; +++ +++ pw[0] = ROLLBALL_PASSWORD; +++ pw[1] = 0xff; +++ pw[2] = 0xff; +++ pw[3] = 0xff; +++ pw[4] = 0xff; +++ +++ msg.addr = ROLLBALL_PHY_I2C_ADDR; +++ msg.flags = 0; +++ msg.len = sizeof(pw); +++ msg.buf = pw; +++ +++ ret = i2c_transfer(i2c, &msg, 1); +++ if (ret < 0) +++ return ret; +++ else if (ret != 1) +++ return -EIO; +++ else +++ return 0; +++} +++ +++struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, +++ enum mdio_i2c_proto protocol) ++ { ++ struct mii_bus *mii; +++ int ret; ++ ++ if (!i2c_check_functionality(i2c, I2C_FUNC_I2C)) ++ return ERR_PTR(-EINVAL); ++@@ -104,10 +386,28 @@ struct mii_bus *mdio_i2c_alloc(struct de ++ ++ snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent)); ++ mii->parent = parent; ++- mii->read = i2c_mii_read; ++- mii->write = i2c_mii_write; ++ mii->priv = i2c; ++ +++ switch (protocol) { +++ case MDIO_I2C_ROLLBALL: +++ ret = i2c_mii_init_rollball(i2c); +++ if (ret < 0) { +++ dev_err(parent, +++ "Cannot initialize RollBall MDIO I2C protocol: %d\n", +++ ret); +++ mdiobus_free(mii); +++ return ERR_PTR(ret); +++ } +++ +++ mii->read = i2c_mii_read_rollball; +++ mii->write = i2c_mii_write_rollball; +++ break; +++ default: +++ mii->read = i2c_mii_read_default; +++ mii->write = i2c_mii_write_default; +++ break; +++ } +++ ++ return mii; ++ } ++ EXPORT_SYMBOL_GPL(mdio_i2c_alloc); ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -553,7 +553,7 @@ static int sfp_i2c_mdiobus_create(struct ++ struct mii_bus *i2c_mii; ++ int ret; ++ ++- i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c); +++ i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c, sfp->mdio_protocol); ++ if (IS_ERR(i2c_mii)) ++ return PTR_ERR(i2c_mii); ++ ++@@ -1776,6 +1776,10 @@ static int sfp_sm_probe_for_phy(struct s ++ case MDIO_I2C_C45: ++ err = sfp_sm_probe_phy(sfp, true); ++ break; +++ +++ case MDIO_I2C_ROLLBALL: +++ err = -EOPNOTSUPP; +++ break; ++ } ++ ++ return err; ++--- a/include/linux/mdio/mdio-i2c.h +++++ b/include/linux/mdio/mdio-i2c.h ++@@ -15,8 +15,10 @@ enum mdio_i2c_proto { ++ MDIO_I2C_NONE, ++ MDIO_I2C_MARVELL_C22, ++ MDIO_I2C_C45, +++ MDIO_I2C_ROLLBALL, ++ }; ++ ++-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c); +++struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, +++ enum mdio_i2c_proto protocol); ++ ++ #endif +diff --git a/target/linux/mvebu/patches-5.15/706-03-12-net-sfp-add-support-for-multigig-RollBall-transceive.patch b/target/linux/mvebu/patches-5.15/706-03-12-net-sfp-add-support-for-multigig-RollBall-transceive.patch +new file mode 100644 +index 0000000000..ecac95fb86 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-03-12-net-sfp-add-support-for-multigig-RollBall-transceive.patch +@@ -0,0 +1,152 @@ ++From 324e88cbe3b7be03af67828469cedb52c8610bd1 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Fri, 30 Sep 2022 16:21:10 +0200 ++Subject: [PATCH] net: sfp: add support for multigig RollBall transceivers ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++This adds support for multigig copper SFP modules from RollBall/Hilink. ++These modules have a specific way to access clause 45 registers of the ++internal PHY. ++ ++We also need to wait at least 22 seconds after deasserting TX disable ++before accessing the PHY. The code waits for 25 seconds just to be sure. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Reviewed-by: Russell King <rmk+kernel@armlinux.org.uk> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -166,6 +166,7 @@ static const enum gpiod_flags gpio_flags ++ * on board (for a copper SFP) time to initialise. ++ */ ++ #define T_WAIT msecs_to_jiffies(50) +++#define T_WAIT_ROLLBALL msecs_to_jiffies(25000) ++ #define T_START_UP msecs_to_jiffies(300) ++ #define T_START_UP_BAD_GPON msecs_to_jiffies(60000) ++ ++@@ -205,8 +206,11 @@ static const enum gpiod_flags gpio_flags ++ ++ /* SFP modules appear to always have their PHY configured for bus address ++ * 0x56 (which with mdio-i2c, translates to a PHY address of 22). +++ * RollBall SFPs access phy via SFP Enhanced Digital Diagnostic Interface +++ * via address 0x51 (mdio-i2c will use RollBall protocol on this address). ++ */ ++-#define SFP_PHY_ADDR 22 +++#define SFP_PHY_ADDR 22 +++#define SFP_PHY_ADDR_ROLLBALL 17 ++ ++ /* SFP_EEPROM_BLOCK_SIZE is the size of data chunk to read the EEPROM ++ * at a time. Some SFP modules and also some Linux I2C drivers do not like ++@@ -258,6 +262,7 @@ struct sfp { ++ struct sfp_eeprom_id id; ++ unsigned int module_power_mW; ++ unsigned int module_t_start_up; +++ unsigned int module_t_wait; ++ bool tx_fault_ignore; ++ ++ const struct sfp_quirk *quirk; ++@@ -337,6 +342,22 @@ static void sfp_fixup_halny_gsfp(struct ++ sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS); ++ } ++ +++static void sfp_fixup_rollball(struct sfp *sfp) +++{ +++ sfp->mdio_protocol = MDIO_I2C_ROLLBALL; +++ sfp->module_t_wait = T_WAIT_ROLLBALL; +++} +++ +++static void sfp_fixup_rollball_cc(struct sfp *sfp) +++{ +++ sfp_fixup_rollball(sfp); +++ +++ /* Some RollBall SFPs may have wrong (zero) extended compliance code +++ * burned in EEPROM. For PHY probing we need the correct one. +++ */ +++ sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SFI; +++} +++ ++ static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, ++ unsigned long *modes, ++ unsigned long *interfaces) ++@@ -385,6 +406,12 @@ static const struct sfp_quirk sfp_quirks ++ SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex), ++ ++ SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant), +++ +++ SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), +++ SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc), +++ SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc), +++ SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball), +++ SFP_QUIRK_F("Turris", "RTSFP-10G", sfp_fixup_rollball), ++ }; ++ ++ static size_t sfp_strlen(const char *str, size_t maxlen) ++@@ -1641,12 +1668,12 @@ static void sfp_sm_phy_detach(struct sfp ++ sfp->mod_phy = NULL; ++ } ++ ++-static int sfp_sm_probe_phy(struct sfp *sfp, bool is_c45) +++static int sfp_sm_probe_phy(struct sfp *sfp, int addr, bool is_c45) ++ { ++ struct phy_device *phy; ++ int err; ++ ++- phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45); +++ phy = get_phy_device(sfp->i2c_mii, addr, is_c45); ++ if (phy == ERR_PTR(-ENODEV)) ++ return PTR_ERR(phy); ++ if (IS_ERR(phy)) { ++@@ -1770,15 +1797,15 @@ static int sfp_sm_probe_for_phy(struct s ++ break; ++ ++ case MDIO_I2C_MARVELL_C22: ++- err = sfp_sm_probe_phy(sfp, false); +++ err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR, false); ++ break; ++ ++ case MDIO_I2C_C45: ++- err = sfp_sm_probe_phy(sfp, true); +++ err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR, true); ++ break; ++ ++ case MDIO_I2C_ROLLBALL: ++- err = -EOPNOTSUPP; +++ err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR_ROLLBALL, true); ++ break; ++ } ++ ++@@ -2101,6 +2128,7 @@ static int sfp_sm_mod_probe(struct sfp * ++ sfp->state_hw_mask |= SFP_F_LOS; ++ ++ sfp->module_t_start_up = T_START_UP; +++ sfp->module_t_wait = T_WAIT; ++ ++ sfp->tx_fault_ignore = false; ++ ++@@ -2315,9 +2343,10 @@ static void sfp_sm_main(struct sfp *sfp, ++ ++ /* We need to check the TX_FAULT state, which is not defined ++ * while TX_DISABLE is asserted. The earliest we want to do ++- * anything (such as probe for a PHY) is 50ms. +++ * anything (such as probe for a PHY) is 50ms (or more on +++ * specific modules). ++ */ ++- sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT); +++ sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait); ++ break; ++ ++ case SFP_S_WAIT: ++@@ -2331,8 +2360,8 @@ static void sfp_sm_main(struct sfp *sfp, ++ * deasserting. ++ */ ++ timeout = sfp->module_t_start_up; ++- if (timeout > T_WAIT) ++- timeout -= T_WAIT; +++ if (timeout > sfp->module_t_wait) +++ timeout -= sfp->module_t_wait; ++ else ++ timeout = 1; ++ +diff --git a/target/linux/mvebu/patches-5.15/706-04-net-sfp-fill-also-5gbase-r-and-25gbase-r-modes-in-sf.patch b/target/linux/mvebu/patches-5.15/706-04-net-sfp-fill-also-5gbase-r-and-25gbase-r-modes-in-sf.patch +new file mode 100644 +index 0000000000..494cfbb021 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-04-net-sfp-fill-also-5gbase-r-and-25gbase-r-modes-in-sf.patch +@@ -0,0 +1,44 @@ ++From 5b4c189d660a9b8a852f0863360eb40a100226fc Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Fri, 7 Oct 2022 10:48:44 +0200 ++Subject: [PATCH] net: sfp: fill also 5gbase-r and 25gbase-r modes in ++ sfp_parse_support() ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Fill in also 5gbase-r and 25gbase-r PHY interface modes into the ++phy_interface_t bitmap in sfp_parse_support(). ++ ++Fixes: fd580c983031 ("net: sfp: augment SFP parsing with phy_interface_t bitmap") ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Link: https://lore.kernel.org/r/20221007084844.20352-1-kabel@kernel.org ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp-bus.c +++++ b/drivers/net/phy/sfp-bus.c ++@@ -257,6 +257,7 @@ void sfp_parse_support(struct sfp_bus *b ++ case SFF8024_ECC_100GBASE_SR4_25GBASE_SR: ++ phylink_set(modes, 100000baseSR4_Full); ++ phylink_set(modes, 25000baseSR_Full); +++ __set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces); ++ break; ++ case SFF8024_ECC_100GBASE_LR4_25GBASE_LR: ++ case SFF8024_ECC_100GBASE_ER4_25GBASE_ER: ++@@ -268,6 +269,7 @@ void sfp_parse_support(struct sfp_bus *b ++ case SFF8024_ECC_25GBASE_CR_S: ++ case SFF8024_ECC_25GBASE_CR_N: ++ phylink_set(modes, 25000baseCR_Full); +++ __set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces); ++ break; ++ case SFF8024_ECC_10GBASE_T_SFI: ++ case SFF8024_ECC_10GBASE_T_SR: ++@@ -276,6 +278,7 @@ void sfp_parse_support(struct sfp_bus *b ++ break; ++ case SFF8024_ECC_5GBASE_T: ++ phylink_set(modes, 5000baseT_Full); +++ __set_bit(PHY_INTERFACE_MODE_5GBASER, interfaces); ++ break; ++ case SFF8024_ECC_2_5GBASE_T: ++ phylink_set(modes, 2500baseT_Full); +diff --git a/target/linux/mvebu/patches-5.15/706-05-1-net-sfp-check-firmware-provided-max-power.patch b/target/linux/mvebu/patches-5.15/706-05-1-net-sfp-check-firmware-provided-max-power.patch +new file mode 100644 +index 0000000000..0789da6f55 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-05-1-net-sfp-check-firmware-provided-max-power.patch +@@ -0,0 +1,57 @@ ++From 02eaf5a79100468425fae2d0baf144b6068fc4cc Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 21 Oct 2022 16:09:43 +0100 ++Subject: [PATCH] net: sfp: check firmware provided max power ++ ++Check that the firmware provided maximum power is at least 1W, which ++is the minimum power level for any SFP module. ++ ++Now that we enforce the minimum of 1W, we can exit early from ++sfp_module_parse_power() if the module power is 1W or less. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -1822,6 +1822,12 @@ static int sfp_module_parse_power(struct ++ if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL)) ++ power_mW = 2000; ++ +++ /* Power level 1 modules (max. 1W) are always supported. */ +++ if (power_mW <= 1000) { +++ sfp->module_power_mW = power_mW; +++ return 0; +++ } +++ ++ supports_a2 = sfp->id.ext.sff8472_compliance != ++ SFP_SFF8472_COMPLIANCE_NONE || ++ sfp->id.ext.diagmon & SFP_DIAGMON_DDM; ++@@ -1845,12 +1851,6 @@ static int sfp_module_parse_power(struct ++ } ++ } ++ ++- if (power_mW <= 1000) { ++- /* Modules below 1W do not require a power change sequence */ ++- sfp->module_power_mW = power_mW; ++- return 0; ++- } ++- ++ if (!supports_a2) { ++ /* The module power level is below the host maximum and the ++ * module appears not to implement bus address 0xa2, so assume ++@@ -2782,8 +2782,12 @@ static int sfp_probe(struct platform_dev ++ ++ device_property_read_u32(&pdev->dev, "maximum-power-milliwatt", ++ &sfp->max_power_mW); ++- if (!sfp->max_power_mW) +++ if (sfp->max_power_mW < 1000) { +++ if (sfp->max_power_mW) +++ dev_warn(sfp->dev, +++ "Firmware bug: host maximum power should be at least 1W\n"); ++ sfp->max_power_mW = 1000; +++ } ++ ++ dev_info(sfp->dev, "Host maximum power %u.%uW\n", ++ sfp->max_power_mW / 1000, (sfp->max_power_mW / 100) % 10); +diff --git a/target/linux/mvebu/patches-5.15/706-05-2-net-sfp-ignore-power-level-2-prior-to-SFF-8472-Rev-1.patch b/target/linux/mvebu/patches-5.15/706-05-2-net-sfp-ignore-power-level-2-prior-to-SFF-8472-Rev-1.patch +new file mode 100644 +index 0000000000..210cfa76fd +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-05-2-net-sfp-ignore-power-level-2-prior-to-SFF-8472-Rev-1.patch +@@ -0,0 +1,27 @@ ++From 18cc659e95ab1661254bde815fc9345246d98906 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 21 Oct 2022 16:09:49 +0100 ++Subject: [PATCH] net: sfp: ignore power level 2 prior to SFF-8472 Rev 10.2 ++ ++Power level 2 was introduced by SFF-8472 revision 10.2. Ignore ++the power declaration bit for modules that are not compliant with ++at least this revision. ++ ++This should remove any spurious indication of 1.5W modules. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -1817,7 +1817,8 @@ static int sfp_module_parse_power(struct ++ u32 power_mW = 1000; ++ bool supports_a2; ++ ++- if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL)) +++ if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 && +++ sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL)) ++ power_mW = 1500; ++ if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL)) ++ power_mW = 2000; +diff --git a/target/linux/mvebu/patches-5.15/706-05-3-net-sfp-ignore-power-level-3-prior-to-SFF-8472-Rev-1.patch b/target/linux/mvebu/patches-5.15/706-05-3-net-sfp-ignore-power-level-3-prior-to-SFF-8472-Rev-1.patch +new file mode 100644 +index 0000000000..aaefe3d33b +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-05-3-net-sfp-ignore-power-level-3-prior-to-SFF-8472-Rev-1.patch +@@ -0,0 +1,28 @@ ++From f8810ca7582933e436e6c987808bbcc14f5543df Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 21 Oct 2022 16:09:54 +0100 ++Subject: [PATCH] net: sfp: ignore power level 3 prior to SFF-8472 Rev 11.4 ++ ++Power level 3 was included in SFF-8472 revision 11.9, but this does ++not have a compliance code. Use revision 11.4 as the minimum ++compliance level instead. ++ ++This should avoid any spurious indication of 2W modules. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -1820,7 +1820,9 @@ static int sfp_module_parse_power(struct ++ if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 && ++ sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL)) ++ power_mW = 1500; ++- if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL)) +++ /* Added in Rev 11.9, but there is no compliance code for this */ +++ if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV11_4 && +++ sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL)) ++ power_mW = 2000; ++ ++ /* Power level 1 modules (max. 1W) are always supported. */ +diff --git a/target/linux/mvebu/patches-5.15/706-05-4-net-sfp-provide-a-definition-for-the-power-level-sel.patch b/target/linux/mvebu/patches-5.15/706-05-4-net-sfp-provide-a-definition-for-the-power-level-sel.patch +new file mode 100644 +index 0000000000..f20dd12a6a +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-05-4-net-sfp-provide-a-definition-for-the-power-level-sel.patch +@@ -0,0 +1,42 @@ ++From 398900498485fa9465386454681763d81efaad25 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 21 Oct 2022 16:09:59 +0100 ++Subject: [PATCH] net: sfp: provide a definition for the power level select bit ++ ++Provide a named definition for the power level select bit in the ++extended status register, rather than using BIT(0) in the code. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -1893,13 +1893,13 @@ static int sfp_sm_mod_hpower(struct sfp ++ * all bytes 0xff) at 0x51 but does not accept writes. In any case, ++ * if the bit is already set, we're already in high power mode. ++ */ ++- if (!!(val & BIT(0)) == enable) +++ if (!!(val & SFP_EXT_STATUS_PWRLVL_SELECT) == enable) ++ return 0; ++ ++ if (enable) ++- val |= BIT(0); +++ val |= SFP_EXT_STATUS_PWRLVL_SELECT; ++ else ++- val &= ~BIT(0); +++ val &= ~SFP_EXT_STATUS_PWRLVL_SELECT; ++ ++ err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); ++ if (err != sizeof(val)) { ++--- a/include/linux/sfp.h +++++ b/include/linux/sfp.h ++@@ -489,6 +489,8 @@ enum { ++ SFP_WARN1_RXPWR_LOW = BIT(6), ++ ++ SFP_EXT_STATUS = 0x76, +++ SFP_EXT_STATUS_PWRLVL_SELECT = BIT(0), +++ ++ SFP_VSL = 0x78, ++ SFP_PAGE = 0x7f, ++ }; +diff --git a/target/linux/mvebu/patches-5.15/706-05-5-net-sfp-add-sfp_modify_u8-helper.patch b/target/linux/mvebu/patches-5.15/706-05-5-net-sfp-add-sfp_modify_u8-helper.patch +new file mode 100644 +index 0000000000..b1ece79fc1 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-05-5-net-sfp-add-sfp_modify_u8-helper.patch +@@ -0,0 +1,61 @@ ++From a3c536fc75803b298fd6ba75af33eecf43d31785 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 21 Oct 2022 16:10:04 +0100 ++Subject: [PATCH] net: sfp: add sfp_modify_u8() helper ++ ++Add a helper to modify bits in a single byte in memory space, and use ++it when updating the soft tx-disable flag in the module. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -615,6 +615,22 @@ static int sfp_write(struct sfp *sfp, bo ++ return sfp->write(sfp, a2, addr, buf, len); ++ } ++ +++static int sfp_modify_u8(struct sfp *sfp, bool a2, u8 addr, u8 mask, u8 val) +++{ +++ int ret; +++ u8 old, v; +++ +++ ret = sfp_read(sfp, a2, addr, &old, sizeof(old)); +++ if (ret != sizeof(old)) +++ return ret; +++ +++ v = (old & ~mask) | (val & mask); +++ if (v == old) +++ return sizeof(v); +++ +++ return sfp_write(sfp, a2, addr, &v, sizeof(v)); +++} +++ ++ static unsigned int sfp_soft_get_state(struct sfp *sfp) ++ { ++ unsigned int state = 0; ++@@ -640,17 +656,14 @@ static unsigned int sfp_soft_get_state(s ++ ++ static void sfp_soft_set_state(struct sfp *sfp, unsigned int state) ++ { ++- u8 status; +++ u8 mask = SFP_STATUS_TX_DISABLE_FORCE; +++ u8 val = 0; ++ ++- if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) == ++- sizeof(status)) { ++- if (state & SFP_F_TX_DISABLE) ++- status |= SFP_STATUS_TX_DISABLE_FORCE; ++- else ++- status &= ~SFP_STATUS_TX_DISABLE_FORCE; +++ if (state & SFP_F_TX_DISABLE) +++ val |= SFP_STATUS_TX_DISABLE_FORCE; ++ ++- sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status)); ++- } +++ +++ sfp_modify_u8(sfp, true, SFP_STATUS, mask, val); ++ } ++ ++ static void sfp_soft_start_poll(struct sfp *sfp) +diff --git a/target/linux/mvebu/patches-5.15/706-05-6-net-sfp-get-rid-of-DM7052-hack-when-enabling-high-po.patch b/target/linux/mvebu/patches-5.15/706-05-6-net-sfp-get-rid-of-DM7052-hack-when-enabling-high-po.patch +new file mode 100644 +index 0000000000..291fc28a83 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-05-6-net-sfp-get-rid-of-DM7052-hack-when-enabling-high-po.patch +@@ -0,0 +1,53 @@ ++From bd1432f68ddc28bf3ed6e86b16ed29c0b406f91f Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 21 Oct 2022 16:10:09 +0100 ++Subject: [PATCH] net: sfp: get rid of DM7052 hack when enabling high power ++ ++Since we no longer mis-detect high-power mode with the DM7052 module, ++we no longer need the hack in sfp_module_enable_high_power(), and can ++now switch this to use sfp_modify_u8(). ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -1893,31 +1893,14 @@ static int sfp_module_parse_power(struct ++ ++ static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable) ++ { ++- u8 val; ++ int err; ++ ++- err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); ++- if (err != sizeof(val)) { ++- dev_err(sfp->dev, "Failed to read EEPROM: %pe\n", ERR_PTR(err)); ++- return -EAGAIN; ++- } ++- ++- /* DM7052 reports as a high power module, responds to reads (with ++- * all bytes 0xff) at 0x51 but does not accept writes. In any case, ++- * if the bit is already set, we're already in high power mode. ++- */ ++- if (!!(val & SFP_EXT_STATUS_PWRLVL_SELECT) == enable) ++- return 0; ++- ++- if (enable) ++- val |= SFP_EXT_STATUS_PWRLVL_SELECT; ++- else ++- val &= ~SFP_EXT_STATUS_PWRLVL_SELECT; ++- ++- err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); ++- if (err != sizeof(val)) { ++- dev_err(sfp->dev, "Failed to write EEPROM: %pe\n", ++- ERR_PTR(err)); +++ err = sfp_modify_u8(sfp, true, SFP_EXT_STATUS, +++ SFP_EXT_STATUS_PWRLVL_SELECT, +++ enable ? SFP_EXT_STATUS_PWRLVL_SELECT : 0); +++ if (err != sizeof(u8)) { +++ dev_err(sfp->dev, "failed to %sable high power: %pe\n", +++ enable ? "en" : "dis", ERR_PTR(err)); ++ return -EAGAIN; ++ } ++ +diff --git a/target/linux/mvebu/patches-5.15/706-06-1-net-sfp-convert-register-indexes-from-hex-to-decimal.patch b/target/linux/mvebu/patches-5.15/706-06-1-net-sfp-convert-register-indexes-from-hex-to-decimal.patch +new file mode 100644 +index 0000000000..6d3f247088 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-06-1-net-sfp-convert-register-indexes-from-hex-to-decimal.patch +@@ -0,0 +1,234 @@ ++From 17dd361119e5bc4cfb85aed660674a846b613817 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Thu, 27 Oct 2022 14:21:16 +0100 ++Subject: [PATCH] net: sfp: convert register indexes from hex to decimal ++ ++The register indexes in the standards are in decimal rather than hex, ++so lets specify them in decimal in the header file so we can easily ++cross-reference without converting between hex and decimal. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/include/linux/sfp.h +++++ b/include/linux/sfp.h ++@@ -332,37 +332,37 @@ enum { ++ ++ /* SFP EEPROM registers */ ++ enum { ++- SFP_PHYS_ID = 0x00, ++- SFP_PHYS_EXT_ID = 0x01, ++- SFP_CONNECTOR = 0x02, ++- SFP_COMPLIANCE = 0x03, ++- SFP_ENCODING = 0x0b, ++- SFP_BR_NOMINAL = 0x0c, ++- SFP_RATE_ID = 0x0d, ++- SFP_LINK_LEN_SM_KM = 0x0e, ++- SFP_LINK_LEN_SM_100M = 0x0f, ++- SFP_LINK_LEN_50UM_OM2_10M = 0x10, ++- SFP_LINK_LEN_62_5UM_OM1_10M = 0x11, ++- SFP_LINK_LEN_COPPER_1M = 0x12, ++- SFP_LINK_LEN_50UM_OM4_10M = 0x12, ++- SFP_LINK_LEN_50UM_OM3_10M = 0x13, ++- SFP_VENDOR_NAME = 0x14, ++- SFP_VENDOR_OUI = 0x25, ++- SFP_VENDOR_PN = 0x28, ++- SFP_VENDOR_REV = 0x38, ++- SFP_OPTICAL_WAVELENGTH_MSB = 0x3c, ++- SFP_OPTICAL_WAVELENGTH_LSB = 0x3d, ++- SFP_CABLE_SPEC = 0x3c, ++- SFP_CC_BASE = 0x3f, ++- SFP_OPTIONS = 0x40, /* 2 bytes, MSB, LSB */ ++- SFP_BR_MAX = 0x42, ++- SFP_BR_MIN = 0x43, ++- SFP_VENDOR_SN = 0x44, ++- SFP_DATECODE = 0x54, ++- SFP_DIAGMON = 0x5c, ++- SFP_ENHOPTS = 0x5d, ++- SFP_SFF8472_COMPLIANCE = 0x5e, ++- SFP_CC_EXT = 0x5f, +++ SFP_PHYS_ID = 0, +++ SFP_PHYS_EXT_ID = 1, +++ SFP_CONNECTOR = 2, +++ SFP_COMPLIANCE = 3, +++ SFP_ENCODING = 11, +++ SFP_BR_NOMINAL = 12, +++ SFP_RATE_ID = 13, +++ SFP_LINK_LEN_SM_KM = 14, +++ SFP_LINK_LEN_SM_100M = 15, +++ SFP_LINK_LEN_50UM_OM2_10M = 16, +++ SFP_LINK_LEN_62_5UM_OM1_10M = 17, +++ SFP_LINK_LEN_COPPER_1M = 18, +++ SFP_LINK_LEN_50UM_OM4_10M = 18, +++ SFP_LINK_LEN_50UM_OM3_10M = 19, +++ SFP_VENDOR_NAME = 20, +++ SFP_VENDOR_OUI = 37, +++ SFP_VENDOR_PN = 40, +++ SFP_VENDOR_REV = 56, +++ SFP_OPTICAL_WAVELENGTH_MSB = 60, +++ SFP_OPTICAL_WAVELENGTH_LSB = 61, +++ SFP_CABLE_SPEC = 60, +++ SFP_CC_BASE = 63, +++ SFP_OPTIONS = 64, /* 2 bytes, MSB, LSB */ +++ SFP_BR_MAX = 66, +++ SFP_BR_MIN = 67, +++ SFP_VENDOR_SN = 68, +++ SFP_DATECODE = 84, +++ SFP_DIAGMON = 92, +++ SFP_ENHOPTS = 93, +++ SFP_SFF8472_COMPLIANCE = 94, +++ SFP_CC_EXT = 95, ++ ++ SFP_PHYS_EXT_ID_SFP = 0x04, ++ SFP_OPTIONS_HIGH_POWER_LEVEL = BIT(13), ++@@ -404,63 +404,63 @@ enum { ++ /* SFP Diagnostics */ ++ enum { ++ /* Alarm and warnings stored MSB at lower address then LSB */ ++- SFP_TEMP_HIGH_ALARM = 0x00, ++- SFP_TEMP_LOW_ALARM = 0x02, ++- SFP_TEMP_HIGH_WARN = 0x04, ++- SFP_TEMP_LOW_WARN = 0x06, ++- SFP_VOLT_HIGH_ALARM = 0x08, ++- SFP_VOLT_LOW_ALARM = 0x0a, ++- SFP_VOLT_HIGH_WARN = 0x0c, ++- SFP_VOLT_LOW_WARN = 0x0e, ++- SFP_BIAS_HIGH_ALARM = 0x10, ++- SFP_BIAS_LOW_ALARM = 0x12, ++- SFP_BIAS_HIGH_WARN = 0x14, ++- SFP_BIAS_LOW_WARN = 0x16, ++- SFP_TXPWR_HIGH_ALARM = 0x18, ++- SFP_TXPWR_LOW_ALARM = 0x1a, ++- SFP_TXPWR_HIGH_WARN = 0x1c, ++- SFP_TXPWR_LOW_WARN = 0x1e, ++- SFP_RXPWR_HIGH_ALARM = 0x20, ++- SFP_RXPWR_LOW_ALARM = 0x22, ++- SFP_RXPWR_HIGH_WARN = 0x24, ++- SFP_RXPWR_LOW_WARN = 0x26, ++- SFP_LASER_TEMP_HIGH_ALARM = 0x28, ++- SFP_LASER_TEMP_LOW_ALARM = 0x2a, ++- SFP_LASER_TEMP_HIGH_WARN = 0x2c, ++- SFP_LASER_TEMP_LOW_WARN = 0x2e, ++- SFP_TEC_CUR_HIGH_ALARM = 0x30, ++- SFP_TEC_CUR_LOW_ALARM = 0x32, ++- SFP_TEC_CUR_HIGH_WARN = 0x34, ++- SFP_TEC_CUR_LOW_WARN = 0x36, ++- SFP_CAL_RXPWR4 = 0x38, ++- SFP_CAL_RXPWR3 = 0x3c, ++- SFP_CAL_RXPWR2 = 0x40, ++- SFP_CAL_RXPWR1 = 0x44, ++- SFP_CAL_RXPWR0 = 0x48, ++- SFP_CAL_TXI_SLOPE = 0x4c, ++- SFP_CAL_TXI_OFFSET = 0x4e, ++- SFP_CAL_TXPWR_SLOPE = 0x50, ++- SFP_CAL_TXPWR_OFFSET = 0x52, ++- SFP_CAL_T_SLOPE = 0x54, ++- SFP_CAL_T_OFFSET = 0x56, ++- SFP_CAL_V_SLOPE = 0x58, ++- SFP_CAL_V_OFFSET = 0x5a, ++- SFP_CHKSUM = 0x5f, ++- ++- SFP_TEMP = 0x60, ++- SFP_VCC = 0x62, ++- SFP_TX_BIAS = 0x64, ++- SFP_TX_POWER = 0x66, ++- SFP_RX_POWER = 0x68, ++- SFP_LASER_TEMP = 0x6a, ++- SFP_TEC_CUR = 0x6c, +++ SFP_TEMP_HIGH_ALARM = 0, +++ SFP_TEMP_LOW_ALARM = 2, +++ SFP_TEMP_HIGH_WARN = 4, +++ SFP_TEMP_LOW_WARN = 6, +++ SFP_VOLT_HIGH_ALARM = 8, +++ SFP_VOLT_LOW_ALARM = 10, +++ SFP_VOLT_HIGH_WARN = 12, +++ SFP_VOLT_LOW_WARN = 14, +++ SFP_BIAS_HIGH_ALARM = 16, +++ SFP_BIAS_LOW_ALARM = 18, +++ SFP_BIAS_HIGH_WARN = 20, +++ SFP_BIAS_LOW_WARN = 22, +++ SFP_TXPWR_HIGH_ALARM = 24, +++ SFP_TXPWR_LOW_ALARM = 26, +++ SFP_TXPWR_HIGH_WARN = 28, +++ SFP_TXPWR_LOW_WARN = 30, +++ SFP_RXPWR_HIGH_ALARM = 32, +++ SFP_RXPWR_LOW_ALARM = 34, +++ SFP_RXPWR_HIGH_WARN = 36, +++ SFP_RXPWR_LOW_WARN = 38, +++ SFP_LASER_TEMP_HIGH_ALARM = 40, +++ SFP_LASER_TEMP_LOW_ALARM = 42, +++ SFP_LASER_TEMP_HIGH_WARN = 44, +++ SFP_LASER_TEMP_LOW_WARN = 46, +++ SFP_TEC_CUR_HIGH_ALARM = 48, +++ SFP_TEC_CUR_LOW_ALARM = 50, +++ SFP_TEC_CUR_HIGH_WARN = 52, +++ SFP_TEC_CUR_LOW_WARN = 54, +++ SFP_CAL_RXPWR4 = 56, +++ SFP_CAL_RXPWR3 = 60, +++ SFP_CAL_RXPWR2 = 64, +++ SFP_CAL_RXPWR1 = 68, +++ SFP_CAL_RXPWR0 = 72, +++ SFP_CAL_TXI_SLOPE = 76, +++ SFP_CAL_TXI_OFFSET = 78, +++ SFP_CAL_TXPWR_SLOPE = 80, +++ SFP_CAL_TXPWR_OFFSET = 82, +++ SFP_CAL_T_SLOPE = 84, +++ SFP_CAL_T_OFFSET = 86, +++ SFP_CAL_V_SLOPE = 88, +++ SFP_CAL_V_OFFSET = 90, +++ SFP_CHKSUM = 95, +++ +++ SFP_TEMP = 96, +++ SFP_VCC = 98, +++ SFP_TX_BIAS = 100, +++ SFP_TX_POWER = 102, +++ SFP_RX_POWER = 104, +++ SFP_LASER_TEMP = 106, +++ SFP_TEC_CUR = 108, ++ ++- SFP_STATUS = 0x6e, +++ SFP_STATUS = 110, ++ SFP_STATUS_TX_DISABLE = BIT(7), ++ SFP_STATUS_TX_DISABLE_FORCE = BIT(6), ++ SFP_STATUS_TX_FAULT = BIT(2), ++ SFP_STATUS_RX_LOS = BIT(1), ++- SFP_ALARM0 = 0x70, +++ SFP_ALARM0 = 112, ++ SFP_ALARM0_TEMP_HIGH = BIT(7), ++ SFP_ALARM0_TEMP_LOW = BIT(6), ++ SFP_ALARM0_VCC_HIGH = BIT(5), ++@@ -470,11 +470,11 @@ enum { ++ SFP_ALARM0_TXPWR_HIGH = BIT(1), ++ SFP_ALARM0_TXPWR_LOW = BIT(0), ++ ++- SFP_ALARM1 = 0x71, +++ SFP_ALARM1 = 113, ++ SFP_ALARM1_RXPWR_HIGH = BIT(7), ++ SFP_ALARM1_RXPWR_LOW = BIT(6), ++ ++- SFP_WARN0 = 0x74, +++ SFP_WARN0 = 116, ++ SFP_WARN0_TEMP_HIGH = BIT(7), ++ SFP_WARN0_TEMP_LOW = BIT(6), ++ SFP_WARN0_VCC_HIGH = BIT(5), ++@@ -484,15 +484,15 @@ enum { ++ SFP_WARN0_TXPWR_HIGH = BIT(1), ++ SFP_WARN0_TXPWR_LOW = BIT(0), ++ ++- SFP_WARN1 = 0x75, +++ SFP_WARN1 = 117, ++ SFP_WARN1_RXPWR_HIGH = BIT(7), ++ SFP_WARN1_RXPWR_LOW = BIT(6), ++ ++- SFP_EXT_STATUS = 0x76, +++ SFP_EXT_STATUS = 118, ++ SFP_EXT_STATUS_PWRLVL_SELECT = BIT(0), ++ ++- SFP_VSL = 0x78, ++- SFP_PAGE = 0x7f, +++ SFP_VSL = 120, +++ SFP_PAGE = 127, ++ }; ++ ++ struct fwnode_handle; +diff --git a/target/linux/mvebu/patches-5.15/706-06-2-net-sfp-move-field-definitions-along-side-register-i.patch b/target/linux/mvebu/patches-5.15/706-06-2-net-sfp-move-field-definitions-along-side-register-i.patch +new file mode 100644 +index 0000000000..88a4548356 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-06-2-net-sfp-move-field-definitions-along-side-register-i.patch +@@ -0,0 +1,83 @@ ++From d83845d224a059165902ecd0e1203015c5713a78 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Thu, 27 Oct 2022 14:21:21 +0100 ++Subject: [PATCH] net: sfp: move field definitions along side register index ++ ++Just as we do for the A2h enum, arrange the A0h enum to have the ++field definitions next to their corresponding register index. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/include/linux/sfp.h +++++ b/include/linux/sfp.h ++@@ -333,7 +333,10 @@ enum { ++ /* SFP EEPROM registers */ ++ enum { ++ SFP_PHYS_ID = 0, +++ ++ SFP_PHYS_EXT_ID = 1, +++ SFP_PHYS_EXT_ID_SFP = 0x04, +++ ++ SFP_CONNECTOR = 2, ++ SFP_COMPLIANCE = 3, ++ SFP_ENCODING = 11, ++@@ -354,17 +357,8 @@ enum { ++ SFP_OPTICAL_WAVELENGTH_LSB = 61, ++ SFP_CABLE_SPEC = 60, ++ SFP_CC_BASE = 63, ++- SFP_OPTIONS = 64, /* 2 bytes, MSB, LSB */ ++- SFP_BR_MAX = 66, ++- SFP_BR_MIN = 67, ++- SFP_VENDOR_SN = 68, ++- SFP_DATECODE = 84, ++- SFP_DIAGMON = 92, ++- SFP_ENHOPTS = 93, ++- SFP_SFF8472_COMPLIANCE = 94, ++- SFP_CC_EXT = 95, ++ ++- SFP_PHYS_EXT_ID_SFP = 0x04, +++ SFP_OPTIONS = 64, /* 2 bytes, MSB, LSB */ ++ SFP_OPTIONS_HIGH_POWER_LEVEL = BIT(13), ++ SFP_OPTIONS_PAGING_A2 = BIT(12), ++ SFP_OPTIONS_RETIMER = BIT(11), ++@@ -378,11 +372,20 @@ enum { ++ SFP_OPTIONS_TX_FAULT = BIT(3), ++ SFP_OPTIONS_LOS_INVERTED = BIT(2), ++ SFP_OPTIONS_LOS_NORMAL = BIT(1), +++ +++ SFP_BR_MAX = 66, +++ SFP_BR_MIN = 67, +++ SFP_VENDOR_SN = 68, +++ SFP_DATECODE = 84, +++ +++ SFP_DIAGMON = 92, ++ SFP_DIAGMON_DDM = BIT(6), ++ SFP_DIAGMON_INT_CAL = BIT(5), ++ SFP_DIAGMON_EXT_CAL = BIT(4), ++ SFP_DIAGMON_RXPWR_AVG = BIT(3), ++ SFP_DIAGMON_ADDRMODE = BIT(2), +++ +++ SFP_ENHOPTS = 93, ++ SFP_ENHOPTS_ALARMWARN = BIT(7), ++ SFP_ENHOPTS_SOFT_TX_DISABLE = BIT(6), ++ SFP_ENHOPTS_SOFT_TX_FAULT = BIT(5), ++@@ -390,6 +393,8 @@ enum { ++ SFP_ENHOPTS_SOFT_RATE_SELECT = BIT(3), ++ SFP_ENHOPTS_APP_SELECT_SFF8079 = BIT(2), ++ SFP_ENHOPTS_SOFT_RATE_SFF8431 = BIT(1), +++ +++ SFP_SFF8472_COMPLIANCE = 94, ++ SFP_SFF8472_COMPLIANCE_NONE = 0x00, ++ SFP_SFF8472_COMPLIANCE_REV9_3 = 0x01, ++ SFP_SFF8472_COMPLIANCE_REV9_5 = 0x02, ++@@ -399,6 +404,8 @@ enum { ++ SFP_SFF8472_COMPLIANCE_REV11_3 = 0x06, ++ SFP_SFF8472_COMPLIANCE_REV11_4 = 0x07, ++ SFP_SFF8472_COMPLIANCE_REV12_0 = 0x08, +++ +++ SFP_CC_EXT = 95, ++ }; ++ ++ /* SFP Diagnostics */ +diff --git a/target/linux/mvebu/patches-5.15/706-07-1-net-sfp-add-A2h-presence-flag.patch b/target/linux/mvebu/patches-5.15/706-07-1-net-sfp-add-A2h-presence-flag.patch +new file mode 100644 +index 0000000000..515828f0c2 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-07-1-net-sfp-add-A2h-presence-flag.patch +@@ -0,0 +1,100 @@ ++From f94b9bed12e8244717512941494fe83c94773a58 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Thu, 9 Mar 2023 15:57:11 +0000 ++Subject: [PATCH] net: sfp: add A2h presence flag ++ ++The hwmon code wants to know when it is safe to access the A2h data ++stored in a separate address. We indicate that this is present when ++we have SFF-8472 compliance and the lack of an address-change ++sequence., ++ ++The same conditions are also true if we want to access other controls ++and status in the A2h address. So let's make a flag to indicate whether ++we can access it, instead of repeating the conditions throughout the ++code. ++ ++For now, only convert the hwmon code. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -263,6 +263,8 @@ struct sfp { ++ unsigned int module_power_mW; ++ unsigned int module_t_start_up; ++ unsigned int module_t_wait; +++ +++ bool have_a2; ++ bool tx_fault_ignore; ++ ++ const struct sfp_quirk *quirk; ++@@ -1511,20 +1513,10 @@ static void sfp_hwmon_probe(struct work_ ++ ++ static int sfp_hwmon_insert(struct sfp *sfp) ++ { ++- if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE) ++- return 0; ++- ++- if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) ++- return 0; ++- ++- if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) ++- /* This driver in general does not support address ++- * change. ++- */ ++- return 0; ++- ++- mod_delayed_work(system_wq, &sfp->hwmon_probe, 1); ++- sfp->hwmon_tries = R_PROBE_RETRY_SLOW; +++ if (sfp->have_a2 && sfp->id.ext.diagmon & SFP_DIAGMON_DDM) { +++ mod_delayed_work(system_wq, &sfp->hwmon_probe, 1); +++ sfp->hwmon_tries = R_PROBE_RETRY_SLOW; +++ } ++ ++ return 0; ++ } ++@@ -1974,6 +1966,18 @@ static int sfp_cotsworks_fixup_check(str ++ return 0; ++ } ++ +++static int sfp_module_parse_sff8472(struct sfp *sfp) +++{ +++ /* If the module requires address swap mode, warn about it */ +++ if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) +++ dev_warn(sfp->dev, +++ "module address swap to access page 0xA2 is not supported.\n"); +++ else +++ sfp->have_a2 = true; +++ +++ return 0; +++} +++ ++ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) ++ { ++ /* SFP module inserted - read I2C data */ ++@@ -2107,10 +2111,11 @@ static int sfp_sm_mod_probe(struct sfp * ++ return -EINVAL; ++ } ++ ++- /* If the module requires address swap mode, warn about it */ ++- if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) ++- dev_warn(sfp->dev, ++- "module address swap to access page 0xA2 is not supported.\n"); +++ if (sfp->id.ext.sff8472_compliance != SFP_SFF8472_COMPLIANCE_NONE) { +++ ret = sfp_module_parse_sff8472(sfp); +++ if (ret < 0) +++ return ret; +++ } ++ ++ /* Parse the module power requirement */ ++ ret = sfp_module_parse_power(sfp); ++@@ -2157,6 +2162,7 @@ static void sfp_sm_mod_remove(struct sfp ++ ++ memset(&sfp->id, 0, sizeof(sfp->id)); ++ sfp->module_power_mW = 0; +++ sfp->have_a2 = false; ++ ++ dev_info(sfp->dev, "module removed\n"); ++ } +diff --git a/target/linux/mvebu/patches-5.15/706-07-2-net-sfp-only-use-soft-polling-if-we-have-A2h-access.patch b/target/linux/mvebu/patches-5.15/706-07-2-net-sfp-only-use-soft-polling-if-we-have-A2h-access.patch +new file mode 100644 +index 0000000000..2ea6b71b42 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-07-2-net-sfp-only-use-soft-polling-if-we-have-A2h-access.patch +@@ -0,0 +1,28 @@ ++From 5daed426f012a1c0db0048339e359ee98a2c8752 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Thu, 9 Mar 2023 15:57:16 +0000 ++Subject: [PATCH] net: sfp: only use soft polling if we have A2h access ++ ++The soft state bits are stored in the A2h memory space, and require ++SFF-8472 compliance. This is what our have_a2 flag tells us, so use ++this to indicate whether we should attempt to use the soft signals. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -2338,7 +2338,11 @@ static void sfp_sm_main(struct sfp *sfp, ++ sfp->sm_dev_state != SFP_DEV_UP) ++ break; ++ ++- if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)) +++ /* Only use the soft state bits if we have access to the A2h +++ * memory, which implies that we have some level of SFF-8472 +++ * compliance. +++ */ +++ if (sfp->have_a2) ++ sfp_soft_start_poll(sfp); ++ ++ sfp_module_tx_enable(sfp); +diff --git a/target/linux/mvebu/patches-5.15/706-08-net-sfp-fix-state-loss-when-updating-state_hw_mask.patch b/target/linux/mvebu/patches-5.15/706-08-net-sfp-fix-state-loss-when-updating-state_hw_mask.patch +new file mode 100644 +index 0000000000..a433a25fdb +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-08-net-sfp-fix-state-loss-when-updating-state_hw_mask.patch +@@ -0,0 +1,41 @@ ++From 04361b8bb81819efb68bf39c276025e2250ac537 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 17 Mar 2023 07:28:00 +0000 ++Subject: [PATCH] net: sfp: fix state loss when updating state_hw_mask ++ ++Andrew reports that the SFF modules on one of the ZII platforms do not ++indicate link up due to the SFP code believing that LOS indicating that ++there is no signal being received from the remote end, but in fact the ++LOS signal is showing that there is signal. ++ ++What makes SFF modules different from SFPs is they typically have an ++inverted LOS, which uncovered this issue. When we read the hardware ++state, we mask it with state_hw_mask so we ignore anything we're not ++interested in. However, we don't re-read when state_hw_mask changes, ++leading to sfp->state being stale. ++ ++Arrange for a software poll of the module state after we have parsed ++the EEPROM in sfp_sm_mod_probe() and updated state_*_mask. This will ++generate any necessary events for signal changes for the state ++machine as well as updating sfp->state. ++ ++Reported-by: Andrew Lunn <andrew@lunn.ch> ++Tested-by: Andrew Lunn <andrew@lunn.ch> ++Fixes: 8475c4b70b04 ("net: sfp: re-implement soft state polling setup") ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -2250,6 +2250,11 @@ static void sfp_sm_module(struct sfp *sf ++ break; ++ } ++ +++ /* Force a poll to re-read the hardware signal state after +++ * sfp_sm_mod_probe() changed state_hw_mask. +++ */ +++ mod_delayed_work(system_wq, &sfp->poll, 1); +++ ++ err = sfp_hwmon_insert(sfp); ++ if (err) ++ dev_warn(sfp->dev, "hwmon probe failed: %pe\n", +diff --git a/target/linux/mvebu/patches-5.15/706-09-1-net-sfp-bus-allow-SFP-quirks-to-override-Autoneg-and.patch b/target/linux/mvebu/patches-5.15/706-09-1-net-sfp-bus-allow-SFP-quirks-to-override-Autoneg-and.patch +new file mode 100644 +index 0000000000..98499b230e +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-09-1-net-sfp-bus-allow-SFP-quirks-to-override-Autoneg-and.patch +@@ -0,0 +1,43 @@ ++From 8110633db49d7de2e4852f697322e1f3f8e61b04 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Tue, 21 Mar 2023 16:58:46 +0000 ++Subject: [PATCH] net: sfp-bus: allow SFP quirks to override Autoneg and pause ++ bits ++ ++Allow SFP quirks to override the Autoneg, Pause and Asym_Pause bits in ++the support mask. ++ ++Some modules have an inaccessible PHY on which is only accessible via ++2500base-X without Autonegotiation. We therefore want to be able to ++clear the Autoneg bit. Rearrange sfp_parse_support() to allow a SFP ++modes quirk to override this bit. ++ ++Tested-by: Frank Wunderlich <frank-w@public-files.de> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp-bus.c +++++ b/drivers/net/phy/sfp-bus.c ++@@ -151,6 +151,10 @@ void sfp_parse_support(struct sfp_bus *b ++ unsigned int br_min, br_nom, br_max; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, }; ++ +++ phylink_set(modes, Autoneg); +++ phylink_set(modes, Pause); +++ phylink_set(modes, Asym_Pause); +++ ++ /* Decode the bitrate information to MBd */ ++ br_min = br_nom = br_max = 0; ++ if (id->base.br_nominal) { ++@@ -329,10 +333,6 @@ void sfp_parse_support(struct sfp_bus *b ++ bus->sfp_quirk->modes(id, modes, interfaces); ++ ++ linkmode_or(support, support, modes); ++- ++- phylink_set(support, Autoneg); ++- phylink_set(support, Pause); ++- phylink_set(support, Asym_Pause); ++ } ++ EXPORT_SYMBOL_GPL(sfp_parse_support); ++ +diff --git a/target/linux/mvebu/patches-5.15/706-09-2-net-sfp-add-quirk-for-2.5G-copper-SFP.patch b/target/linux/mvebu/patches-5.15/706-09-2-net-sfp-add-quirk-for-2.5G-copper-SFP.patch +new file mode 100644 +index 0000000000..ce3339ceb2 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-09-2-net-sfp-add-quirk-for-2.5G-copper-SFP.patch +@@ -0,0 +1,51 @@ ++From 50e96acbe11667b6fe9d99e1348c6c224b2f11dd Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Tue, 21 Mar 2023 16:58:51 +0000 ++Subject: [PATCH] net: sfp: add quirk for 2.5G copper SFP ++ ++Add a quirk for a copper SFP that identifies itself as "OEM" ++"SFP-2.5G-T". This module's PHY is inaccessible, and can only run ++at 2500base-X with the host without negotiation. Add a quirk to ++enable the 2500base-X interface mode with 2500base-T support, and ++disable autonegotiation. ++ ++Reported-by: Frank Wunderlich <frank-w@public-files.de> ++Tested-by: Frank Wunderlich <frank-w@public-files.de> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -368,6 +368,23 @@ static void sfp_quirk_2500basex(const st ++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); ++ } ++ +++static void sfp_quirk_disable_autoneg(const struct sfp_eeprom_id *id, +++ unsigned long *modes, +++ unsigned long *interfaces) +++{ +++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, modes); +++} +++ +++static void sfp_quirk_oem_2_5g(const struct sfp_eeprom_id *id, +++ unsigned long *modes, +++ unsigned long *interfaces) +++{ +++ /* Copper 2.5G SFP */ +++ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, modes); +++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); +++ sfp_quirk_disable_autoneg(id, modes, interfaces); +++} +++ ++ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, ++ unsigned long *modes, ++ unsigned long *interfaces) ++@@ -410,6 +427,7 @@ static const struct sfp_quirk sfp_quirks ++ SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant), ++ ++ SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), +++ SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), ++ SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc), ++ SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc), ++ SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball), +diff --git a/target/linux/mvebu/patches-5.15/706-10-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch b/target/linux/mvebu/patches-5.15/706-10-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch +new file mode 100644 +index 0000000000..16a88e582e +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-10-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch +@@ -0,0 +1,34 @@ ++From ad651d68cee75e9ac20002254c4e5d09ee67a84b Mon Sep 17 00:00:00 2001 ++From: Daniel Golle <daniel@makrotopia.org> ++Date: Sun, 2 Apr 2023 12:44:37 +0100 ++Subject: [PATCH] net: sfp: add quirk enabling 2500Base-x for HG MXPD-483II ++ ++The HG MXPD-483II 1310nm SFP module is meant to operate with 2500Base-X, ++however, in their EEPROM they incorrectly specify: ++ Transceiver type : Ethernet: 1000BASE-LX ++ ... ++ BR, Nominal : 2600MBd ++ ++Use sfp_quirk_2500basex for this module to allow 2500Base-X mode anyway. ++ ++https://forum.banana-pi.org/t/bpi-r3-sfp-module-compatibility/14573/60 ++ ++Reported-by: chowtom <chowtom@gmail.com> ++Tested-by: chowtom <chowtom@gmail.com> ++Signed-off-by: Daniel Golle <daniel@makrotopia.org> ++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -415,6 +415,10 @@ static const struct sfp_quirk sfp_quirks ++ ++ SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp), ++ +++ // HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports +++ // 2600MBd in their EERPOM +++ SFP_QUIRK_M("HG GENUINE", "MXPD-483II", sfp_quirk_2500basex), +++ ++ // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in ++ // their EEPROM ++ SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex, +diff --git a/target/linux/mvebu/patches-5.15/706-11-net-sfp-avoid-EEPROM-read-of-absent-SFP-module.patch b/target/linux/mvebu/patches-5.15/706-11-net-sfp-avoid-EEPROM-read-of-absent-SFP-module.patch +new file mode 100644 +index 0000000000..f392e99e26 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-11-net-sfp-avoid-EEPROM-read-of-absent-SFP-module.patch +@@ -0,0 +1,36 @@ ++From bef227c1537cb8005311c0842bc5449e8c7a5973 Mon Sep 17 00:00:00 2001 ++From: Ivan Bornyakov <i.bornyakov@metrotek.ru> ++Date: Thu, 6 Apr 2023 16:08:33 +0300 ++Subject: [PATCH] net: sfp: avoid EEPROM read of absent SFP module ++ ++If SFP module is not present, it is sensible to fail sfp_module_eeprom() ++and sfp_module_eeprom_by_page() early to avoid excessive I2C transfers ++which are garanteed to fail. ++ ++Suggested-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Ivan Bornyakov <i.bornyakov@metrotek.ru> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -2567,6 +2567,9 @@ static int sfp_module_eeprom(struct sfp ++ unsigned int first, last, len; ++ int ret; ++ +++ if (!(sfp->state & SFP_F_PRESENT)) +++ return -ENODEV; +++ ++ if (ee->len == 0) ++ return -EINVAL; ++ ++@@ -2599,6 +2602,9 @@ static int sfp_module_eeprom_by_page(str ++ const struct ethtool_module_eeprom *page, ++ struct netlink_ext_ack *extack) ++ { +++ if (!(sfp->state & SFP_F_PRESENT)) +++ return -ENODEV; +++ ++ if (page->bank) { ++ NL_SET_ERR_MSG(extack, "Banks not supported"); ++ return -EOPNOTSUPP; +diff --git a/target/linux/mvebu/patches-5.15/706-12-1-net-sfp-add-helper-to-modify-signal-states.patch b/target/linux/mvebu/patches-5.15/706-12-1-net-sfp-add-helper-to-modify-signal-states.patch +new file mode 100644 +index 0000000000..b780ecaa6f +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-12-1-net-sfp-add-helper-to-modify-signal-states.patch +@@ -0,0 +1,64 @@ ++From 418c1214741cf3ac5e420382a85c4f8a40586024 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 17 May 2023 11:37:47 +0100 ++Subject: [PATCH] net: sfp: add helper to modify signal states ++ ++There are a couple of locations in the code where we modify ++sfp->state, and then call sfp_set_state(, sfp->state) to update ++the outputs/soft state to control the module. Provide a helper ++which takes a mask and new state so that this is encapsulated in ++one location. ++ ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++From 418c1214741cf3ac5e420382a85c4f8a40586024 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 17 May 2023 11:37:47 +0100 ++Subject: [PATCH] net: sfp: add helper to modify signal states ++ ++There are a couple of locations in the code where we modify ++sfp->state, and then call sfp_set_state(, sfp->state) to update ++the outputs/soft state to control the module. Provide a helper ++which takes a mask and new state so that this is encapsulated in ++one location. ++ ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -737,6 +737,12 @@ static void sfp_set_state(struct sfp *sf ++ sfp_soft_set_state(sfp, state); ++ } ++ +++static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set) +++{ +++ sfp->state = (sfp->state & ~mask) | set; +++ sfp_set_state(sfp, sfp->state); +++} +++ ++ static unsigned int sfp_check(void *buf, size_t len) ++ { ++ u8 *p, check; ++@@ -1589,16 +1595,14 @@ static void sfp_module_tx_disable(struct ++ { ++ dev_dbg(sfp->dev, "tx disable %u -> %u\n", ++ sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 1); ++- sfp->state |= SFP_F_TX_DISABLE; ++- sfp_set_state(sfp, sfp->state); +++ sfp_mod_state(sfp, SFP_F_TX_DISABLE, SFP_F_TX_DISABLE); ++ } ++ ++ static void sfp_module_tx_enable(struct sfp *sfp) ++ { ++ dev_dbg(sfp->dev, "tx disable %u -> %u\n", ++ sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 0); ++- sfp->state &= ~SFP_F_TX_DISABLE; ++- sfp_set_state(sfp, sfp->state); +++ sfp_mod_state(sfp, SFP_F_TX_DISABLE, 0); ++ } ++ ++ #if IS_ENABLED(CONFIG_DEBUG_FS) +diff --git a/target/linux/mvebu/patches-5.15/706-12-2-net-sfp-move-rtnl-lock-to-cover-reading-state.patch b/target/linux/mvebu/patches-5.15/706-12-2-net-sfp-move-rtnl-lock-to-cover-reading-state.patch +new file mode 100644 +index 0000000000..22c5c390ab +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-12-2-net-sfp-move-rtnl-lock-to-cover-reading-state.patch +@@ -0,0 +1,42 @@ ++From d47e5a430dfd8b15739a118e4a2add5fa90347fd Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 17 May 2023 11:37:52 +0100 ++Subject: [PATCH] net: sfp: move rtnl lock to cover reading state ++ ++As preparation to moving st_mutex inside rtnl_lock, we need to first ++move the rtnl lock to cover reading the state. ++ ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++From d47e5a430dfd8b15739a118e4a2add5fa90347fd Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 17 May 2023 11:37:52 +0100 ++Subject: [PATCH] net: sfp: move rtnl lock to cover reading state ++ ++As preparation to moving st_mutex inside rtnl_lock, we need to first ++move the rtnl lock to cover reading the state. ++ ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -2653,6 +2653,7 @@ static void sfp_check_state(struct sfp * ++ unsigned int state, i, changed; ++ ++ mutex_lock(&sfp->st_mutex); +++ rtnl_lock(); ++ state = sfp_get_state(sfp); ++ changed = state ^ sfp->state; ++ if (sfp->tx_fault_ignore) ++@@ -2668,7 +2669,6 @@ static void sfp_check_state(struct sfp * ++ state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT); ++ sfp->state = state; ++ ++- rtnl_lock(); ++ if (changed & SFP_F_PRESENT) ++ sfp_sm_event(sfp, state & SFP_F_PRESENT ? ++ SFP_E_INSERT : SFP_E_REMOVE); +diff --git a/target/linux/mvebu/patches-5.15/706-12-3-net-sfp-swap-order-of-rtnl-and-st_mutex-locks.patch b/target/linux/mvebu/patches-5.15/706-12-3-net-sfp-swap-order-of-rtnl-and-st_mutex-locks.patch +new file mode 100644 +index 0000000000..a3b861253a +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-12-3-net-sfp-swap-order-of-rtnl-and-st_mutex-locks.patch +@@ -0,0 +1,36 @@ ++From a9fe964e7aaeb3fc06a91c21269d0ac8b5afcea8 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 17 May 2023 11:37:57 +0100 ++Subject: [PATCH] net: sfp: swap order of rtnl and st_mutex locks ++ ++Swap the order of the rtnl and st_mutex locks - st_mutex is now nested ++beneath rtnl lock instead of rtnl being beneath st_mutex. This will ++allow us to hold st_mutex only while manipulating the module's hardware ++or software control state. ++ ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -2652,8 +2652,8 @@ static void sfp_check_state(struct sfp * ++ { ++ unsigned int state, i, changed; ++ ++- mutex_lock(&sfp->st_mutex); ++ rtnl_lock(); +++ mutex_lock(&sfp->st_mutex); ++ state = sfp_get_state(sfp); ++ changed = state ^ sfp->state; ++ if (sfp->tx_fault_ignore) ++@@ -2680,8 +2680,8 @@ static void sfp_check_state(struct sfp * ++ if (changed & SFP_F_LOS) ++ sfp_sm_event(sfp, state & SFP_F_LOS ? ++ SFP_E_LOS_HIGH : SFP_E_LOS_LOW); ++- rtnl_unlock(); ++ mutex_unlock(&sfp->st_mutex); +++ rtnl_unlock(); ++ } ++ ++ static irqreturn_t sfp_irq(int irq, void *data) +diff --git a/target/linux/mvebu/patches-5.15/706-12-4-net-sfp-move-sm_mutex-into-sfp_check_state.patch b/target/linux/mvebu/patches-5.15/706-12-4-net-sfp-move-sm_mutex-into-sfp_check_state.patch +new file mode 100644 +index 0000000000..fa678484cc +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-12-4-net-sfp-move-sm_mutex-into-sfp_check_state.patch +@@ -0,0 +1,66 @@ ++From 97a492050aa5e15507fd7b8774e7adaf8d6e4bb5 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 17 May 2023 11:38:02 +0100 ++Subject: [PATCH] net: sfp: move sm_mutex into sfp_check_state() ++ ++Provide an unlocked version of sfp_sm_event() which can be used by ++sfp_check_state() to avoid having to keep re-taking the lock if ++several signals have changed state. ++ ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -2508,10 +2508,8 @@ static void sfp_sm_main(struct sfp *sfp, ++ } ++ } ++ ++-static void sfp_sm_event(struct sfp *sfp, unsigned int event) +++static void __sfp_sm_event(struct sfp *sfp, unsigned int event) ++ { ++- mutex_lock(&sfp->sm_mutex); ++- ++ dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n", ++ mod_state_to_str(sfp->sm_mod_state), ++ dev_state_to_str(sfp->sm_dev_state), ++@@ -2526,7 +2524,12 @@ static void sfp_sm_event(struct sfp *sfp ++ mod_state_to_str(sfp->sm_mod_state), ++ dev_state_to_str(sfp->sm_dev_state), ++ sm_state_to_str(sfp->sm_state)); +++} ++ +++static void sfp_sm_event(struct sfp *sfp, unsigned int event) +++{ +++ mutex_lock(&sfp->sm_mutex); +++ __sfp_sm_event(sfp, event); ++ mutex_unlock(&sfp->sm_mutex); ++ } ++ ++@@ -2669,17 +2672,19 @@ static void sfp_check_state(struct sfp * ++ state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT); ++ sfp->state = state; ++ +++ mutex_lock(&sfp->sm_mutex); ++ if (changed & SFP_F_PRESENT) ++- sfp_sm_event(sfp, state & SFP_F_PRESENT ? ++- SFP_E_INSERT : SFP_E_REMOVE); +++ __sfp_sm_event(sfp, state & SFP_F_PRESENT ? +++ SFP_E_INSERT : SFP_E_REMOVE); ++ ++ if (changed & SFP_F_TX_FAULT) ++- sfp_sm_event(sfp, state & SFP_F_TX_FAULT ? ++- SFP_E_TX_FAULT : SFP_E_TX_CLEAR); +++ __sfp_sm_event(sfp, state & SFP_F_TX_FAULT ? +++ SFP_E_TX_FAULT : SFP_E_TX_CLEAR); ++ ++ if (changed & SFP_F_LOS) ++- sfp_sm_event(sfp, state & SFP_F_LOS ? ++- SFP_E_LOS_HIGH : SFP_E_LOS_LOW); +++ __sfp_sm_event(sfp, state & SFP_F_LOS ? +++ SFP_E_LOS_HIGH : SFP_E_LOS_LOW); +++ mutex_unlock(&sfp->sm_mutex); ++ mutex_unlock(&sfp->st_mutex); ++ rtnl_unlock(); ++ } +diff --git a/target/linux/mvebu/patches-5.15/706-12-5-net-sfp-change-st_mutex-locking.patch b/target/linux/mvebu/patches-5.15/706-12-5-net-sfp-change-st_mutex-locking.patch +new file mode 100644 +index 0000000000..f618e4c17c +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-12-5-net-sfp-change-st_mutex-locking.patch +@@ -0,0 +1,182 @@ ++From 1974fd3bf0f04589dea1a4a76273bbc8fd5760f6 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 17 May 2023 11:38:07 +0100 ++Subject: [PATCH] net: sfp: change st_mutex locking ++ ++Change st_mutex's use within SFP such that it only protects the various ++state members, as it was originally supposed to, and isn't held while ++making various calls outside the driver. ++ ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -244,10 +244,17 @@ struct sfp { ++ ++ bool need_poll; ++ +++ /* Access rules: +++ * state_hw_drive: st_mutex held +++ * state_hw_mask: st_mutex held +++ * state_soft_mask: st_mutex held +++ * state: st_mutex held unless reading input bits +++ */ ++ struct mutex st_mutex; /* Protects state */ ++ unsigned int state_hw_mask; ++ unsigned int state_soft_mask; ++ unsigned int state; +++ ++ struct delayed_work poll; ++ struct delayed_work timeout; ++ struct mutex sm_mutex; /* Protects state machine */ ++@@ -695,7 +702,6 @@ static void sfp_soft_start_poll(struct s ++ const struct sfp_eeprom_id *id = &sfp->id; ++ unsigned int mask = 0; ++ ++- sfp->state_soft_mask = 0; ++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE) ++ mask |= SFP_F_TX_DISABLE; ++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT) ++@@ -703,19 +709,26 @@ static void sfp_soft_start_poll(struct s ++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS) ++ mask |= SFP_F_LOS; ++ +++ mutex_lock(&sfp->st_mutex); ++ // Poll the soft state for hardware pins we want to ignore ++ sfp->state_soft_mask = ~sfp->state_hw_mask & mask; ++ ++ if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) && ++ !sfp->need_poll) ++ mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); +++ mutex_unlock(&sfp->st_mutex); ++ } ++ ++ static void sfp_soft_stop_poll(struct sfp *sfp) ++ { +++ mutex_lock(&sfp->st_mutex); ++ sfp->state_soft_mask = 0; +++ mutex_unlock(&sfp->st_mutex); ++ } ++ +++/* sfp_get_state() - must be called with st_mutex held, or in the +++ * initialisation path. +++ */ ++ static unsigned int sfp_get_state(struct sfp *sfp) ++ { ++ unsigned int soft = sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT); ++@@ -728,6 +741,9 @@ static unsigned int sfp_get_state(struct ++ return state; ++ } ++ +++/* sfp_set_state() - must be called with st_mutex held, or in the +++ * initialisation path. +++ */ ++ static void sfp_set_state(struct sfp *sfp, unsigned int state) ++ { ++ sfp->set_state(sfp, state); ++@@ -739,8 +755,10 @@ static void sfp_set_state(struct sfp *sf ++ ++ static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set) ++ { +++ mutex_lock(&sfp->st_mutex); ++ sfp->state = (sfp->state & ~mask) | set; ++ sfp_set_state(sfp, sfp->state); +++ mutex_unlock(&sfp->st_mutex); ++ } ++ ++ static unsigned int sfp_check(void *buf, size_t len) ++@@ -1655,16 +1673,18 @@ static void sfp_debugfs_exit(struct sfp ++ ++ static void sfp_module_tx_fault_reset(struct sfp *sfp) ++ { ++- unsigned int state = sfp->state; ++- ++- if (state & SFP_F_TX_DISABLE) ++- return; +++ unsigned int state; ++ ++- sfp_set_state(sfp, state | SFP_F_TX_DISABLE); +++ mutex_lock(&sfp->st_mutex); +++ state = sfp->state; +++ if (!(state & SFP_F_TX_DISABLE)) { +++ sfp_set_state(sfp, state | SFP_F_TX_DISABLE); ++ ++- udelay(T_RESET_US); +++ udelay(T_RESET_US); ++ ++- sfp_set_state(sfp, state); +++ sfp_set_state(sfp, state); +++ } +++ mutex_unlock(&sfp->st_mutex); ++ } ++ ++ /* SFP state machine */ ++@@ -2009,6 +2029,7 @@ static int sfp_sm_mod_probe(struct sfp * ++ /* SFP module inserted - read I2C data */ ++ struct sfp_eeprom_id id; ++ bool cotsworks_sfbg; +++ unsigned int mask; ++ bool cotsworks; ++ u8 check; ++ int ret; ++@@ -2148,14 +2169,13 @@ static int sfp_sm_mod_probe(struct sfp * ++ if (ret < 0) ++ return ret; ++ ++- /* Initialise state bits to use from hardware */ ++- sfp->state_hw_mask = SFP_F_PRESENT; +++ mask = SFP_F_PRESENT; ++ if (sfp->gpio[GPIO_TX_DISABLE]) ++- sfp->state_hw_mask |= SFP_F_TX_DISABLE; +++ mask |= SFP_F_TX_DISABLE; ++ if (sfp->gpio[GPIO_TX_FAULT]) ++- sfp->state_hw_mask |= SFP_F_TX_FAULT; +++ mask |= SFP_F_TX_FAULT; ++ if (sfp->gpio[GPIO_LOS]) ++- sfp->state_hw_mask |= SFP_F_LOS; +++ mask |= SFP_F_LOS; ++ ++ sfp->module_t_start_up = T_START_UP; ++ sfp->module_t_wait = T_WAIT; ++@@ -2173,8 +2193,14 @@ static int sfp_sm_mod_probe(struct sfp * ++ sfp->mdio_protocol = MDIO_I2C_NONE; ++ ++ sfp->quirk = sfp_lookup_quirk(&id); +++ +++ mutex_lock(&sfp->st_mutex); +++ /* Initialise state bits to use from hardware */ +++ sfp->state_hw_mask = mask; +++ ++ if (sfp->quirk && sfp->quirk->fixup) ++ sfp->quirk->fixup(sfp); +++ mutex_unlock(&sfp->st_mutex); ++ ++ return 0; ++ } ++@@ -2671,6 +2697,7 @@ static void sfp_check_state(struct sfp * ++ ++ state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT); ++ sfp->state = state; +++ mutex_unlock(&sfp->st_mutex); ++ ++ mutex_lock(&sfp->sm_mutex); ++ if (changed & SFP_F_PRESENT) ++@@ -2685,7 +2712,6 @@ static void sfp_check_state(struct sfp * ++ __sfp_sm_event(sfp, state & SFP_F_LOS ? ++ SFP_E_LOS_HIGH : SFP_E_LOS_LOW); ++ mutex_unlock(&sfp->sm_mutex); ++- mutex_unlock(&sfp->st_mutex); ++ rtnl_unlock(); ++ } ++ ++@@ -2704,6 +2730,8 @@ static void sfp_poll(struct work_struct ++ ++ sfp_check_state(sfp); ++ +++ // st_mutex doesn't need to be held here for state_soft_mask, +++ // it's unimportant if we race while reading this. ++ if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) || ++ sfp->need_poll) ++ mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); +diff --git a/target/linux/mvebu/patches-5.15/706-12-6-net-sfp-add-support-for-setting-signalling-rate.patch b/target/linux/mvebu/patches-5.15/706-12-6-net-sfp-add-support-for-setting-signalling-rate.patch +new file mode 100644 +index 0000000000..cd79d03af9 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-12-6-net-sfp-add-support-for-setting-signalling-rate.patch +@@ -0,0 +1,142 @@ ++From dc18582211b34bce8250ddf3cac2a2230e192120 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 17 May 2023 11:38:12 +0100 ++Subject: [PATCH] net: sfp: add support for setting signalling rate ++ ++Add support to the SFP layer to allow phylink to set the signalling ++rate for a SFP module. The rate given will be in units of kilo-baud ++(1000 baud). ++ ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -116,6 +116,23 @@ do { \ ++ }) ++ #endif ++ +++static unsigned int phylink_interface_signal_rate(phy_interface_t interface) +++{ +++ switch (interface) { +++ case PHY_INTERFACE_MODE_SGMII: +++ case PHY_INTERFACE_MODE_1000BASEX: /* 1.25Mbd */ +++ return 1250; +++ case PHY_INTERFACE_MODE_2500BASEX: /* 3.125Mbd */ +++ return 3125; +++ case PHY_INTERFACE_MODE_5GBASER: /* 5.15625Mbd */ +++ return 5156; +++ case PHY_INTERFACE_MODE_10GBASER: /* 10.3125Mbd */ +++ return 10313; +++ default: +++ return 0; +++ } +++} +++ ++ /** ++ * phylink_set_port_modes() - set the port type modes in the ethtool mask ++ * @mask: ethtool link mode mask ++@@ -802,6 +819,7 @@ static void phylink_major_config(struct ++ const struct phylink_link_state *state) ++ { ++ struct phylink_pcs *pcs = NULL; +++ unsigned int rate_kbd; ++ int err; ++ ++ phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); ++@@ -856,6 +874,12 @@ static void phylink_major_config(struct ++ phylink_err(pl, "mac_finish failed: %pe\n", ++ ERR_PTR(err)); ++ } +++ +++ if (pl->sfp_bus) { +++ rate_kbd = phylink_interface_signal_rate(state->interface); +++ if (rate_kbd) +++ sfp_upstream_set_signal_rate(pl->sfp_bus, rate_kbd); +++ } ++ } ++ ++ /* ++--- a/drivers/net/phy/sfp-bus.c +++++ b/drivers/net/phy/sfp-bus.c ++@@ -576,6 +576,26 @@ static void sfp_upstream_clear(struct sf ++ } ++ ++ /** +++ * sfp_upstream_set_signal_rate() - set data signalling rate +++ * @bus: a pointer to the &struct sfp_bus structure for the sfp module +++ * @rate_kbd: signalling rate in units of 1000 baud +++ * +++ * Configure the rate select settings on the SFP module for the signalling +++ * rate (not the same as the data rate). +++ * +++ * Locks that may be held: +++ * Phylink's state_mutex +++ * rtnl lock +++ * SFP's sm_mutex +++ */ +++void sfp_upstream_set_signal_rate(struct sfp_bus *bus, unsigned int rate_kbd) +++{ +++ if (bus->registered) +++ bus->socket_ops->set_signal_rate(bus->sfp, rate_kbd); +++} +++EXPORT_SYMBOL_GPL(sfp_upstream_set_signal_rate); +++ +++/** ++ * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode ++ * @fwnode: firmware node for the parent device (MAC or PHY) ++ * ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -2579,6 +2579,10 @@ static void sfp_stop(struct sfp *sfp) ++ sfp_sm_event(sfp, SFP_E_DEV_DOWN); ++ } ++ +++static void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd) +++{ +++} +++ ++ static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo) ++ { ++ /* locking... and check module is present */ ++@@ -2663,6 +2667,7 @@ static const struct sfp_socket_ops sfp_m ++ .detach = sfp_detach, ++ .start = sfp_start, ++ .stop = sfp_stop, +++ .set_signal_rate = sfp_set_signal_rate, ++ .module_info = sfp_module_info, ++ .module_eeprom = sfp_module_eeprom, ++ .module_eeprom_by_page = sfp_module_eeprom_by_page, ++--- a/drivers/net/phy/sfp.h +++++ b/drivers/net/phy/sfp.h ++@@ -19,6 +19,7 @@ struct sfp_socket_ops { ++ void (*detach)(struct sfp *sfp); ++ void (*start)(struct sfp *sfp); ++ void (*stop)(struct sfp *sfp); +++ void (*set_signal_rate)(struct sfp *sfp, unsigned int rate_kbd); ++ int (*module_info)(struct sfp *sfp, struct ethtool_modinfo *modinfo); ++ int (*module_eeprom)(struct sfp *sfp, struct ethtool_eeprom *ee, ++ u8 *data); ++--- a/include/linux/sfp.h +++++ b/include/linux/sfp.h ++@@ -556,6 +556,7 @@ int sfp_get_module_eeprom_by_page(struct ++ struct netlink_ext_ack *extack); ++ void sfp_upstream_start(struct sfp_bus *bus); ++ void sfp_upstream_stop(struct sfp_bus *bus); +++void sfp_upstream_set_signal_rate(struct sfp_bus *bus, unsigned int rate_kbd); ++ void sfp_bus_put(struct sfp_bus *bus); ++ struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode); ++ int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream, ++@@ -615,6 +616,11 @@ static inline void sfp_upstream_stop(str ++ { ++ } ++ +++static inline void sfp_upstream_set_signal_rate(struct sfp_bus *bus, +++ unsigned int rate_kbd) +++{ +++} +++ ++ static inline void sfp_bus_put(struct sfp_bus *bus) ++ { ++ } +diff --git a/target/linux/mvebu/patches-5.15/706-12-7-net-sfp-add-support-for-rate-selection.patch b/target/linux/mvebu/patches-5.15/706-12-7-net-sfp-add-support-for-rate-selection.patch +new file mode 100644 +index 0000000000..2aa6f6e54b +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-12-7-net-sfp-add-support-for-rate-selection.patch +@@ -0,0 +1,422 @@ ++From fc082b39d0a29891ab4b54c88a40f42385103f71 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 17 May 2023 11:38:17 +0100 ++Subject: [PATCH] net: sfp: add support for rate selection ++ ++Add support for parsing the rate select thresholds and switching of the ++RS0 and RS1 signals to the transceiver. This is complicated by various ++revisions of SFF-8472 and interaction of SFF-8431, SFF-8079 and ++INF-8074. ++ ++Reviewed-by: Simon Horman <simon.horman@corigine.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -26,14 +26,18 @@ enum { ++ GPIO_LOS, ++ GPIO_TX_FAULT, ++ GPIO_TX_DISABLE, ++- GPIO_RATE_SELECT, +++ GPIO_RS0, +++ GPIO_RS1, ++ GPIO_MAX, ++ ++ SFP_F_PRESENT = BIT(GPIO_MODDEF0), ++ SFP_F_LOS = BIT(GPIO_LOS), ++ SFP_F_TX_FAULT = BIT(GPIO_TX_FAULT), ++ SFP_F_TX_DISABLE = BIT(GPIO_TX_DISABLE), ++- SFP_F_RATE_SELECT = BIT(GPIO_RATE_SELECT), +++ SFP_F_RS0 = BIT(GPIO_RS0), +++ SFP_F_RS1 = BIT(GPIO_RS1), +++ +++ SFP_F_OUTPUTS = SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1, ++ ++ SFP_E_INSERT = 0, ++ SFP_E_REMOVE, ++@@ -150,6 +154,7 @@ static const char *gpio_of_names[] = { ++ "tx-fault", ++ "tx-disable", ++ "rate-select0", +++ "rate-select1", ++ }; ++ ++ static const enum gpiod_flags gpio_flags[] = { ++@@ -158,6 +163,7 @@ static const enum gpiod_flags gpio_flags ++ GPIOD_IN, ++ GPIOD_ASIS, ++ GPIOD_ASIS, +++ GPIOD_ASIS, ++ }; ++ ++ /* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a ++@@ -251,6 +257,7 @@ struct sfp { ++ * state: st_mutex held unless reading input bits ++ */ ++ struct mutex st_mutex; /* Protects state */ +++ unsigned int state_hw_drive; ++ unsigned int state_hw_mask; ++ unsigned int state_soft_mask; ++ unsigned int state; ++@@ -271,6 +278,10 @@ struct sfp { ++ unsigned int module_t_start_up; ++ unsigned int module_t_wait; ++ +++ unsigned int rate_kbd; +++ unsigned int rs_threshold_kbd; +++ unsigned int rs_state_mask; +++ ++ bool have_a2; ++ bool tx_fault_ignore; ++ ++@@ -321,7 +332,7 @@ static bool sfp_module_supported(const s ++ ++ static const struct sff_data sfp_data = { ++ .gpios = SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT | ++- SFP_F_TX_DISABLE | SFP_F_RATE_SELECT, +++ SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1, ++ .module_supported = sfp_module_supported, ++ }; ++ ++@@ -510,20 +521,37 @@ static unsigned int sff_gpio_get_state(s ++ ++ static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state) ++ { ++- if (state & SFP_F_PRESENT) { ++- /* If the module is present, drive the signals */ ++- if (sfp->gpio[GPIO_TX_DISABLE]) +++ unsigned int drive; +++ +++ if (state & SFP_F_PRESENT) +++ /* If the module is present, drive the requested signals */ +++ drive = sfp->state_hw_drive; +++ else +++ /* Otherwise, let them float to the pull-ups */ +++ drive = 0; +++ +++ if (sfp->gpio[GPIO_TX_DISABLE]) { +++ if (drive & SFP_F_TX_DISABLE) ++ gpiod_direction_output(sfp->gpio[GPIO_TX_DISABLE], ++ state & SFP_F_TX_DISABLE); ++- if (state & SFP_F_RATE_SELECT) ++- gpiod_direction_output(sfp->gpio[GPIO_RATE_SELECT], ++- state & SFP_F_RATE_SELECT); ++- } else { ++- /* Otherwise, let them float to the pull-ups */ ++- if (sfp->gpio[GPIO_TX_DISABLE]) +++ else ++ gpiod_direction_input(sfp->gpio[GPIO_TX_DISABLE]); ++- if (state & SFP_F_RATE_SELECT) ++- gpiod_direction_input(sfp->gpio[GPIO_RATE_SELECT]); +++ } +++ +++ if (sfp->gpio[GPIO_RS0]) { +++ if (drive & SFP_F_RS0) +++ gpiod_direction_output(sfp->gpio[GPIO_RS0], +++ state & SFP_F_RS0); +++ else +++ gpiod_direction_input(sfp->gpio[GPIO_RS0]); +++ } +++ +++ if (sfp->gpio[GPIO_RS1]) { +++ if (drive & SFP_F_RS1) +++ gpiod_direction_output(sfp->gpio[GPIO_RS1], +++ state & SFP_F_RS1); +++ else +++ gpiod_direction_input(sfp->gpio[GPIO_RS1]); ++ } ++ } ++ ++@@ -685,16 +713,33 @@ static unsigned int sfp_soft_get_state(s ++ return state & sfp->state_soft_mask; ++ } ++ ++-static void sfp_soft_set_state(struct sfp *sfp, unsigned int state) +++static void sfp_soft_set_state(struct sfp *sfp, unsigned int state, +++ unsigned int soft) ++ { ++- u8 mask = SFP_STATUS_TX_DISABLE_FORCE; +++ u8 mask = 0; ++ u8 val = 0; ++ +++ if (soft & SFP_F_TX_DISABLE) +++ mask |= SFP_STATUS_TX_DISABLE_FORCE; ++ if (state & SFP_F_TX_DISABLE) ++ val |= SFP_STATUS_TX_DISABLE_FORCE; ++ +++ if (soft & SFP_F_RS0) +++ mask |= SFP_STATUS_RS0_SELECT; +++ if (state & SFP_F_RS0) +++ val |= SFP_STATUS_RS0_SELECT; +++ +++ if (mask) +++ sfp_modify_u8(sfp, true, SFP_STATUS, mask, val); +++ +++ val = mask = 0; +++ if (soft & SFP_F_RS1) +++ mask |= SFP_EXT_STATUS_RS1_SELECT; +++ if (state & SFP_F_RS1) +++ val |= SFP_EXT_STATUS_RS1_SELECT; ++ ++- sfp_modify_u8(sfp, true, SFP_STATUS, mask, val); +++ if (mask) +++ sfp_modify_u8(sfp, true, SFP_EXT_STATUS, mask, val); ++ } ++ ++ static void sfp_soft_start_poll(struct sfp *sfp) ++@@ -708,6 +753,8 @@ static void sfp_soft_start_poll(struct s ++ mask |= SFP_F_TX_FAULT; ++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS) ++ mask |= SFP_F_LOS; +++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RATE_SELECT) +++ mask |= sfp->rs_state_mask; ++ ++ mutex_lock(&sfp->st_mutex); ++ // Poll the soft state for hardware pins we want to ignore ++@@ -746,11 +793,13 @@ static unsigned int sfp_get_state(struct ++ */ ++ static void sfp_set_state(struct sfp *sfp, unsigned int state) ++ { +++ unsigned int soft; +++ ++ sfp->set_state(sfp, state); ++ ++- if (state & SFP_F_PRESENT && ++- sfp->state_soft_mask & SFP_F_TX_DISABLE) ++- sfp_soft_set_state(sfp, state); +++ soft = sfp->state_soft_mask & SFP_F_OUTPUTS; +++ if (state & SFP_F_PRESENT && soft) +++ sfp_soft_set_state(sfp, state, soft); ++ } ++ ++ static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set) ++@@ -1641,10 +1690,15 @@ static int sfp_debug_state_show(struct s ++ sfp->sm_fault_retries); ++ seq_printf(s, "PHY probe remaining retries: %d\n", ++ sfp->sm_phy_retries); +++ seq_printf(s, "Signalling rate: %u kBd\n", sfp->rate_kbd); +++ seq_printf(s, "Rate select threshold: %u kBd\n", +++ sfp->rs_threshold_kbd); ++ seq_printf(s, "moddef0: %d\n", !!(sfp->state & SFP_F_PRESENT)); ++ seq_printf(s, "rx_los: %d\n", !!(sfp->state & SFP_F_LOS)); ++ seq_printf(s, "tx_fault: %d\n", !!(sfp->state & SFP_F_TX_FAULT)); ++ seq_printf(s, "tx_disable: %d\n", !!(sfp->state & SFP_F_TX_DISABLE)); +++ seq_printf(s, "rs0: %d\n", !!(sfp->state & SFP_F_RS0)); +++ seq_printf(s, "rs1: %d\n", !!(sfp->state & SFP_F_RS1)); ++ return 0; ++ } ++ DEFINE_SHOW_ATTRIBUTE(sfp_debug_state); ++@@ -1950,6 +2004,95 @@ static int sfp_sm_mod_hpower(struct sfp ++ return 0; ++ } ++ +++static void sfp_module_parse_rate_select(struct sfp *sfp) +++{ +++ u8 rate_id; +++ +++ sfp->rs_threshold_kbd = 0; +++ sfp->rs_state_mask = 0; +++ +++ if (!(sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_RATE_SELECT))) +++ /* No support for RateSelect */ +++ return; +++ +++ /* Default to INF-8074 RateSelect operation. The signalling threshold +++ * rate is not well specified, so always select "Full Bandwidth", but +++ * SFF-8079 reveals that it is understood that RS0 will be low for +++ * 1.0625Gb/s and high for 2.125Gb/s. Choose a value half-way between. +++ * This method exists prior to SFF-8472. +++ */ +++ sfp->rs_state_mask = SFP_F_RS0; +++ sfp->rs_threshold_kbd = 1594; +++ +++ /* Parse the rate identifier, which is complicated due to history: +++ * SFF-8472 rev 9.5 marks this field as reserved. +++ * SFF-8079 references SFF-8472 rev 9.5 and defines bit 0. SFF-8472 +++ * compliance is not required. +++ * SFF-8472 rev 10.2 defines this field using values 0..4 +++ * SFF-8472 rev 11.0 redefines this field with bit 0 for SFF-8079 +++ * and even values. +++ */ +++ rate_id = sfp->id.base.rate_id; +++ if (rate_id == 0) +++ /* Unspecified */ +++ return; +++ +++ /* SFF-8472 rev 10.0..10.4 did not account for SFF-8079 using bit 0, +++ * and allocated value 3 to SFF-8431 independent tx/rx rate select. +++ * Convert this to a SFF-8472 rev 11.0 rate identifier. +++ */ +++ if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 && +++ sfp->id.ext.sff8472_compliance < SFP_SFF8472_COMPLIANCE_REV11_0 && +++ rate_id == 3) +++ rate_id = SFF_RID_8431; +++ +++ if (rate_id & SFF_RID_8079) { +++ /* SFF-8079 RateSelect / Application Select in conjunction with +++ * SFF-8472 rev 9.5. SFF-8079 defines rate_id as a bitfield +++ * with only bit 0 used, which takes precedence over SFF-8472. +++ */ +++ if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_APP_SELECT_SFF8079)) { +++ /* SFF-8079 Part 1 - rate selection between Fibre +++ * Channel 1.0625/2.125/4.25 Gbd modes. Note that RS0 +++ * is high for 2125, so we have to subtract 1 to +++ * include it. +++ */ +++ sfp->rs_threshold_kbd = 2125 - 1; +++ sfp->rs_state_mask = SFP_F_RS0; +++ } +++ return; +++ } +++ +++ /* SFF-8472 rev 9.5 does not define the rate identifier */ +++ if (sfp->id.ext.sff8472_compliance <= SFP_SFF8472_COMPLIANCE_REV9_5) +++ return; +++ +++ /* SFF-8472 rev 11.0 defines rate_id as a numerical value which will +++ * always have bit 0 clear due to SFF-8079's bitfield usage of rate_id. +++ */ +++ switch (rate_id) { +++ case SFF_RID_8431_RX_ONLY: +++ sfp->rs_threshold_kbd = 4250; +++ sfp->rs_state_mask = SFP_F_RS0; +++ break; +++ +++ case SFF_RID_8431_TX_ONLY: +++ sfp->rs_threshold_kbd = 4250; +++ sfp->rs_state_mask = SFP_F_RS1; +++ break; +++ +++ case SFF_RID_8431: +++ sfp->rs_threshold_kbd = 4250; +++ sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1; +++ break; +++ +++ case SFF_RID_10G8G: +++ sfp->rs_threshold_kbd = 9000; +++ sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1; +++ break; +++ } +++} +++ ++ /* GPON modules based on Realtek RTL8672 and RTL9601C chips (e.g. V-SOL ++ * V2801F, CarlitoxxPro CPGOS03-0490, Ubiquiti U-Fiber Instant, ...) do ++ * not support multibyte reads from the EEPROM. Each multi-byte read ++@@ -2169,6 +2312,8 @@ static int sfp_sm_mod_probe(struct sfp * ++ if (ret < 0) ++ return ret; ++ +++ sfp_module_parse_rate_select(sfp); +++ ++ mask = SFP_F_PRESENT; ++ if (sfp->gpio[GPIO_TX_DISABLE]) ++ mask |= SFP_F_TX_DISABLE; ++@@ -2176,6 +2321,10 @@ static int sfp_sm_mod_probe(struct sfp * ++ mask |= SFP_F_TX_FAULT; ++ if (sfp->gpio[GPIO_LOS]) ++ mask |= SFP_F_LOS; +++ if (sfp->gpio[GPIO_RS0]) +++ mask |= SFP_F_RS0; +++ if (sfp->gpio[GPIO_RS1]) +++ mask |= SFP_F_RS1; ++ ++ sfp->module_t_start_up = T_START_UP; ++ sfp->module_t_wait = T_WAIT; ++@@ -2198,6 +2347,9 @@ static int sfp_sm_mod_probe(struct sfp * ++ /* Initialise state bits to use from hardware */ ++ sfp->state_hw_mask = mask; ++ +++ /* We want to drive the rate select pins that the module is using */ +++ sfp->state_hw_drive |= sfp->rs_state_mask; +++ ++ if (sfp->quirk && sfp->quirk->fixup) ++ sfp->quirk->fixup(sfp); ++ mutex_unlock(&sfp->st_mutex); ++@@ -2214,6 +2366,7 @@ static void sfp_sm_mod_remove(struct sfp ++ ++ memset(&sfp->id, 0, sizeof(sfp->id)); ++ sfp->module_power_mW = 0; +++ sfp->state_hw_drive = SFP_F_TX_DISABLE; ++ sfp->have_a2 = false; ++ ++ dev_info(sfp->dev, "module removed\n"); ++@@ -2581,6 +2734,16 @@ static void sfp_stop(struct sfp *sfp) ++ ++ static void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd) ++ { +++ unsigned int set; +++ +++ sfp->rate_kbd = rate_kbd; +++ +++ if (rate_kbd > sfp->rs_threshold_kbd) +++ set = sfp->rs_state_mask; +++ else +++ set = 0; +++ +++ sfp_mod_state(sfp, SFP_F_RS0 | SFP_F_RS1, set); ++ } ++ ++ static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo) ++@@ -2700,7 +2863,7 @@ static void sfp_check_state(struct sfp * ++ dev_dbg(sfp->dev, "%s %u -> %u\n", gpio_of_names[i], ++ !!(sfp->state & BIT(i)), !!(state & BIT(i))); ++ ++- state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT); +++ state |= sfp->state & SFP_F_OUTPUTS; ++ sfp->state = state; ++ mutex_unlock(&sfp->st_mutex); ++ ++@@ -2856,6 +3019,7 @@ static int sfp_probe(struct platform_dev ++ } ++ ++ sfp->state_hw_mask = SFP_F_PRESENT; +++ sfp->state_hw_drive = SFP_F_TX_DISABLE; ++ ++ sfp->get_state = sfp_gpio_get_state; ++ sfp->set_state = sfp_gpio_set_state; ++@@ -2881,9 +3045,9 @@ static int sfp_probe(struct platform_dev ++ */ ++ sfp->state = sfp_get_state(sfp) | SFP_F_TX_DISABLE; ++ ++- if (sfp->gpio[GPIO_RATE_SELECT] && ++- gpiod_get_value_cansleep(sfp->gpio[GPIO_RATE_SELECT])) ++- sfp->state |= SFP_F_RATE_SELECT; +++ if (sfp->gpio[GPIO_RS0] && +++ gpiod_get_value_cansleep(sfp->gpio[GPIO_RS0])) +++ sfp->state |= SFP_F_RS0; ++ sfp_set_state(sfp, sfp->state); ++ sfp_module_tx_disable(sfp); ++ if (sfp->state & SFP_F_PRESENT) { ++--- a/include/linux/sfp.h +++++ b/include/linux/sfp.h ++@@ -342,6 +342,12 @@ enum { ++ SFP_ENCODING = 11, ++ SFP_BR_NOMINAL = 12, ++ SFP_RATE_ID = 13, +++ SFF_RID_8079 = 0x01, +++ SFF_RID_8431_RX_ONLY = 0x02, +++ SFF_RID_8431_TX_ONLY = 0x04, +++ SFF_RID_8431 = 0x06, +++ SFF_RID_10G8G = 0x0e, +++ ++ SFP_LINK_LEN_SM_KM = 14, ++ SFP_LINK_LEN_SM_100M = 15, ++ SFP_LINK_LEN_50UM_OM2_10M = 16, ++@@ -465,6 +471,7 @@ enum { ++ SFP_STATUS = 110, ++ SFP_STATUS_TX_DISABLE = BIT(7), ++ SFP_STATUS_TX_DISABLE_FORCE = BIT(6), +++ SFP_STATUS_RS0_SELECT = BIT(3), ++ SFP_STATUS_TX_FAULT = BIT(2), ++ SFP_STATUS_RX_LOS = BIT(1), ++ SFP_ALARM0 = 112, ++@@ -496,6 +503,7 @@ enum { ++ SFP_WARN1_RXPWR_LOW = BIT(6), ++ ++ SFP_EXT_STATUS = 118, +++ SFP_EXT_STATUS_RS1_SELECT = BIT(3), ++ SFP_EXT_STATUS_PWRLVL_SELECT = BIT(0), ++ ++ SFP_VSL = 120, +diff --git a/target/linux/mvebu/patches-5.15/706-13-net-sfp-add-support-for-a-couple-of-copper-multi-rat.patch b/target/linux/mvebu/patches-5.15/706-13-net-sfp-add-support-for-a-couple-of-copper-multi-rat.patch +new file mode 100644 +index 0000000000..938e14627a +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-13-net-sfp-add-support-for-a-couple-of-copper-multi-rat.patch +@@ -0,0 +1,93 @@ ++From 5859a99b52254be356d3cca2e40f7f371ef24b0a Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Sat, 20 May 2023 11:18:30 +0100 ++Subject: [PATCH] net: sfp: add support for a couple of copper multi-rate ++ modules ++ ++Add support for the Fiberstore SFP-10G-T and Walsun HXSX-ATRC-1 ++modules. Internally, the PCB silkscreen has what seems to be a part ++number of WT_502. Fiberstore use v2.2 whereas Walsun use v2.6. ++ ++These modules contain a Marvell AQrate AQR113C PHY, accessible through ++I2C 0x51 using the "rollball" protocol. In both cases, the PHY is ++programmed to use 10GBASE-R with pause-mode rate adaption. ++ ++Unlike the other rollball modules, these only need a four second delay ++before we can talk to the PHY. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Link: https://lore.kernel.org/r/E1q0JfS-006Dqc-8t@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -172,7 +172,6 @@ static const enum gpiod_flags gpio_flags ++ * on board (for a copper SFP) time to initialise. ++ */ ++ #define T_WAIT msecs_to_jiffies(50) ++-#define T_WAIT_ROLLBALL msecs_to_jiffies(25000) ++ #define T_START_UP msecs_to_jiffies(300) ++ #define T_START_UP_BAD_GPON msecs_to_jiffies(60000) ++ ++@@ -353,6 +352,27 @@ static void sfp_fixup_ignore_tx_fault(st ++ sfp->tx_fault_ignore = true; ++ } ++ +++// For 10GBASE-T short-reach modules +++static void sfp_fixup_10gbaset_30m(struct sfp *sfp) +++{ +++ sfp->id.base.connector = SFF8024_CONNECTOR_RJ45; +++ sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SR; +++} +++ +++static void sfp_fixup_rollball_proto(struct sfp *sfp, unsigned int secs) +++{ +++ sfp->mdio_protocol = MDIO_I2C_ROLLBALL; +++ sfp->module_t_wait = msecs_to_jiffies(secs * 1000); +++} +++ +++static void sfp_fixup_fs_10gt(struct sfp *sfp) +++{ +++ sfp_fixup_10gbaset_30m(sfp); +++ +++ // These SFPs need 4 seconds before the PHY can be accessed +++ sfp_fixup_rollball_proto(sfp, 4); +++} +++ ++ static void sfp_fixup_halny_gsfp(struct sfp *sfp) ++ { ++ /* Ignore the TX_FAULT and LOS signals on this module. ++@@ -364,8 +384,8 @@ static void sfp_fixup_halny_gsfp(struct ++ ++ static void sfp_fixup_rollball(struct sfp *sfp) ++ { ++- sfp->mdio_protocol = MDIO_I2C_ROLLBALL; ++- sfp->module_t_wait = T_WAIT_ROLLBALL; +++ // Rollball SFPs need 25 seconds before the PHY can be accessed +++ sfp_fixup_rollball_proto(sfp, 25); ++ } ++ ++ static void sfp_fixup_rollball_cc(struct sfp *sfp) ++@@ -431,6 +451,10 @@ static const struct sfp_quirk sfp_quirks ++ SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex, ++ sfp_fixup_long_startup), ++ +++ // Fiberstore SFP-10G-T doesn't identify as copper, and uses the +++ // Rollball protocol to talk to the PHY. +++ SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt), +++ ++ SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp), ++ ++ // HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports ++@@ -448,6 +472,10 @@ static const struct sfp_quirk sfp_quirks ++ ++ SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant), ++ +++ // Walsun HXSX-ATRC-1 doesn't identify as copper, and uses the +++ // Rollball protocol to talk to the PHY. +++ SFP_QUIRK_F("Walsun", "HXSX-ATRC-1", sfp_fixup_fs_10gt), +++ ++ SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), ++ SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), ++ SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc), +diff --git a/target/linux/mvebu/patches-5.15/706-14-net-sfp-add-support-for-HXSX-ATRI-1-copper-SFP-modul.patch b/target/linux/mvebu/patches-5.15/706-14-net-sfp-add-support-for-HXSX-ATRI-1-copper-SFP-modul.patch +new file mode 100644 +index 0000000000..c6512692c8 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-14-net-sfp-add-support-for-HXSX-ATRI-1-copper-SFP-modul.patch +@@ -0,0 +1,30 @@ ++From ac2e8e3cfe48439a2403b3d616fb654db313e362 Mon Sep 17 00:00:00 2001 ++From: Josua Mayer <josua@solid-run.com> ++Date: Mon, 22 May 2023 17:52:42 +0300 ++Subject: [PATCH] net: sfp: add support for HXSX-ATRI-1 copper SFP+ module ++ ++Walsun offers commercial ("C") and industrial ("I") variants of ++multi-rate copper SFP+ modules. ++ ++Add quirk for HXSX-ATRI-1 using same parameters as the already supported ++commercial variant HXSX-ATRC-1. ++ ++Signed-off-by: Josua Mayer <josua@solid-run.com> ++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Link: https://lore.kernel.org/r/20230522145242.30192-2-josua@solid-run.com/ ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -472,9 +472,10 @@ static const struct sfp_quirk sfp_quirks ++ ++ SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant), ++ ++- // Walsun HXSX-ATRC-1 doesn't identify as copper, and uses the +++ // Walsun HXSX-ATR[CI]-1 don't identify as copper, and use the ++ // Rollball protocol to talk to the PHY. ++ SFP_QUIRK_F("Walsun", "HXSX-ATRC-1", sfp_fixup_fs_10gt), +++ SFP_QUIRK_F("Walsun", "HXSX-ATRI-1", sfp_fixup_fs_10gt), ++ ++ SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), ++ SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), +diff --git a/target/linux/mvebu/patches-5.15/706-15-net-phy-move-marking-PHY-on-SFP-module-into-SFP-code.patch b/target/linux/mvebu/patches-5.15/706-15-net-phy-move-marking-PHY-on-SFP-module-into-SFP-code.patch +new file mode 100644 +index 0000000000..45587fad0c +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-15-net-phy-move-marking-PHY-on-SFP-module-into-SFP-code.patch +@@ -0,0 +1,39 @@ ++From f4bf467883f210d0bfbe784fffca52887de147fb Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Thu, 3 Aug 2023 16:56:24 +0100 ++Subject: [PATCH] net: phy: move marking PHY on SFP module into SFP code ++ ++Move marking the PHY as being on a SFP module into the SFP code between ++getting the PHY device (and thus initialising the phy_device structure) ++and registering the discovered device. ++ ++This means that PHY drivers can use phy_on_sfp() in their match and ++get_features methods. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Link: https://lore.kernel.org/r/E1qRaga-001vKt-8X@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/phy_device.c +++++ b/drivers/net/phy/phy_device.c ++@@ -1452,8 +1452,6 @@ int phy_attach_direct(struct net_device ++ ++ if (phydev->sfp_bus_attached) ++ dev->sfp_bus = phydev->sfp_bus; ++- else if (dev->sfp_bus) ++- phydev->is_on_sfp_module = true; ++ } ++ ++ /* Some Ethernet drivers try to connect to a PHY device before ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -1815,6 +1815,9 @@ static int sfp_sm_probe_phy(struct sfp * ++ return PTR_ERR(phy); ++ } ++ +++ /* Mark this PHY as being on a SFP module */ +++ phy->is_on_sfp_module = true; +++ ++ err = phy_device_register(phy); ++ if (err) { ++ phy_device_free(phy); +diff --git a/target/linux/mvebu/patches-5.15/706-16-net-sfp-add-quirk-for-Fiberstone-GPON-ONU-34-20BI.patch b/target/linux/mvebu/patches-5.15/706-16-net-sfp-add-quirk-for-Fiberstone-GPON-ONU-34-20BI.patch +new file mode 100644 +index 0000000000..ce17622591 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-16-net-sfp-add-quirk-for-Fiberstone-GPON-ONU-34-20BI.patch +@@ -0,0 +1,29 @@ ++From d387e34fec407f881fdf165b5d7ec128ebff362f Mon Sep 17 00:00:00 2001 ++From: Christian Marangi <ansuelsmth@gmail.com> ++Date: Tue, 19 Sep 2023 14:47:20 +0200 ++Subject: [PATCH] net: sfp: add quirk for Fiberstone GPON-ONU-34-20BI ++ ++Fiberstone GPON-ONU-34-20B can operate at 2500base-X, but report 1.2GBd ++NRZ in their EEPROM. ++ ++The module also require the ignore tx fault fixup similar to Huawei MA5671A ++as it gets disabled on error messages with serial redirection enabled. ++ ++Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> ++Link: https://lore.kernel.org/r/20230919124720.8210-1-ansuelsmth@gmail.com ++Signed-off-by: Paolo Abeni <pabeni@redhat.com> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -455,6 +455,11 @@ static const struct sfp_quirk sfp_quirks ++ // Rollball protocol to talk to the PHY. ++ SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt), ++ +++ // Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd +++ // NRZ in their EEPROM +++ SFP_QUIRK("FS", "GPON-ONU-34-20BI", sfp_quirk_2500basex, +++ sfp_fixup_ignore_tx_fault), +++ ++ SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp), ++ ++ // HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports +diff --git a/target/linux/mvebu/patches-5.15/706-17-net-sfp-add-quirk-for-FS-s-2.5G-copper-SFP.patch b/target/linux/mvebu/patches-5.15/706-17-net-sfp-add-quirk-for-FS-s-2.5G-copper-SFP.patch +new file mode 100644 +index 0000000000..7da5a924c5 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-17-net-sfp-add-quirk-for-FS-s-2.5G-copper-SFP.patch +@@ -0,0 +1,26 @@ ++From e27aca3760c08b7b05aea71068bd609aa93e7b35 Mon Sep 17 00:00:00 2001 ++From: Raju Lakkaraju <Raju.Lakkaraju@microchip.com> ++Date: Mon, 25 Sep 2023 13:30:59 +0530 ++Subject: [PATCH] net: sfp: add quirk for FS's 2.5G copper SFP ++ ++Add a quirk for a copper SFP that identifies itself as "FS" "SFP-2.5G-T". ++This module's PHY is inaccessible, and can only run at 2500base-X with the ++host without negotiation. Add a quirk to enable the 2500base-X interface mode ++with 2500base-T support and disable auto negotiation. ++ ++Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microchip.com> ++Link: https://lore.kernel.org/r/20230925080059.266240-1-Raju.Lakkaraju@microchip.com ++Signed-off-by: Paolo Abeni <pabeni@redhat.com> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -471,6 +471,9 @@ static const struct sfp_quirk sfp_quirks ++ SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex, ++ sfp_fixup_ignore_tx_fault), ++ +++ // FS 2.5G Base-T +++ SFP_QUIRK_M("FS", "SFP-2.5G-T", sfp_quirk_oem_2_5g), +++ ++ // Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report ++ // 2500MBd NRZ in their EEPROM ++ SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex), +diff --git a/target/linux/mvebu/patches-5.15/706-18-1-net-sfp-re-implement-ignoring-the-hardware-TX_FAULT-.patch b/target/linux/mvebu/patches-5.15/706-18-1-net-sfp-re-implement-ignoring-the-hardware-TX_FAULT-.patch +new file mode 100644 +index 0000000000..434210cd87 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-18-1-net-sfp-re-implement-ignoring-the-hardware-TX_FAULT-.patch +@@ -0,0 +1,82 @@ ++From e184e8609f8c1cd9fef703f667245b6ebd89c2ed Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Tue, 3 Oct 2023 14:34:24 +0100 ++Subject: [PATCH] net: sfp: re-implement ignoring the hardware TX_FAULT signal ++ ++Re-implement how we ignore the hardware TX_FAULT signal. Rather than ++having a separate boolean for this, use a bitmask of the hardware ++signals that we wish to ignore. This gives more flexibility in the ++future to ignore other signals such as RX_LOS. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Tested-by: Christian Marangi <ansuelsmth@gmail.com> ++Link: https://lore.kernel.org/r/E1qnfXc-008UDY-91@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -259,6 +259,7 @@ struct sfp { ++ unsigned int state_hw_drive; ++ unsigned int state_hw_mask; ++ unsigned int state_soft_mask; +++ unsigned int state_ignore_mask; ++ unsigned int state; ++ ++ struct delayed_work poll; ++@@ -282,7 +283,6 @@ struct sfp { ++ unsigned int rs_state_mask; ++ ++ bool have_a2; ++- bool tx_fault_ignore; ++ ++ const struct sfp_quirk *quirk; ++ ++@@ -349,7 +349,7 @@ static void sfp_fixup_long_startup(struc ++ ++ static void sfp_fixup_ignore_tx_fault(struct sfp *sfp) ++ { ++- sfp->tx_fault_ignore = true; +++ sfp->state_ignore_mask |= SFP_F_TX_FAULT; ++ } ++ ++ // For 10GBASE-T short-reach modules ++@@ -795,7 +795,8 @@ static void sfp_soft_start_poll(struct s ++ ++ mutex_lock(&sfp->st_mutex); ++ // Poll the soft state for hardware pins we want to ignore ++- sfp->state_soft_mask = ~sfp->state_hw_mask & mask; +++ sfp->state_soft_mask = ~sfp->state_hw_mask & ~sfp->state_ignore_mask & +++ mask; ++ ++ if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) && ++ !sfp->need_poll) ++@@ -2369,7 +2370,7 @@ static int sfp_sm_mod_probe(struct sfp * ++ sfp->module_t_start_up = T_START_UP; ++ sfp->module_t_wait = T_WAIT; ++ ++- sfp->tx_fault_ignore = false; +++ sfp->state_ignore_mask = 0; ++ ++ if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI || ++ sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR || ++@@ -2392,6 +2393,8 @@ static int sfp_sm_mod_probe(struct sfp * ++ ++ if (sfp->quirk && sfp->quirk->fixup) ++ sfp->quirk->fixup(sfp); +++ +++ sfp->state_hw_mask &= ~sfp->state_ignore_mask; ++ mutex_unlock(&sfp->st_mutex); ++ ++ return 0; ++@@ -2893,10 +2896,7 @@ static void sfp_check_state(struct sfp * ++ mutex_lock(&sfp->st_mutex); ++ state = sfp_get_state(sfp); ++ changed = state ^ sfp->state; ++- if (sfp->tx_fault_ignore) ++- changed &= SFP_F_PRESENT | SFP_F_LOS; ++- else ++- changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT; +++ changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT; ++ ++ for (i = 0; i < GPIO_MAX; i++) ++ if (changed & BIT(i)) +diff --git a/target/linux/mvebu/patches-5.15/706-18-2-net-sfp-improve-Nokia-GPON-sfp-fixup.patch b/target/linux/mvebu/patches-5.15/706-18-2-net-sfp-improve-Nokia-GPON-sfp-fixup.patch +new file mode 100644 +index 0000000000..37afcd1c7b +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-18-2-net-sfp-improve-Nokia-GPON-sfp-fixup.patch +@@ -0,0 +1,54 @@ ++From 5ffe330e40bdfad9c49a615c54d2d89343b2f08a Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Tue, 3 Oct 2023 14:34:29 +0100 ++Subject: [PATCH] net: sfp: improve Nokia GPON sfp fixup ++ ++Improve the Nokia GPON fixup - we need to ignore not only the hardware ++LOS signal, but also the software implementation as well. Do this by ++using the new state_ignore_mask to indicate that we should ignore not ++only the hardware RX_LOS signal, and also clear the LOS bits in the ++option field. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Tested-by: Christian Marangi <ansuelsmth@gmail.com> ++Link: https://lore.kernel.org/r/E1qnfXh-008UDe-F9@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -347,11 +347,26 @@ static void sfp_fixup_long_startup(struc ++ sfp->module_t_start_up = T_START_UP_BAD_GPON; ++ } ++ +++static void sfp_fixup_ignore_los(struct sfp *sfp) +++{ +++ /* This forces LOS to zero, so we ignore transitions */ +++ sfp->state_ignore_mask |= SFP_F_LOS; +++ /* Make sure that LOS options are clear */ +++ sfp->id.ext.options &= ~cpu_to_be16(SFP_OPTIONS_LOS_INVERTED | +++ SFP_OPTIONS_LOS_NORMAL); +++} +++ ++ static void sfp_fixup_ignore_tx_fault(struct sfp *sfp) ++ { ++ sfp->state_ignore_mask |= SFP_F_TX_FAULT; ++ } ++ +++static void sfp_fixup_nokia(struct sfp *sfp) +++{ +++ sfp_fixup_long_startup(sfp); +++ sfp_fixup_ignore_los(sfp); +++} +++ ++ // For 10GBASE-T short-reach modules ++ static void sfp_fixup_10gbaset_30m(struct sfp *sfp) ++ { ++@@ -449,7 +464,7 @@ static const struct sfp_quirk sfp_quirks ++ // Alcatel Lucent G-010S-A can operate at 2500base-X, but report 3.2GBd ++ // NRZ in their EEPROM ++ SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex, ++- sfp_fixup_long_startup), +++ sfp_fixup_nokia), ++ ++ // Fiberstore SFP-10G-T doesn't identify as copper, and uses the ++ // Rollball protocol to talk to the PHY. +diff --git a/target/linux/mvebu/patches-5.15/706-19-1-net-linkmode-add-linkmode_fill-helper.patch b/target/linux/mvebu/patches-5.15/706-19-1-net-linkmode-add-linkmode_fill-helper.patch +new file mode 100644 +index 0000000000..892edde0e2 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-19-1-net-linkmode-add-linkmode_fill-helper.patch +@@ -0,0 +1,26 @@ ++From 96fa96e198f9707285003075fbbce7db6a485112 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 15 Nov 2023 11:39:18 +0000 ++Subject: [PATCH] net: linkmode: add linkmode_fill() helper ++ ++Add a linkmode_fill() helper, which will allow us to convert phylink's ++open coded bitmap_fill() operations. ++ ++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> ++ ++--- a/include/linux/linkmode.h +++++ b/include/linux/linkmode.h ++@@ -10,6 +10,11 @@ static inline void linkmode_zero(unsigne ++ bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ } ++ +++static inline void linkmode_fill(unsigned long *dst) +++{ +++ bitmap_fill(dst, __ETHTOOL_LINK_MODE_MASK_NBITS); +++} +++ ++ static inline void linkmode_copy(unsigned long *dst, const unsigned long *src) ++ { ++ bitmap_copy(dst, src, __ETHTOOL_LINK_MODE_MASK_NBITS); +diff --git a/target/linux/mvebu/patches-5.15/706-19-2-net-phylink-use-linkmode_fill.patch b/target/linux/mvebu/patches-5.15/706-19-2-net-phylink-use-linkmode_fill.patch +new file mode 100644 +index 0000000000..bf32262638 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-19-2-net-phylink-use-linkmode_fill.patch +@@ -0,0 +1,31 @@ ++From ba50a8d40258081325db15f5a86cbb301867a3ba Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 15 Nov 2023 11:39:23 +0000 ++Subject: [PATCH] net: phylink: use linkmode_fill() ++ ++Use linkmode_fill() rather than open coding the bitmap operation. ++ ++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> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -603,7 +603,7 @@ static int phylink_parse_fixedlink(struc ++ phylink_warn(pl, "fixed link specifies half duplex for %dMbps link?\n", ++ pl->link_config.speed); ++ ++- bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); +++ linkmode_fill(pl->supported); ++ linkmode_copy(pl->link_config.advertising, pl->supported); ++ phylink_validate(pl, pl->supported, &pl->link_config); ++ ++@@ -1288,7 +1288,7 @@ struct phylink *phylink_create(struct ph ++ __set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); ++ timer_setup(&pl->link_poll, phylink_fixed_poll, 0); ++ ++- bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); +++ linkmode_fill(pl->supported); ++ linkmode_copy(pl->link_config.advertising, pl->supported); ++ phylink_validate(pl, pl->supported, &pl->link_config); ++ +diff --git a/target/linux/mvebu/patches-5.15/706-19-3-net-sfp-use-linkmode_-rather-than-open-coding.patch b/target/linux/mvebu/patches-5.15/706-19-3-net-sfp-use-linkmode_-rather-than-open-coding.patch +new file mode 100644 +index 0000000000..fa8b1a6536 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-19-3-net-sfp-use-linkmode_-rather-than-open-coding.patch +@@ -0,0 +1,23 @@ ++From 466b97b1871a49c272757f7527db2f85ea6338b4 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Wed, 15 Nov 2023 11:39:28 +0000 ++Subject: [PATCH] net: sfp: use linkmode_*() rather than open coding ++ ++Use the linkmode_*() helpers rather than open coding the calls to the ++bitmap operators. ++ ++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> ++ ++--- a/drivers/net/phy/sfp-bus.c +++++ b/drivers/net/phy/sfp-bus.c ++@@ -318,7 +318,7 @@ void sfp_parse_support(struct sfp_bus *b ++ * modules use 2500Mbaud rather than 3100 or 3200Mbaud for ++ * 2500BASE-X, so we allow some slack here. ++ */ ++- if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS) && br_nom) { +++ if (linkmode_empty(modes) && br_nom) { ++ if (br_min <= 1300 && br_max >= 1200) { ++ phylink_set(modes, 1000baseX_Full); ++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); +diff --git a/target/linux/mvebu/patches-5.15/706-20-net-sfp-rework-the-RollBall-PHY-waiting-code.patch b/target/linux/mvebu/patches-5.15/706-20-net-sfp-rework-the-RollBall-PHY-waiting-code.patch +new file mode 100644 +index 0000000000..088ae6c1ba +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-20-net-sfp-rework-the-RollBall-PHY-waiting-code.patch +@@ -0,0 +1,131 @@ ++From 2f3ce7a56c6e02bc0b258507f3a82b7511f62f9e Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Tue, 21 Nov 2023 18:20:24 +0100 ++Subject: [PATCH] net: sfp: rework the RollBall PHY waiting code ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++RollBall SFP modules allow the access to PHY registers only after a ++certain time has passed. Until then, the registers read 0xffff. ++ ++Currently we have quirks for modules where we need to wait either 25 ++seconds or 4 seconds, but recently I got hands on another module where ++the wait is even shorter. ++ ++Instead of hardcoding different wait times, lets rework the code: ++- increase the PHY retry count to 25 ++- when RollBall module is detected, increase the PHY retry time from ++ 50ms to 1s ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -193,7 +193,7 @@ static const enum gpiod_flags gpio_flags ++ * R_PHY_RETRY is the number of attempts. ++ */ ++ #define T_PHY_RETRY msecs_to_jiffies(50) ++-#define R_PHY_RETRY 12 +++#define R_PHY_RETRY 25 ++ ++ /* SFP module presence detection is poor: the three MOD DEF signals are ++ * the same length on the PCB, which means it's possible for MOD DEF 0 to ++@@ -276,7 +276,7 @@ struct sfp { ++ struct sfp_eeprom_id id; ++ unsigned int module_power_mW; ++ unsigned int module_t_start_up; ++- unsigned int module_t_wait; +++ unsigned int phy_t_retry; ++ ++ unsigned int rate_kbd; ++ unsigned int rs_threshold_kbd; ++@@ -374,18 +374,22 @@ static void sfp_fixup_10gbaset_30m(struc ++ sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SR; ++ } ++ ++-static void sfp_fixup_rollball_proto(struct sfp *sfp, unsigned int secs) +++static void sfp_fixup_rollball(struct sfp *sfp) ++ { ++ sfp->mdio_protocol = MDIO_I2C_ROLLBALL; ++- sfp->module_t_wait = msecs_to_jiffies(secs * 1000); +++ +++ /* RollBall modules may disallow access to PHY registers for up to 25 +++ * seconds, and the reads return 0xffff before that. Increase the time +++ * between PHY probe retries from 50ms to 1s so that we will wait for +++ * the PHY for a sufficient amount of time. +++ */ +++ sfp->phy_t_retry = msecs_to_jiffies(1000); ++ } ++ ++ static void sfp_fixup_fs_10gt(struct sfp *sfp) ++ { ++ sfp_fixup_10gbaset_30m(sfp); ++- ++- // These SFPs need 4 seconds before the PHY can be accessed ++- sfp_fixup_rollball_proto(sfp, 4); +++ sfp_fixup_rollball(sfp); ++ } ++ ++ static void sfp_fixup_halny_gsfp(struct sfp *sfp) ++@@ -397,12 +401,6 @@ static void sfp_fixup_halny_gsfp(struct ++ sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS); ++ } ++ ++-static void sfp_fixup_rollball(struct sfp *sfp) ++-{ ++- // Rollball SFPs need 25 seconds before the PHY can be accessed ++- sfp_fixup_rollball_proto(sfp, 25); ++-} ++- ++ static void sfp_fixup_rollball_cc(struct sfp *sfp) ++ { ++ sfp_fixup_rollball(sfp); ++@@ -2383,7 +2381,7 @@ static int sfp_sm_mod_probe(struct sfp * ++ mask |= SFP_F_RS1; ++ ++ sfp->module_t_start_up = T_START_UP; ++- sfp->module_t_wait = T_WAIT; +++ sfp->phy_t_retry = T_PHY_RETRY; ++ ++ sfp->state_ignore_mask = 0; ++ ++@@ -2620,10 +2618,9 @@ static void sfp_sm_main(struct sfp *sfp, ++ ++ /* We need to check the TX_FAULT state, which is not defined ++ * while TX_DISABLE is asserted. The earliest we want to do ++- * anything (such as probe for a PHY) is 50ms (or more on ++- * specific modules). +++ * anything (such as probe for a PHY) is 50ms. ++ */ ++- sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait); +++ sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT); ++ break; ++ ++ case SFP_S_WAIT: ++@@ -2637,8 +2634,8 @@ static void sfp_sm_main(struct sfp *sfp, ++ * deasserting. ++ */ ++ timeout = sfp->module_t_start_up; ++- if (timeout > sfp->module_t_wait) ++- timeout -= sfp->module_t_wait; +++ if (timeout > T_WAIT) +++ timeout -= T_WAIT; ++ else ++ timeout = 1; ++ ++@@ -2681,7 +2678,11 @@ static void sfp_sm_main(struct sfp *sfp, ++ ret = sfp_sm_probe_for_phy(sfp); ++ if (ret == -ENODEV) { ++ if (--sfp->sm_phy_retries) { ++- sfp_sm_next(sfp, SFP_S_INIT_PHY, T_PHY_RETRY); +++ sfp_sm_next(sfp, SFP_S_INIT_PHY, +++ sfp->phy_t_retry); +++ dev_dbg(sfp->dev, +++ "no PHY detected, %u tries left\n", +++ sfp->sm_phy_retries); ++ break; ++ } else { ++ dev_info(sfp->dev, "no PHY detected\n"); +diff --git a/target/linux/mvebu/patches-5.15/706-21-net-sfp-fix-PHY-discovery-for-FS-SFP-10G-T-module.patch b/target/linux/mvebu/patches-5.15/706-21-net-sfp-fix-PHY-discovery-for-FS-SFP-10G-T-module.patch +new file mode 100644 +index 0000000000..6fd406742a +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-21-net-sfp-fix-PHY-discovery-for-FS-SFP-10G-T-module.patch +@@ -0,0 +1,82 @@ ++From e9301af385e7864dea353f5e58cad7339dd6c718 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Tue, 19 Dec 2023 17:24:15 +0100 ++Subject: [PATCH] net: sfp: fix PHY discovery for FS SFP-10G-T module ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Commit 2f3ce7a56c6e ("net: sfp: rework the RollBall PHY waiting code") ++changed the long wait before accessing RollBall / FS modules into ++probing for PHY every 1 second, and trying 25 times. ++ ++Wei Lei reports that this does not work correctly on FS modules: when ++initializing, they may report values different from 0xffff in PHY ID ++registers for some MMDs, causing get_phy_c45_ids() to find some bogus ++MMD. ++ ++Fix this by adding the module_t_wait member back, and setting it to 4 ++seconds for FS modules. ++ ++Fixes: 2f3ce7a56c6e ("net: sfp: rework the RollBall PHY waiting code") ++Reported-by: Wei Lei <quic_leiwei@quicinc.com> ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Tested-by: Lei Wei <quic_leiwei@quicinc.com> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -276,6 +276,7 @@ struct sfp { ++ struct sfp_eeprom_id id; ++ unsigned int module_power_mW; ++ unsigned int module_t_start_up; +++ unsigned int module_t_wait; ++ unsigned int phy_t_retry; ++ ++ unsigned int rate_kbd; ++@@ -390,6 +391,12 @@ static void sfp_fixup_fs_10gt(struct sfp ++ { ++ sfp_fixup_10gbaset_30m(sfp); ++ sfp_fixup_rollball(sfp); +++ +++ /* The RollBall fixup is not enough for FS modules, the AQR chip inside +++ * them does not return 0xffff for PHY ID registers in all MMDs for the +++ * while initializing. They need a 4 second wait before accessing PHY. +++ */ +++ sfp->module_t_wait = msecs_to_jiffies(4000); ++ } ++ ++ static void sfp_fixup_halny_gsfp(struct sfp *sfp) ++@@ -2381,6 +2388,7 @@ static int sfp_sm_mod_probe(struct sfp * ++ mask |= SFP_F_RS1; ++ ++ sfp->module_t_start_up = T_START_UP; +++ sfp->module_t_wait = T_WAIT; ++ sfp->phy_t_retry = T_PHY_RETRY; ++ ++ sfp->state_ignore_mask = 0; ++@@ -2618,9 +2626,10 @@ static void sfp_sm_main(struct sfp *sfp, ++ ++ /* We need to check the TX_FAULT state, which is not defined ++ * while TX_DISABLE is asserted. The earliest we want to do ++- * anything (such as probe for a PHY) is 50ms. +++ * anything (such as probe for a PHY) is 50ms (or more on +++ * specific modules). ++ */ ++- sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT); +++ sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait); ++ break; ++ ++ case SFP_S_WAIT: ++@@ -2634,8 +2643,8 @@ static void sfp_sm_main(struct sfp *sfp, ++ * deasserting. ++ */ ++ timeout = sfp->module_t_start_up; ++- if (timeout > T_WAIT) ++- timeout -= T_WAIT; +++ if (timeout > sfp->module_t_wait) +++ timeout -= sfp->module_t_wait; ++ else ++ timeout = 1; ++ +diff --git a/target/linux/mvebu/patches-5.15/706-22-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch b/target/linux/mvebu/patches-5.15/706-22-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch +new file mode 100644 +index 0000000000..7d3210d341 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/706-22-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch +@@ -0,0 +1,43 @@ ++From 97eb5d51b4a584a60e5d096bdb6b33edc9f50d8d Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Mon, 15 Jan 2024 12:43:38 +0000 ++Subject: [PATCH] net: sfp-bus: fix SFP mode detect from bitrate ++ ++The referenced commit moved the setting of the Autoneg and pause bits ++early in sfp_parse_support(). However, we check whether the modes are ++empty before using the bitrate to set some modes. Setting these bits ++so early causes that test to always be false, preventing this working, ++and thus some modules that used to work no longer do. ++ ++Move them just before the call to the quirk. ++ ++Fixes: 8110633db49d ("net: sfp-bus: allow SFP quirks to override Autoneg and pause bits") ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com> ++Link: https://lore.kernel.org/r/E1rPMJW-001Ahf-L0@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/sfp-bus.c +++++ b/drivers/net/phy/sfp-bus.c ++@@ -151,10 +151,6 @@ void sfp_parse_support(struct sfp_bus *b ++ unsigned int br_min, br_nom, br_max; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, }; ++ ++- phylink_set(modes, Autoneg); ++- phylink_set(modes, Pause); ++- phylink_set(modes, Asym_Pause); ++- ++ /* Decode the bitrate information to MBd */ ++ br_min = br_nom = br_max = 0; ++ if (id->base.br_nominal) { ++@@ -329,6 +325,10 @@ void sfp_parse_support(struct sfp_bus *b ++ } ++ } ++ +++ phylink_set(modes, Autoneg); +++ phylink_set(modes, Pause); +++ phylink_set(modes, Asym_Pause); +++ ++ if (bus->sfp_quirk && bus->sfp_quirk->modes) ++ bus->sfp_quirk->modes(id, modes, interfaces); ++ +diff --git a/target/linux/mvebu/patches-5.15/707-01-net-phy-marvell10g-add-downshift-tunable-support.patch b/target/linux/mvebu/patches-5.15/707-01-net-phy-marvell10g-add-downshift-tunable-support.patch +new file mode 100644 +index 0000000000..e00b1a406c +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-01-net-phy-marvell10g-add-downshift-tunable-support.patch +@@ -0,0 +1,212 @@ ++From 4075a6a047bbb4c67a0670f4ad981cfc5ffb5c76 Mon Sep 17 00:00:00 2001 ++From: Russell King <rmk+kernel@armlinux.org.uk> ++Date: Wed, 29 Sep 2021 16:28:53 +0100 ++Subject: [PATCH] net: phy: marvell10g: add downshift tunable support ++ ++Add support for the downshift tunable for the Marvell 88x3310 PHY. ++Downshift is only usable with firmware 0.3.5.0 and later. ++ ++Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/marvell10g.c +++++ b/drivers/net/phy/marvell10g.c ++@@ -22,6 +22,7 @@ ++ * If both the fiber and copper ports are connected, the first to gain ++ * link takes priority and the other port is completely locked out. ++ */ +++#include <linux/bitfield.h> ++ #include <linux/ctype.h> ++ #include <linux/delay.h> ++ #include <linux/hwmon.h> ++@@ -33,6 +34,8 @@ ++ #define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe ++ #define MV_PHY_ALASKA_NBT_QUIRK_REV (MARVELL_PHY_ID_88X3310 | 0xa) ++ +++#define MV_VERSION(a,b,c,d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) +++ ++ enum { ++ MV_PMA_FW_VER0 = 0xc011, ++ MV_PMA_FW_VER1 = 0xc012, ++@@ -62,6 +65,15 @@ enum { ++ MV_PCS_CSCR1_MDIX_MDIX = 0x0020, ++ MV_PCS_CSCR1_MDIX_AUTO = 0x0060, ++ +++ MV_PCS_DSC1 = 0x8003, +++ MV_PCS_DSC1_ENABLE = BIT(9), +++ MV_PCS_DSC1_10GBT = 0x01c0, +++ MV_PCS_DSC1_1GBR = 0x0038, +++ MV_PCS_DSC1_100BTX = 0x0007, +++ MV_PCS_DSC2 = 0x8004, +++ MV_PCS_DSC2_2P5G = 0xf000, +++ MV_PCS_DSC2_5G = 0x0f00, +++ ++ MV_PCS_CSSR1 = 0x8008, ++ MV_PCS_CSSR1_SPD1_MASK = 0xc000, ++ MV_PCS_CSSR1_SPD1_SPD2 = 0xc000, ++@@ -130,6 +142,7 @@ enum { ++ }; ++ ++ struct mv3310_chip { +++ bool (*has_downshift)(struct phy_device *phydev); ++ void (*init_supported_interfaces)(unsigned long *mask); ++ int (*get_mactype)(struct phy_device *phydev); ++ int (*set_mactype)(struct phy_device *phydev, int mactype); ++@@ -145,6 +158,7 @@ struct mv3310_priv { ++ DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX); ++ ++ u32 firmware_ver; +++ bool has_downshift; ++ bool rate_match; ++ phy_interface_t const_interface; ++ ++@@ -344,6 +358,71 @@ static int mv3310_reset(struct phy_devic ++ 5000, 100000, true); ++ } ++ +++static int mv3310_get_downshift(struct phy_device *phydev, u8 *ds) +++{ +++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); +++ int val; +++ +++ if (!priv->has_downshift) +++ return -EOPNOTSUPP; +++ +++ val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1); +++ if (val < 0) +++ return val; +++ +++ if (val & MV_PCS_DSC1_ENABLE) +++ /* assume that all fields are the same */ +++ *ds = 1 + FIELD_GET(MV_PCS_DSC1_10GBT, (u16)val); +++ else +++ *ds = DOWNSHIFT_DEV_DISABLE; +++ +++ return 0; +++} +++ +++static int mv3310_set_downshift(struct phy_device *phydev, u8 ds) +++{ +++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); +++ u16 val; +++ int err; +++ +++ if (!priv->has_downshift) +++ return -EOPNOTSUPP; +++ +++ if (ds == DOWNSHIFT_DEV_DISABLE) +++ return phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1, +++ MV_PCS_DSC1_ENABLE); +++ +++ /* DOWNSHIFT_DEV_DEFAULT_COUNT is confusing. It looks like it should +++ * set the default settings for the PHY. However, it is used for +++ * "ethtool --set-phy-tunable ethN downshift on". The intention is +++ * to enable downshift at a default number of retries. The default +++ * settings for 88x3310 are for two retries with downshift disabled. +++ * So let's use two retries with downshift enabled. +++ */ +++ if (ds == DOWNSHIFT_DEV_DEFAULT_COUNT) +++ ds = 2; +++ +++ if (ds > 8) +++ return -E2BIG; +++ +++ ds -= 1; +++ val = FIELD_PREP(MV_PCS_DSC2_2P5G, ds); +++ val |= FIELD_PREP(MV_PCS_DSC2_5G, ds); +++ err = phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC2, +++ MV_PCS_DSC2_2P5G | MV_PCS_DSC2_5G, val); +++ if (err < 0) +++ return err; +++ +++ val = MV_PCS_DSC1_ENABLE; +++ val |= FIELD_PREP(MV_PCS_DSC1_10GBT, ds); +++ val |= FIELD_PREP(MV_PCS_DSC1_1GBR, ds); +++ val |= FIELD_PREP(MV_PCS_DSC1_100BTX, ds); +++ +++ return phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1, +++ MV_PCS_DSC1_ENABLE | MV_PCS_DSC1_10GBT | +++ MV_PCS_DSC1_1GBR | MV_PCS_DSC1_100BTX, val); +++} +++ ++ static int mv3310_get_edpd(struct phy_device *phydev, u16 *edpd) ++ { ++ int val; ++@@ -463,6 +542,9 @@ static int mv3310_probe(struct phy_devic ++ priv->firmware_ver >> 24, (priv->firmware_ver >> 16) & 255, ++ (priv->firmware_ver >> 8) & 255, priv->firmware_ver & 255); ++ +++ if (chip->has_downshift) +++ priv->has_downshift = chip->has_downshift(phydev); +++ ++ /* Powering down the port when not in use saves about 600mW */ ++ ret = mv3310_power_down(phydev); ++ if (ret) ++@@ -728,7 +810,16 @@ static int mv3310_config_init(struct phy ++ } ++ ++ /* Enable EDPD mode - saving 600mW */ ++- return mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS); +++ err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS); +++ if (err) +++ return err; +++ +++ /* Allow downshift */ +++ err = mv3310_set_downshift(phydev, DOWNSHIFT_DEV_DEFAULT_COUNT); +++ if (err && err != -EOPNOTSUPP) +++ return err; +++ +++ return 0; ++ } ++ ++ static int mv3310_get_features(struct phy_device *phydev) ++@@ -998,6 +1089,8 @@ static int mv3310_get_tunable(struct phy ++ struct ethtool_tunable *tuna, void *data) ++ { ++ switch (tuna->id) { +++ case ETHTOOL_PHY_DOWNSHIFT: +++ return mv3310_get_downshift(phydev, data); ++ case ETHTOOL_PHY_EDPD: ++ return mv3310_get_edpd(phydev, data); ++ default: ++@@ -1009,6 +1102,8 @@ static int mv3310_set_tunable(struct phy ++ struct ethtool_tunable *tuna, const void *data) ++ { ++ switch (tuna->id) { +++ case ETHTOOL_PHY_DOWNSHIFT: +++ return mv3310_set_downshift(phydev, *(u8 *)data); ++ case ETHTOOL_PHY_EDPD: ++ return mv3310_set_edpd(phydev, *(u16 *)data); ++ default: ++@@ -1016,6 +1111,14 @@ static int mv3310_set_tunable(struct phy ++ } ++ } ++ +++static bool mv3310_has_downshift(struct phy_device *phydev) +++{ +++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); +++ +++ /* Fails to downshift with firmware older than v0.3.5.0 */ +++ return priv->firmware_ver >= MV_VERSION(0,3,5,0); +++} +++ ++ static void mv3310_init_supported_interfaces(unsigned long *mask) ++ { ++ __set_bit(PHY_INTERFACE_MODE_SGMII, mask); ++@@ -1055,6 +1158,7 @@ static void mv2111_init_supported_interf ++ } ++ ++ static const struct mv3310_chip mv3310_type = { +++ .has_downshift = mv3310_has_downshift, ++ .init_supported_interfaces = mv3310_init_supported_interfaces, ++ .get_mactype = mv3310_get_mactype, ++ .set_mactype = mv3310_set_mactype, ++@@ -1067,6 +1171,7 @@ static const struct mv3310_chip mv3310_t ++ }; ++ ++ static const struct mv3310_chip mv3340_type = { +++ .has_downshift = mv3310_has_downshift, ++ .init_supported_interfaces = mv3340_init_supported_interfaces, ++ .get_mactype = mv3310_get_mactype, ++ .set_mactype = mv3310_set_mactype, +diff --git a/target/linux/mvebu/patches-5.15/707-02-net-phylink-use-for_each_set_bit.patch b/target/linux/mvebu/patches-5.15/707-02-net-phylink-use-for_each_set_bit.patch +new file mode 100644 +index 0000000000..77a47a9930 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-02-net-phylink-use-for_each_set_bit.patch +@@ -0,0 +1,43 @@ ++From 335662889f5a5f4d5668ed6c8b5fd58913d91d15 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Sun, 19 Nov 2023 21:07:43 +0000 ++Subject: [PATCH] net: phylink: use for_each_set_bit() ++ ++Use for_each_set_bit() rather than open coding the for() test_bit() ++loop. ++ ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com> ++Link: https://lore.kernel.org/r/E1r4p15-00Cpxe-C7@rmk-PC.armlinux.org.uk ++Signed-off-by: Paolo Abeni <pabeni@redhat.com> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -493,18 +493,16 @@ static int phylink_validate_mask(struct ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, }; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(s); ++ struct phylink_link_state t; ++- int intf; +++ int interface; ++ ++- for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) { ++- if (test_bit(intf, interfaces)) { ++- linkmode_copy(s, supported); +++ for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) { +++ linkmode_copy(s, supported); ++ ++- t = *state; ++- t.interface = intf; ++- if (!phylink_validate_mac_and_pcs(pl, s, &t)) { ++- linkmode_or(all_s, all_s, s); ++- linkmode_or(all_adv, all_adv, t.advertising); ++- } +++ t = *state; +++ t.interface = interface; +++ if (!phylink_validate_mac_and_pcs(pl, s, &t)) { +++ linkmode_or(all_s, all_s, s); +++ linkmode_or(all_adv, all_adv, t.advertising); ++ } ++ } ++ +diff --git a/target/linux/mvebu/patches-5.15/707-03-net-phylink-Support-disabling-autonegotiation-for-PC.patch b/target/linux/mvebu/patches-5.15/707-03-net-phylink-Support-disabling-autonegotiation-for-PC.patch +new file mode 100644 +index 0000000000..4e8cf853b4 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-03-net-phylink-Support-disabling-autonegotiation-for-PC.patch +@@ -0,0 +1,79 @@ ++From 92817dad7dcb781561dcebbf1b19a177774d84c2 Mon Sep 17 00:00:00 2001 ++From: Robert Hancock <robert.hancock@calian.com> ++Date: Tue, 19 Oct 2021 11:24:50 +0100 ++Subject: [PATCH] net: phylink: Support disabling autonegotiation for PCS ++ ++The auto-negotiation state in the PCS as set by ++phylink_mii_c22_pcs_config was previously always enabled when the ++driver is configured for in-band autonegotiation, even if ++autonegotiation was disabled on the interface with ethtool. Update the ++code to set the BMCR_ANENABLE bit based on the interface's ++autonegotiation enabled state. ++ ++Update phylink_mii_c22_pcs_get_state to not check ++autonegotiation-related fields when autonegotiation is disabled. ++ ++Update phylink_mac_pcs_get_state to initialize the state based on the ++interface's configured speed, duplex and pause parameters rather than ++to unknown when autonegotiation is disabled, before calling the ++driver's pcs_get_state functions, as they are not likely to provide ++meaningful data for these fields when autonegotiation is disabled. In ++this case the driver is really just filling in the link state field. ++ ++Note that in cases where there is a downstream PHY connected, such as ++with SGMII and a copper PHY, the configuration set by ethtool is ++handled by phy_ethtool_ksettings_set and not propagated to the PCS. ++This is correct since SGMII or 1000Base-X autonegotiation with the PCS ++should normally still be used even if the copper side has disabled it. ++ ++Signed-off-by: Robert Hancock <robert.hancock@calian.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -930,9 +930,15 @@ static void phylink_mac_pcs_get_state(st ++ linkmode_zero(state->lp_advertising); ++ state->interface = pl->link_config.interface; ++ state->an_enabled = pl->link_config.an_enabled; ++- state->speed = SPEED_UNKNOWN; ++- state->duplex = DUPLEX_UNKNOWN; ++- state->pause = MLO_PAUSE_NONE; +++ if (state->an_enabled) { +++ state->speed = SPEED_UNKNOWN; +++ state->duplex = DUPLEX_UNKNOWN; +++ state->pause = MLO_PAUSE_NONE; +++ } else { +++ state->speed = pl->link_config.speed; +++ state->duplex = pl->link_config.duplex; +++ state->pause = pl->link_config.pause; +++ } ++ state->an_complete = 0; ++ state->link = 1; ++ ++@@ -3091,7 +3097,10 @@ void phylink_mii_c22_pcs_get_state(struc ++ ++ state->link = !!(bmsr & BMSR_LSTATUS); ++ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); ++- if (!state->link) +++ /* If there is no link or autonegotiation is disabled, the LP advertisement +++ * data is not meaningful, so don't go any further. +++ */ +++ if (!state->link || !state->an_enabled) ++ return; ++ ++ switch (state->interface) { ++@@ -3214,7 +3223,12 @@ int phylink_mii_c22_pcs_config(struct md ++ changed = ret > 0; ++ ++ /* Ensure ISOLATE bit is disabled */ ++- bmcr = mode == MLO_AN_INBAND ? BMCR_ANENABLE : 0; +++ if (mode == MLO_AN_INBAND && +++ linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising)) +++ bmcr = BMCR_ANENABLE; +++ else +++ bmcr = 0; +++ ++ ret = mdiobus_modify(pcs->bus, pcs->addr, MII_BMCR, ++ BMCR_ANENABLE | BMCR_ISOLATE, bmcr); ++ if (ret < 0) +diff --git a/target/linux/mvebu/patches-5.15/707-04-net-phy-Introduce-QUSGMII-PHY-mode.patch b/target/linux/mvebu/patches-5.15/707-04-net-phy-Introduce-QUSGMII-PHY-mode.patch +new file mode 100644 +index 0000000000..cfccdb4636 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-04-net-phy-Introduce-QUSGMII-PHY-mode.patch +@@ -0,0 +1,117 @@ ++From 5e61fe157a27afc7c0d4f7bcbceefdca536c015f Mon Sep 17 00:00:00 2001 ++From: Maxime Chevallier <maxime.chevallier@bootlin.com> ++Date: Wed, 17 Aug 2022 14:32:52 +0200 ++Subject: [PATCH] net: phy: Introduce QUSGMII PHY mode ++ ++The QUSGMII mode is a derivative of Cisco's USXGMII standard. This ++standard is pretty similar to SGMII, but allows for faster speeds, and ++has the build-in bits for Quad and Octa variants (like QSGMII). ++ ++The main difference with SGMII/QSGMII is that USXGMII/QUSGMII re-uses ++the preamble to carry various information, named 'Extensions'. ++ ++As of today, the USXGMII standard only mentions the "PCH" extension, ++which is used to convey timestamps, allowing in-band signaling of PTP ++timestamps without having to modify the frame itself. ++ ++This commit adds support for that mode. When no extension is in use, it ++behaves exactly like QSGMII, although it's not compatible with QSGMII. ++ ++Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++From 5e61fe157a27afc7c0d4f7bcbceefdca536c015f Mon Sep 17 00:00:00 2001 ++From: Maxime Chevallier <maxime.chevallier@bootlin.com> ++Date: Wed, 17 Aug 2022 14:32:52 +0200 ++Subject: [PATCH] net: phy: Introduce QUSGMII PHY mode ++ ++The QUSGMII mode is a derivative of Cisco's USXGMII standard. This ++standard is pretty similar to SGMII, but allows for faster speeds, and ++has the build-in bits for Quad and Octa variants (like QSGMII). ++ ++The main difference with SGMII/QSGMII is that USXGMII/QUSGMII re-uses ++the preamble to carry various information, named 'Extensions'. ++ ++As of today, the USXGMII standard only mentions the "PCH" extension, ++which is used to convey timestamps, allowing in-band signaling of PTP ++timestamps without having to modify the frame itself. ++ ++This commit adds support for that mode. When no extension is in use, it ++behaves exactly like QSGMII, although it's not compatible with QSGMII. ++ ++Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/Documentation/networking/phy.rst +++++ b/Documentation/networking/phy.rst ++@@ -303,6 +303,15 @@ Some of the interface modes are describe ++ rate of 125Mpbs using a 4B/5B encoding scheme, resulting in an underlying ++ data rate of 100Mpbs. ++ +++``PHY_INTERFACE_MODE_QUSGMII`` +++ This defines the Cisco the Quad USGMII mode, which is the Quad variant of +++ the USGMII (Universal SGMII) link. It's very similar to QSGMII, but uses +++ a Packet Control Header (PCH) instead of the 7 bytes preamble to carry not +++ only the port id, but also so-called "extensions". The only documented +++ extension so-far in the specification is the inclusion of timestamps, for +++ PTP-enabled PHYs. This mode isn't compatible with QSGMII, but offers the +++ same capabilities in terms of link speed and negociation. +++ ++ Pause frames / flow control ++ =========================== ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -396,6 +396,7 @@ void phylink_get_linkmodes(unsigned long ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_QSGMII: +++ case PHY_INTERFACE_MODE_QUSGMII: ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_GMII: ++ caps |= MAC_1000HD | MAC_1000FD; ++@@ -660,6 +661,7 @@ static int phylink_parse_mode(struct phy ++ switch (pl->link_config.interface) { ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_QSGMII: +++ case PHY_INTERFACE_MODE_QUSGMII: ++ phylink_set(pl->supported, 10baseT_Half); ++ phylink_set(pl->supported, 10baseT_Full); ++ phylink_set(pl->supported, 100baseT_Half); ++@@ -3114,6 +3116,7 @@ void phylink_mii_c22_pcs_get_state(struc ++ ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_QSGMII: +++ case PHY_INTERFACE_MODE_QUSGMII: ++ phylink_decode_sgmii_word(state, lpa); ++ break; ++ ++--- a/include/linux/phy.h +++++ b/include/linux/phy.h ++@@ -115,6 +115,7 @@ extern const int phy_10gbit_features_arr ++ * @PHY_INTERFACE_MODE_25GBASER: 25G BaseR ++ * @PHY_INTERFACE_MODE_USXGMII: Universal Serial 10GE MII ++ * @PHY_INTERFACE_MODE_10GKR: 10GBASE-KR - with Clause 73 AN +++ * @PHY_INTERFACE_MODE_QUSGMII: Quad Universal SGMII ++ * @PHY_INTERFACE_MODE_MAX: Book keeping ++ * ++ * Describes the interface between the MAC and PHY. ++@@ -152,6 +153,7 @@ typedef enum { ++ PHY_INTERFACE_MODE_USXGMII, ++ /* 10GBASE-KR - with Clause 73 AN */ ++ PHY_INTERFACE_MODE_10GKR, +++ PHY_INTERFACE_MODE_QUSGMII, ++ PHY_INTERFACE_MODE_MAX, ++ } phy_interface_t; ++ ++@@ -267,6 +269,8 @@ static inline const char *phy_modes(phy_ ++ return "10gbase-kr"; ++ case PHY_INTERFACE_MODE_100BASEX: ++ return "100base-x"; +++ case PHY_INTERFACE_MODE_QUSGMII: +++ return "qusgmii"; ++ default: ++ return "unknown"; ++ } +diff --git a/target/linux/mvebu/patches-5.15/707-05-net-phy-Add-1000BASE-KX-interface-mode.patch b/target/linux/mvebu/patches-5.15/707-05-net-phy-Add-1000BASE-KX-interface-mode.patch +new file mode 100644 +index 0000000000..69b824a4a6 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-05-net-phy-Add-1000BASE-KX-interface-mode.patch +@@ -0,0 +1,80 @@ ++From 05ad5d4581c3c1cc724fe50d4652833fb9f3037b Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Fri, 2 Sep 2022 18:02:39 -0400 ++Subject: [PATCH] net: phy: Add 1000BASE-KX interface mode ++ ++Add 1000BASE-KX interface mode. This 1G backplane ethernet as described in ++clause 70. Clause 73 autonegotiation is mandatory, and only full duplex ++operation is supported. ++ ++Although at the PMA level this interface mode is identical to ++1000BASE-X, it uses a different form of in-band autonegation. This ++justifies a separate interface mode, since the interface mode (along ++with the MLO_AN_* autonegotiation mode) sets the type of autonegotiation ++which will be used on a link. This results in more than just electrical ++differences between the link modes. ++ ++With regard to 1000BASE-X, 1000BASE-KX holds a similar position to ++SGMII: same signaling, but different autonegotiation. PCS drivers ++(which typically handle in-band autonegotiation) may only support ++1000BASE-X, and not 1000BASE-KX. Similarly, the phy mode is used to ++configure serdes phys with phy_set_mode_ext. Due to the different ++electrical standards (SFI or XFI vs Clause 70), they will likely want to ++use different configuration. Adding a phy interface mode for ++1000BASE-KX helps simplify configuration in these areas. ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/Documentation/networking/phy.rst +++++ b/Documentation/networking/phy.rst ++@@ -312,6 +312,12 @@ Some of the interface modes are describe ++ PTP-enabled PHYs. This mode isn't compatible with QSGMII, but offers the ++ same capabilities in terms of link speed and negociation. ++ +++``PHY_INTERFACE_MODE_1000BASEKX`` +++ This is 1000BASE-X as defined by IEEE 802.3 Clause 36 with Clause 73 +++ autonegotiation. Generally, it will be used with a Clause 70 PMD. To +++ contrast with the 1000BASE-X phy mode used for Clause 38 and 39 PMDs, this +++ interface mode has different autonegotiation and only supports full duplex. +++ ++ Pause frames / flow control ++ =========================== ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -419,6 +419,7 @@ void phylink_get_linkmodes(unsigned long ++ case PHY_INTERFACE_MODE_1000BASEX: ++ caps |= MAC_1000HD; ++ fallthrough; +++ case PHY_INTERFACE_MODE_1000BASEKX: ++ case PHY_INTERFACE_MODE_TRGMII: ++ caps |= MAC_1000FD; ++ break; ++--- a/include/linux/phy.h +++++ b/include/linux/phy.h ++@@ -116,6 +116,7 @@ extern const int phy_10gbit_features_arr ++ * @PHY_INTERFACE_MODE_USXGMII: Universal Serial 10GE MII ++ * @PHY_INTERFACE_MODE_10GKR: 10GBASE-KR - with Clause 73 AN ++ * @PHY_INTERFACE_MODE_QUSGMII: Quad Universal SGMII +++ * @PHY_INTERFACE_MODE_1000BASEKX: 1000Base-KX - with Clause 73 AN ++ * @PHY_INTERFACE_MODE_MAX: Book keeping ++ * ++ * Describes the interface between the MAC and PHY. ++@@ -154,6 +155,7 @@ typedef enum { ++ /* 10GBASE-KR - with Clause 73 AN */ ++ PHY_INTERFACE_MODE_10GKR, ++ PHY_INTERFACE_MODE_QUSGMII, +++ PHY_INTERFACE_MODE_1000BASEKX, ++ PHY_INTERFACE_MODE_MAX, ++ } phy_interface_t; ++ ++@@ -251,6 +253,8 @@ static inline const char *phy_modes(phy_ ++ return "trgmii"; ++ case PHY_INTERFACE_MODE_1000BASEX: ++ return "1000base-x"; +++ case PHY_INTERFACE_MODE_1000BASEKX: +++ return "1000base-kx"; ++ case PHY_INTERFACE_MODE_2500BASEX: ++ return "2500base-x"; ++ case PHY_INTERFACE_MODE_5GBASER: +diff --git a/target/linux/mvebu/patches-5.15/707-06-1-net-phylink-Document-MAC_-A-SYM_PAUSE.patch b/target/linux/mvebu/patches-5.15/707-06-1-net-phylink-Document-MAC_-A-SYM_PAUSE.patch +new file mode 100644 +index 0000000000..7fa798f2bc +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-06-1-net-phylink-Document-MAC_-A-SYM_PAUSE.patch +@@ -0,0 +1,66 @@ ++From 72bc36956f73ac54f19a7ac7302fb274069bec18 Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:28 -0400 ++Subject: [PATCH] net: phylink: Document MAC_(A)SYM_PAUSE ++ ++This documents the possible MLO_PAUSE_* settings which can result from ++different combinations of MAC_(A)SYM_PAUSE. Special note is paid to ++settings which can result from user configuration (MLO_PAUSE_AN). The ++autonegotiation results are more-or-less a direct consequence of IEEE ++802.3 Table 28B-2. ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++From 72bc36956f73ac54f19a7ac7302fb274069bec18 Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:28 -0400 ++Subject: [PATCH] net: phylink: Document MAC_(A)SYM_PAUSE ++ ++This documents the possible MLO_PAUSE_* settings which can result from ++different combinations of MAC_(A)SYM_PAUSE. Special note is paid to ++settings which can result from user configuration (MLO_PAUSE_AN). The ++autonegotiation results are more-or-less a direct consequence of IEEE ++802.3 Table 28B-2. ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/include/linux/phylink.h +++++ b/include/linux/phylink.h ++@@ -21,6 +21,35 @@ enum { ++ MLO_AN_FIXED, /* Fixed-link mode */ ++ MLO_AN_INBAND, /* In-band protocol */ ++ +++ /* MAC_SYM_PAUSE and MAC_ASYM_PAUSE are used when configuring our +++ * autonegotiation advertisement. They correspond to the PAUSE and +++ * ASM_DIR bits defined by 802.3, respectively. +++ * +++ * The following table lists the values of tx_pause and rx_pause which +++ * might be requested in mac_link_up. The exact values depend on either +++ * the results of autonegotation (if MLO_PAUSE_AN is set) or user +++ * configuration (if MLO_PAUSE_AN is not set). +++ * +++ * MAC_SYM_PAUSE MAC_ASYM_PAUSE MLO_PAUSE_AN tx_pause/rx_pause +++ * ============= ============== ============ ================== +++ * 0 0 0 0/0 +++ * 0 0 1 0/0 +++ * 0 1 0 0/0, 0/1, 1/0, 1/1 +++ * 0 1 1 0/0, 1/0 +++ * 1 0 0 0/0, 1/1 +++ * 1 0 1 0/0, 1/1 +++ * 1 1 0 0/0, 0/1, 1/0, 1/1 +++ * 1 1 1 0/0, 0/1, 1/1 +++ * +++ * If you set MAC_ASYM_PAUSE, the user may request any combination of +++ * tx_pause and rx_pause. You do not have to support these +++ * combinations. +++ * +++ * However, you should support combinations of tx_pause and rx_pause +++ * which might be the result of autonegotation. For example, don't set +++ * MAC_SYM_PAUSE unless your device can support tx_pause and rx_pause +++ * at the same time. +++ */ ++ MAC_SYM_PAUSE = BIT(0), ++ MAC_ASYM_PAUSE = BIT(1), ++ MAC_10HD = BIT(2), +diff --git a/target/linux/mvebu/patches-5.15/707-06-2-net-phylink-Export-phylink_caps_to_linkmodes.patch b/target/linux/mvebu/patches-5.15/707-06-2-net-phylink-Export-phylink_caps_to_linkmodes.patch +new file mode 100644 +index 0000000000..5a34f22b34 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-06-2-net-phylink-Export-phylink_caps_to_linkmodes.patch +@@ -0,0 +1,62 @@ ++From 606116529ab2d12e93bf751f74ed50a621b46846 Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:29 -0400 ++Subject: [PATCH] net: phylink: Export phylink_caps_to_linkmodes ++ ++This function is convenient for MAC drivers. They can use it to add or ++remove particular link modes based on capabilities (such as if half ++duplex is not supported for a particular interface mode). ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++From 606116529ab2d12e93bf751f74ed50a621b46846 Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:29 -0400 ++Subject: [PATCH] net: phylink: Export phylink_caps_to_linkmodes ++ ++This function is convenient for MAC drivers. They can use it to add or ++remove particular link modes based on capabilities (such as if half ++duplex is not supported for a particular interface mode). ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -233,8 +233,15 @@ static int phylink_validate_mac_and_pcs( ++ return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; ++ } ++ ++-static void phylink_caps_to_linkmodes(unsigned long *linkmodes, ++- unsigned long caps) +++/** +++ * phylink_caps_to_linkmodes() - Convert capabilities to ethtool link modes +++ * @linkmodes: ethtool linkmode mask (must be already initialised) +++ * @caps: bitmask of MAC capabilities +++ * +++ * Set all possible pause, speed and duplex linkmodes in @linkmodes that are +++ * supported by the @caps. @linkmodes must have been initialised previously. +++ */ +++void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps) ++ { ++ if (caps & MAC_SYM_PAUSE) ++ __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes); ++@@ -370,6 +377,7 @@ static void phylink_caps_to_linkmodes(un ++ __set_bit(ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, linkmodes); ++ } ++ } +++EXPORT_SYMBOL_GPL(phylink_caps_to_linkmodes); ++ ++ /** ++ * phylink_get_linkmodes() - get acceptable link modes ++--- a/include/linux/phylink.h +++++ b/include/linux/phylink.h ++@@ -556,6 +556,7 @@ void pcs_link_up(struct phylink_pcs *pcs ++ phy_interface_t interface, int speed, int duplex); ++ #endif ++ +++void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps); ++ void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface, ++ unsigned long mac_capabilities); ++ void phylink_generic_validate(struct phylink_config *config, +diff --git a/target/linux/mvebu/patches-5.15/707-06-3-net-phylink-Generate-caps-and-convert-to-linkmodes-s.patch b/target/linux/mvebu/patches-5.15/707-06-3-net-phylink-Generate-caps-and-convert-to-linkmodes-s.patch +new file mode 100644 +index 0000000000..d453e5da3d +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-06-3-net-phylink-Generate-caps-and-convert-to-linkmodes-s.patch +@@ -0,0 +1,113 @@ ++From 3e6eab8f3ef93cd78cd4b67f497ef6035eb073ad Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:30 -0400 ++Subject: [PATCH] net: phylink: Generate caps and convert to linkmodes ++ separately ++ ++If we call phylink_caps_to_linkmodes directly from ++phylink_get_linkmodes, it is difficult to re-use this functionality in ++MAC drivers. This is because MAC drivers must then work with an ethtool ++linkmode bitmap, instead of with mac capabilities. Instead, let the ++caller of phylink_get_linkmodes do the conversion. To reflect this ++change, rename the function to phylink_get_capabilities. ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++From 3e6eab8f3ef93cd78cd4b67f497ef6035eb073ad Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:30 -0400 ++Subject: [PATCH] net: phylink: Generate caps and convert to linkmodes ++ separately ++ ++If we call phylink_caps_to_linkmodes directly from ++phylink_get_linkmodes, it is difficult to re-use this functionality in ++MAC drivers. This is because MAC drivers must then work with an ethtool ++linkmode bitmap, instead of with mac capabilities. Instead, let the ++caller of phylink_get_linkmodes do the conversion. To reflect this ++change, rename the function to phylink_get_capabilities. ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++From 3e6eab8f3ef93cd78cd4b67f497ef6035eb073ad Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:30 -0400 ++Subject: [PATCH] net: phylink: Generate caps and convert to linkmodes ++ separately ++ ++If we call phylink_caps_to_linkmodes directly from ++phylink_get_linkmodes, it is difficult to re-use this functionality in ++MAC drivers. This is because MAC drivers must then work with an ethtool ++linkmode bitmap, instead of with mac capabilities. Instead, let the ++caller of phylink_get_linkmodes do the conversion. To reflect this ++change, rename the function to phylink_get_capabilities. ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -380,17 +380,15 @@ void phylink_caps_to_linkmodes(unsigned ++ EXPORT_SYMBOL_GPL(phylink_caps_to_linkmodes); ++ ++ /** ++- * phylink_get_linkmodes() - get acceptable link modes ++- * @linkmodes: ethtool linkmode mask (must be already initialised) +++ * phylink_get_capabilities() - get capabilities for a given MAC ++ * @interface: phy interface mode defined by &typedef phy_interface_t ++ * @mac_capabilities: bitmask of MAC capabilities ++ * ++- * Set all possible pause, speed and duplex linkmodes in @linkmodes that ++- * are supported by the @interface mode and @mac_capabilities. @linkmodes ++- * must have been initialised previously. +++ * Get the MAC capabilities that are supported by the @interface mode and +++ * @mac_capabilities. ++ */ ++-void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface, ++- unsigned long mac_capabilities) +++unsigned long phylink_get_capabilities(phy_interface_t interface, +++ unsigned long mac_capabilities) ++ { ++ unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE; ++ ++@@ -466,9 +464,9 @@ void phylink_get_linkmodes(unsigned long ++ break; ++ } ++ ++- phylink_caps_to_linkmodes(linkmodes, caps & mac_capabilities); +++ return caps & mac_capabilities; ++ } ++-EXPORT_SYMBOL_GPL(phylink_get_linkmodes); +++EXPORT_SYMBOL_GPL(phylink_get_capabilities); ++ ++ /** ++ * phylink_generic_validate() - generic validate() callback implementation ++@@ -485,10 +483,13 @@ void phylink_generic_validate(struct phy ++ struct phylink_link_state *state) ++ { ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; +++ unsigned long caps; ++ ++ phylink_set_port_modes(mask); ++ phylink_set(mask, Autoneg); ++- phylink_get_linkmodes(mask, state->interface, config->mac_capabilities); +++ caps = phylink_get_capabilities(state->interface, +++ config->mac_capabilities); +++ phylink_caps_to_linkmodes(mask, caps); ++ ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); ++--- a/include/linux/phylink.h +++++ b/include/linux/phylink.h ++@@ -557,8 +557,8 @@ void pcs_link_up(struct phylink_pcs *pcs ++ #endif ++ ++ void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps); ++-void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface, ++- unsigned long mac_capabilities); +++unsigned long phylink_get_capabilities(phy_interface_t interface, +++ unsigned long mac_capabilities); ++ void phylink_generic_validate(struct phylink_config *config, ++ unsigned long *supported, ++ struct phylink_link_state *state); +diff --git a/target/linux/mvebu/patches-5.15/707-06-4-net-phy-Add-support-for-rate-matching.patch b/target/linux/mvebu/patches-5.15/707-06-4-net-phy-Add-support-for-rate-matching.patch +new file mode 100644 +index 0000000000..902431a69c +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-06-4-net-phy-Add-support-for-rate-matching.patch +@@ -0,0 +1,284 @@ ++From 0c3e10cb44232833a50cb8e3e784c432906a60c1 Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:31 -0400 ++Subject: [PATCH] net: phy: Add support for rate matching ++ ++This adds support for rate matching (also known as rate adaptation) to ++the phy subsystem. The general idea is that the phy interface runs at ++one speed, and the MAC throttles the rate at which it sends packets to ++the link speed. There's a good overview of several techniques for ++achieving this at [1]. This patch adds support for three: pause-frame ++based (such as in Aquantia phys), CRS-based (such as in 10PASS-TS and ++2BASE-TL), and open-loop-based (such as in 10GBASE-W). ++ ++This patch makes a few assumptions and a few non assumptions about the ++types of rate matching available. First, it assumes that different phys ++may use different forms of rate matching. Second, it assumes that phys ++can use rate matching for any of their supported link speeds (e.g. if a ++phy supports 10BASE-T and XGMII, then it can adapt XGMII to 10BASE-T). ++Third, it does not assume that all interface modes will use the same ++form of rate matching. Fourth, it does not assume that all phy devices ++will support rate matching (even if some do). Relaxing or strengthening ++these (non-)assumptions could result in a different API. For example, if ++all interface modes were assumed to use the same form of rate matching, ++then a bitmask of interface modes supportting rate matching would ++suffice. ++ ++For some better visibility into the process, the current rate matching ++mode is exposed as part of the ethtool ksettings. For the moment, only ++read access is supported. I'm not sure what userspace might want to ++configure yet (disable it altogether, disable just one mode, specify the ++mode to use, etc.). For the moment, since only pause-based rate ++adaptation support is added in the next few commits, rate matching can ++be disabled altogether by adjusting the advertisement. ++ ++802.3 calls this feature "rate adaptation" in clause 49 (10GBASE-R) and ++"rate matching" in clause 61 (10PASS-TL and 2BASE-TS). Aquantia also calls ++this feature "rate adaptation". I chose "rate matching" because it is ++shorter, and because Russell doesn't think "adaptation" is correct in this ++context. ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/Documentation/networking/ethtool-netlink.rst +++++ b/Documentation/networking/ethtool-netlink.rst ++@@ -418,6 +418,7 @@ Kernel response contents: ++ ``ETHTOOL_A_LINKMODES_DUPLEX`` u8 duplex mode ++ ``ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG`` u8 Master/slave port mode ++ ``ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE`` u8 Master/slave port state +++ ``ETHTOOL_A_LINKMODES_RATE_MATCHING`` u8 PHY rate matching ++ ========================================== ====== ========================== ++ ++ For ``ETHTOOL_A_LINKMODES_OURS``, value represents advertised modes and mask ++@@ -441,6 +442,7 @@ Request contents: ++ ``ETHTOOL_A_LINKMODES_SPEED`` u32 link speed (Mb/s) ++ ``ETHTOOL_A_LINKMODES_DUPLEX`` u8 duplex mode ++ ``ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG`` u8 Master/slave port mode +++ ``ETHTOOL_A_LINKMODES_RATE_MATCHING`` u8 PHY rate matching ++ ``ETHTOOL_A_LINKMODES_LANES`` u32 lanes ++ ========================================== ====== ========================== ++ ++--- a/drivers/net/phy/phy-core.c +++++ b/drivers/net/phy/phy-core.c ++@@ -58,6 +58,27 @@ const char *phy_speed_to_str(int speed) ++ EXPORT_SYMBOL_GPL(phy_speed_to_str); ++ ++ /** +++ * phy_rate_matching_to_str - Return a string describing the rate matching +++ * +++ * @rate_matching: Type of rate matching to describe +++ */ +++const char *phy_rate_matching_to_str(int rate_matching) +++{ +++ switch (rate_matching) { +++ case RATE_MATCH_NONE: +++ return "none"; +++ case RATE_MATCH_PAUSE: +++ return "pause"; +++ case RATE_MATCH_CRS: +++ return "crs"; +++ case RATE_MATCH_OPEN_LOOP: +++ return "open-loop"; +++ } +++ return "Unsupported (update phy-core.c)"; +++} +++EXPORT_SYMBOL_GPL(phy_rate_matching_to_str); +++ +++/** ++ * phy_duplex_to_str - Return string describing the duplex ++ * ++ * @duplex: Duplex setting to describe ++--- a/drivers/net/phy/phy.c +++++ b/drivers/net/phy/phy.c ++@@ -127,6 +127,33 @@ void phy_print_status(struct phy_device ++ EXPORT_SYMBOL(phy_print_status); ++ ++ /** +++ * phy_get_rate_matching - determine if rate matching is supported +++ * @phydev: The phy device to return rate matching for +++ * @iface: The interface mode to use +++ * +++ * This determines the type of rate matching (if any) that @phy supports +++ * using @iface. @iface may be %PHY_INTERFACE_MODE_NA to determine if any +++ * interface supports rate matching. +++ * +++ * Return: The type of rate matching @phy supports for @iface, or +++ * %RATE_MATCH_NONE. +++ */ +++int phy_get_rate_matching(struct phy_device *phydev, +++ phy_interface_t iface) +++{ +++ int ret = RATE_MATCH_NONE; +++ +++ if (phydev->drv->get_rate_matching) { +++ mutex_lock(&phydev->lock); +++ ret = phydev->drv->get_rate_matching(phydev, iface); +++ mutex_unlock(&phydev->lock); +++ } +++ +++ return ret; +++} +++EXPORT_SYMBOL_GPL(phy_get_rate_matching); +++ +++/** ++ * phy_config_interrupt - configure the PHY device for the requested interrupts ++ * @phydev: the phy_device struct ++ * @interrupts: interrupt flags to configure for this @phydev ++@@ -268,6 +295,7 @@ void phy_ethtool_ksettings_get(struct ph ++ cmd->base.duplex = phydev->duplex; ++ cmd->base.master_slave_cfg = phydev->master_slave_get; ++ cmd->base.master_slave_state = phydev->master_slave_state; +++ cmd->base.rate_matching = phydev->rate_matching; ++ if (phydev->interface == PHY_INTERFACE_MODE_MOCA) ++ cmd->base.port = PORT_BNC; ++ else ++--- a/include/linux/phy.h +++++ b/include/linux/phy.h ++@@ -280,7 +280,6 @@ static inline const char *phy_modes(phy_ ++ } ++ } ++ ++- ++ #define PHY_INIT_TIMEOUT 100000 ++ #define PHY_FORCE_TIMEOUT 10 ++ ++@@ -574,6 +573,7 @@ struct macsec_ops; ++ * @host_interfaces: PHY interface modes supported by host ++ * @eee_broken_modes: Energy efficient ethernet modes which should be prohibited ++ * @autoneg: Flag autoneg being used +++ * @rate_matching: Current rate matching mode ++ * @link: Current link state ++ * @autoneg_complete: Flag auto negotiation of the link has completed ++ * @mdix: Current crossover ++@@ -640,6 +640,8 @@ struct phy_device { ++ unsigned irq_suspended:1; ++ unsigned irq_rerun:1; ++ +++ int rate_matching; +++ ++ enum phy_state state; ++ ++ u32 dev_flags; ++@@ -805,6 +807,21 @@ struct phy_driver { ++ */ ++ int (*get_features)(struct phy_device *phydev); ++ +++ /** +++ * @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 +++ * assumed that if a rate matching mode is supported on an interface, +++ * then that interface's rate can be adapted to all slower link speeds +++ * supported by the phy. If iface is %PHY_INTERFACE_MODE_NA, and the phy +++ * supports any kind of rate matching for any interface, then it must +++ * return that rate matching mode (preferring %RATE_MATCH_PAUSE to +++ * %RATE_MATCH_CRS). If the interface is not supported, this should +++ * return %RATE_MATCH_NONE. +++ */ +++ int (*get_rate_matching)(struct phy_device *phydev, +++ phy_interface_t iface); +++ ++ /* PHY Power Management */ ++ /** @suspend: Suspend the hardware, saving state if needed */ ++ int (*suspend)(struct phy_device *phydev); ++@@ -977,6 +994,7 @@ struct phy_fixup { ++ ++ const char *phy_speed_to_str(int speed); ++ const char *phy_duplex_to_str(unsigned int duplex); +++const char *phy_rate_matching_to_str(int rate_matching); ++ ++ /* A structure for mapping a particular speed and duplex ++ * combination to a particular SUPPORTED and ADVERTISED value ++@@ -1683,6 +1701,8 @@ int phy_disable_interrupts(struct phy_de ++ void phy_request_interrupt(struct phy_device *phydev); ++ void phy_free_interrupt(struct phy_device *phydev); ++ void phy_print_status(struct phy_device *phydev); +++int phy_get_rate_matching(struct phy_device *phydev, +++ phy_interface_t iface); ++ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed); ++ void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode); ++ void phy_advertise_supported(struct phy_device *phydev); ++--- a/include/uapi/linux/ethtool.h +++++ b/include/uapi/linux/ethtool.h ++@@ -1809,6 +1809,20 @@ static inline int ethtool_validate_duple ++ #define MASTER_SLAVE_STATE_SLAVE 3 ++ #define MASTER_SLAVE_STATE_ERR 4 ++ +++/* These are used to throttle the rate of data on the phy interface when the +++ * native speed of the interface is higher than the link speed. These should +++ * not be used for phy interfaces which natively support multiple speeds (e.g. +++ * MII or SGMII). +++ */ +++/* No rate matching performed. */ +++#define RATE_MATCH_NONE 0 +++/* The phy sends pause frames to throttle the MAC. */ +++#define RATE_MATCH_PAUSE 1 +++/* The phy asserts CRS to prevent the MAC from transmitting. */ +++#define RATE_MATCH_CRS 2 +++/* The MAC is programmed with a sufficiently-large IPG. */ +++#define RATE_MATCH_OPEN_LOOP 3 +++ ++ /* Which connector port. */ ++ #define PORT_TP 0x00 ++ #define PORT_AUI 0x01 ++@@ -2002,8 +2016,8 @@ enum ethtool_reset_flags { ++ * reported consistently by PHYLIB. Read-only. ++ * @master_slave_cfg: Master/slave port mode. ++ * @master_slave_state: Master/slave port state. +++ * @rate_matching: Rate adaptation performed by the PHY ++ * @reserved: Reserved for future use; see the note on reserved space. ++- * @reserved1: Reserved for future use; see the note on reserved space. ++ * @link_mode_masks: Variable length bitmaps. ++ * ++ * If autonegotiation is disabled, the speed and @duplex represent the ++@@ -2054,7 +2068,7 @@ struct ethtool_link_settings { ++ __u8 transceiver; ++ __u8 master_slave_cfg; ++ __u8 master_slave_state; ++- __u8 reserved1[1]; +++ __u8 rate_matching; ++ __u32 reserved[7]; ++ __u32 link_mode_masks[0]; ++ /* layout of link_mode_masks fields: ++--- a/include/uapi/linux/ethtool_netlink.h +++++ b/include/uapi/linux/ethtool_netlink.h ++@@ -238,6 +238,7 @@ enum { ++ ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG, /* u8 */ ++ ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE, /* u8 */ ++ ETHTOOL_A_LINKMODES_LANES, /* u32 */ +++ ETHTOOL_A_LINKMODES_RATE_MATCHING, /* u8 */ ++ ++ /* add new constants above here */ ++ __ETHTOOL_A_LINKMODES_CNT, ++--- a/net/ethtool/ioctl.c +++++ b/net/ethtool/ioctl.c ++@@ -559,6 +559,7 @@ static int ethtool_get_link_ksettings(st ++ = __ETHTOOL_LINK_MODE_MASK_NU32; ++ link_ksettings.base.master_slave_cfg = MASTER_SLAVE_CFG_UNSUPPORTED; ++ link_ksettings.base.master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; +++ link_ksettings.base.rate_matching = RATE_MATCH_NONE; ++ ++ return store_link_ksettings_for_user(useraddr, &link_ksettings); ++ } ++--- a/net/ethtool/linkmodes.c +++++ b/net/ethtool/linkmodes.c ++@@ -70,6 +70,7 @@ static int linkmodes_reply_size(const st ++ + nla_total_size(sizeof(u32)) /* LINKMODES_SPEED */ ++ + nla_total_size(sizeof(u32)) /* LINKMODES_LANES */ ++ + nla_total_size(sizeof(u8)) /* LINKMODES_DUPLEX */ +++ + nla_total_size(sizeof(u8)) /* LINKMODES_RATE_MATCHING */ ++ + 0; ++ ret = ethnl_bitset_size(ksettings->link_modes.advertising, ++ ksettings->link_modes.supported, ++@@ -143,6 +144,10 @@ static int linkmodes_fill_reply(struct s ++ lsettings->master_slave_state)) ++ return -EMSGSIZE; ++ +++ if (nla_put_u8(skb, ETHTOOL_A_LINKMODES_RATE_MATCHING, +++ lsettings->rate_matching)) +++ return -EMSGSIZE; +++ ++ return 0; ++ } ++ +diff --git a/target/linux/mvebu/patches-5.15/707-06-5-net-phylink-Adjust-link-settings-based-on-rate-match.patch b/target/linux/mvebu/patches-5.15/707-06-5-net-phylink-Adjust-link-settings-based-on-rate-match.patch +new file mode 100644 +index 0000000000..3bde950c49 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-06-5-net-phylink-Adjust-link-settings-based-on-rate-match.patch +@@ -0,0 +1,256 @@ ++From ae0e4bb2a0e0e434e9f98fb4994093ec2ee71997 Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:32 -0400 ++Subject: [PATCH] net: phylink: Adjust link settings based on rate matching ++ ++If the phy is configured to use pause-based rate matching, ensure that ++the link is full duplex with pause frame reception enabled. As ++suggested, if pause-based rate matching is enabled by the phy, then ++pause reception is unconditionally enabled. ++ ++The interface duplex is determined based on the rate matching type. ++When rate matching is enabled, so is the speed. We assume the maximum ++interface speed is used. This is only relevant for MLO_AN_PHY. For ++MLO_AN_INBAND, the MAC/PCS's view of the interface speed will be used. ++ ++Although there are no RATE_ADAPT_CRS phys in-tree, it has been added for ++comparison (and the implementation is quite simple). ++ ++Co-developed-by: Russell King <linux@armlinux.org.uk> ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -234,6 +234,75 @@ static int phylink_validate_mac_and_pcs( ++ } ++ ++ /** +++ * phylink_interface_max_speed() - get the maximum speed of a phy interface +++ * @interface: phy interface mode defined by &typedef phy_interface_t +++ * +++ * Determine the maximum speed of a phy interface. This is intended to help +++ * determine the correct speed to pass to the MAC when the phy is performing +++ * rate matching. +++ * +++ * Return: The maximum speed of @interface +++ */ +++static int phylink_interface_max_speed(phy_interface_t interface) +++{ +++ switch (interface) { +++ case PHY_INTERFACE_MODE_100BASEX: +++ case PHY_INTERFACE_MODE_REVRMII: +++ case PHY_INTERFACE_MODE_RMII: +++ case PHY_INTERFACE_MODE_SMII: +++ case PHY_INTERFACE_MODE_REVMII: +++ case PHY_INTERFACE_MODE_MII: +++ return SPEED_100; +++ +++ case PHY_INTERFACE_MODE_TBI: +++ case PHY_INTERFACE_MODE_MOCA: +++ case PHY_INTERFACE_MODE_RTBI: +++ case PHY_INTERFACE_MODE_1000BASEX: +++ case PHY_INTERFACE_MODE_1000BASEKX: +++ case PHY_INTERFACE_MODE_TRGMII: +++ case PHY_INTERFACE_MODE_RGMII_TXID: +++ case PHY_INTERFACE_MODE_RGMII_RXID: +++ case PHY_INTERFACE_MODE_RGMII_ID: +++ case PHY_INTERFACE_MODE_RGMII: +++ case PHY_INTERFACE_MODE_QSGMII: +++ case PHY_INTERFACE_MODE_SGMII: +++ case PHY_INTERFACE_MODE_GMII: +++ return SPEED_1000; +++ +++ case PHY_INTERFACE_MODE_2500BASEX: +++ return SPEED_2500; +++ +++ case PHY_INTERFACE_MODE_5GBASER: +++ return SPEED_5000; +++ +++ case PHY_INTERFACE_MODE_XGMII: +++ case PHY_INTERFACE_MODE_RXAUI: +++ case PHY_INTERFACE_MODE_XAUI: +++ case PHY_INTERFACE_MODE_10GBASER: +++ case PHY_INTERFACE_MODE_10GKR: +++ case PHY_INTERFACE_MODE_USXGMII: +++ case PHY_INTERFACE_MODE_QUSGMII: +++ return SPEED_10000; +++ +++ case PHY_INTERFACE_MODE_25GBASER: +++ return SPEED_25000; +++ +++ case PHY_INTERFACE_MODE_XLGMII: +++ return SPEED_40000; +++ +++ case PHY_INTERFACE_MODE_INTERNAL: +++ case PHY_INTERFACE_MODE_NA: +++ case PHY_INTERFACE_MODE_MAX: +++ /* No idea! Garbage in, unknown out */ +++ return SPEED_UNKNOWN; +++ } +++ +++ /* If we get here, someone forgot to add an interface mode above */ +++ WARN_ON_ONCE(1); +++ return SPEED_UNKNOWN; +++} +++ +++/** ++ * phylink_caps_to_linkmodes() - Convert capabilities to ethtool link modes ++ * @linkmodes: ethtool linkmode mask (must be already initialised) ++ * @caps: bitmask of MAC capabilities ++@@ -802,11 +871,12 @@ static void phylink_mac_config(struct ph ++ const struct phylink_link_state *state) ++ { ++ phylink_dbg(pl, ++- "%s: mode=%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n", +++ "%s: mode=%s/%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n", ++ __func__, phylink_an_mode_str(pl->cur_link_an_mode), ++ phy_modes(state->interface), ++ phy_speed_to_str(state->speed), ++ phy_duplex_to_str(state->duplex), +++ phy_rate_matching_to_str(state->rate_matching), ++ __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising, ++ state->pause, state->link, state->an_enabled); ++ ++@@ -942,7 +1012,8 @@ static void phylink_mac_pcs_get_state(st ++ linkmode_zero(state->lp_advertising); ++ state->interface = pl->link_config.interface; ++ state->an_enabled = pl->link_config.an_enabled; ++- if (state->an_enabled) { +++ state->rate_matching = pl->link_config.rate_matching; +++ if (state->an_enabled) { ++ state->speed = SPEED_UNKNOWN; ++ state->duplex = DUPLEX_UNKNOWN; ++ state->pause = MLO_PAUSE_NONE; ++@@ -1025,19 +1096,43 @@ static void phylink_link_up(struct phyli ++ struct phylink_link_state link_state) ++ { ++ struct net_device *ndev = pl->netdev; +++ int speed, duplex; +++ bool rx_pause; +++ +++ speed = link_state.speed; +++ duplex = link_state.duplex; +++ rx_pause = !!(link_state.pause & MLO_PAUSE_RX); +++ +++ switch (link_state.rate_matching) { +++ case RATE_MATCH_PAUSE: +++ /* The PHY is doing rate matchion from the media rate (in +++ * the link_state) to the interface speed, and will send +++ * pause frames to the MAC to limit its transmission speed. +++ */ +++ speed = phylink_interface_max_speed(link_state.interface); +++ duplex = DUPLEX_FULL; +++ rx_pause = true; +++ break; +++ +++ case RATE_MATCH_CRS: +++ /* The PHY is doing rate matchion from the media rate (in +++ * the link_state) to the interface speed, and will cause +++ * collisions to the MAC to limit its transmission speed. +++ */ +++ speed = phylink_interface_max_speed(link_state.interface); +++ duplex = DUPLEX_HALF; +++ break; +++ } ++ ++ pl->cur_interface = link_state.interface; ++ ++ if (pl->pcs_ops && pl->pcs_ops->pcs_link_up) ++ pl->pcs_ops->pcs_link_up(pl->pcs, pl->cur_link_an_mode, ++- pl->cur_interface, ++- link_state.speed, link_state.duplex); +++ pl->cur_interface, speed, duplex); ++ ++- pl->mac_ops->mac_link_up(pl->config, pl->phydev, ++- pl->cur_link_an_mode, pl->cur_interface, ++- link_state.speed, link_state.duplex, ++- !!(link_state.pause & MLO_PAUSE_TX), ++- !!(link_state.pause & MLO_PAUSE_RX)); +++ pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode, +++ pl->cur_interface, speed, duplex, +++ !!(link_state.pause & MLO_PAUSE_TX), rx_pause); ++ ++ if (ndev) ++ netif_carrier_on(ndev); ++@@ -1129,6 +1224,17 @@ static void phylink_resolve(struct work_ ++ } ++ 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. ++ */ ++@@ -1394,6 +1500,7 @@ static void phylink_phy_change(struct ph ++ mutex_lock(&pl->state_mutex); ++ pl->phy_state.speed = phydev->speed; ++ pl->phy_state.duplex = phydev->duplex; +++ pl->phy_state.rate_matching = phydev->rate_matching; ++ pl->phy_state.pause = MLO_PAUSE_NONE; ++ if (tx_pause) ++ pl->phy_state.pause |= MLO_PAUSE_TX; ++@@ -1405,10 +1512,11 @@ static void phylink_phy_change(struct ph ++ ++ phylink_run_resolve(pl); ++ ++- phylink_dbg(pl, "phy link %s %s/%s/%s/%s\n", up ? "up" : "down", +++ phylink_dbg(pl, "phy link %s %s/%s/%s/%s/%s\n", up ? "up" : "down", ++ phy_modes(phydev->interface), ++ phy_speed_to_str(phydev->speed), ++ phy_duplex_to_str(phydev->duplex), +++ phy_rate_matching_to_str(phydev->rate_matching), ++ phylink_pause_to_str(pl->phy_state.pause)); ++ } ++ ++@@ -1472,6 +1580,7 @@ static int phylink_bringup_phy(struct ph ++ pl->phy_state.pause = MLO_PAUSE_NONE; ++ pl->phy_state.speed = SPEED_UNKNOWN; ++ pl->phy_state.duplex = DUPLEX_UNKNOWN; +++ pl->phy_state.rate_matching = RATE_MATCH_NONE; ++ linkmode_copy(pl->supported, supported); ++ linkmode_copy(pl->link_config.advertising, config.advertising); ++ ++@@ -1909,8 +2018,10 @@ static void phylink_get_ksettings(const ++ { ++ phylink_merge_link_mode(kset->link_modes.advertising, state->advertising); ++ linkmode_copy(kset->link_modes.lp_advertising, state->lp_advertising); ++- kset->base.speed = state->speed; ++- kset->base.duplex = state->duplex; +++ if (kset->base.rate_matching == RATE_MATCH_NONE) { +++ kset->base.speed = state->speed; +++ kset->base.duplex = state->duplex; +++ } ++ kset->base.autoneg = state->an_enabled ? AUTONEG_ENABLE : ++ AUTONEG_DISABLE; ++ } ++--- a/include/linux/phylink.h +++++ b/include/linux/phylink.h ++@@ -88,6 +88,10 @@ static inline bool phylink_autoneg_inban ++ * @speed: link speed, one of the SPEED_* constants. ++ * @duplex: link duplex mode, one of DUPLEX_* constants. ++ * @pause: link pause state, described by MLO_PAUSE_* constants. +++ * @rate_matching: rate matching being performed, one of the RATE_MATCH_* +++ * constants. If rate matching is taking place, then the speed/duplex of +++ * the medium link mode (@speed and @duplex) and the speed/duplex of the phy +++ * interface mode (@interface) are different. ++ * @link: true if the link is up. ++ * @an_enabled: true if autonegotiation is enabled/desired. ++ * @an_complete: true if autonegotiation has completed. ++@@ -99,6 +103,7 @@ struct phylink_link_state { ++ int speed; ++ int duplex; ++ int pause; +++ int rate_matching; ++ unsigned int link:1; ++ unsigned int an_enabled:1; ++ unsigned int an_complete:1; +diff --git a/target/linux/mvebu/patches-5.15/707-06-6-net-phylink-Adjust-advertisement-based-on-rate-match.patch b/target/linux/mvebu/patches-5.15/707-06-6-net-phylink-Adjust-advertisement-based-on-rate-match.patch +new file mode 100644 +index 0000000000..29344604f1 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-06-6-net-phylink-Adjust-advertisement-based-on-rate-match.patch +@@ -0,0 +1,187 @@ ++From b7e9294885b610791fcebc799bf2a9e219446fd6 Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:33 -0400 ++Subject: [PATCH] net: phylink: Adjust advertisement based on rate matching ++ ++This adds support for adjusting the advertisement for pause-based rate ++matching. This may result in a lossy link, since the final link settings ++are not adjusted. Asymmetric pause support is necessary. It would be ++possible for a MAC supporting only symmetric pause to use pause-based rate ++adaptation, but only if pause reception was enabled as well. ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++From b7e9294885b610791fcebc799bf2a9e219446fd6 Mon Sep 17 00:00:00 2001 ++From: Sean Anderson <sean.anderson@seco.com> ++Date: Tue, 20 Sep 2022 18:12:33 -0400 ++Subject: [PATCH] net: phylink: Adjust advertisement based on rate matching ++ ++This adds support for adjusting the advertisement for pause-based rate ++matching. This may result in a lossy link, since the final link settings ++are not adjusted. Asymmetric pause support is necessary. It would be ++possible for a MAC supporting only symmetric pause to use pause-based rate ++adaptation, but only if pause reception was enabled as well. ++ ++Signed-off-by: Sean Anderson <sean.anderson@seco.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/phylink.c +++++ b/drivers/net/phy/phylink.c ++@@ -448,18 +448,70 @@ void phylink_caps_to_linkmodes(unsigned ++ } ++ EXPORT_SYMBOL_GPL(phylink_caps_to_linkmodes); ++ +++static struct { +++ unsigned long mask; +++ int speed; +++ unsigned int duplex; +++} phylink_caps_params[] = { +++ { MAC_400000FD, SPEED_400000, DUPLEX_FULL }, +++ { MAC_200000FD, SPEED_200000, DUPLEX_FULL }, +++ { MAC_100000FD, SPEED_100000, DUPLEX_FULL }, +++ { MAC_56000FD, SPEED_56000, DUPLEX_FULL }, +++ { MAC_50000FD, SPEED_50000, DUPLEX_FULL }, +++ { MAC_40000FD, SPEED_40000, DUPLEX_FULL }, +++ { MAC_25000FD, SPEED_25000, DUPLEX_FULL }, +++ { MAC_20000FD, SPEED_20000, DUPLEX_FULL }, +++ { MAC_10000FD, SPEED_10000, DUPLEX_FULL }, +++ { MAC_5000FD, SPEED_5000, DUPLEX_FULL }, +++ { MAC_2500FD, SPEED_2500, DUPLEX_FULL }, +++ { MAC_1000FD, SPEED_1000, DUPLEX_FULL }, +++ { MAC_1000HD, SPEED_1000, DUPLEX_HALF }, +++ { MAC_100FD, SPEED_100, DUPLEX_FULL }, +++ { MAC_100HD, SPEED_100, DUPLEX_HALF }, +++ { MAC_10FD, SPEED_10, DUPLEX_FULL }, +++ { MAC_10HD, SPEED_10, DUPLEX_HALF }, +++}; +++ +++/** +++ * phylink_cap_from_speed_duplex - Get mac capability from speed/duplex +++ * @speed: the speed to search for +++ * @duplex: the duplex to search for +++ * +++ * Find the mac capability for a given speed and duplex. +++ * +++ * Return: A mask with the mac capability patching @speed and @duplex, or 0 if +++ * there were no matches. +++ */ +++static unsigned long phylink_cap_from_speed_duplex(int speed, +++ unsigned int duplex) +++{ +++ int i; +++ +++ for (i = 0; i < ARRAY_SIZE(phylink_caps_params); i++) { +++ if (speed == phylink_caps_params[i].speed && +++ duplex == phylink_caps_params[i].duplex) +++ return phylink_caps_params[i].mask; +++ } +++ +++ return 0; +++} +++ ++ /** ++ * phylink_get_capabilities() - get capabilities for a given MAC ++ * @interface: phy interface mode defined by &typedef phy_interface_t ++ * @mac_capabilities: bitmask of MAC capabilities +++ * @rate_matching: type of rate matching being performed ++ * ++ * Get the MAC capabilities that are supported by the @interface mode and ++ * @mac_capabilities. ++ */ ++ unsigned long phylink_get_capabilities(phy_interface_t interface, ++- unsigned long mac_capabilities) +++ unsigned long mac_capabilities, +++ int rate_matching) ++ { +++ int max_speed = phylink_interface_max_speed(interface); ++ unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE; +++ unsigned long matched_caps = 0; ++ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_USXGMII: ++@@ -533,7 +585,53 @@ unsigned long phylink_get_capabilities(p ++ break; ++ } ++ ++- return caps & mac_capabilities; +++ switch (rate_matching) { +++ case RATE_MATCH_OPEN_LOOP: +++ /* TODO */ +++ fallthrough; +++ case RATE_MATCH_NONE: +++ matched_caps = 0; +++ break; +++ case RATE_MATCH_PAUSE: { +++ /* The MAC must support asymmetric pause towards the local +++ * device for this. We could allow just symmetric pause, but +++ * then we might have to renegotiate if the link partner +++ * doesn't support pause. This is because there's no way to +++ * accept pause frames without transmitting them if we only +++ * support symmetric pause. +++ */ +++ if (!(mac_capabilities & MAC_SYM_PAUSE) || +++ !(mac_capabilities & MAC_ASYM_PAUSE)) +++ break; +++ +++ /* We can't adapt if the MAC doesn't support the interface's +++ * max speed at full duplex. +++ */ +++ if (mac_capabilities & +++ phylink_cap_from_speed_duplex(max_speed, DUPLEX_FULL)) { +++ /* Although a duplex-matching phy might exist, we +++ * conservatively remove these modes because the MAC +++ * will not be aware of the half-duplex nature of the +++ * link. +++ */ +++ matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD)); +++ matched_caps &= ~(MAC_1000HD | MAC_100HD | MAC_10HD); +++ } +++ break; +++ } +++ case RATE_MATCH_CRS: +++ /* The MAC must support half duplex at the interface's max +++ * speed. +++ */ +++ if (mac_capabilities & +++ phylink_cap_from_speed_duplex(max_speed, DUPLEX_HALF)) { +++ matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD)); +++ matched_caps &= mac_capabilities; +++ } +++ break; +++ } +++ +++ return (caps & mac_capabilities) | matched_caps; ++ } ++ EXPORT_SYMBOL_GPL(phylink_get_capabilities); ++ ++@@ -557,7 +655,8 @@ void phylink_generic_validate(struct phy ++ phylink_set_port_modes(mask); ++ phylink_set(mask, Autoneg); ++ caps = phylink_get_capabilities(state->interface, ++- config->mac_capabilities); +++ config->mac_capabilities, +++ state->rate_matching); ++ phylink_caps_to_linkmodes(mask, caps); ++ ++ linkmode_and(supported, supported, mask); ++@@ -1553,6 +1652,7 @@ static int phylink_bringup_phy(struct ph ++ config.interface = PHY_INTERFACE_MODE_NA; ++ else ++ config.interface = interface; +++ config.rate_matching = phy_get_rate_matching(phy, config.interface); ++ ++ ret = phylink_validate(pl, supported, &config); ++ if (ret) { ++--- a/include/linux/phylink.h +++++ b/include/linux/phylink.h ++@@ -563,7 +563,8 @@ void pcs_link_up(struct phylink_pcs *pcs ++ ++ void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps); ++ unsigned long phylink_get_capabilities(phy_interface_t interface, ++- unsigned long mac_capabilities); +++ unsigned long mac_capabilities, +++ int rate_matching); ++ void phylink_generic_validate(struct phylink_config *config, ++ unsigned long *supported, ++ struct phylink_link_state *state); +diff --git a/target/linux/mvebu/patches-5.15/707-07-1-net-phy-add-possible-interfaces.patch b/target/linux/mvebu/patches-5.15/707-07-1-net-phy-add-possible-interfaces.patch +new file mode 100644 +index 0000000000..db8e5f2fdc +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-07-1-net-phy-add-possible-interfaces.patch +@@ -0,0 +1,56 @@ ++From 243ad8df7a1bd24c2e01bd99d9f0bb88844dae91 Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 24 Nov 2023 12:27:52 +0000 ++Subject: [PATCH] net: phy: add possible interfaces ++ ++Add a possible_interfaces member to struct phy_device to indicate which ++interfaces a clause 45 PHY may switch between depending on the media. ++This must be populated by the PHY driver by the time the .config_init() ++method completes according to the PHYs host-side configuration. ++ ++For example, the Marvell 88x3310 PHY can switch between 10GBASE-R, ++5GBASE-R, 2500BASE-X, and SGMII on the host side depending on the media ++side speed, so all these interface modes are set in the ++possible_interfaces member. ++ ++This allows phylib users (such as phylink) to know in advance which ++interface modes to expect, which allows them to appropriately restrict ++the advertised link modes according to the capabilities of other parts ++of the link. ++ ++Tested-by: Luo Jie <quic_luoj@quicinc.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Link: https://lore.kernel.org/r/E1r6VHk-00DDLN-I7@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/phy_device.c +++++ b/drivers/net/phy/phy_device.c ++@@ -1210,6 +1210,8 @@ int phy_init_hw(struct phy_device *phyde ++ if (ret < 0) ++ return ret; ++ +++ phy_interface_zero(phydev->possible_interfaces); +++ ++ if (phydev->drv->config_init) { ++ ret = phydev->drv->config_init(phydev); ++ if (ret < 0) ++--- a/include/linux/phy.h +++++ b/include/linux/phy.h ++@@ -584,6 +584,8 @@ struct macsec_ops; ++ * @irq_rerun: Flag indicating interrupts occurred while PHY was suspended, ++ * requiring a rerun of the interrupt handler after resume ++ * @interface: enum phy_interface_t value +++ * @possible_interfaces: bitmap if interface modes that the attached PHY +++ * will switch between depending on media speed. ++ * @skb: Netlink message for cable diagnostics ++ * @nest: Netlink nest used for cable diagnostics ++ * @ehdr: nNtlink header for cable diagnostics ++@@ -647,6 +649,7 @@ struct phy_device { ++ u32 dev_flags; ++ ++ phy_interface_t interface; +++ DECLARE_PHY_INTERFACE_MASK(possible_interfaces); ++ ++ /* ++ * forced speed & duplex (no autoneg) +diff --git a/target/linux/mvebu/patches-5.15/707-07-2-net-phy-marvell10g-table-driven-mactype-decode.patch b/target/linux/mvebu/patches-5.15/707-07-2-net-phy-marvell10g-table-driven-mactype-decode.patch +new file mode 100644 +index 0000000000..044cad8264 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-07-2-net-phy-marvell10g-table-driven-mactype-decode.patch +@@ -0,0 +1,295 @@ ++From 2cb6d63b30c6fbc7cf5f671279be4a94049e141f Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 24 Nov 2023 12:27:58 +0000 ++Subject: [PATCH] net: phy: marvell10g: table driven mactype decode ++ ++Replace the code-based mactype decode with a table driven approach. ++This will allow us to fill in the possible_interfaces cleanly. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Link: https://lore.kernel.org/r/E1r6VHq-00DDLT-In@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/marvell10g.c +++++ b/drivers/net/phy/marvell10g.c ++@@ -141,13 +141,21 @@ enum { ++ MV_V2_TEMP_UNKNOWN = 0x9600, /* unknown function */ ++ }; ++ +++struct mv3310_mactype { +++ bool valid; +++ bool fixed_interface; +++ phy_interface_t interface_10g; +++}; +++ ++ struct mv3310_chip { ++ bool (*has_downshift)(struct phy_device *phydev); ++ void (*init_supported_interfaces)(unsigned long *mask); ++ int (*get_mactype)(struct phy_device *phydev); ++ int (*set_mactype)(struct phy_device *phydev, int mactype); ++ int (*select_mactype)(unsigned long *interfaces); ++- int (*init_interface)(struct phy_device *phydev, int mactype); +++ +++ const struct mv3310_mactype *mactypes; +++ size_t n_mactypes; ++ ++ #ifdef CONFIG_HWMON ++ int (*hwmon_read_temp_reg)(struct phy_device *phydev); ++@@ -156,11 +164,10 @@ struct mv3310_chip { ++ ++ struct mv3310_priv { ++ DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX); +++ const struct mv3310_mactype *mactype; ++ ++ u32 firmware_ver; ++ bool has_downshift; ++- bool rate_match; ++- phy_interface_t const_interface; ++ ++ struct device *hwmon_dev; ++ char *hwmon_name; ++@@ -702,71 +709,99 @@ static int mv3310_select_mactype(unsigne ++ return -1; ++ } ++ ++-static int mv2110_init_interface(struct phy_device *phydev, int mactype) ++-{ ++- struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++- ++- priv->rate_match = false; ++- ++- if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH) ++- priv->rate_match = true; ++- ++- if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII) ++- priv->const_interface = PHY_INTERFACE_MODE_USXGMII; ++- else if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH) ++- priv->const_interface = PHY_INTERFACE_MODE_10GBASER; ++- else if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER || ++- mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN) ++- priv->const_interface = PHY_INTERFACE_MODE_NA; ++- else ++- return -EINVAL; ++- ++- return 0; ++-} ++- ++-static int mv3310_init_interface(struct phy_device *phydev, int mactype) ++-{ ++- struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++- ++- priv->rate_match = false; ++- ++- if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH || ++- mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH || ++- mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH) ++- priv->rate_match = true; ++- ++- if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII) ++- priv->const_interface = PHY_INTERFACE_MODE_USXGMII; ++- else if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH || ++- mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN || ++- mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER) ++- priv->const_interface = PHY_INTERFACE_MODE_10GBASER; ++- else if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH || ++- mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI) ++- priv->const_interface = PHY_INTERFACE_MODE_RXAUI; ++- else if (mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH || ++- mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI) ++- priv->const_interface = PHY_INTERFACE_MODE_XAUI; ++- else ++- return -EINVAL; ++- ++- return 0; ++-} ++- ++-static int mv3340_init_interface(struct phy_device *phydev, int mactype) ++-{ ++- struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++- int err = 0; ++- ++- priv->rate_match = false; +++static const struct mv3310_mactype mv2110_mactypes[] = { +++ [MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII] = { +++ .valid = true, +++ .fixed_interface = true, +++ .interface_10g = PHY_INTERFACE_MODE_USXGMII, +++ }, +++ [MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER] = { +++ .valid = true, +++ .interface_10g = PHY_INTERFACE_MODE_NA, +++ }, +++ [MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN] = { +++ .valid = true, +++ .interface_10g = PHY_INTERFACE_MODE_NA, +++ }, +++ [MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = { +++ .valid = true, +++ .fixed_interface = true, +++ .interface_10g = PHY_INTERFACE_MODE_10GBASER, +++ }, +++}; ++ ++- if (mactype == MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN) ++- priv->const_interface = PHY_INTERFACE_MODE_RXAUI; ++- else ++- err = mv3310_init_interface(phydev, mactype); +++static const struct mv3310_mactype mv3310_mactypes[] = { +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI] = { +++ .valid = true, +++ .interface_10g = PHY_INTERFACE_MODE_RXAUI, +++ }, +++ [MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH] = { +++ .valid = true, +++ .fixed_interface = true, +++ .interface_10g = PHY_INTERFACE_MODE_XAUI, +++ }, +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH] = { +++ .valid = true, +++ .fixed_interface = true, +++ .interface_10g = PHY_INTERFACE_MODE_RXAUI, +++ }, +++ [MV_V2_3310_PORT_CTRL_MACTYPE_XAUI] = { +++ .valid = true, +++ .interface_10g = PHY_INTERFACE_MODE_XAUI, +++ }, +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER] = { +++ .valid = true, +++ .interface_10g = PHY_INTERFACE_MODE_10GBASER, +++ }, +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN] = { +++ .valid = true, +++ .interface_10g = PHY_INTERFACE_MODE_10GBASER, +++ }, +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = { +++ .valid = true, +++ .fixed_interface = true, +++ .interface_10g = PHY_INTERFACE_MODE_10GBASER, +++ }, +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII] = { +++ .valid = true, +++ .fixed_interface = true, +++ .interface_10g = PHY_INTERFACE_MODE_USXGMII, +++ }, +++}; ++ ++- return err; ++-} +++static const struct mv3310_mactype mv3340_mactypes[] = { +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI] = { +++ .valid = true, +++ .interface_10g = PHY_INTERFACE_MODE_RXAUI, +++ }, +++ [MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN] = { +++ .valid = true, +++ .interface_10g = PHY_INTERFACE_MODE_RXAUI, +++ }, +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH] = { +++ .valid = true, +++ .fixed_interface = true, +++ .interface_10g = PHY_INTERFACE_MODE_RXAUI, +++ }, +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER] = { +++ .valid = true, +++ .interface_10g = PHY_INTERFACE_MODE_10GBASER, +++ }, +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN] = { +++ .valid = true, +++ .interface_10g = PHY_INTERFACE_MODE_10GBASER, +++ }, +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = { +++ .valid = true, +++ .fixed_interface = true, +++ .interface_10g = PHY_INTERFACE_MODE_10GBASER, +++ }, +++ [MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII] = { +++ .valid = true, +++ .fixed_interface = true, +++ .interface_10g = PHY_INTERFACE_MODE_USXGMII, +++ }, +++}; ++ ++ static int mv3310_config_init(struct phy_device *phydev) ++ { ++@@ -803,12 +838,13 @@ static int mv3310_config_init(struct phy ++ if (mactype < 0) ++ return mactype; ++ ++- err = chip->init_interface(phydev, mactype); ++- if (err) { +++ if (mactype >= chip->n_mactypes || !chip->mactypes[mactype].valid) { ++ phydev_err(phydev, "MACTYPE configuration invalid\n"); ++- return err; +++ return -EINVAL; ++ } ++ +++ priv->mactype = &chip->mactypes[mactype]; +++ ++ /* Enable EDPD mode - saving 600mW */ ++ err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS); ++ if (err) ++@@ -935,9 +971,8 @@ static void mv3310_update_interface(stru ++ * ++ * In USXGMII mode the PHY interface mode is also fixed. ++ */ ++- if (priv->rate_match || ++- priv->const_interface == PHY_INTERFACE_MODE_USXGMII) { ++- phydev->interface = priv->const_interface; +++ if (priv->mactype->fixed_interface) { +++ phydev->interface = priv->mactype->interface_10g; ++ return; ++ } ++ ++@@ -949,7 +984,7 @@ static void mv3310_update_interface(stru ++ */ ++ switch (phydev->speed) { ++ case SPEED_10000: ++- phydev->interface = priv->const_interface; +++ phydev->interface = priv->mactype->interface_10g; ++ break; ++ case SPEED_5000: ++ phydev->interface = PHY_INTERFACE_MODE_5GBASER; ++@@ -1163,7 +1198,9 @@ static const struct mv3310_chip mv3310_t ++ .get_mactype = mv3310_get_mactype, ++ .set_mactype = mv3310_set_mactype, ++ .select_mactype = mv3310_select_mactype, ++- .init_interface = mv3310_init_interface, +++ +++ .mactypes = mv3310_mactypes, +++ .n_mactypes = ARRAY_SIZE(mv3310_mactypes), ++ ++ #ifdef CONFIG_HWMON ++ .hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg, ++@@ -1176,7 +1213,9 @@ static const struct mv3310_chip mv3340_t ++ .get_mactype = mv3310_get_mactype, ++ .set_mactype = mv3310_set_mactype, ++ .select_mactype = mv3310_select_mactype, ++- .init_interface = mv3340_init_interface, +++ +++ .mactypes = mv3340_mactypes, +++ .n_mactypes = ARRAY_SIZE(mv3340_mactypes), ++ ++ #ifdef CONFIG_HWMON ++ .hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg, ++@@ -1188,7 +1227,9 @@ static const struct mv3310_chip mv2110_t ++ .get_mactype = mv2110_get_mactype, ++ .set_mactype = mv2110_set_mactype, ++ .select_mactype = mv2110_select_mactype, ++- .init_interface = mv2110_init_interface, +++ +++ .mactypes = mv2110_mactypes, +++ .n_mactypes = ARRAY_SIZE(mv2110_mactypes), ++ ++ #ifdef CONFIG_HWMON ++ .hwmon_read_temp_reg = mv2110_hwmon_read_temp_reg, ++@@ -1200,7 +1241,9 @@ static const struct mv3310_chip mv2111_t ++ .get_mactype = mv2110_get_mactype, ++ .set_mactype = mv2110_set_mactype, ++ .select_mactype = mv2110_select_mactype, ++- .init_interface = mv2110_init_interface, +++ +++ .mactypes = mv2110_mactypes, +++ .n_mactypes = ARRAY_SIZE(mv2110_mactypes), ++ ++ #ifdef CONFIG_HWMON ++ .hwmon_read_temp_reg = mv2110_hwmon_read_temp_reg, +diff --git a/target/linux/mvebu/patches-5.15/707-07-3-net-phy-marvell10g-fill-in-possible_interfaces.patch b/target/linux/mvebu/patches-5.15/707-07-3-net-phy-marvell10g-fill-in-possible_interfaces.patch +new file mode 100644 +index 0000000000..092f561dec +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-07-3-net-phy-marvell10g-fill-in-possible_interfaces.patch +@@ -0,0 +1,47 @@ ++From 82f2e76b660a490ae226db80d495b7c785e00d7a Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 24 Nov 2023 12:28:03 +0000 ++Subject: [PATCH] net: phy: marvell10g: fill in possible_interfaces ++ ++Fill in the possible_interfaces member according to the selected ++mactype mode. ++ ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Link: https://lore.kernel.org/r/E1r6VHv-00DDLZ-OL@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/marvell10g.c +++++ b/drivers/net/phy/marvell10g.c ++@@ -803,6 +803,22 @@ static const struct mv3310_mactype mv334 ++ }, ++ }; ++ +++static void mv3310_fill_possible_interfaces(struct phy_device *phydev) +++{ +++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); +++ unsigned long *possible = phydev->possible_interfaces; +++ const struct mv3310_mactype *mactype = priv->mactype; +++ +++ if (mactype->interface_10g != PHY_INTERFACE_MODE_NA) +++ __set_bit(priv->mactype->interface_10g, possible); +++ +++ if (!mactype->fixed_interface) { +++ __set_bit(PHY_INTERFACE_MODE_5GBASER, possible); +++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible); +++ __set_bit(PHY_INTERFACE_MODE_SGMII, possible); +++ } +++} +++ ++ static int mv3310_config_init(struct phy_device *phydev) ++ { ++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); ++@@ -845,6 +861,8 @@ static int mv3310_config_init(struct phy ++ ++ priv->mactype = &chip->mactypes[mactype]; ++ +++ mv3310_fill_possible_interfaces(phydev); +++ ++ /* Enable EDPD mode - saving 600mW */ ++ err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS); ++ if (err) +diff --git a/target/linux/mvebu/patches-5.15/707-07-4-net-phy-bcm84881-fill-in-possible_interfaces.patch b/target/linux/mvebu/patches-5.15/707-07-4-net-phy-bcm84881-fill-in-possible_interfaces.patch +new file mode 100644 +index 0000000000..482ea97eb5 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-07-4-net-phy-bcm84881-fill-in-possible_interfaces.patch +@@ -0,0 +1,44 @@ ++From a22583338e535ba2512283da4aee893163a4b78d Mon Sep 17 00:00:00 2001 ++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> ++Date: Fri, 24 Nov 2023 12:28:08 +0000 ++Subject: [PATCH] net: phy: bcm84881: fill in possible_interfaces ++ ++Fill in the possible_interfaces member. This PHY driver only supports ++a single configuration found on SFPs. ++ ++Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com> ++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Link: https://lore.kernel.org/r/E1r6VI0-00DDLf-Tb@rmk-PC.armlinux.org.uk ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/bcm84881.c +++++ b/drivers/net/phy/bcm84881.c ++@@ -29,8 +29,19 @@ static int bcm84881_wait_init(struct phy ++ 100000, 2000000, false); ++ } ++ +++static void bcm84881_fill_possible_interfaces(struct phy_device *phydev) +++{ +++ unsigned long *possible = phydev->possible_interfaces; +++ +++ __set_bit(PHY_INTERFACE_MODE_SGMII, possible); +++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible); +++ __set_bit(PHY_INTERFACE_MODE_10GBASER, possible); +++} +++ ++ static int bcm84881_config_init(struct phy_device *phydev) ++ { +++ bcm84881_fill_possible_interfaces(phydev); +++ ++ switch (phydev->interface) { ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_2500BASEX: ++@@ -39,6 +50,7 @@ static int bcm84881_config_init(struct p ++ default: ++ return -ENODEV; ++ } +++ ++ return 0; ++ } ++ +diff --git a/target/linux/mvebu/patches-5.15/707-08-1-net-mdio-add-2.5g-and-5g-related-PMA-speed-constants.patch b/target/linux/mvebu/patches-5.15/707-08-1-net-mdio-add-2.5g-and-5g-related-PMA-speed-constants.patch +new file mode 100644 +index 0000000000..6cb63c9577 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-08-1-net-mdio-add-2.5g-and-5g-related-PMA-speed-constants.patch +@@ -0,0 +1,27 @@ ++From 6c06c88fa838fcc1b7e5380facd086f57fd9d1c4 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Sun, 4 Feb 2024 15:16:46 +0100 ++Subject: [PATCH] net: mdio: add 2.5g and 5g related PMA speed constants ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Add constants indicating 2.5g and 5g ability in the MMD PMA speed ++register. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> ++Link: https://lore.kernel.org/r/98e15038-d96c-442f-93e4-410100d27866@gmail.com ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/include/uapi/linux/mdio.h +++++ b/include/uapi/linux/mdio.h ++@@ -119,6 +119,8 @@ ++ #define MDIO_PMA_SPEED_1000 0x0010 /* 1000M capable */ ++ #define MDIO_PMA_SPEED_100 0x0020 /* 100M capable */ ++ #define MDIO_PMA_SPEED_10 0x0040 /* 10M capable */ +++#define MDIO_PMA_SPEED_2_5G 0x2000 /* 2.5G capable */ +++#define MDIO_PMA_SPEED_5G 0x4000 /* 5G capable */ ++ #define MDIO_PCS_SPEED_10P2B 0x0002 /* 10PASS-TS/2BASE-TL capable */ ++ #define MDIO_PCS_SPEED_2_5G 0x0040 /* 2.5G capable */ ++ #define MDIO_PCS_SPEED_5G 0x0080 /* 5G capable */ +diff --git a/target/linux/mvebu/patches-5.15/707-08-2-net-phy-realtek-use-generic-MDIO-constants.patch b/target/linux/mvebu/patches-5.15/707-08-2-net-phy-realtek-use-generic-MDIO-constants.patch +new file mode 100644 +index 0000000000..55ca8ace53 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-08-2-net-phy-realtek-use-generic-MDIO-constants.patch +@@ -0,0 +1,90 @@ ++From 2b9ec5dfb8255656ca731ab9d9bf59d94566d377 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Sun, 4 Feb 2024 15:17:53 +0100 ++Subject: [PATCH] net: phy: realtek: use generic MDIO constants ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Drop the ad-hoc MDIO constants used in the driver and use generic ++constants instead. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Link: https://lore.kernel.org/r/732a70d6-4191-4aae-8862-3716b062aa9e@gmail.com ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/realtek.c +++++ b/drivers/net/phy/realtek.c ++@@ -56,14 +56,6 @@ ++ #define RTL8366RB_POWER_SAVE 0x15 ++ #define RTL8366RB_POWER_SAVE_ON BIT(12) ++ ++-#define RTL_SUPPORTS_5000FULL BIT(14) ++-#define RTL_SUPPORTS_2500FULL BIT(13) ++-#define RTL_SUPPORTS_10000FULL BIT(0) ++-#define RTL_ADV_2500FULL BIT(7) ++-#define RTL_LPADV_10000FULL BIT(11) ++-#define RTL_LPADV_5000FULL BIT(6) ++-#define RTL_LPADV_2500FULL BIT(5) ++- ++ #define RTL9000A_GINMR 0x14 ++ #define RTL9000A_GINMR_LINK_STATUS BIT(4) ++ ++@@ -638,11 +630,11 @@ static int rtl822x_get_features(struct p ++ return val; ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, ++- phydev->supported, val & RTL_SUPPORTS_2500FULL); +++ phydev->supported, val & MDIO_PMA_SPEED_2_5G); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, ++- phydev->supported, val & RTL_SUPPORTS_5000FULL); +++ phydev->supported, val & MDIO_PMA_SPEED_5G); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, ++- phydev->supported, val & RTL_SUPPORTS_10000FULL); +++ phydev->supported, val & MDIO_SPEED_10G); ++ ++ return genphy_read_abilities(phydev); ++ } ++@@ -656,10 +648,11 @@ static int rtl822x_config_aneg(struct ph ++ ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, ++ phydev->advertising)) ++- adv2500 = RTL_ADV_2500FULL; +++ adv2500 = MDIO_AN_10GBT_CTRL_ADV2_5G; ++ ++ ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, ++- RTL_ADV_2500FULL, adv2500); +++ MDIO_AN_10GBT_CTRL_ADV2_5G, +++ adv2500); ++ if (ret < 0) ++ return ret; ++ } ++@@ -678,11 +671,14 @@ static int rtl822x_read_status(struct ph ++ return lpadv; ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, ++- phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL); +++ phydev->lp_advertising, +++ lpadv & MDIO_AN_10GBT_STAT_LP10G); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, ++- phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL); +++ phydev->lp_advertising, +++ lpadv & MDIO_AN_10GBT_STAT_LP5G); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, ++- phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL); +++ phydev->lp_advertising, +++ lpadv & MDIO_AN_10GBT_STAT_LP2_5G); ++ } ++ ++ ret = genphy_read_status(phydev); ++@@ -700,7 +696,7 @@ static bool rtlgen_supports_2_5gbps(stru ++ val = phy_read(phydev, 0x13); ++ phy_write(phydev, RTL821x_PAGE_SELECT, 0); ++ ++- return val >= 0 && val & RTL_SUPPORTS_2500FULL; +++ return val >= 0 && val & MDIO_PMA_SPEED_2_5G; ++ } ++ ++ static int rtlgen_match_phy_device(struct phy_device *phydev) +diff --git a/target/linux/mvebu/patches-5.15/707-08-3-net-phy-realtek-add-5Gbps-support-to-rtl822x_config_.patch b/target/linux/mvebu/patches-5.15/707-08-3-net-phy-realtek-add-5Gbps-support-to-rtl822x_config_.patch +new file mode 100644 +index 0000000000..290ca699a8 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-08-3-net-phy-realtek-add-5Gbps-support-to-rtl822x_config_.patch +@@ -0,0 +1,39 @@ ++From db1bb7741ff29bf2cefcbc0ca567644e9ed1caa9 Mon Sep 17 00:00:00 2001 ++From: Heiner Kallweit <hkallweit1@gmail.com> ++Date: Sun, 4 Feb 2024 15:18:50 +0100 ++Subject: [PATCH] net: phy: realtek: add 5Gbps support to rtl822x_config_aneg() ++ ++RTL8126 as an evolution of RTL8125 supports 5Gbps. rtl822x_config_aneg() ++is used by the PHY driver for the integrated PHY, therefore add 5Gbps ++support to it. ++ ++Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> ++Link: https://lore.kernel.org/r/5644ab50-e3e9-477c-96db-05cd5bdc2563@gmail.com ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/realtek.c +++++ b/drivers/net/phy/realtek.c ++@@ -644,15 +644,19 @@ static int rtl822x_config_aneg(struct ph ++ int ret = 0; ++ ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++- u16 adv2500 = 0; +++ u16 adv = 0; ++ ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, ++ phydev->advertising)) ++- adv2500 = MDIO_AN_10GBT_CTRL_ADV2_5G; +++ adv |= MDIO_AN_10GBT_CTRL_ADV2_5G; +++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, +++ phydev->advertising)) +++ adv |= MDIO_AN_10GBT_CTRL_ADV5G; ++ ++ ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, ++- MDIO_AN_10GBT_CTRL_ADV2_5G, ++- adv2500); +++ MDIO_AN_10GBT_CTRL_ADV2_5G | +++ MDIO_AN_10GBT_CTRL_ADV5G, +++ adv); ++ if (ret < 0) ++ return ret; ++ } +diff --git a/target/linux/mvebu/patches-5.15/707-09-net-phy-realtek-use-generic-MDIO-helpers-to-simplify.patch b/target/linux/mvebu/patches-5.15/707-09-net-phy-realtek-use-generic-MDIO-helpers-to-simplify.patch +new file mode 100644 +index 0000000000..8409275336 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-09-net-phy-realtek-use-generic-MDIO-helpers-to-simplify.patch +@@ -0,0 +1,49 @@ ++From b63cc73341e076961d564a74cc3d29b2fd444079 Mon Sep 17 00:00:00 2001 ++From: Heiner Kallweit <hkallweit1@gmail.com> ++Date: Thu, 8 Feb 2024 07:59:18 +0100 ++Subject: [PATCH] net: phy: realtek: use generic MDIO helpers to simplify the ++ code ++ ++Use generic MDIO helpers to simplify the code. ++ ++Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Link: https://lore.kernel.org/r/422ae70f-7305-45fd-ab3e-0dd604b9fd6c@gmail.com ++Signed-off-by: Jakub Kicinski <kuba@kernel.org> ++ ++--- a/drivers/net/phy/realtek.c +++++ b/drivers/net/phy/realtek.c ++@@ -644,14 +644,7 @@ static int rtl822x_config_aneg(struct ph ++ int ret = 0; ++ ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++- u16 adv = 0; ++- ++- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, ++- phydev->advertising)) ++- adv |= MDIO_AN_10GBT_CTRL_ADV2_5G; ++- if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, ++- phydev->advertising)) ++- adv |= MDIO_AN_10GBT_CTRL_ADV5G; +++ u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); ++ ++ ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, ++ MDIO_AN_10GBT_CTRL_ADV2_5G | ++@@ -674,15 +667,8 @@ static int rtl822x_read_status(struct ph ++ if (lpadv < 0) ++ return lpadv; ++ ++- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, ++- phydev->lp_advertising, ++- lpadv & MDIO_AN_10GBT_STAT_LP10G); ++- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, ++- phydev->lp_advertising, ++- lpadv & MDIO_AN_10GBT_STAT_LP5G); ++- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, ++- phydev->lp_advertising, ++- lpadv & MDIO_AN_10GBT_STAT_LP2_5G); +++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, +++ lpadv); ++ } ++ ++ ret = genphy_read_status(phydev); +diff --git a/target/linux/mvebu/patches-5.15/707-10-1-net-phy-realtek-configure-SerDes-mode-for-rtl822xb-P.patch b/target/linux/mvebu/patches-5.15/707-10-1-net-phy-realtek-configure-SerDes-mode-for-rtl822xb-P.patch +new file mode 100644 +index 0000000000..bf95e8ff1e +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-10-1-net-phy-realtek-configure-SerDes-mode-for-rtl822xb-P.patch +@@ -0,0 +1,206 @@ ++From deb8af5243504e379878ae3f9a091b21422d65b2 Mon Sep 17 00:00:00 2001 ++From: Alexander Couzens <lynxis@fe80.eu> ++Date: Tue, 9 Apr 2024 09:30:11 +0200 ++Subject: [PATCH] net: phy: realtek: configure SerDes mode for rtl822xb PHYs ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++The rtl8221b and rtl8226b series support switching SerDes mode between ++2500base-x and sgmii based on the negotiated copper speed. ++ ++Configure this switching mode according to SerDes modes supported by ++host. ++ ++There is an additional datasheet for RTL8226B/RTL8221B called ++"SERDES MODE SETTING FLOW APPLICATION NOTE" where a sequence is ++described to setup interface and rate adapter mode. ++ ++However, there is no documentation about the meaning of registers ++and bits, it's literally just magic numbers and pseudo-code. ++ ++Signed-off-by: Alexander Couzens <lynxis@fe80.eu> ++[ refactored, dropped HiSGMII mode and changed commit message ] ++Signed-off-by: Marek Behún <kabel@kernel.org> ++[ changed rtl822x_update_interface() to use vendor register ] ++[ always fill in possible interfaces ] ++[ only apply to rtl8221b and rtl8226b phy's ] ++[ set phydev->rate_matching in .config_init() ] ++Signed-off-by: Eric Woudstra <ericwouds@gmail.com> ++ ++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Reviewed-by: should come before them, without any blank lines. As the ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/realtek.c +++++ b/drivers/net/phy/realtek.c ++@@ -53,6 +53,16 @@ ++ RTL8201F_ISR_LINK) ++ #define RTL8201F_IER 0x13 ++ +++#define RTL822X_VND1_SERDES_OPTION 0x697a +++#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) +++#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0 +++#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2 +++ +++#define RTL822X_VND1_SERDES_CTRL3 0x7580 +++#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0) +++#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02 +++#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16 +++ ++ #define RTL8366RB_POWER_SAVE 0x15 ++ #define RTL8366RB_POWER_SAVE_ON BIT(12) ++ ++@@ -621,6 +631,63 @@ static int rtl822x_write_mmd(struct phy_ ++ return ret; ++ } ++ +++static int rtl822xb_config_init(struct phy_device *phydev) +++{ +++ bool has_2500, has_sgmii; +++ u16 mode; +++ int ret; +++ +++ has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, +++ phydev->host_interfaces) || +++ phydev->interface == PHY_INTERFACE_MODE_2500BASEX; +++ +++ has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII, +++ phydev->host_interfaces) || +++ phydev->interface == PHY_INTERFACE_MODE_SGMII; +++ +++ /* fill in possible interfaces */ +++ __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, +++ has_2500); +++ __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces, +++ has_sgmii); +++ +++ if (!has_2500 && !has_sgmii) +++ return 0; +++ +++ /* determine SerDes option mode */ +++ if (has_2500 && !has_sgmii) { +++ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX; +++ phydev->rate_matching = RATE_MATCH_PAUSE; +++ } else { +++ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII; +++ phydev->rate_matching = RATE_MATCH_NONE; +++ } +++ +++ /* the following sequence with magic numbers sets up the SerDes +++ * option mode +++ */ +++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); +++ if (ret < 0) +++ return ret; +++ +++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, +++ RTL822X_VND1_SERDES_OPTION, +++ RTL822X_VND1_SERDES_OPTION_MODE_MASK, +++ mode); +++ if (ret < 0) +++ return ret; +++ +++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); +++ if (ret < 0) +++ return ret; +++ +++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); +++ if (ret < 0) +++ return ret; +++ +++ return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); +++} +++ ++ static int rtl822x_get_features(struct phy_device *phydev) ++ { ++ int val; ++@@ -657,6 +724,28 @@ static int rtl822x_config_aneg(struct ph ++ return __genphy_config_aneg(phydev, ret); ++ } ++ +++static void rtl822xb_update_interface(struct phy_device *phydev) +++{ +++ int val; +++ +++ if (!phydev->link) +++ return; +++ +++ /* Change interface according to serdes mode */ +++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3); +++ if (val < 0) +++ return; +++ +++ switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) { +++ case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX: +++ phydev->interface = PHY_INTERFACE_MODE_2500BASEX; +++ break; +++ case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII: +++ phydev->interface = PHY_INTERFACE_MODE_SGMII; +++ break; +++ } +++} +++ ++ static int rtl822x_read_status(struct phy_device *phydev) ++ { ++ int ret; ++@@ -678,6 +767,19 @@ static int rtl822x_read_status(struct ph ++ return rtlgen_get_speed(phydev); ++ } ++ +++static int rtl822xb_read_status(struct phy_device *phydev) +++{ +++ int ret; +++ +++ ret = rtl822x_read_status(phydev); +++ if (ret < 0) +++ return ret; +++ +++ rtl822xb_update_interface(phydev); +++ +++ return 0; +++} +++ ++ static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) ++ { ++ int val; ++@@ -936,7 +1038,8 @@ static struct phy_driver realtek_drvs[] ++ .name = "RTL8226B_RTL8221B 2.5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++- .read_status = rtl822x_read_status, +++ .config_init = rtl822xb_config_init, +++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++@@ -958,7 +1061,8 @@ static struct phy_driver realtek_drvs[] ++ .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++- .read_status = rtl822x_read_status, +++ .config_init = rtl822xb_config_init, +++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++@@ -968,7 +1072,8 @@ static struct phy_driver realtek_drvs[] ++ .name = "RTL8221B-VB-CG 2.5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++- .read_status = rtl822x_read_status, +++ .config_init = rtl822xb_config_init, +++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++@@ -978,7 +1083,8 @@ static struct phy_driver realtek_drvs[] ++ .name = "RTL8221B-VM-CG 2.5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++- .read_status = rtl822x_read_status, +++ .config_init = rtl822xb_config_init, +++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, +diff --git a/target/linux/mvebu/patches-5.15/707-10-2-net-phy-realtek-add-get_rate_matching-for-rtl822xb-P.patch b/target/linux/mvebu/patches-5.15/707-10-2-net-phy-realtek-add-get_rate_matching-for-rtl822xb-P.patch +new file mode 100644 +index 0000000000..5eddd6cc18 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-10-2-net-phy-realtek-add-get_rate_matching-for-rtl822xb-P.patch +@@ -0,0 +1,74 @@ ++From c189dbd738243be6775bb6878366bf63e27bfd05 Mon Sep 17 00:00:00 2001 ++From: Eric Woudstra <ericwouds@gmail.com> ++Date: Tue, 9 Apr 2024 09:30:12 +0200 ++Subject: [PATCH] net: phy: realtek: add get_rate_matching() for rtl822xb PHYs ++ ++Uses vendor register to determine if SerDes is setup in rate-matching mode. ++ ++Rate-matching only supported when SerDes is set to 2500base-x. ++ ++Signed-off-by: Eric Woudstra <ericwouds@gmail.com> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/realtek.c +++++ b/drivers/net/phy/realtek.c ++@@ -688,6 +688,27 @@ static int rtl822xb_config_init(struct p ++ return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); ++ } ++ +++static int rtl822xb_get_rate_matching(struct phy_device *phydev, +++ phy_interface_t iface) +++{ +++ int val; +++ +++ /* Only rate matching at 2500base-x */ +++ if (iface != PHY_INTERFACE_MODE_2500BASEX) +++ return RATE_MATCH_NONE; +++ +++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION); +++ if (val < 0) +++ return val; +++ +++ if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) == +++ RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX) +++ return RATE_MATCH_PAUSE; +++ +++ /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */ +++ return RATE_MATCH_NONE; +++} +++ ++ static int rtl822x_get_features(struct phy_device *phydev) ++ { ++ int val; ++@@ -1039,6 +1060,7 @@ static struct phy_driver realtek_drvs[] ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, +++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++@@ -1062,6 +1084,7 @@ static struct phy_driver realtek_drvs[] ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, +++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++@@ -1073,6 +1096,7 @@ static struct phy_driver realtek_drvs[] ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, +++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++@@ -1084,6 +1108,7 @@ static struct phy_driver realtek_drvs[] ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, +++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, +diff --git a/target/linux/mvebu/patches-5.15/707-10-3-net-phy-realtek-Add-driver-instances-for-rtl8221b-vi.patch b/target/linux/mvebu/patches-5.15/707-10-3-net-phy-realtek-Add-driver-instances-for-rtl8221b-vi.patch +new file mode 100644 +index 0000000000..ff80be2370 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-10-3-net-phy-realtek-Add-driver-instances-for-rtl8221b-vi.patch +@@ -0,0 +1,215 @@ ++From ad5ce743a6b0329f642d80be50ef7b534e908fba Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Tue, 9 Apr 2024 09:30:13 +0200 ++Subject: [PATCH] net: phy: realtek: Add driver instances for rtl8221b via ++ Clause 45 ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Collected from several commits in [PATCH net-next] ++"Realtek RTL822x PHY rework to c45 and SerDes interface switching" ++ ++The instances are used by Clause 45 only accessible PHY's on several sfp ++modules, which are using RollBall protocol. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++[ Added matching functions to differentiate C45 instances ] ++Signed-off-by: Eric Woudstra <ericwouds@gmail.com> ++ ++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/realtek.c +++++ b/drivers/net/phy/realtek.c ++@@ -63,6 +63,13 @@ ++ #define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02 ++ #define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16 ++ +++/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 +++ * is set, they cannot be accessed by C45-over-C22. +++ */ +++#define RTL822X_VND2_GBCR 0xa412 +++ +++#define RTL822X_VND2_GANLPAR 0xa414 +++ ++ #define RTL8366RB_POWER_SAVE 0x15 ++ #define RTL8366RB_POWER_SAVE_ON BIT(12) ++ ++@@ -72,6 +79,9 @@ ++ #define RTLGEN_SPEED_MASK 0x0630 ++ ++ #define RTL_GENERIC_PHYID 0x001cc800 +++#define RTL_8221B_VB_CG 0x001cc849 +++#define RTL_8221B_VN_CG 0x001cc84a +++#define RTL_8251B 0x001cc862 ++ ++ MODULE_DESCRIPTION("Realtek PHY driver"); ++ MODULE_AUTHOR("Johnson Leung"); ++@@ -801,6 +811,67 @@ static int rtl822xb_read_status(struct p ++ return 0; ++ } ++ +++static int rtl822x_c45_config_aneg(struct phy_device *phydev) +++{ +++ bool changed = false; +++ int ret, val; +++ +++ if (phydev->autoneg == AUTONEG_DISABLE) +++ return genphy_c45_pma_setup_forced(phydev); +++ +++ ret = genphy_c45_an_config_aneg(phydev); +++ if (ret < 0) +++ return ret; +++ if (ret > 0) +++ changed = true; +++ +++ val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); +++ +++ /* Vendor register as C45 has no standardized support for 1000BaseT */ +++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, +++ ADVERTISE_1000FULL, val); +++ if (ret < 0) +++ return ret; +++ if (ret > 0) +++ changed = true; +++ +++ return genphy_c45_check_and_restart_aneg(phydev, changed); +++} +++ +++static int rtl822x_c45_read_status(struct phy_device *phydev) +++{ +++ int ret, val; +++ +++ ret = genphy_c45_read_status(phydev); +++ if (ret < 0) +++ return ret; +++ +++ /* Vendor register as C45 has no standardized support for 1000BaseT */ +++ if (phydev->autoneg == AUTONEG_ENABLE) { +++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, +++ RTL822X_VND2_GANLPAR); +++ if (val < 0) +++ return val; +++ +++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); +++ } +++ +++ return 0; +++} +++ +++static int rtl822xb_c45_read_status(struct phy_device *phydev) +++{ +++ int ret; +++ +++ ret = rtl822x_c45_read_status(phydev); +++ if (ret < 0) +++ return ret; +++ +++ rtl822xb_update_interface(phydev); +++ +++ return 0; +++} +++ ++ static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) ++ { ++ int val; ++@@ -824,6 +895,35 @@ static int rtl8226_match_phy_device(stru ++ rtlgen_supports_2_5gbps(phydev); ++ } ++ +++static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, +++ bool is_c45) +++{ +++ if (phydev->is_c45) +++ return is_c45 && (id == phydev->c45_ids.device_ids[1]); +++ else +++ return !is_c45 && (id == phydev->phy_id); +++} +++ +++static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) +++{ +++ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); +++} +++ +++static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev) +++{ +++ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true); +++} +++ +++static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev) +++{ +++ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false); +++} +++ +++static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) +++{ +++ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); +++} +++ ++ static int rtlgen_resume(struct phy_device *phydev) ++ { ++ int ret = genphy_resume(phydev); ++@@ -834,6 +934,15 @@ static int rtlgen_resume(struct phy_devi ++ return ret; ++ } ++ +++static int rtlgen_c45_resume(struct phy_device *phydev) +++{ +++ int ret = genphy_c45_pma_resume(phydev); +++ +++ msleep(20); +++ +++ return ret; +++} +++ ++ static int rtl9000a_config_init(struct phy_device *phydev) ++ { ++ phydev->autoneg = AUTONEG_DISABLE; ++@@ -1091,8 +1200,8 @@ static struct phy_driver realtek_drvs[] ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++- PHY_ID_MATCH_EXACT(0x001cc849), ++- .name = "RTL8221B-VB-CG 2.5Gbps PHY", +++ .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, +++ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, ++@@ -1103,8 +1212,17 @@ static struct phy_driver realtek_drvs[] ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++- PHY_ID_MATCH_EXACT(0x001cc84a), ++- .name = "RTL8221B-VM-CG 2.5Gbps PHY", +++ .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, +++ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", +++ .config_init = rtl822xb_config_init, +++ .get_rate_matching = rtl822xb_get_rate_matching, +++ .config_aneg = rtl822x_c45_config_aneg, +++ .read_status = rtl822xb_c45_read_status, +++ .suspend = genphy_c45_pma_suspend, +++ .resume = rtlgen_c45_resume, +++ }, { +++ .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, +++ .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, ++@@ -1115,6 +1233,15 @@ static struct phy_driver realtek_drvs[] ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { +++ .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, +++ .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", +++ .config_init = rtl822xb_config_init, +++ .get_rate_matching = rtl822xb_get_rate_matching, +++ .config_aneg = rtl822x_c45_config_aneg, +++ .read_status = rtl822xb_c45_read_status, +++ .suspend = genphy_c45_pma_suspend, +++ .resume = rtlgen_c45_resume, +++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc961), ++ .name = "RTL8366RB Gigabit Ethernet", ++ .config_init = &rtl8366rb_config_init, +diff --git a/target/linux/mvebu/patches-5.15/707-10-4-net-phy-realtek-Change-rtlgen_get_speed-to-rtlgen_de.patch b/target/linux/mvebu/patches-5.15/707-10-4-net-phy-realtek-Change-rtlgen_get_speed-to-rtlgen_de.patch +new file mode 100644 +index 0000000000..b832de6feb +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-10-4-net-phy-realtek-Change-rtlgen_get_speed-to-rtlgen_de.patch +@@ -0,0 +1,122 @@ ++From 2e4ea707c7e04eb83e58c43e0e744bbdf6b23ff2 Mon Sep 17 00:00:00 2001 ++From: Eric Woudstra <ericwouds@gmail.com> ++Date: Tue, 9 Apr 2024 09:30:14 +0200 ++Subject: [PATCH] net: phy: realtek: Change rtlgen_get_speed() to ++ rtlgen_decode_speed() ++ ++The value of the register to determine the speed, is retrieved ++differently when using Clause 45 only. To use the rtlgen_get_speed() ++function in this case, pass the value of the register as argument to ++rtlgen_get_speed(). The function would then always return 0, so change it ++to void. A better name for this function now is rtlgen_decode_speed(). ++ ++Replace a call to genphy_read_status() followed by rtlgen_get_speed() ++with a call to rtlgen_read_status() in rtl822x_read_status(). ++ ++Add reading speed to rtl822x_c45_read_status(). ++ ++Signed-off-by: Eric Woudstra <ericwouds@gmail.com> ++ ++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/realtek.c +++++ b/drivers/net/phy/realtek.c ++@@ -70,6 +70,8 @@ ++ ++ #define RTL822X_VND2_GANLPAR 0xa414 ++ +++#define RTL822X_VND2_PHYSR 0xa434 +++ ++ #define RTL8366RB_POWER_SAVE 0x15 ++ #define RTL8366RB_POWER_SAVE_ON BIT(12) ++ ++@@ -513,17 +515,8 @@ static int rtl8366rb_config_init(struct ++ } ++ ++ /* get actual speed to cover the downshift case */ ++-static int rtlgen_get_speed(struct phy_device *phydev) +++static void rtlgen_decode_speed(struct phy_device *phydev, int val) ++ { ++- int val; ++- ++- if (!phydev->link) ++- return 0; ++- ++- val = phy_read_paged(phydev, 0xa43, 0x12); ++- if (val < 0) ++- return val; ++- ++ switch (val & RTLGEN_SPEED_MASK) { ++ case 0x0000: ++ phydev->speed = SPEED_10; ++@@ -546,19 +539,26 @@ static int rtlgen_get_speed(struct phy_d ++ default: ++ break; ++ } ++- ++- return 0; ++ } ++ ++ static int rtlgen_read_status(struct phy_device *phydev) ++ { ++- int ret; +++ int ret, val; ++ ++ ret = genphy_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++- return rtlgen_get_speed(phydev); +++ if (!phydev->link) +++ return 0; +++ +++ val = phy_read_paged(phydev, 0xa43, 0x12); +++ if (val < 0) +++ return val; +++ +++ rtlgen_decode_speed(phydev, val); +++ +++ return 0; ++ } ++ ++ static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) ++@@ -779,8 +779,6 @@ static void rtl822xb_update_interface(st ++ ++ static int rtl822x_read_status(struct phy_device *phydev) ++ { ++- int ret; ++- ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++ int lpadv = phy_read_paged(phydev, 0xa5d, 0x13); ++ ++@@ -791,11 +789,7 @@ static int rtl822x_read_status(struct ph ++ lpadv); ++ } ++ ++- ret = genphy_read_status(phydev); ++- if (ret < 0) ++- return ret; ++- ++- return rtlgen_get_speed(phydev); +++ return rtlgen_read_status(phydev); ++ } ++ ++ static int rtl822xb_read_status(struct phy_device *phydev) ++@@ -856,6 +850,16 @@ static int rtl822x_c45_read_status(struc ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); ++ } ++ +++ if (!phydev->link) +++ return 0; +++ +++ /* Read actual speed from vendor register. */ +++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_PHYSR); +++ if (val < 0) +++ return val; +++ +++ rtlgen_decode_speed(phydev, val); +++ ++ return 0; ++ } ++ +diff --git a/target/linux/mvebu/patches-5.15/707-10-5-net-phy-realtek-add-rtl822x_c45_get_features-to-set-.patch b/target/linux/mvebu/patches-5.15/707-10-5-net-phy-realtek-add-rtl822x_c45_get_features-to-set-.patch +new file mode 100644 +index 0000000000..21fefd8d21 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-10-5-net-phy-realtek-add-rtl822x_c45_get_features-to-set-.patch +@@ -0,0 +1,45 @@ ++From 2d9ce64862705b33397d54dafecc5f51d8b1bb06 Mon Sep 17 00:00:00 2001 ++From: Eric Woudstra <ericwouds@gmail.com> ++Date: Tue, 9 Apr 2024 09:30:15 +0200 ++Subject: [PATCH] net: phy: realtek: add rtl822x_c45_get_features() to set ++ supported port ++ ++Sets ETHTOOL_LINK_MODE_TP_BIT in phydev->supported. ++ ++Signed-off-by: Eric Woudstra <ericwouds@gmail.com> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/realtek.c +++++ b/drivers/net/phy/realtek.c ++@@ -805,6 +805,14 @@ static int rtl822xb_read_status(struct p ++ return 0; ++ } ++ +++static int rtl822x_c45_get_features(struct phy_device *phydev) +++{ +++ linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, +++ phydev->supported); +++ +++ return genphy_c45_pma_read_abilities(phydev); +++} +++ ++ static int rtl822x_c45_config_aneg(struct phy_device *phydev) ++ { ++ bool changed = false; ++@@ -1220,6 +1228,7 @@ static struct phy_driver realtek_drvs[] ++ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, +++ .get_features = rtl822x_c45_get_features, ++ .config_aneg = rtl822x_c45_config_aneg, ++ .read_status = rtl822xb_c45_read_status, ++ .suspend = genphy_c45_pma_suspend, ++@@ -1241,6 +1250,7 @@ static struct phy_driver realtek_drvs[] ++ .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, +++ .get_features = rtl822x_c45_get_features, ++ .config_aneg = rtl822x_c45_config_aneg, ++ .read_status = rtl822xb_c45_read_status, ++ .suspend = genphy_c45_pma_suspend, +diff --git a/target/linux/mvebu/patches-5.15/707-10-6-net-sfp-add-quirk-for-another-multigig-RollBall-tran.patch b/target/linux/mvebu/patches-5.15/707-10-6-net-sfp-add-quirk-for-another-multigig-RollBall-tran.patch +new file mode 100644 +index 0000000000..f85443bdc6 +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-10-6-net-sfp-add-quirk-for-another-multigig-RollBall-tran.patch +@@ -0,0 +1,27 @@ ++From 1c77c721916ae108c2c5865986735bfe92000908 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Tue, 9 Apr 2024 09:30:16 +0200 ++Subject: [PATCH] net: sfp: add quirk for another multigig RollBall transceiver ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Add quirk for another RollBall copper transceiver: Turris RTSFP-2.5G, ++containing 2.5g capable RTL8221B PHY. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Signed-off-by: Eric Woudstra <ericwouds@gmail.com> ++ ++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> ++Signed-off-by: David S. Miller <davem@davemloft.net> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -509,6 +509,7 @@ static const struct sfp_quirk sfp_quirks ++ SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), ++ SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc), ++ SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc), +++ SFP_QUIRK_F("Turris", "RTSFP-2.5G", sfp_fixup_rollball), ++ SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball), ++ SFP_QUIRK_F("Turris", "RTSFP-10G", sfp_fixup_rollball), ++ }; +diff --git a/target/linux/mvebu/patches-5.15/707-11-1-net-sfp-update-comment-for-FS-SFP-10G-T-quirk.patch b/target/linux/mvebu/patches-5.15/707-11-1-net-sfp-update-comment-for-FS-SFP-10G-T-quirk.patch +new file mode 100644 +index 0000000000..0b96cfa5bb +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-11-1-net-sfp-update-comment-for-FS-SFP-10G-T-quirk.patch +@@ -0,0 +1,30 @@ ++From 92fadf3c4ef9a3d1b5bdc75d89366d2138e0ef12 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Mon, 22 Apr 2024 11:19:09 +0200 ++Subject: [PATCH] net: sfp: update comment for FS SFP-10G-T quirk ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Update the comment for the Fibrestore SFP-10G-T module: since commit ++e9301af385e7 ("net: sfp: fix PHY discovery for FS SFP-10G-T module") ++we also do a 4 second wait before probing the PHY. ++ ++Fixes: e9301af385e7 ("net: sfp: fix PHY discovery for FS SFP-10G-T module") ++Signed-off-by: Marek Behún <kabel@kernel.org> ++Reviewed-by: Andrew Lunn <andrew@lunn.ch> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -471,8 +471,9 @@ static const struct sfp_quirk sfp_quirks ++ SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex, ++ sfp_fixup_nokia), ++ ++- // Fiberstore SFP-10G-T doesn't identify as copper, and uses the ++- // Rollball protocol to talk to the PHY. +++ // Fiberstore SFP-10G-T doesn't identify as copper, uses the Rollball +++ // protocol to talk to the PHY and needs 4 sec wait before probing the +++ // PHY. ++ SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt), ++ ++ // Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd +diff --git a/target/linux/mvebu/patches-5.15/707-11-2-net-sfp-enhance-quirk-for-Fibrestore-2.5G-copper-SFP.patch b/target/linux/mvebu/patches-5.15/707-11-2-net-sfp-enhance-quirk-for-Fibrestore-2.5G-copper-SFP.patch +new file mode 100644 +index 0000000000..622f883baa +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-11-2-net-sfp-enhance-quirk-for-Fibrestore-2.5G-copper-SFP.patch +@@ -0,0 +1,71 @@ ++From dda80a7dd0819a758cf2ab0b20e40fbcb88091ca Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> ++Date: Mon, 22 Apr 2024 11:09:29 +0200 ++Subject: [PATCH] net: sfp: enhance quirk for Fibrestore 2.5G copper SFP module ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Enhance the quirk for Fibrestore 2.5G copper SFP module. The original ++commit e27aca3760c0 ("net: sfp: add quirk for FS's 2.5G copper SFP") ++introducing the quirk says that the PHY is inaccessible, but that is ++not true. ++ ++The module uses Rollball protocol to talk to the PHY, and needs a 4 ++second wait before probing it, same as FS 10G module. ++ ++The PHY inside the module is Realtek RTL8221B-VB-CG PHY. The realtek ++driver recently gained support to set it up via clause 45 accesses. ++ ++Signed-off-by: Marek Behún <kabel@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -387,18 +387,23 @@ static void sfp_fixup_rollball(struct sf ++ sfp->phy_t_retry = msecs_to_jiffies(1000); ++ } ++ ++-static void sfp_fixup_fs_10gt(struct sfp *sfp) +++static void sfp_fixup_fs_2_5gt(struct sfp *sfp) ++ { ++- sfp_fixup_10gbaset_30m(sfp); ++ sfp_fixup_rollball(sfp); ++ ++- /* The RollBall fixup is not enough for FS modules, the AQR chip inside +++ /* The RollBall fixup is not enough for FS modules, the PHY chip inside ++ * them does not return 0xffff for PHY ID registers in all MMDs for the ++ * while initializing. They need a 4 second wait before accessing PHY. ++ */ ++ sfp->module_t_wait = msecs_to_jiffies(4000); ++ } ++ +++static void sfp_fixup_fs_10gt(struct sfp *sfp) +++{ +++ sfp_fixup_10gbaset_30m(sfp); +++ sfp_fixup_fs_2_5gt(sfp); +++} +++ ++ static void sfp_fixup_halny_gsfp(struct sfp *sfp) ++ { ++ /* Ignore the TX_FAULT and LOS signals on this module. ++@@ -476,6 +481,10 @@ static const struct sfp_quirk sfp_quirks ++ // PHY. ++ SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt), ++ +++ // Fiberstore SFP-2.5G-T uses Rollball protocol to talk to the PHY and +++ // needs 4 sec wait before probing the PHY. +++ SFP_QUIRK_F("FS", "SFP-2.5G-T", sfp_fixup_fs_2_5gt), +++ ++ // Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd ++ // NRZ in their EEPROM ++ SFP_QUIRK("FS", "GPON-ONU-34-20BI", sfp_quirk_2500basex, ++@@ -492,9 +501,6 @@ static const struct sfp_quirk sfp_quirks ++ SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex, ++ sfp_fixup_ignore_tx_fault), ++ ++- // FS 2.5G Base-T ++- SFP_QUIRK_M("FS", "SFP-2.5G-T", sfp_quirk_oem_2_5g), ++- ++ // Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report ++ // 2500MBd NRZ in their EEPROM ++ SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex), +diff --git a/target/linux/mvebu/patches-5.15/707-12-net-sfp-add-quirk-for-ATS-SFP-GE-T-1000Base-TX-modul.patch b/target/linux/mvebu/patches-5.15/707-12-net-sfp-add-quirk-for-ATS-SFP-GE-T-1000Base-TX-modul.patch +new file mode 100644 +index 0000000000..24e901413c +--- /dev/null ++++ b/target/linux/mvebu/patches-5.15/707-12-net-sfp-add-quirk-for-ATS-SFP-GE-T-1000Base-TX-modul.patch +@@ -0,0 +1,30 @@ ++From e0237a52ec29fe07ef2c83d8e97dca91d9a270ce Mon Sep 17 00:00:00 2001 ++From: Daniel Golle <daniel@makrotopia.org> ++Date: Tue, 23 Apr 2024 10:58:12 +0200 ++Subject: [PATCH] net: sfp: add quirk for ATS SFP-GE-T 1000Base-TX module ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Add quirk for ATS SFP-GE-T 1000Base-TX module. ++ ++This copper module comes with broken TX_FAULT indicator which must be ++ignored for it to work. ++ ++Co-authored-by: Josef Schlehofer <pepe.schlehofer@gmail.com> ++Signed-off-by: Daniel Golle <daniel@makrotopia.org> ++[ rebased on top of net-next ] ++Signed-off-by: Marek Behún <kabel@kernel.org> ++ ++--- a/drivers/net/phy/sfp.c +++++ b/drivers/net/phy/sfp.c ++@@ -512,6 +512,9 @@ static const struct sfp_quirk sfp_quirks ++ SFP_QUIRK_F("Walsun", "HXSX-ATRC-1", sfp_fixup_fs_10gt), ++ SFP_QUIRK_F("Walsun", "HXSX-ATRI-1", sfp_fixup_fs_10gt), ++ +++ // OEM SFP-GE-T is a 1000Base-T module with broken TX_FAULT indicator +++ SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault), +++ ++ SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), ++ SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), ++ SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc), +-- +2.43.2 + diff --git a/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-add-support-for-Turris-SFP-module.patch b/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-add-support-for-Turris-SFP-module.patch deleted file mode 100644 index 7c9221d24b813850d59ff45758831b4ac277e5fe..0000000000000000000000000000000000000000 --- a/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-add-support-for-Turris-SFP-module.patch +++ /dev/null @@ -1,2297 +0,0 @@ -From 5c7fed78547688817c24ceac4f341e30830bcd26 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <marek.behun@nic.cz> -Date: Thu, 24 Sep 2020 00:28:51 +0200 -Subject: [PATCH 9/9] mvebu: add support for Turris SFP module - ---- - target/linux/mvebu/config-5.15 | 1 + - ...te-supported_interfaces-with-lower-m.patch | 144 ++++++ - ...-supported-PHY-interface-modes-to-ph.patch | 123 +++++ - ...ell10g-add-downshift-tunable-support.patch | 220 +++++++++ - ...0g-Use-generic-macro-for-supported-i.patch | 35 ++ - ...0g-Use-tabs-instead-of-spaces-for-in.patch | 51 ++ - ...0g-select-host-interface-configurati.patch | 242 ++++++++++ - ...w-attaching-phy-for-SFP-modules-on-8.patch | 48 ++ - ...estroy-I2C-mdiobus-before-PHY-probe-.patch | 181 ++++++++ - ...-support-I2C-MDIO-protocol-for-RollB.patch | 434 ++++++++++++++++++ - ...ort-for-multigig-RollBall-transceive.patch | 156 +++++++ - ...SFP-parsing-with-phy_interface_t-bit.patch | 340 ++++++++++++++ - ...phy_interface_t-bitmaps-for-optical-.patch | 203 ++++++++ - 13 files changed, 2178 insertions(+) - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-01-net-phylink-update-supported_interfaces-with-lower-m.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-02-net-phylink-pass-supported-PHY-interface-modes-to-ph.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-03-net-phy-marvell10g-add-downshift-tunable-support.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-04-net-phy-marvell10g-Use-generic-macro-for-supported-i.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-05-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-06-net-phy-marvell10g-select-host-interface-configurati.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-07-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-08-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-09-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-10-net-sfp-add-support-for-multigig-RollBall-transceive.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-11-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch - create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-12-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch - -diff --git a/target/linux/mvebu/config-5.15 b/target/linux/mvebu/config-5.15 -index 0811ee6d4c..f3548c94b7 100644 ---- a/target/linux/mvebu/config-5.15 -+++ b/target/linux/mvebu/config-5.15 -@@ -241,6 +241,7 @@ CONFIG_MACH_MVEBU_V7=y - CONFIG_MAGIC_SYSRQ=y - CONFIG_MANGLE_BOOTARGS=y - CONFIG_MARVELL_PHY=y -+CONFIG_MARVELL_10G_PHY=y - CONFIG_MDIO_BUS=y - CONFIG_MDIO_DEVICE=y - CONFIG_MDIO_DEVRES=y -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-01-net-phylink-update-supported_interfaces-with-lower-m.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-01-net-phylink-update-supported_interfaces-with-lower-m.patch -new file mode 100644 -index 0000000000..c0c274d278 ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-01-net-phylink-update-supported_interfaces-with-lower-m.patch -@@ -0,0 +1,144 @@ -+From e6ad7e8ac63cf2190a94af5e4d88f19c4353c1ba Mon Sep 17 00:00:00 2001 -+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> -+Date: Thu, 4 Nov 2021 20:57:33 +0100 -+Subject: [PATCH 01/12] net: phylink: update supported_interfaces with lower -+ modes -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+Update the bitmap of interfaces supported by the MAC with lower modes -+that should be supported if upper are. -+ -+As Russell King says, -+ conventionally phy-mode has meant "this is the mode we want to operate -+ the PHY interface in" which was fine when PHYs didn't change their -+ mode depending on the media speed -+ -+An example is DT defining -+ phy-mode = "sgmii"; -+but the board supporting also 1000base-x and 2500base-x. -+ -+Add the following logic to keep this backwards compatiblity: -+- if one PHY mode is defined: -+ - if it is sgmii, 1000base-x or 2500base-x, add all three and then do -+ the intersection -+ - if it is 10gbase-r or usxgmii, add both, and also 5gbase-r, -+ 2500base-x, 1000base-x and sgmii, and then do the intersection -+ -+This is simple enough and should work for all boards. -+ -+Nonetheless it is possible (although extremely unlikely, in my opinion) -+that a board will be found that (for example) defines -+ phy-mode = "sgmii"; -+and the MAC drivers supports sgmii, 1000base-x and 2500base-x, but the -+board DOESN'T support 2500base-x, because of electrical reasons (since -+the frequency is 2.5x of sgmii). -+Our code will in this case incorrectly infer also support for -+2500base-x. To avoid this, the board maintainer should add a fix into -+the function we are introducing in this commit. -+ -+Another example would be a board with device-tree defining -+ phy-mode = "10gbase-r"; -+We infer from this all other modes (sgmii, 1000base-x, 2500base-x, -+5gbase-r, usxgmii), and these then get filtered by those supported by -+the driver. But it is possible that a driver supports all of these -+modes, and yet not all are supported because the board has an older -+version of the TF-A firmware, which implements changing of PHY modes via -+SMC calls. For this case, the board maintainer should add a fix into -+this function that somehow checks for this situation. But this is a -+really improbable scenario, in my opinion. -+ -+Signed-off-by: Marek Behún <kabel@kernel.org> -+--- -+ drivers/net/phy/phylink.c | 67 +++++++++++++++++++++++++++++++++++++++ -+ 1 file changed, 67 insertions(+) -+ -+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c -+index 49eb7fd4ed51..fbcab015ff7d 100644 -+--- a/drivers/net/phy/phylink.c -++++ b/drivers/net/phy/phylink.c -+@@ -300,6 +300,71 @@ static int phylink_parse_fixedlink(struct phylink *pl, -+ return 0; -+ } -+ -++static void phylink_update_phy_modes(struct phylink *pl, -++ struct fwnode_handle *fwnode) -++{ -++ unsigned long *supported = pl->config->supported_interfaces; -++ DECLARE_PHY_INTERFACE_MASK(modes); -++ -++ /* FIXME: If supported is empty, leave it as it is. This happens for -++ * unconverted drivers that don't fill up supported_interfaces. Once all -++ * such drivers are converted, we can drop this. -++ */ -++ if (phy_interface_empty(supported)) -++ return; -++ -++ /* If no modes are defined in fwnode, interpret it as all modes -++ * supported by the MAC are supported by the board. -++ */ -++ if (phy_interface_empty(modes)) -++ return; -++ -++ /* We want the intersection of given supported modes with those defined -++ * in DT. -++ * -++ * Some older device-trees mention only one of `sgmii`, `1000base-x` or -++ * `2500base-x`, while supporting all three. Other mention `10gbase-r` -++ * or `usxgmii`, while supporting both, and also `sgmii`, `1000base-x`, -++ * `2500base-x` and `5gbase-r`. -++ * For backwards compatibility with these older DTs, make it so that if -++ * one of these modes is mentioned in DT and MAC supports more of them, -++ * keep all that are supported according to the logic above. -++ * -++ * Nonetheless it is possible that a device may support only one mode, -++ * for example 1000base-x, due to strapping pins or some other reasons. -++ * If a specific device supports only the mode mentioned in DT, the -++ * exception should be made here with of_machine_is_compatible(). -++ */ -++ if (bitmap_weight(modes, PHY_INTERFACE_MODE_MAX) == 1) { -++ DECLARE_PHY_INTERFACE_MASK(mask); -++ bool lower = false; -++ -++ if (test_bit(PHY_INTERFACE_MODE_10GBASER, modes) || -++ test_bit(PHY_INTERFACE_MODE_USXGMII, modes)) { -++ phy_interface_zero(mask); -++ __set_bit(PHY_INTERFACE_MODE_5GBASER, mask); -++ __set_bit(PHY_INTERFACE_MODE_10GBASER, mask); -++ __set_bit(PHY_INTERFACE_MODE_USXGMII, mask); -++ phy_interface_and(mask, supported, mask); -++ phy_interface_or(modes, modes, mask); -++ lower = true; -++ } -++ -++ if (lower || (test_bit(PHY_INTERFACE_MODE_SGMII, modes) || -++ test_bit(PHY_INTERFACE_MODE_1000BASEX, modes) || -++ test_bit(PHY_INTERFACE_MODE_2500BASEX, modes))) { -++ phy_interface_zero(mask); -++ __set_bit(PHY_INTERFACE_MODE_SGMII, mask); -++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, mask); -++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, mask); -++ phy_interface_and(mask, supported, mask); -++ phy_interface_or(modes, modes, mask); -++ } -++ } -++ -++ phy_interface_and(supported, supported, modes); -++} -++ -+ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode) -+ { -+ struct fwnode_handle *dn; -+@@ -911,6 +976,8 @@ struct phylink *phylink_create(struct phylink_config *config, -+ __set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); -+ timer_setup(&pl->link_poll, phylink_fixed_poll, 0); -+ -++ phylink_update_phy_modes(pl, fwnode); -++ -+ bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_copy(pl->link_config.advertising, pl->supported); -+ phylink_validate(pl, pl->supported, &pl->link_config); -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-02-net-phylink-pass-supported-PHY-interface-modes-to-ph.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-02-net-phylink-pass-supported-PHY-interface-modes-to-ph.patch -new file mode 100644 -index 0000000000..a528045987 ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-02-net-phylink-pass-supported-PHY-interface-modes-to-ph.patch -@@ -0,0 +1,123 @@ -+From 3b7db3ec50d7ccc39ab98b592a2f0bdeee632cc1 Mon Sep 17 00:00:00 2001 -+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> -+Date: Mon, 22 Nov 2021 21:39:41 +0100 -+Subject: [PATCH 02/12] net: phylink: pass supported PHY interface modes to -+ phylib -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+Pass the supported PHY interface types to phylib so that PHY drivers -+can select an appropriate host configuration mode for their interface -+according to the host capabilities. -+ -+Signed-off-by: Marek Behún <kabel@kernel.org> -+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> -+--- -+ drivers/net/phy/phylink.c | 28 ++++++++++++++++++++++++++++ -+ include/linux/phy.h | 10 ++++++++++ -+ 2 files changed, 38 insertions(+) -+ -+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c -+index fbcab015ff7d..9d248802253a 100644 -+--- a/drivers/net/phy/phylink.c -++++ b/drivers/net/phy/phylink.c -+@@ -1195,6 +1195,10 @@ int phylink_connect_phy(struct phylink *pl, struct phy_device *phy) -+ pl->link_config.interface = pl->link_interface; -+ } -+ -++ /* Set the PHY's host supported interfaces */ -++ phy_interface_copy(phy->host_interfaces, -++ pl->config->supported_interfaces); -++ -+ ret = phylink_attach_phy(pl, phy, pl->link_interface); -+ if (ret < 0) -+ return ret; -+@@ -1264,6 +1268,10 @@ int phylink_fwnode_phy_connect(struct phylink *pl, -+ if (!phy_dev) -+ return -ENODEV; -+ -++ /* Set the PHY's host supported interfaces */ -++ phy_interface_copy(phy_dev->host_interfaces, -++ pl->config->supported_interfaces); -++ -+ ret = phy_attach_direct(pl->netdev, phy_dev, flags, -+ pl->link_interface); -+ if (ret) { -+@@ -2448,6 +2456,8 @@ static bool phylink_phy_no_inband(struct phy_device *phy) -+ (phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150; -+ } -+ -++static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces); -++ -+ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) -+ { -+ struct phylink *pl = upstream; -+@@ -2469,6 +2479,10 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *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(pl, mode, phy->supported, phy->advertising); -+ if (ret < 0) -+@@ -2852,4 +2866,18 @@ void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs, -+ } -+ EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state); -+ -++static int __init phylink_init(void) -++{ -++ __set_bit(PHY_INTERFACE_MODE_USXGMII, phylink_sfp_interfaces); -++ __set_bit(PHY_INTERFACE_MODE_10GBASER, phylink_sfp_interfaces); -++ __set_bit(PHY_INTERFACE_MODE_5GBASER, phylink_sfp_interfaces); -++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, phylink_sfp_interfaces); -++ __set_bit(PHY_INTERFACE_MODE_SGMII, phylink_sfp_interfaces); -++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, phylink_sfp_interfaces); -++ __set_bit(PHY_INTERFACE_MODE_100BASEX, phylink_sfp_interfaces); -++ -++ return 0; -++} -++module_init(phylink_init); -++ -+ MODULE_LICENSE("GPL v2"); -+diff --git a/include/linux/phy.h b/include/linux/phy.h -+index c270e6b3c3f6..4262f49c1eae 100644 -+--- a/include/linux/phy.h -++++ b/include/linux/phy.h -+@@ -169,6 +169,12 @@ static inline bool phy_interface_empty(const unsigned long *intf) -+ return bitmap_empty(intf, PHY_INTERFACE_MODE_MAX); -+ } -+ -++static inline void phy_interface_copy(unsigned long *dst, -++ const unsigned long *src) -++{ -++ bitmap_copy(dst, src, PHY_INTERFACE_MODE_MAX); -++} -++ -+ static inline void phy_interface_and(unsigned long *dst, const unsigned long *a, -+ const unsigned long *b) -+ { -+@@ -563,6 +569,7 @@ struct macsec_ops; -+ * @advertising: Currently advertised linkmodes -+ * @adv_old: Saved advertised while power saving for WoL -+ * @lp_advertising: Current link partner advertised linkmodes -++ * @host_interfaces: PHY interface modes supported by host -+ * @eee_broken_modes: Energy efficient ethernet modes which should be prohibited -+ * @autoneg: Flag autoneg being used -+ * @link: Current link state -+@@ -658,6 +665,9 @@ struct phy_device { -+ /* used with phy_speed_down */ -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); -+ -++ /* host supported PHY interface types */ -++ DECLARE_PHY_INTERFACE_MASK(host_interfaces); -++ -+ /* Energy efficient ethernet modes which should be prohibited */ -+ u32 eee_broken_modes; -+ -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-03-net-phy-marvell10g-add-downshift-tunable-support.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-03-net-phy-marvell10g-add-downshift-tunable-support.patch -new file mode 100644 -index 0000000000..4ccb537861 ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-03-net-phy-marvell10g-add-downshift-tunable-support.patch -@@ -0,0 +1,220 @@ -+From b09b1757932fb02420dcb29933bc8d15f9797403 Mon Sep 17 00:00:00 2001 -+From: Russell King <rmk+kernel@armlinux.org.uk> -+Date: Wed, 29 Sep 2021 16:28:53 +0100 -+Subject: [PATCH 03/12] net: phy: marvell10g: add downshift tunable support -+ -+Add support for the downshift tunable for the Marvell 88x3310 PHY. -+Downshift is only usable with firmware 0.3.5.0 and later. -+ -+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> -+Reviewed-by: Andrew Lunn <andrew@lunn.ch> -+Signed-off-by: David S. Miller <davem@davemloft.net> -+--- -+ drivers/net/phy/marvell10g.c | 107 ++++++++++++++++++++++++++++++++++- -+ 1 file changed, 106 insertions(+), 1 deletion(-) -+ -+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c -+index df33637c5269..2b7d0720720b 100644 -+--- a/drivers/net/phy/marvell10g.c -++++ b/drivers/net/phy/marvell10g.c -+@@ -22,6 +22,7 @@ -+ * If both the fiber and copper ports are connected, the first to gain -+ * link takes priority and the other port is completely locked out. -+ */ -++#include <linux/bitfield.h> -+ #include <linux/ctype.h> -+ #include <linux/delay.h> -+ #include <linux/hwmon.h> -+@@ -33,6 +34,8 @@ -+ #define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe -+ #define MV_PHY_ALASKA_NBT_QUIRK_REV (MARVELL_PHY_ID_88X3310 | 0xa) -+ -++#define MV_VERSION(a,b,c,d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) -++ -+ enum { -+ MV_PMA_FW_VER0 = 0xc011, -+ MV_PMA_FW_VER1 = 0xc012, -+@@ -62,6 +65,15 @@ enum { -+ MV_PCS_CSCR1_MDIX_MDIX = 0x0020, -+ MV_PCS_CSCR1_MDIX_AUTO = 0x0060, -+ -++ MV_PCS_DSC1 = 0x8003, -++ MV_PCS_DSC1_ENABLE = BIT(9), -++ MV_PCS_DSC1_10GBT = 0x01c0, -++ MV_PCS_DSC1_1GBR = 0x0038, -++ MV_PCS_DSC1_100BTX = 0x0007, -++ MV_PCS_DSC2 = 0x8004, -++ MV_PCS_DSC2_2P5G = 0xf000, -++ MV_PCS_DSC2_5G = 0x0f00, -++ -+ MV_PCS_CSSR1 = 0x8008, -+ MV_PCS_CSSR1_SPD1_MASK = 0xc000, -+ MV_PCS_CSSR1_SPD1_SPD2 = 0xc000, -+@@ -125,6 +137,7 @@ enum { -+ }; -+ -+ struct mv3310_chip { -++ bool (*has_downshift)(struct phy_device *phydev); -+ void (*init_supported_interfaces)(unsigned long *mask); -+ int (*get_mactype)(struct phy_device *phydev); -+ int (*init_interface)(struct phy_device *phydev, int mactype); -+@@ -138,6 +151,7 @@ struct mv3310_priv { -+ DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX); -+ -+ u32 firmware_ver; -++ bool has_downshift; -+ bool rate_match; -+ phy_interface_t const_interface; -+ -+@@ -330,6 +344,71 @@ static int mv3310_reset(struct phy_device *phydev, u32 unit) -+ 5000, 100000, true); -+ } -+ -++static int mv3310_get_downshift(struct phy_device *phydev, u8 *ds) -++{ -++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); -++ int val; -++ -++ if (!priv->has_downshift) -++ return -EOPNOTSUPP; -++ -++ val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1); -++ if (val < 0) -++ return val; -++ -++ if (val & MV_PCS_DSC1_ENABLE) -++ /* assume that all fields are the same */ -++ *ds = 1 + FIELD_GET(MV_PCS_DSC1_10GBT, (u16)val); -++ else -++ *ds = DOWNSHIFT_DEV_DISABLE; -++ -++ return 0; -++} -++ -++static int mv3310_set_downshift(struct phy_device *phydev, u8 ds) -++{ -++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); -++ u16 val; -++ int err; -++ -++ if (!priv->has_downshift) -++ return -EOPNOTSUPP; -++ -++ if (ds == DOWNSHIFT_DEV_DISABLE) -++ return phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1, -++ MV_PCS_DSC1_ENABLE); -++ -++ /* DOWNSHIFT_DEV_DEFAULT_COUNT is confusing. It looks like it should -++ * set the default settings for the PHY. However, it is used for -++ * "ethtool --set-phy-tunable ethN downshift on". The intention is -++ * to enable downshift at a default number of retries. The default -++ * settings for 88x3310 are for two retries with downshift disabled. -++ * So let's use two retries with downshift enabled. -++ */ -++ if (ds == DOWNSHIFT_DEV_DEFAULT_COUNT) -++ ds = 2; -++ -++ if (ds > 8) -++ return -E2BIG; -++ -++ ds -= 1; -++ val = FIELD_PREP(MV_PCS_DSC2_2P5G, ds); -++ val |= FIELD_PREP(MV_PCS_DSC2_5G, ds); -++ err = phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC2, -++ MV_PCS_DSC2_2P5G | MV_PCS_DSC2_5G, val); -++ if (err < 0) -++ return err; -++ -++ val = MV_PCS_DSC1_ENABLE; -++ val |= FIELD_PREP(MV_PCS_DSC1_10GBT, ds); -++ val |= FIELD_PREP(MV_PCS_DSC1_1GBR, ds); -++ val |= FIELD_PREP(MV_PCS_DSC1_100BTX, ds); -++ -++ return phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1, -++ MV_PCS_DSC1_ENABLE | MV_PCS_DSC1_10GBT | -++ MV_PCS_DSC1_1GBR | MV_PCS_DSC1_100BTX, val); -++} -++ -+ static int mv3310_get_edpd(struct phy_device *phydev, u16 *edpd) -+ { -+ int val; -+@@ -448,6 +527,9 @@ static int mv3310_probe(struct phy_device *phydev) -+ priv->firmware_ver >> 24, (priv->firmware_ver >> 16) & 255, -+ (priv->firmware_ver >> 8) & 255, priv->firmware_ver & 255); -+ -++ if (chip->has_downshift) -++ priv->has_downshift = chip->has_downshift(phydev); -++ -+ /* Powering down the port when not in use saves about 600mW */ -+ ret = mv3310_power_down(phydev); -+ if (ret) -+@@ -616,7 +698,16 @@ static int mv3310_config_init(struct phy_device *phydev) -+ } -+ -+ /* Enable EDPD mode - saving 600mW */ -+- return mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS); -++ err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS); -++ if (err) -++ return err; -++ -++ /* Allow downshift */ -++ err = mv3310_set_downshift(phydev, DOWNSHIFT_DEV_DEFAULT_COUNT); -++ if (err && err != -EOPNOTSUPP) -++ return err; -++ -++ return 0; -+ } -+ -+ static int mv3310_get_features(struct phy_device *phydev) -+@@ -886,6 +977,8 @@ static int mv3310_get_tunable(struct phy_device *phydev, -+ struct ethtool_tunable *tuna, void *data) -+ { -+ switch (tuna->id) { -++ case ETHTOOL_PHY_DOWNSHIFT: -++ return mv3310_get_downshift(phydev, data); -+ case ETHTOOL_PHY_EDPD: -+ return mv3310_get_edpd(phydev, data); -+ default: -+@@ -897,6 +990,8 @@ static int mv3310_set_tunable(struct phy_device *phydev, -+ struct ethtool_tunable *tuna, const void *data) -+ { -+ switch (tuna->id) { -++ case ETHTOOL_PHY_DOWNSHIFT: -++ return mv3310_set_downshift(phydev, *(u8 *)data); -+ case ETHTOOL_PHY_EDPD: -+ return mv3310_set_edpd(phydev, *(u16 *)data); -+ default: -+@@ -904,6 +999,14 @@ static int mv3310_set_tunable(struct phy_device *phydev, -+ } -+ } -+ -++static bool mv3310_has_downshift(struct phy_device *phydev) -++{ -++ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); -++ -++ /* Fails to downshift with firmware older than v0.3.5.0 */ -++ return priv->firmware_ver >= MV_VERSION(0,3,5,0); -++} -++ -+ static void mv3310_init_supported_interfaces(unsigned long *mask) -+ { -+ __set_bit(PHY_INTERFACE_MODE_SGMII, mask); -+@@ -943,6 +1046,7 @@ static void mv2111_init_supported_interfaces(unsigned long *mask) -+ } -+ -+ static const struct mv3310_chip mv3310_type = { -++ .has_downshift = mv3310_has_downshift, -+ .init_supported_interfaces = mv3310_init_supported_interfaces, -+ .get_mactype = mv3310_get_mactype, -+ .init_interface = mv3310_init_interface, -+@@ -953,6 +1057,7 @@ static const struct mv3310_chip mv3310_type = { -+ }; -+ -+ static const struct mv3310_chip mv3340_type = { -++ .has_downshift = mv3310_has_downshift, -+ .init_supported_interfaces = mv3340_init_supported_interfaces, -+ .get_mactype = mv3310_get_mactype, -+ .init_interface = mv3340_init_interface, -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-04-net-phy-marvell10g-Use-generic-macro-for-supported-i.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-04-net-phy-marvell10g-Use-generic-macro-for-supported-i.patch -new file mode 100644 -index 0000000000..76f3479f3a ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-04-net-phy-marvell10g-Use-generic-macro-for-supported-i.patch -@@ -0,0 +1,35 @@ -+From 9a4f26cb3e71400555c0c3a7edbcbd0d29fd4464 Mon Sep 17 00:00:00 2001 -+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> -+Date: Thu, 4 Nov 2021 17:25:25 +0100 -+Subject: [PATCH 04/12] net: phy: marvell10g: Use generic macro for supported -+ interfaces -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+Now that phy.h defines macro DECLARE_PHY_INTERFACE_MASK(), use it -+instead of DECLARE_BITMAP(). -+ -+Signed-off-by: Marek Behún <kabel@kernel.org> -+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> -+Reviewed-by: Andrew Lunn <andrew@lunn.ch> -+--- -+ drivers/net/phy/marvell10g.c | 2 +- -+ 1 file changed, 1 insertion(+), 1 deletion(-) -+ -+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c -+index 2b7d0720720b..6e8de692c0f5 100644 -+--- a/drivers/net/phy/marvell10g.c -++++ b/drivers/net/phy/marvell10g.c -+@@ -148,7 +148,7 @@ struct mv3310_chip { -+ }; -+ -+ struct mv3310_priv { -+- DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX); -++ DECLARE_PHY_INTERFACE_MASK(supported_interfaces); -+ -+ u32 firmware_ver; -+ bool has_downshift; -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-05-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-05-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch -new file mode 100644 -index 0000000000..2d931ba43e ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-05-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch -@@ -0,0 +1,51 @@ -+From fe4dc078a329618d3a14bec90d365942953e9a47 Mon Sep 17 00:00:00 2001 -+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> -+Date: Thu, 4 Nov 2021 17:26:35 +0100 -+Subject: [PATCH 05/12] net: phy: marvell10g: Use tabs instead of spaces for -+ indentation -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+Some register definitions were defined with spaces used for indentation. -+Change them to tabs. -+ -+Signed-off-by: Marek Behún <kabel@kernel.org> -+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> -+--- -+ drivers/net/phy/marvell10g.c | 18 +++++++++--------- -+ 1 file changed, 9 insertions(+), 9 deletions(-) -+ -+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c -+index 6e8de692c0f5..2249f737beaf 100644 -+--- a/drivers/net/phy/marvell10g.c -++++ b/drivers/net/phy/marvell10g.c -+@@ -117,16 +117,16 @@ enum { -+ MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN = 0x5, -+ MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6, -+ MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII = 0x7, -+- MV_V2_PORT_INTR_STS = 0xf040, -+- MV_V2_PORT_INTR_MASK = 0xf043, -+- MV_V2_PORT_INTR_STS_WOL_EN = BIT(8), -+- MV_V2_MAGIC_PKT_WORD0 = 0xf06b, -+- MV_V2_MAGIC_PKT_WORD1 = 0xf06c, -+- MV_V2_MAGIC_PKT_WORD2 = 0xf06d, -++ MV_V2_PORT_INTR_STS = 0xf040, -++ MV_V2_PORT_INTR_MASK = 0xf043, -++ MV_V2_PORT_INTR_STS_WOL_EN = BIT(8), -++ MV_V2_MAGIC_PKT_WORD0 = 0xf06b, -++ MV_V2_MAGIC_PKT_WORD1 = 0xf06c, -++ MV_V2_MAGIC_PKT_WORD2 = 0xf06d, -+ /* Wake on LAN registers */ -+- MV_V2_WOL_CTRL = 0xf06e, -+- MV_V2_WOL_CTRL_CLEAR_STS = BIT(15), -+- MV_V2_WOL_CTRL_MAGIC_PKT_EN = BIT(0), -++ MV_V2_WOL_CTRL = 0xf06e, -++ MV_V2_WOL_CTRL_CLEAR_STS = BIT(15), -++ MV_V2_WOL_CTRL_MAGIC_PKT_EN = BIT(0), -+ /* Temperature control/read registers (88X3310 only) */ -+ MV_V2_TEMP_CTRL = 0xf08a, -+ MV_V2_TEMP_CTRL_MASK = 0xc000, -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-06-net-phy-marvell10g-select-host-interface-configurati.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-06-net-phy-marvell10g-select-host-interface-configurati.patch -new file mode 100644 -index 0000000000..b40e361036 ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-06-net-phy-marvell10g-select-host-interface-configurati.patch -@@ -0,0 +1,242 @@ -+From 18cdeb60b63e4362df32da136ece815b38c3031e Mon Sep 17 00:00:00 2001 -+From: Russell King <rmk+kernel@armlinux.org.uk> -+Date: Thu, 4 Nov 2021 23:23:38 +0100 -+Subject: [PATCH 06/12] net: phy: marvell10g: select host interface -+ configuration -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+Select the host interface configuration according to the capabilities of -+the host. -+ -+The PHY supports several configurations of host communication: -+- always communicate with host in 10gbase-r, even if copper speed is -+ lower (rate matching mode), -+- the same as above but use xaui/rxaui instead of 10gbase-r, -+- switch host SerDes mode between 10gbase-r, 5gbase-r, 2500base-x and -+ sgmii according to copper speed, -+- the same as above but use xaui/rxaui instead of 10gbase-r. -+ -+This mode of host communication, called MACTYPE, is by default selected -+by strapping pins, but it can be changed in software. -+ -+This adds support for selecting this mode according to which modes are -+supported by the host. -+ -+This allows the kernel to: -+- support SFP modules with 88X33X0 or 88E21X0 inside them -+- switch interface modes when the PHY is used with the mvpp2 MAC -+ (e.g. on MacchiatoBIN) -+ -+Note: we use mv3310_select_mactype() for both 88X3310 and 88X3340, -+although 88X3340 does not support XAUI. This is not a problem because -+88X3340 does not declare XAUI in it's supported_interfaces, and so this -+function will never choose that MACTYPE. -+ -+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> -+[ rebase, updated, also added support for 88E21X0 ] -+Signed-off-by: Marek Behún <kabel@kernel.org> -+--- -+ drivers/net/phy/marvell10g.c | 120 +++++++++++++++++++++++++++++++++-- -+ 1 file changed, 115 insertions(+), 5 deletions(-) -+ -+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c -+index 2249f737beaf..b16e67b352bf 100644 -+--- a/drivers/net/phy/marvell10g.c -++++ b/drivers/net/phy/marvell10g.c -+@@ -96,6 +96,11 @@ enum { -+ MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380, -+ MV_PCS_PORT_INFO_NPORTS_SHIFT = 7, -+ -++ /* SerDes reinitialization 88E21X0 */ -++ MV_AN_21X0_SERDES_CTRL2 = 0x800f, -++ MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS = BIT(13), -++ MV_AN_21X0_SERDES_CTRL2_RUN_INIT = BIT(15), -++ -+ /* These registers appear at 0x800X and 0xa00X - the 0xa00X control -+ * registers appear to set themselves to the 0x800X when AN is -+ * restarted, but status registers appear readable from either. -+@@ -140,6 +145,8 @@ struct mv3310_chip { -+ bool (*has_downshift)(struct phy_device *phydev); -+ void (*init_supported_interfaces)(unsigned long *mask); -+ int (*get_mactype)(struct phy_device *phydev); -++ int (*set_mactype)(struct phy_device *phydev, int mactype); -++ int (*select_mactype)(unsigned long *interfaces); -+ int (*init_interface)(struct phy_device *phydev, int mactype); -+ -+ #ifdef CONFIG_HWMON -+@@ -593,6 +600,49 @@ static int mv2110_get_mactype(struct phy_device *phydev) -+ return mactype & MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK; -+ } -+ -++static int mv2110_set_mactype(struct phy_device *phydev, int mactype) -++{ -++ int err, val; -++ -++ mactype &= MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK; -++ err = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_21X0_PORT_CTRL, -++ MV_PMA_21X0_PORT_CTRL_SWRST | -++ MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK, -++ MV_PMA_21X0_PORT_CTRL_SWRST | mactype); -++ if (err) -++ return err; -++ -++ err = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2, -++ MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS | -++ MV_AN_21X0_SERDES_CTRL2_RUN_INIT); -++ if (err) -++ return err; -++ -++ err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_AN, -++ MV_AN_21X0_SERDES_CTRL2, val, -++ !(val & -++ MV_AN_21X0_SERDES_CTRL2_RUN_INIT), -++ 5000, 100000, true); -++ if (err) -++ return err; -++ -++ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2, -++ MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS); -++} -++ -++static int mv2110_select_mactype(unsigned long *interfaces) -++{ -++ if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces)) -++ return MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII; -++ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) && -++ !test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces)) -++ return MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER; -++ else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces)) -++ return MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH; -++ else -++ return -1; -++} -++ -+ static int mv3310_get_mactype(struct phy_device *phydev) -+ { -+ int mactype; -+@@ -604,6 +654,46 @@ static int mv3310_get_mactype(struct phy_device *phydev) -+ return mactype & MV_V2_33X0_PORT_CTRL_MACTYPE_MASK; -+ } -+ -++static int mv3310_set_mactype(struct phy_device *phydev, int mactype) -++{ -++ int ret; -++ -++ mactype &= MV_V2_33X0_PORT_CTRL_MACTYPE_MASK; -++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, -++ MV_V2_33X0_PORT_CTRL_MACTYPE_MASK, -++ mactype); -++ if (ret <= 0) -++ return ret; -++ -++ return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, -++ MV_V2_33X0_PORT_CTRL_SWRST); -++} -++ -++static int mv3310_select_mactype(unsigned long *interfaces) -++{ -++ if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces)) -++ return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII; -++ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) && -++ test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces)) -++ return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER; -++ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) && -++ test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces)) -++ return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI; -++ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) && -++ test_bit(PHY_INTERFACE_MODE_XAUI, interfaces)) -++ return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI; -++ else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces)) -++ return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH; -++ else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces)) -++ return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH; -++ else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces)) -++ return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH; -++ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces)) -++ return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER; -++ else -++ return -1; -++} -++ -+ static int mv2110_init_interface(struct phy_device *phydev, int mactype) -+ { -+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); -+@@ -674,10 +764,16 @@ static int mv3310_config_init(struct phy_device *phydev) -+ { -+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); -+ const struct mv3310_chip *chip = to_mv3310_chip(phydev); -++ DECLARE_PHY_INTERFACE_MASK(interfaces); -+ int err, mactype; -+ -+- /* Check that the PHY interface type is compatible */ -+- if (!test_bit(phydev->interface, priv->supported_interfaces)) -++ /* In case host didn't provide supported interfaces */ -++ __set_bit(phydev->interface, phydev->host_interfaces); -++ -++ /* Check that there is at least one compatible PHY interface type */ -++ phy_interface_and(interfaces, phydev->host_interfaces, -++ priv->supported_interfaces); -++ if (phy_interface_empty(interfaces)) -+ return -ENODEV; -+ -+ phydev->mdix_ctrl = ETH_TP_MDI_AUTO; -+@@ -687,9 +783,15 @@ static int mv3310_config_init(struct phy_device *phydev) -+ if (err) -+ return err; -+ -+- mactype = chip->get_mactype(phydev); -+- if (mactype < 0) -+- return mactype; -++ mactype = chip->select_mactype(interfaces); -++ if (mactype < 0) { -++ mactype = chip->get_mactype(phydev); -++ } else { -++ phydev_info(phydev, "Changing MACTYPE to %i\n", mactype); -++ err = chip->set_mactype(phydev, mactype); -++ if (err) -++ return err; -++ } -+ -+ err = chip->init_interface(phydev, mactype); -+ if (err) { -+@@ -1049,6 +1151,8 @@ static const struct mv3310_chip mv3310_type = { -+ .has_downshift = mv3310_has_downshift, -+ .init_supported_interfaces = mv3310_init_supported_interfaces, -+ .get_mactype = mv3310_get_mactype, -++ .set_mactype = mv3310_set_mactype, -++ .select_mactype = mv3310_select_mactype, -+ .init_interface = mv3310_init_interface, -+ -+ #ifdef CONFIG_HWMON -+@@ -1060,6 +1164,8 @@ static const struct mv3310_chip mv3340_type = { -+ .has_downshift = mv3310_has_downshift, -+ .init_supported_interfaces = mv3340_init_supported_interfaces, -+ .get_mactype = mv3310_get_mactype, -++ .set_mactype = mv3310_set_mactype, -++ .select_mactype = mv3310_select_mactype, -+ .init_interface = mv3340_init_interface, -+ -+ #ifdef CONFIG_HWMON -+@@ -1070,6 +1176,8 @@ static const struct mv3310_chip mv3340_type = { -+ static const struct mv3310_chip mv2110_type = { -+ .init_supported_interfaces = mv2110_init_supported_interfaces, -+ .get_mactype = mv2110_get_mactype, -++ .set_mactype = mv2110_set_mactype, -++ .select_mactype = mv2110_select_mactype, -+ .init_interface = mv2110_init_interface, -+ -+ #ifdef CONFIG_HWMON -+@@ -1080,6 +1188,8 @@ static const struct mv3310_chip mv2110_type = { -+ static const struct mv3310_chip mv2111_type = { -+ .init_supported_interfaces = mv2111_init_supported_interfaces, -+ .get_mactype = mv2110_get_mactype, -++ .set_mactype = mv2110_set_mactype, -++ .select_mactype = mv2110_select_mactype, -+ .init_interface = mv2110_init_interface, -+ -+ #ifdef CONFIG_HWMON -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-07-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-07-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch -new file mode 100644 -index 0000000000..bd9f2b6ae0 ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-07-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch -@@ -0,0 +1,48 @@ -+From 3f8b2734f1df8dc6f4f619d8f165d70fdea25232 Mon Sep 17 00:00:00 2001 -+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> -+Date: Sun, 10 Jan 2021 00:29:41 +0100 -+Subject: [PATCH 07/12] net: phylink: allow attaching phy for SFP modules on -+ 802.3z mode -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+Some SFPs may contain an internal PHY which may in some cases want to -+connect with the host interface in 1000base-x/2500base-x mode. -+Do not fail if such PHY is being attached in one of these PHY interface -+modes. -+ -+Signed-off-by: Marek Behún <kabel@kernel.org> -+Reviewed-by: Russell King <rmk+kernel@armlinux.org.uk> -+Reviewed-by: Pali Rohár <pali@kernel.org> -+Cc: Andrew Lunn <andrew@lunn.ch> -+--- -+ drivers/net/phy/phylink.c | 5 +---- -+ 1 file changed, 1 insertion(+), 4 deletions(-) -+ -+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c -+index 9d248802253a..f1fad9e18d03 100644 -+--- a/drivers/net/phy/phylink.c -++++ b/drivers/net/phy/phylink.c -+@@ -1161,7 +1161,7 @@ static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy, -+ { -+ if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED || -+ (pl->cfg_link_an_mode == MLO_AN_INBAND && -+- phy_interface_mode_is_8023z(interface)))) -++ phy_interface_mode_is_8023z(interface) && !pl->sfp_bus))) -+ return -EINVAL; -+ -+ if (pl->phydev) -+@@ -2347,9 +2347,6 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode, -+ phylink_an_mode_str(mode), phy_modes(config.interface), -+ __ETHTOOL_LINK_MODE_MASK_NBITS, support); -+ -+- if (phy_interface_mode_is_8023z(iface) && pl->phydev) -+- return -EINVAL; -+- -+ changed = !linkmode_equal(pl->supported, support) || -+ !linkmode_equal(pl->link_config.advertising, -+ config.advertising); -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-08-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-08-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch -new file mode 100644 -index 0000000000..8ce0a3fcd0 ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-08-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch -@@ -0,0 +1,181 @@ -+From 36941751c1ebc9b8d755c49688e7e4637cbc25ea Mon Sep 17 00:00:00 2001 -+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> -+Date: Thu, 4 Nov 2021 23:58:53 +0100 -+Subject: [PATCH 08/12] net: sfp: create/destroy I2C mdiobus before PHY -+ probe/after PHY release -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+Instead of configuring the I2C mdiobus when SFP driver is probed, -+create/destroy the mdiobus before the PHY is probed for/after it is -+released. -+ -+This way we can tell the mdio-i2c code which protocol to use for each -+SFP transceiver. -+ -+Move the code that determines MDIO I2C protocol from -+sfp_sm_probe_for_phy() to sfp_sm_mod_probe(), where most of the SFP ID -+parsing is done. Don't allocate I2C bus if no PHY is expected. -+ -+Signed-off-by: Marek Behún <kabel@kernel.org> -+--- -+ drivers/net/phy/sfp.c | 64 ++++++++++++++++++++++++++++------- -+ include/linux/mdio/mdio-i2c.h | 6 ++++ -+ 2 files changed, 57 insertions(+), 13 deletions(-) -+ -+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c -+index 1df5d5008ab2..5932addfc5d9 100644 -+--- a/drivers/net/phy/sfp.c -++++ b/drivers/net/phy/sfp.c -+@@ -218,6 +218,7 @@ struct sfp { -+ struct i2c_adapter *i2c; -+ struct mii_bus *i2c_mii; -+ struct sfp_bus *sfp_bus; -++ enum mdio_i2c_proto mdio_protocol; -+ struct phy_device *mod_phy; -+ const struct sff_data *type; -+ size_t i2c_block_size; -+@@ -532,9 +533,6 @@ static int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf, -+ -+ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) -+ { -+- struct mii_bus *i2c_mii; -+- int ret; -+- -+ if (!i2c_check_functionality(i2c, I2C_FUNC_I2C)) -+ return -EINVAL; -+ -+@@ -542,7 +540,15 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) -+ sfp->read = sfp_i2c_read; -+ sfp->write = sfp_i2c_write; -+ -+- i2c_mii = mdio_i2c_alloc(sfp->dev, i2c); -++ return 0; -++} -++ -++static int sfp_i2c_mdiobus_create(struct sfp *sfp) -++{ -++ struct mii_bus *i2c_mii; -++ int ret; -++ -++ i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c); -+ if (IS_ERR(i2c_mii)) -+ return PTR_ERR(i2c_mii); -+ -+@@ -560,6 +566,12 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) -+ return 0; -+ } -+ -++static void sfp_i2c_mdiobus_destroy(struct sfp *sfp) -++{ -++ mdiobus_unregister(sfp->i2c_mii); -++ sfp->i2c_mii = NULL; -++} -++ -+ /* Interface */ -+ static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) -+ { -+@@ -1724,6 +1736,14 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn) -+ } -+ } -+ -++static int sfp_sm_add_mdio_bus(struct sfp *sfp) -++{ -++ if (sfp->mdio_protocol != MDIO_I2C_NONE) -++ return sfp_i2c_mdiobus_create(sfp); -++ -++ return 0; -++} -++ -+ /* Probe a SFP for a PHY device if the module supports copper - the PHY -+ * normally sits at I2C bus address 0x56, and may either be a clause 22 -+ * or clause 45 PHY. -+@@ -1739,19 +1759,19 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp) -+ { -+ int err = 0; -+ -+- switch (sfp->id.base.extended_cc) { -+- case SFF8024_ECC_10GBASE_T_SFI: -+- case SFF8024_ECC_10GBASE_T_SR: -+- case SFF8024_ECC_5GBASE_T: -+- case SFF8024_ECC_2_5GBASE_T: -+- err = sfp_sm_probe_phy(sfp, true); -++ switch (sfp->mdio_protocol) { -++ case MDIO_I2C_NONE: -+ break; -+ -+- default: -+- if (sfp->id.base.e1000_base_t) -+- err = sfp_sm_probe_phy(sfp, false); -++ case MDIO_I2C_MARVELL_C22: -++ err = sfp_sm_probe_phy(sfp, false); -++ break; -++ -++ case MDIO_I2C_C45: -++ err = sfp_sm_probe_phy(sfp, true); -+ break; -+ } -++ -+ return err; -+ } -+ -+@@ -2073,6 +2093,16 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) -+ if (sfp->quirk && sfp->quirk->fixup) -+ sfp->quirk->fixup(sfp); -+ -++ if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI || -++ sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR || -++ sfp->id.base.extended_cc == SFF8024_ECC_5GBASE_T || -++ sfp->id.base.extended_cc == SFF8024_ECC_2_5GBASE_T) -++ sfp->mdio_protocol = MDIO_I2C_C45; -++ else if (sfp->id.base.e1000_base_t) -++ sfp->mdio_protocol = MDIO_I2C_MARVELL_C22; -++ else -++ sfp->mdio_protocol = MDIO_I2C_NONE; -++ -+ return 0; -+ } -+ -+@@ -2244,6 +2274,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) -+ sfp_module_stop(sfp->sfp_bus); -+ if (sfp->mod_phy) -+ sfp_sm_phy_detach(sfp); -++ if (sfp->i2c_mii) -++ sfp_i2c_mdiobus_destroy(sfp); -+ sfp_module_tx_disable(sfp); -+ sfp_soft_stop_poll(sfp); -+ sfp_sm_next(sfp, SFP_S_DOWN, 0); -+@@ -2306,6 +2338,12 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) -+ sfp->sm_fault_retries == N_FAULT_INIT); -+ } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { -+ init_done: -++ /* Create mdiobus and start trying for PHY */ -++ ret = sfp_sm_add_mdio_bus(sfp); -++ if (ret < 0) { -++ sfp_sm_next(sfp, SFP_S_FAIL, 0); -++ break; -++ } -+ sfp->sm_phy_retries = R_PHY_RETRY; -+ goto phy_probe; -+ } -+diff --git a/include/linux/mdio/mdio-i2c.h b/include/linux/mdio/mdio-i2c.h -+index b1d27f7cd23f..3bde1a555a49 100644 -+--- a/include/linux/mdio/mdio-i2c.h -++++ b/include/linux/mdio/mdio-i2c.h -+@@ -11,6 +11,12 @@ struct device; -+ struct i2c_adapter; -+ struct mii_bus; -+ -++enum mdio_i2c_proto { -++ MDIO_I2C_NONE, -++ MDIO_I2C_MARVELL_C22, -++ MDIO_I2C_C45, -++}; -++ -+ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c); -+ -+ #endif -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-09-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-09-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch -new file mode 100644 -index 0000000000..2806501dd0 ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-09-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch -@@ -0,0 +1,434 @@ -+From afa187b54a94c9a2de7873c2c78accd195bcb60c Mon Sep 17 00:00:00 2001 -+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> -+Date: Mon, 11 Jan 2021 05:36:26 +0100 -+Subject: [PATCH 09/12] net: phy: mdio-i2c: support I2C MDIO protocol for -+ RollBall SFP modules -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+Some multigig SFPs from RollBall and Hilink do not expose functional -+MDIO access to the internal PHY of the SFP via I2C address 0x56 -+(although there seems to be read-only clause 22 access on this address). -+ -+Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced -+Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be -+selected to 3 and the password must be filled with 0xff bytes for this -+PHY communication to work. -+ -+This extends the mdio-i2c driver to support this protocol by adding a -+special parameter to mdio_i2c_alloc function via which this RollBall -+protocol can be selected. -+ -+Signed-off-by: Marek Behún <kabel@kernel.org> -+Cc: Andrew Lunn <andrew@lunn.ch> -+Cc: Russell King <rmk+kernel@armlinux.org.uk> -+--- -+ drivers/net/mdio/mdio-i2c.c | 310 +++++++++++++++++++++++++++++++++- -+ drivers/net/phy/sfp.c | 6 +- -+ include/linux/mdio/mdio-i2c.h | 4 +- -+ 3 files changed, 313 insertions(+), 7 deletions(-) -+ -+diff --git a/drivers/net/mdio/mdio-i2c.c b/drivers/net/mdio/mdio-i2c.c -+index 09200a70b315..bf8bf5e20faf 100644 -+--- a/drivers/net/mdio/mdio-i2c.c -++++ b/drivers/net/mdio/mdio-i2c.c -+@@ -3,6 +3,7 @@ -+ * MDIO I2C bridge -+ * -+ * Copyright (C) 2015-2016 Russell King -++ * Copyright (C) 2021 Marek Behun -+ * -+ * Network PHYs can appear on I2C buses when they are part of SFP module. -+ * This driver exposes these PHYs to the networking PHY code, allowing -+@@ -12,6 +13,7 @@ -+ #include <linux/i2c.h> -+ #include <linux/mdio/mdio-i2c.h> -+ #include <linux/phy.h> -++#include <linux/sfp.h> -+ -+ /* -+ * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is -+@@ -28,7 +30,7 @@ static unsigned int i2c_mii_phy_addr(int phy_id) -+ return phy_id + 0x40; -+ } -+ -+-static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg) -++static int i2c_mii_read_default(struct mii_bus *bus, int phy_id, int reg) -+ { -+ struct i2c_adapter *i2c = bus->priv; -+ struct i2c_msg msgs[2]; -+@@ -62,7 +64,8 @@ static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg) -+ return data[0] << 8 | data[1]; -+ } -+ -+-static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val) -++static int i2c_mii_write_default(struct mii_bus *bus, int phy_id, int reg, -++ u16 val) -+ { -+ struct i2c_adapter *i2c = bus->priv; -+ struct i2c_msg msg; -+@@ -91,9 +94,288 @@ static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val) -+ return ret < 0 ? ret : 0; -+ } -+ -+-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c) -++/* RollBall SFPs do not access internal PHY via I2C address 0x56, but -++ * instead via address 0x51, when SFP page is set to 0x03 and password to -++ * 0xffffffff. -++ * -++ * address size contents description -++ * ------- ---- -------- ----------- -++ * 0x80 1 CMD 0x01/0x02/0x04 for write/read/done -++ * 0x81 1 DEV Clause 45 device -++ * 0x82 2 REG Clause 45 register -++ * 0x84 2 VAL Register value -++ */ -++#define ROLLBALL_PHY_I2C_ADDR 0x51 -++ -++#define ROLLBALL_PASSWORD (SFP_VSL + 3) -++ -++#define ROLLBALL_CMD_ADDR 0x80 -++#define ROLLBALL_DATA_ADDR 0x81 -++ -++#define ROLLBALL_CMD_WRITE 0x01 -++#define ROLLBALL_CMD_READ 0x02 -++#define ROLLBALL_CMD_DONE 0x04 -++ -++#define SFP_PAGE_ROLLBALL_MDIO 3 -++ -++static int __i2c_transfer_err(struct i2c_adapter *i2c, struct i2c_msg *msgs, -++ int num) -++{ -++ int ret; -++ -++ ret = __i2c_transfer(i2c, msgs, num); -++ if (ret < 0) -++ return ret; -++ else if (ret != num) -++ return -EIO; -++ else -++ return 0; -++} -++ -++static int __i2c_rollball_get_page(struct i2c_adapter *i2c, int bus_addr, -++ u8 *page) -++{ -++ struct i2c_msg msgs[2]; -++ u8 addr = SFP_PAGE; -++ -++ msgs[0].addr = bus_addr; -++ msgs[0].flags = 0; -++ msgs[0].len = 1; -++ msgs[0].buf = &addr; -++ -++ msgs[1].addr = bus_addr; -++ msgs[1].flags = I2C_M_RD; -++ msgs[1].len = 1; -++ msgs[1].buf = page; -++ -++ return __i2c_transfer_err(i2c, msgs, 2); -++} -++ -++static int __i2c_rollball_set_page(struct i2c_adapter *i2c, int bus_addr, -++ u8 page) -++{ -++ struct i2c_msg msg; -++ u8 buf[2]; -++ -++ buf[0] = SFP_PAGE; -++ buf[1] = page; -++ -++ msg.addr = bus_addr; -++ msg.flags = 0; -++ msg.len = 2; -++ msg.buf = buf; -++ -++ return __i2c_transfer_err(i2c, &msg, 1); -++} -++ -++/* In order to not interfere with other SFP code (which possibly may manipulate -++ * SFP_PAGE), for every transfer we do this: -++ * 1. lock the bus -++ * 2. save content of SFP_PAGE -++ * 3. set SFP_PAGE to 3 -++ * 4. do the transfer -++ * 5. restore original SFP_PAGE -++ * 6. unlock the bus -++ * Note that one might think that steps 2 to 5 could be theoretically done all -++ * in one call to i2c_transfer (by constructing msgs array in such a way), but -++ * unfortunately tests show that this does not work :-( Changed SFP_PAGE does -++ * not take into account until i2c_transfer() is done. -++ */ -++static int i2c_transfer_rollball(struct i2c_adapter *i2c, -++ struct i2c_msg *msgs, int num) -++{ -++ int ret, main_err = 0; -++ u8 saved_page; -++ -++ i2c_lock_bus(i2c, I2C_LOCK_SEGMENT); -++ -++ /* save original page */ -++ ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page); -++ if (ret) -++ goto unlock; -++ -++ /* change to RollBall MDIO page */ -++ ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO); -++ if (ret) -++ goto unlock; -++ -++ /* do the transfer; we try to restore original page if this fails */ -++ ret = __i2c_transfer_err(i2c, msgs, num); -++ if (ret) -++ main_err = ret; -++ -++ /* restore original page */ -++ ret = __i2c_rollball_set_page(i2c, msgs->addr, saved_page); -++ -++unlock: -++ i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT); -++ -++ return main_err ? : ret; -++} -++ -++static int i2c_rollball_mii_poll(struct mii_bus *bus, int bus_addr, u8 *buf, -++ size_t len) -++{ -++ struct i2c_adapter *i2c = bus->priv; -++ struct i2c_msg msgs[2]; -++ u8 cmd_addr, tmp, *res; -++ int i, ret; -++ -++ cmd_addr = ROLLBALL_CMD_ADDR; -++ -++ res = buf ? buf : &tmp; -++ len = buf ? len : 1; -++ -++ msgs[0].addr = bus_addr; -++ msgs[0].flags = 0; -++ msgs[0].len = 1; -++ msgs[0].buf = &cmd_addr; -++ -++ msgs[1].addr = bus_addr; -++ msgs[1].flags = I2C_M_RD; -++ msgs[1].len = len; -++ msgs[1].buf = res; -++ -++ /* By experiment it takes up to 70 ms to access a register for these -++ * SFPs. Sleep 20ms between iterations and try 10 times. -++ */ -++ i = 10; -++ do { -++ msleep(20); -++ -++ ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); -++ if (ret) -++ return ret; -++ -++ if (*res == ROLLBALL_CMD_DONE) -++ return 0; -++ } while (i-- > 0); -++ -++ dev_dbg(&bus->dev, "poll timed out\n"); -++ -++ return -ETIMEDOUT; -++} -++ -++static int i2c_rollball_mii_cmd(struct mii_bus *bus, int bus_addr, u8 cmd, -++ u8 *data, size_t len) -++{ -++ struct i2c_adapter *i2c = bus->priv; -++ struct i2c_msg msgs[2]; -++ u8 cmdbuf[2]; -++ -++ cmdbuf[0] = ROLLBALL_CMD_ADDR; -++ cmdbuf[1] = cmd; -++ -++ msgs[0].addr = bus_addr; -++ msgs[0].flags = 0; -++ msgs[0].len = len; -++ msgs[0].buf = data; -++ -++ msgs[1].addr = bus_addr; -++ msgs[1].flags = 0; -++ msgs[1].len = sizeof(cmdbuf); -++ msgs[1].buf = cmdbuf; -++ -++ return i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); -++} -++ -++static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int reg) -++{ -++ u8 buf[4], res[6]; -++ int bus_addr, ret; -++ u16 val; -++ -++ if (!(reg & MII_ADDR_C45)) -++ return -EOPNOTSUPP; -++ -++ bus_addr = i2c_mii_phy_addr(phy_id); -++ if (bus_addr != ROLLBALL_PHY_I2C_ADDR) -++ return 0xffff; -++ -++ buf[0] = ROLLBALL_DATA_ADDR; -++ buf[1] = (reg >> 16) & 0x1f; -++ buf[2] = (reg >> 8) & 0xff; -++ buf[3] = reg & 0xff; -++ -++ ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_READ, buf, -++ sizeof(buf)); -++ if (ret < 0) -++ return ret; -++ -++ ret = i2c_rollball_mii_poll(bus, bus_addr, res, sizeof(res)); -++ if (ret == -ETIMEDOUT) -++ return 0xffff; -++ else if (ret < 0) -++ return ret; -++ -++ val = res[4] << 8 | res[5]; -++ -++ return val; -++} -++ -++static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int reg, -++ u16 val) -++{ -++ int bus_addr, ret; -++ u8 buf[6]; -++ -++ if (!(reg & MII_ADDR_C45)) -++ return -EOPNOTSUPP; -++ -++ bus_addr = i2c_mii_phy_addr(phy_id); -++ if (bus_addr != ROLLBALL_PHY_I2C_ADDR) -++ return 0; -++ -++ buf[0] = ROLLBALL_DATA_ADDR; -++ buf[1] = (reg >> 16) & 0x1f; -++ buf[2] = (reg >> 8) & 0xff; -++ buf[3] = reg & 0xff; -++ buf[4] = val >> 8; -++ buf[5] = val & 0xff; -++ -++ ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_WRITE, buf, -++ sizeof(buf)); -++ if (ret < 0) -++ return ret; -++ -++ ret = i2c_rollball_mii_poll(bus, bus_addr, NULL, 0); -++ if (ret < 0) -++ return ret; -++ -++ return 0; -++} -++ -++static int i2c_mii_init_rollball(struct i2c_adapter *i2c) -++{ -++ struct i2c_msg msg; -++ u8 pw[5]; -++ int ret; -++ -++ pw[0] = ROLLBALL_PASSWORD; -++ pw[1] = 0xff; -++ pw[2] = 0xff; -++ pw[3] = 0xff; -++ pw[4] = 0xff; -++ -++ msg.addr = ROLLBALL_PHY_I2C_ADDR; -++ msg.flags = 0; -++ msg.len = sizeof(pw); -++ msg.buf = pw; -++ -++ ret = i2c_transfer(i2c, &msg, 1); -++ if (ret < 0) -++ return ret; -++ else if (ret != 1) -++ return -EIO; -++ else -++ return 0; -++} -++ -++struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, -++ enum mdio_i2c_proto protocol) -+ { -+ struct mii_bus *mii; -++ int ret; -+ -+ if (!i2c_check_functionality(i2c, I2C_FUNC_I2C)) -+ return ERR_PTR(-EINVAL); -+@@ -104,10 +386,28 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c) -+ -+ snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent)); -+ mii->parent = parent; -+- mii->read = i2c_mii_read; -+- mii->write = i2c_mii_write; -+ mii->priv = i2c; -+ -++ switch (protocol) { -++ case MDIO_I2C_ROLLBALL: -++ ret = i2c_mii_init_rollball(i2c); -++ if (ret < 0) { -++ dev_err(parent, -++ "Cannot initialize RollBall MDIO I2C protocol: %d\n", -++ ret); -++ mdiobus_free(mii); -++ return ERR_PTR(ret); -++ } -++ -++ mii->read = i2c_mii_read_rollball; -++ mii->write = i2c_mii_write_rollball; -++ break; -++ default: -++ mii->read = i2c_mii_read_default; -++ mii->write = i2c_mii_write_default; -++ break; -++ } -++ -+ return mii; -+ } -+ EXPORT_SYMBOL_GPL(mdio_i2c_alloc); -+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c -+index 5932addfc5d9..b2c8c640ac96 100644 -+--- a/drivers/net/phy/sfp.c -++++ b/drivers/net/phy/sfp.c -+@@ -548,7 +548,7 @@ static int sfp_i2c_mdiobus_create(struct sfp *sfp) -+ struct mii_bus *i2c_mii; -+ int ret; -+ -+- i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c); -++ i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c, sfp->mdio_protocol); -+ if (IS_ERR(i2c_mii)) -+ return PTR_ERR(i2c_mii); -+ -+@@ -1770,6 +1770,10 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp) -+ case MDIO_I2C_C45: -+ err = sfp_sm_probe_phy(sfp, true); -+ break; -++ -++ case MDIO_I2C_ROLLBALL: -++ err = -EOPNOTSUPP; -++ break; -+ } -+ -+ return err; -+diff --git a/include/linux/mdio/mdio-i2c.h b/include/linux/mdio/mdio-i2c.h -+index 3bde1a555a49..65b550a6fc32 100644 -+--- a/include/linux/mdio/mdio-i2c.h -++++ b/include/linux/mdio/mdio-i2c.h -+@@ -15,8 +15,10 @@ enum mdio_i2c_proto { -+ MDIO_I2C_NONE, -+ MDIO_I2C_MARVELL_C22, -+ MDIO_I2C_C45, -++ MDIO_I2C_ROLLBALL, -+ }; -+ -+-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c); -++struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, -++ enum mdio_i2c_proto protocol); -+ -+ #endif -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-10-net-sfp-add-support-for-multigig-RollBall-transceive.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-10-net-sfp-add-support-for-multigig-RollBall-transceive.patch -new file mode 100644 -index 0000000000..1d775870a1 ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-10-net-sfp-add-support-for-multigig-RollBall-transceive.patch -@@ -0,0 +1,156 @@ -+From 4997e61943215ab7940ca633def47f743edc8970 Mon Sep 17 00:00:00 2001 -+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org> -+Date: Fri, 5 Nov 2021 00:21:19 +0100 -+Subject: [PATCH 10/12] net: sfp: add support for multigig RollBall -+ transceivers -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+This adds support for multigig copper SFP modules from RollBall/Hilink. -+These modules have a specific way to access clause 45 registers of the -+internal PHY. -+ -+We also need to wait at least 22 seconds after deasserting TX disable -+before accessing the PHY. The code waits for 25 seconds just to be sure. -+ -+Signed-off-by: Marek Behún <kabel@kernel.org> -+Reviewed-by: Russell King <rmk+kernel@armlinux.org.uk> -+--- -+ drivers/net/phy/sfp-bus.c | 6 ++++++ -+ drivers/net/phy/sfp.c | 41 ++++++++++++++++++++++++++++----------- -+ 2 files changed, 36 insertions(+), 11 deletions(-) -+ -+diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c -+index 0a9099c77694..22dba5895ef6 100644 -+--- a/drivers/net/phy/sfp-bus.c -++++ b/drivers/net/phy/sfp-bus.c -+@@ -130,6 +130,12 @@ bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id) -+ } -+ } -+ -++ if (((!memcmp(id->base.vendor_name, "OEM ", 16) || -++ !memcmp(id->base.vendor_name, "Turris ", 16)) && -++ (!memcmp(id->base.vendor_pn, "SFP-10G-T ", 16) || -++ !memcmp(id->base.vendor_pn, "RTSFP-10", 8)))) -++ return true; -++ -+ return false; -+ } -+ EXPORT_SYMBOL_GPL(sfp_may_have_phy); -+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c -+index b2c8c640ac96..49e69f1d9b1b 100644 -+--- a/drivers/net/phy/sfp.c -++++ b/drivers/net/phy/sfp.c -+@@ -166,6 +166,7 @@ static const enum gpiod_flags gpio_flags[] = { -+ * on board (for a copper SFP) time to initialise. -+ */ -+ #define T_WAIT msecs_to_jiffies(50) -++#define T_WAIT_ROLLBALL msecs_to_jiffies(25000) -+ #define T_START_UP msecs_to_jiffies(300) -+ #define T_START_UP_BAD_GPON msecs_to_jiffies(60000) -+ -+@@ -205,8 +206,11 @@ static const enum gpiod_flags gpio_flags[] = { -+ -+ /* SFP modules appear to always have their PHY configured for bus address -+ * 0x56 (which with mdio-i2c, translates to a PHY address of 22). -++ * RollBall SFPs access phy via SFP Enhanced Digital Diagnostic Interface -++ * via address 0x51 (mdio-i2c will use RollBall protocol on this address). -+ */ -+-#define SFP_PHY_ADDR 22 -++#define SFP_PHY_ADDR 22 -++#define SFP_PHY_ADDR_ROLLBALL 17 -+ -+ struct sff_data { -+ unsigned int gpios; -+@@ -252,6 +256,7 @@ struct sfp { -+ struct sfp_eeprom_id id; -+ unsigned int module_power_mW; -+ unsigned int module_t_start_up; -++ unsigned int module_t_wait; -+ bool tx_fault_ignore; -+ -+ const struct sfp_quirk *quirk; -+@@ -1636,12 +1641,12 @@ static void sfp_sm_phy_detach(struct sfp *sfp) -+ sfp->mod_phy = NULL; -+ } -+ -+-static int sfp_sm_probe_phy(struct sfp *sfp, bool is_c45) -++static int sfp_sm_probe_phy(struct sfp *sfp, int addr, bool is_c45) -+ { -+ struct phy_device *phy; -+ int err; -+ -+- phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45); -++ phy = get_phy_device(sfp->i2c_mii, addr, is_c45); -+ if (phy == ERR_PTR(-ENODEV)) -+ return PTR_ERR(phy); -+ if (IS_ERR(phy)) { -+@@ -1764,15 +1769,15 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp) -+ break; -+ -+ case MDIO_I2C_MARVELL_C22: -+- err = sfp_sm_probe_phy(sfp, false); -++ err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR, false); -+ break; -+ -+ case MDIO_I2C_C45: -+- err = sfp_sm_probe_phy(sfp, true); -++ err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR, true); -+ break; -+ -+ case MDIO_I2C_ROLLBALL: -+- err = -EOPNOTSUPP; -++ err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR_ROLLBALL, true); -+ break; -+ } -+ -+@@ -2097,7 +2102,20 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) -+ if (sfp->quirk && sfp->quirk->fixup) -+ sfp->quirk->fixup(sfp); -+ -+- if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI || -++ sfp->module_t_wait = T_WAIT; -++ -++ if (((!memcmp(id.base.vendor_name, "OEM ", 16) || -++ !memcmp(id.base.vendor_name, "Turris ", 16)) && -++ (!memcmp(id.base.vendor_pn, "SFP-10G-T ", 16) || -++ !memcmp(id.base.vendor_pn, "RTSFP-10", 8)))) { -++ sfp->mdio_protocol = MDIO_I2C_ROLLBALL; -++ sfp->module_t_wait = T_WAIT_ROLLBALL; -++ -++ /* RollBall SFPs may have wrong (zero) extended compliance code -++ * burned in EEPROM. For PHY probing we need the correct one. -++ */ -++ id.base.extended_cc = SFF8024_ECC_10GBASE_T_SFI; -++ } else if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI || -+ sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR || -+ sfp->id.base.extended_cc == SFF8024_ECC_5GBASE_T || -+ sfp->id.base.extended_cc == SFF8024_ECC_2_5GBASE_T) -+@@ -2303,9 +2321,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) -+ -+ /* We need to check the TX_FAULT state, which is not defined -+ * while TX_DISABLE is asserted. The earliest we want to do -+- * anything (such as probe for a PHY) is 50ms. -++ * anything (such as probe for a PHY) is 50ms (or more on -++ * specific modules). -+ */ -+- sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT); -++ sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait); -+ break; -+ -+ case SFP_S_WAIT: -+@@ -2319,8 +2338,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) -+ * deasserting. -+ */ -+ timeout = sfp->module_t_start_up; -+- if (timeout > T_WAIT) -+- timeout -= T_WAIT; -++ if (timeout > sfp->module_t_wait) -++ timeout -= sfp->module_t_wait; -+ else -+ timeout = 1; -+ -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-11-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-11-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch -new file mode 100644 -index 0000000000..bda0114281 ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-11-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch -@@ -0,0 +1,340 @@ -+From abdd0ad38b4e970f98600cdde9de37e2dbbcad5f Mon Sep 17 00:00:00 2001 -+From: Russell King <rmk+kernel@armlinux.org.uk> -+Date: Tue, 3 Mar 2020 11:57:39 +0000 -+Subject: [PATCH 11/12] net: sfp: augment SFP parsing with phy_interface_t -+ bitmap -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+We currently parse the SFP EEPROM to a bitmap of ethtool link modes, -+and then attempt to convert the link modes to a PHY interface mode. -+While this works at present, there are cases where this is sub-optimal. -+For example, where a module can operate with several different PHY -+interface modes. -+ -+To start addressing this, arrange for the SFP EEPROM parsing to also -+provide a bitmap of the possible PHY interface modes. -+ -+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> -+[ added 5gbase-r interface ] -+Signed-off-by: Marek Behún <kabel@kernel.org> -+--- -+ drivers/net/phy/marvell-88x2222.c | 3 +- -+ drivers/net/phy/marvell.c | 3 +- -+ drivers/net/phy/marvell10g.c | 3 +- -+ drivers/net/phy/phylink.c | 4 +- -+ drivers/net/phy/sfp-bus.c | 68 +++++++++++++++++++++++-------- -+ drivers/net/phy/sfp.c | 7 +++- -+ drivers/net/phy/sfp.h | 3 +- -+ include/linux/sfp.h | 5 ++- -+ 8 files changed, 71 insertions(+), 25 deletions(-) -+ -+diff --git a/drivers/net/phy/marvell-88x2222.c b/drivers/net/phy/marvell-88x2222.c -+index d8b31d4d2a73..ae285e4225d6 100644 -+--- a/drivers/net/phy/marvell-88x2222.c -++++ b/drivers/net/phy/marvell-88x2222.c -+@@ -478,6 +478,7 @@ static int mv2222_config_init(struct phy_device *phydev) -+ -+ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) -+ { -++ DECLARE_PHY_INTERFACE_MASK(interfaces); -+ struct phy_device *phydev = upstream; -+ phy_interface_t sfp_interface; -+ struct mv2222_data *priv; -+@@ -489,7 +490,7 @@ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) -+ priv = (struct mv2222_data *)phydev->priv; -+ dev = &phydev->mdio.dev; -+ -+- sfp_parse_support(phydev->sfp_bus, id, sfp_supported); -++ sfp_parse_support(phydev->sfp_bus, id, sfp_supported, interfaces); -+ sfp_interface = sfp_select_interface(phydev->sfp_bus, sfp_supported); -+ -+ dev_info(dev, "%s SFP module inserted\n", phy_modes(sfp_interface)); -+diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c -+index 4d726ee03ce2..288befc9f44b 100644 -+--- a/drivers/net/phy/marvell.c -++++ b/drivers/net/phy/marvell.c -+@@ -2806,6 +2806,7 @@ static int marvell_probe(struct phy_device *phydev) -+ -+ static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) -+ { -++ DECLARE_PHY_INTERFACE_MASK(interfaces); -+ struct phy_device *phydev = upstream; -+ phy_interface_t interface; -+ struct device *dev; -+@@ -2817,7 +2818,7 @@ static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) -+ -+ dev = &phydev->mdio.dev; -+ -+- sfp_parse_support(phydev->sfp_bus, id, supported); -++ sfp_parse_support(phydev->sfp_bus, id, supported, interfaces); -+ interface = sfp_select_interface(phydev->sfp_bus, supported); -+ -+ dev_info(dev, "%s SFP module inserted\n", phy_modes(interface)); -+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c -+index b16e67b352bf..c07d51907418 100644 -+--- a/drivers/net/phy/marvell10g.c -++++ b/drivers/net/phy/marvell10g.c -+@@ -473,9 +473,10 @@ static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) -+ { -+ struct phy_device *phydev = upstream; -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; -++ DECLARE_PHY_INTERFACE_MASK(interfaces); -+ phy_interface_t iface; -+ -+- sfp_parse_support(phydev->sfp_bus, id, support); -++ sfp_parse_support(phydev->sfp_bus, id, support, interfaces); -+ iface = sfp_select_interface(phydev->sfp_bus, support); -+ -+ if (iface != PHY_INTERFACE_MODE_10GBASER) { -+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c -+index f1fad9e18d03..7d0b7a2e69d8 100644 -+--- a/drivers/net/phy/phylink.c -++++ b/drivers/net/phy/phylink.c -+@@ -77,6 +77,7 @@ struct phylink { -+ -+ struct sfp_bus *sfp_bus; -+ bool sfp_may_have_phy; -++ DECLARE_PHY_INTERFACE_MASK(sfp_interfaces); -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); -+ u8 sfp_port; -+ }; -+@@ -2385,7 +2386,8 @@ static int phylink_sfp_module_insert(void *upstream, -+ ASSERT_RTNL(); -+ -+ linkmode_zero(support); -+- sfp_parse_support(pl->sfp_bus, id, support); -++ phy_interface_zero(pl->sfp_interfaces); -++ sfp_parse_support(pl->sfp_bus, id, support, pl->sfp_interfaces); -+ pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support); -+ -+ /* If this module may have a PHY connecting later, defer until later */ -+diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c -+index 22dba5895ef6..98af41843cce 100644 -+--- a/drivers/net/phy/sfp-bus.c -++++ b/drivers/net/phy/sfp-bus.c -+@@ -145,12 +145,14 @@ EXPORT_SYMBOL_GPL(sfp_may_have_phy); -+ * @bus: a pointer to the &struct sfp_bus structure for the sfp module -+ * @id: a pointer to the module's &struct sfp_eeprom_id -+ * @support: pointer to an array of unsigned long for the ethtool support mask -++ * @interfaces: pointer to an array of unsigned long for phy interface modes -++ * mask -+ * -+ * Parse the EEPROM identification information and derive the supported -+ * ethtool link modes for the module. -+ */ -+ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+- unsigned long *support) -++ unsigned long *support, unsigned long *interfaces) -+ { -+ unsigned int br_min, br_nom, br_max; -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, }; -+@@ -177,27 +179,41 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+ } -+ -+ /* Set ethtool support from the compliance fields. */ -+- if (id->base.e10g_base_sr) -++ if (id->base.e10g_base_sr) { -+ phylink_set(modes, 10000baseSR_Full); -+- if (id->base.e10g_base_lr) -++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); -++ } -++ if (id->base.e10g_base_lr) { -+ phylink_set(modes, 10000baseLR_Full); -+- if (id->base.e10g_base_lrm) -++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); -++ } -++ if (id->base.e10g_base_lrm) { -+ phylink_set(modes, 10000baseLRM_Full); -+- if (id->base.e10g_base_er) -++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); -++ } -++ if (id->base.e10g_base_er) { -+ phylink_set(modes, 10000baseER_Full); -++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); -++ } -+ if (id->base.e1000_base_sx || -+ id->base.e1000_base_lx || -+- id->base.e1000_base_cx) -++ id->base.e1000_base_cx) { -+ phylink_set(modes, 1000baseX_Full); -++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); -++ } -+ if (id->base.e1000_base_t) { -+ phylink_set(modes, 1000baseT_Half); -+ phylink_set(modes, 1000baseT_Full); -++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); -++ __set_bit(PHY_INTERFACE_MODE_SGMII, interfaces); -+ } -+ -+ /* 1000Base-PX or 1000Base-BX10 */ -+ if ((id->base.e_base_px || id->base.e_base_bx10) && -+- br_min <= 1300 && br_max >= 1200) -++ br_min <= 1300 && br_max >= 1200) { -+ phylink_set(modes, 1000baseX_Full); -++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); -++ } -+ -+ /* 100Base-FX, 100Base-LX, 100Base-PX, 100Base-BX10 */ -+ if (id->base.e100_base_fx || id->base.e100_base_lx) -+@@ -210,21 +226,30 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+ */ -+ if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) { -+ /* This may look odd, but some manufacturers use 12000MBd */ -+- if (br_min <= 12000 && br_max >= 10300) -++ if (br_min <= 12000 && br_max >= 10300) { -+ phylink_set(modes, 10000baseCR_Full); -+- if (br_min <= 3200 && br_max >= 3100) -++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); -++ } -++ if (br_min <= 3200 && br_max >= 3100) { -+ phylink_set(modes, 2500baseX_Full); -+- if (br_min <= 1300 && br_max >= 1200) -++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); -++ } -++ if (br_min <= 1300 && br_max >= 1200) { -+ phylink_set(modes, 1000baseX_Full); -++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); -++ } -+ } -+ if (id->base.sfp_ct_passive) { -+- if (id->base.passive.sff8431_app_e) -++ if (id->base.passive.sff8431_app_e) { -+ phylink_set(modes, 10000baseCR_Full); -++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); -++ } -+ } -+ if (id->base.sfp_ct_active) { -+ if (id->base.active.sff8431_app_e || -+ id->base.active.sff8431_lim) { -+ phylink_set(modes, 10000baseCR_Full); -++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); -+ } -+ } -+ -+@@ -249,12 +274,15 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+ case SFF8024_ECC_10GBASE_T_SFI: -+ case SFF8024_ECC_10GBASE_T_SR: -+ phylink_set(modes, 10000baseT_Full); -++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); -+ break; -+ case SFF8024_ECC_5GBASE_T: -+ phylink_set(modes, 5000baseT_Full); -++ __set_bit(PHY_INTERFACE_MODE_5GBASER, interfaces); -+ break; -+ case SFF8024_ECC_2_5GBASE_T: -+ phylink_set(modes, 2500baseT_Full); -++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); -+ break; -+ default: -+ dev_warn(bus->sfp_dev, -+@@ -267,10 +295,14 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+ if (id->base.fc_speed_100 || -+ id->base.fc_speed_200 || -+ id->base.fc_speed_400) { -+- if (id->base.br_nominal >= 31) -++ if (id->base.br_nominal >= 31) { -+ phylink_set(modes, 2500baseX_Full); -+- if (id->base.br_nominal >= 12) -++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); -++ } -++ if (id->base.br_nominal >= 12) { -+ phylink_set(modes, 1000baseX_Full); -++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); -++ } -+ } -+ -+ /* If we haven't discovered any modes that this module supports, try -+@@ -283,14 +315,18 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+ * 2500BASE-X, so we allow some slack here. -+ */ -+ if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS) && br_nom) { -+- if (br_min <= 1300 && br_max >= 1200) -++ if (br_min <= 1300 && br_max >= 1200) { -+ phylink_set(modes, 1000baseX_Full); -+- if (br_min <= 3200 && br_max >= 2500) -++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); -++ } -++ if (br_min <= 3200 && br_max >= 2500) { -+ phylink_set(modes, 2500baseX_Full); -++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); -++ } -+ } -+ -+ if (bus->sfp_quirk && bus->sfp_quirk->modes) -+- bus->sfp_quirk->modes(id, modes); -++ bus->sfp_quirk->modes(id, modes, interfaces); -+ -+ linkmode_or(support, support, modes); -+ -+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c -+index 49e69f1d9b1b..02c55fdae8be 100644 -+--- a/drivers/net/phy/sfp.c -++++ b/drivers/net/phy/sfp.c -+@@ -333,13 +333,15 @@ static void sfp_fixup_halny_gsfp(struct sfp *sfp) -+ } -+ -+ static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, -+- unsigned long *modes) -++ unsigned long *modes, unsigned long *interfaces) -+ { -+ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, modes); -++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); -+ } -+ -+ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, -+- unsigned long *modes) -++ unsigned long *modes, -++ unsigned long *interfaces) -+ { -+ /* Ubiquiti U-Fiber Instant module claims that support all transceiver -+ * types including 10G Ethernet which is not truth. So clear all claimed -+@@ -347,6 +349,7 @@ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, -+ */ -+ linkmode_zero(modes); -+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, modes); -++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces); -+ } -+ -+ static const struct sfp_quirk sfp_quirks[] = { -+diff --git a/drivers/net/phy/sfp.h b/drivers/net/phy/sfp.h -+index 7ad06deae76c..6cf1643214d3 100644 -+--- a/drivers/net/phy/sfp.h -++++ b/drivers/net/phy/sfp.h -+@@ -9,7 +9,8 @@ struct sfp; -+ struct sfp_quirk { -+ const char *vendor; -+ const char *part; -+- void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes); -++ void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes, -++ unsigned long *interfaces); -+ void (*fixup)(struct sfp *sfp); -+ }; -+ -+diff --git a/include/linux/sfp.h b/include/linux/sfp.h -+index 302094b855fb..d1f343853b6c 100644 -+--- a/include/linux/sfp.h -++++ b/include/linux/sfp.h -+@@ -535,7 +535,7 @@ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+ unsigned long *support); -+ bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id); -+ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+- unsigned long *support); -++ unsigned long *support, unsigned long *interfaces); -+ phy_interface_t sfp_select_interface(struct sfp_bus *bus, -+ unsigned long *link_modes); -+ -+@@ -568,7 +568,8 @@ static inline bool sfp_may_have_phy(struct sfp_bus *bus, -+ -+ static inline void sfp_parse_support(struct sfp_bus *bus, -+ const struct sfp_eeprom_id *id, -+- unsigned long *support) -++ unsigned long *support, -++ unsigned long *interfaces) -+ { -+ } -+ -+-- -+2.35.1 -+ -diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-12-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-12-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch -new file mode 100644 -index 0000000000..c1adcacf27 ---- /dev/null -+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-12-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch -@@ -0,0 +1,203 @@ -+From c069d5a6e0a41c84d49f870340757910c652cf21 Mon Sep 17 00:00:00 2001 -+From: Russell King <rmk+kernel@armlinux.org.uk> -+Date: Tue, 3 Mar 2020 12:12:43 +0000 -+Subject: [PATCH 12/12] net: phylink: use phy_interface_t bitmaps for optical -+ modules -+ -+Where a MAC provides a phy_interface_t bitmap, use these bitmaps to -+select the operating interface mode for optical SFP modules, rather -+than using the linkmode bitmaps. -+ -+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> -+[ rebased, added 5GBASER into preference array ] -+--- -+ drivers/net/phy/phylink.c | 138 ++++++++++++++++++++++++++++++++++---- -+ 1 file changed, 124 insertions(+), 14 deletions(-) -+ -+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c -+index 7d0b7a2e69d8..4861924303ee 100644 -+--- a/drivers/net/phy/phylink.c -++++ b/drivers/net/phy/phylink.c -+@@ -2296,6 +2296,42 @@ static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus) -+ pl->netdev->sfp_bus = NULL; -+ } -+ -++static const phy_interface_t phylink_sfp_interface_preference[] = { -++ PHY_INTERFACE_MODE_USXGMII, -++ PHY_INTERFACE_MODE_10GBASER, -++ PHY_INTERFACE_MODE_5GBASER, -++ PHY_INTERFACE_MODE_2500BASEX, -++ PHY_INTERFACE_MODE_SGMII, -++ PHY_INTERFACE_MODE_1000BASEX, -++ PHY_INTERFACE_MODE_100BASEX, -++}; -++ -++static phy_interface_t phylink_select_interface(struct phylink *pl, -++ const unsigned long *intf, -++ const char *intf_name) -++{ -++ DECLARE_PHY_INTERFACE_MASK(u); -++ phy_interface_t interface; -++ size_t i; -++ -++ phy_interface_and(u, intf, pl->config->supported_interfaces); -++ -++ interface = PHY_INTERFACE_MODE_NA; -++ for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++) -++ if (test_bit(phylink_sfp_interface_preference[i], u)) { -++ interface = phylink_sfp_interface_preference[i]; -++ break; -++ } -++ -++ phylink_dbg(pl, "interfaces=[mac=%*pbl %s=%*pbl] selected %d (%s)\n", -++ (int)PHY_INTERFACE_MODE_MAX, -++ pl->config->supported_interfaces, -++ intf_name, (int)PHY_INTERFACE_MODE_MAX, intf, -++ interface, phy_modes(interface)); -++ -++ return interface; -++} -++ -+ static int phylink_sfp_config(struct phylink *pl, u8 mode, -+ const unsigned long *supported, -+ const unsigned long *advertising) -+@@ -2377,25 +2413,102 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode, -+ return ret; -+ } -+ -++static int phylink_sfp_config_nophy(struct phylink *pl) -++{ -++ __ETHTOOL_DECLARE_LINK_MODE_MASK(support); -++ struct phylink_link_state config; -++ phy_interface_t interface; -++ bool changed; -++ int ret; -++ -++ if (phy_interface_empty(pl->config->supported_interfaces)) -++ return phylink_sfp_config(pl, MLO_AN_INBAND, -++ pl->sfp_support, pl->sfp_support); -++ -++ memset(&config, 0, sizeof(config)); -++ linkmode_copy(config.advertising, pl->sfp_support); -++ config.interface = PHY_INTERFACE_MODE_NA; -++ config.speed = SPEED_UNKNOWN; -++ config.duplex = DUPLEX_UNKNOWN; -++ config.pause = MLO_PAUSE_AN; -++ config.an_enabled = true; -++ -++ /* Get the full range of supported link modes */ -++ ret = phylink_validate(pl, pl->sfp_support, &config); -++ if (ret) { -++ phylink_err(pl, -++ "initial validation with support %*pb failed: %d\n", -++ __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); -++ return ret; -++ } -++ -++ interface = phylink_select_interface(pl, pl->sfp_interfaces, "sfp"); -++ if (interface == PHY_INTERFACE_MODE_NA) -++ return -EINVAL; -++ -++ linkmode_copy(support, pl->sfp_support); -++ config.interface = interface; -++ -++ /* Ignore errors if we're expecting a PHY to attach later */ -++ ret = phylink_validate(pl, support, &config); -++ if (ret) { -++ phylink_err(pl, "validation with support %*pb failed: %d\n", -++ __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); -++ return ret; -++ } -++ -++ phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n", -++ phylink_an_mode_str(MLO_AN_INBAND), -++ phy_modes(config.interface), -++ __ETHTOOL_LINK_MODE_MASK_NBITS, pl->sfp_support); -++ -++ changed = !linkmode_equal(pl->supported, pl->sfp_support) || -++ !linkmode_equal(pl->link_config.advertising, -++ config.advertising); -++ if (changed) { -++ linkmode_copy(pl->supported, pl->sfp_support); -++ linkmode_copy(pl->link_config.advertising, config.advertising); -++ } -++ -++ if (pl->cur_link_an_mode != MLO_AN_INBAND || -++ pl->link_config.interface != config.interface) { -++ pl->link_config.interface = config.interface; -++ pl->cur_link_an_mode = MLO_AN_INBAND; -++ -++ changed = true; -++ -++ phylink_info(pl, "switched to %s/%s link mode\n", -++ phylink_an_mode_str(MLO_AN_INBAND), -++ phy_modes(config.interface)); -++ } -++ -++ pl->link_port = pl->sfp_port; -++ -++ if (changed && !test_bit(PHYLINK_DISABLE_STOPPED, -++ &pl->phylink_disable_state)) -++ phylink_mac_initial_config(pl, false); -++ -++ return 0; -++} -++ -+ static int phylink_sfp_module_insert(void *upstream, -+ const struct sfp_eeprom_id *id) -+ { -+ struct phylink *pl = upstream; -+- unsigned long *support = pl->sfp_support; -+ -+ ASSERT_RTNL(); -+ -+- linkmode_zero(support); -++ linkmode_zero(pl->sfp_support); -+ phy_interface_zero(pl->sfp_interfaces); -+- sfp_parse_support(pl->sfp_bus, id, support, pl->sfp_interfaces); -+- pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support); -++ sfp_parse_support(pl->sfp_bus, id, pl->sfp_support, pl->sfp_interfaces); -++ pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, pl->sfp_support); -+ -+ /* If this module may have a PHY connecting later, defer until later */ -+ pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id); -+ if (pl->sfp_may_have_phy) -+ return 0; -+ -+- return phylink_sfp_config(pl, MLO_AN_INBAND, support, support); -++ return phylink_sfp_config_nophy(pl); -+ } -+ -+ static int phylink_sfp_module_start(void *upstream) -+@@ -2414,8 +2527,7 @@ static int phylink_sfp_module_start(void *upstream) -+ if (!pl->sfp_may_have_phy) -+ return 0; -+ -+- return phylink_sfp_config(pl, MLO_AN_INBAND, -+- pl->sfp_support, pl->sfp_support); -++ return phylink_sfp_config_nophy(pl); -+ } -+ -+ static void phylink_sfp_module_stop(void *upstream) -+@@ -2867,13 +2979,11 @@ EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state); -+ -+ static int __init phylink_init(void) -+ { -+- __set_bit(PHY_INTERFACE_MODE_USXGMII, phylink_sfp_interfaces); -+- __set_bit(PHY_INTERFACE_MODE_10GBASER, phylink_sfp_interfaces); -+- __set_bit(PHY_INTERFACE_MODE_5GBASER, phylink_sfp_interfaces); -+- __set_bit(PHY_INTERFACE_MODE_2500BASEX, phylink_sfp_interfaces); -+- __set_bit(PHY_INTERFACE_MODE_SGMII, phylink_sfp_interfaces); -+- __set_bit(PHY_INTERFACE_MODE_1000BASEX, phylink_sfp_interfaces); -+- __set_bit(PHY_INTERFACE_MODE_100BASEX, phylink_sfp_interfaces); -++ int i; -++ -++ for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); ++i) -++ __set_bit(phylink_sfp_interface_preference[i], -++ phylink_sfp_interfaces); -+ -+ return 0; -+ } -+-- -+2.35.1 -+ --- -2.35.1 -