diff --git a/target/linux/generic/backport-5.4/768-net-sfp-cope-with-SFPs-that-set-both-LOS-normal-and-.patch b/target/linux/generic/backport-5.4/768-net-sfp-cope-with-SFPs-that-set-both-LOS-normal-and-.patch new file mode 100644 index 0000000000..fbbaae1d2b --- /dev/null +++ b/target/linux/generic/backport-5.4/768-net-sfp-cope-with-SFPs-that-set-both-LOS-normal-and-.patch @@ -0,0 +1,94 @@ +From da5bc1832b325b15e4cca3b63861ecf48be870ef Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Sun, 10 Jan 2021 10:58:32 +0000 +Subject: [PATCH] net: sfp: cope with SFPs that set both LOS normal and LOS + inverted + +The SFP MSA defines two option bits in byte 65 to indicate how the +Rx_LOS signal on SFP pin 8 behaves: + +bit 2 - Loss of Signal implemented, signal inverted from standard + definition in SFP MSA (often called "Signal Detect"). +bit 1 - Loss of Signal implemented, signal as defined in SFP MSA + (often called "Rx_LOS"). + +Clearly, setting both bits results in a meaningless situation: it would +mean that LOS is implemented in both the normal sense (1 = signal loss) +and inverted sense (0 = signal loss). + +Unfortunately, there are modules out there which set both bits, which +will be initially interpret as "inverted" sense, and then, if the LOS +signal changes state, we will toggle between LINK_UP and WAIT_LOS +states. + +Change our LOS handling to give well defined behaviour: only interpret +these bits as meaningful if exactly one is set, otherwise treat it as +if LOS is not implemented. + +Signed-off-by: Russell King +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/E1kyYQa-0004iR-CU@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/sfp.c | 36 ++++++++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 14 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -1430,15 +1430,19 @@ static void sfp_sm_link_down(struct sfp + + static void sfp_sm_link_check_los(struct sfp *sfp) + { +- unsigned int los = sfp->state & SFP_F_LOS; ++ const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED); ++ const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL); ++ __be16 los_options = sfp->id.ext.options & (los_inverted | los_normal); ++ bool los = false; + + /* If neither SFP_OPTIONS_LOS_INVERTED nor SFP_OPTIONS_LOS_NORMAL +- * are set, we assume that no LOS signal is available. ++ * are set, we assume that no LOS signal is available. If both are ++ * set, we assume LOS is not implemented (and is meaningless.) + */ +- if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_INVERTED)) +- los ^= SFP_F_LOS; +- else if (!(sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_NORMAL))) +- los = 0; ++ if (los_options == los_inverted) ++ los = !(sfp->state & SFP_F_LOS); ++ else if (los_options == los_normal) ++ los = !!(sfp->state & SFP_F_LOS); + + if (los) + sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0); +@@ -1448,18 +1452,22 @@ static void sfp_sm_link_check_los(struct + + static bool sfp_los_event_active(struct sfp *sfp, unsigned int event) + { +- return (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_INVERTED) && +- event == SFP_E_LOS_LOW) || +- (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_NORMAL) && +- event == SFP_E_LOS_HIGH); ++ const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED); ++ const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL); ++ __be16 los_options = sfp->id.ext.options & (los_inverted | los_normal); ++ ++ return (los_options == los_inverted && event == SFP_E_LOS_LOW) || ++ (los_options == los_normal && event == SFP_E_LOS_HIGH); + } + + static bool sfp_los_event_inactive(struct sfp *sfp, unsigned int event) + { +- return (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_INVERTED) && +- event == SFP_E_LOS_HIGH) || +- (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_NORMAL) && +- event == SFP_E_LOS_LOW); ++ const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED); ++ const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL); ++ __be16 los_options = sfp->id.ext.options & (los_inverted | los_normal); ++ ++ return (los_options == los_inverted && event == SFP_E_LOS_HIGH) || ++ (los_options == los_normal && event == SFP_E_LOS_LOW); + } + + static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn) diff --git a/target/linux/generic/backport-5.4/852-v5.10-0001-net-sfp-VSOL-V2801F-CarlitoxxPro-CPGOS03-0490-v2.0-w.patch b/target/linux/generic/backport-5.4/852-v5.10-0001-net-sfp-VSOL-V2801F-CarlitoxxPro-CPGOS03-0490-v2.0-w.patch index 1901054a10..39f4b273ae 100644 --- a/target/linux/generic/backport-5.4/852-v5.10-0001-net-sfp-VSOL-V2801F-CarlitoxxPro-CPGOS03-0490-v2.0-w.patch +++ b/target/linux/generic/backport-5.4/852-v5.10-0001-net-sfp-VSOL-V2801F-CarlitoxxPro-CPGOS03-0490-v2.0-w.patch @@ -68,7 +68,7 @@ Signed-off-by: David S. Miller msgs[1].len = this_len; -@@ -1569,6 +1579,28 @@ static int sfp_sm_mod_hpower(struct sfp +@@ -1577,6 +1587,28 @@ static int sfp_sm_mod_hpower(struct sfp return 0; } @@ -97,7 +97,7 @@ Signed-off-by: David S. Miller static int sfp_sm_mod_probe(struct sfp *sfp, bool report) { /* SFP module inserted - read I2C data */ -@@ -1577,14 +1609,20 @@ static int sfp_sm_mod_probe(struct sfp * +@@ -1585,14 +1617,20 @@ static int sfp_sm_mod_probe(struct sfp * u8 check; int ret; @@ -120,7 +120,7 @@ Signed-off-by: David S. Miller dev_err(sfp->dev, "EEPROM short read: %d\n", ret); return -EAGAIN; } -@@ -1612,6 +1650,21 @@ static int sfp_sm_mod_probe(struct sfp * +@@ -1620,6 +1658,21 @@ static int sfp_sm_mod_probe(struct sfp * } } diff --git a/target/linux/generic/backport-5.4/852-v5.10-0002-net-sfp-add-workaround-for-Realtek-RTL8672-and-RTL96.patch b/target/linux/generic/backport-5.4/852-v5.10-0002-net-sfp-add-workaround-for-Realtek-RTL8672-and-RTL96.patch index 27ae97cee7..8c95284280 100644 --- a/target/linux/generic/backport-5.4/852-v5.10-0002-net-sfp-add-workaround-for-Realtek-RTL8672-and-RTL96.patch +++ b/target/linux/generic/backport-5.4/852-v5.10-0002-net-sfp-add-workaround-for-Realtek-RTL8672-and-RTL96.patch @@ -102,7 +102,7 @@ Signed-off-by: Jakub Kicinski err = sfp_read(sfp, true, 0, &sfp->diag, sizeof(sfp->diag)); if (err < 0) { if (sfp->hwmon_tries--) { -@@ -1579,26 +1585,30 @@ static int sfp_sm_mod_hpower(struct sfp +@@ -1587,26 +1593,30 @@ static int sfp_sm_mod_hpower(struct sfp return 0; } @@ -149,7 +149,7 @@ Signed-off-by: Jakub Kicinski } static int sfp_sm_mod_probe(struct sfp *sfp, bool report) -@@ -1609,11 +1619,11 @@ static int sfp_sm_mod_probe(struct sfp * +@@ -1617,11 +1627,11 @@ static int sfp_sm_mod_probe(struct sfp * u8 check; int ret; @@ -165,7 +165,7 @@ Signed-off-by: Jakub Kicinski ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base)); if (ret < 0) { -@@ -1627,6 +1637,33 @@ static int sfp_sm_mod_probe(struct sfp * +@@ -1635,6 +1645,33 @@ static int sfp_sm_mod_probe(struct sfp * return -EAGAIN; } @@ -199,7 +199,7 @@ Signed-off-by: Jakub Kicinski /* Cotsworks do not seem to update the checksums when they * do the final programming with the final module part number, * serial number and date code. -@@ -1650,9 +1687,6 @@ static int sfp_sm_mod_probe(struct sfp * +@@ -1658,9 +1695,6 @@ static int sfp_sm_mod_probe(struct sfp * } } diff --git a/target/linux/generic/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch b/target/linux/generic/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch index 6648d10c81..4c5f99acc5 100644 --- a/target/linux/generic/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch +++ b/target/linux/generic/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch @@ -47,7 +47,7 @@ Signed-off-by: Russell King #if IS_ENABLED(CONFIG_HWMON) struct sfp_diag diag; -@@ -1742,6 +1753,12 @@ static int sfp_sm_mod_probe(struct sfp * +@@ -1750,6 +1761,12 @@ static int sfp_sm_mod_probe(struct sfp * if (ret < 0) return ret; @@ -60,7 +60,7 @@ Signed-off-by: Russell King return 0; } -@@ -1947,11 +1964,12 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -1955,11 +1972,12 @@ static void sfp_sm_main(struct sfp *sfp, break; if (sfp->state & SFP_F_TX_FAULT) { @@ -77,7 +77,7 @@ Signed-off-by: Russell King if (timeout > T_WAIT) timeout -= T_WAIT; else -@@ -1968,8 +1986,8 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -1976,8 +1994,8 @@ static void sfp_sm_main(struct sfp *sfp, case SFP_S_INIT: if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) { @@ -88,7 +88,7 @@ Signed-off-by: Russell King */ sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, sfp->sm_retries == 5); -@@ -1988,7 +2006,7 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -1996,7 +2014,7 @@ static void sfp_sm_main(struct sfp *sfp, case SFP_S_INIT_TX_FAULT: if (event == SFP_E_TIMEOUT) { sfp_module_tx_fault_reset(sfp); @@ -97,7 +97,7 @@ Signed-off-by: Russell King } break; -@@ -2012,7 +2030,7 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -2020,7 +2038,7 @@ static void sfp_sm_main(struct sfp *sfp, case SFP_S_TX_FAULT: if (event == SFP_E_TIMEOUT) { sfp_module_tx_fault_reset(sfp); diff --git a/target/linux/generic/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch b/target/linux/generic/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch index 1abc34e94b..e439d19517 100644 --- a/target/linux/generic/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch +++ b/target/linux/generic/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch @@ -30,7 +30,7 @@ Signed-off-by: Russell King if (phylink_test(link_modes, 1000baseX_Full)) --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c -@@ -1505,18 +1505,7 @@ static void sfp_sm_fault(struct sfp *sfp +@@ -1513,18 +1513,7 @@ static void sfp_sm_fault(struct sfp *sfp static void sfp_sm_probe_for_phy(struct sfp *sfp) { diff --git a/target/linux/generic/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch b/target/linux/generic/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch index ba1b5b5822..50200135dd 100644 --- a/target/linux/generic/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch +++ b/target/linux/generic/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch @@ -78,7 +78,7 @@ Signed-off-by: Russell King [SFP_S_WAIT] = "wait", [SFP_S_INIT] = "init", [SFP_S_INIT_TX_FAULT] = "init_tx_fault", -@@ -1918,6 +1920,8 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -1926,6 +1928,8 @@ static void sfp_sm_main(struct sfp *sfp, if (sfp->sm_state == SFP_S_LINK_UP && sfp->sm_dev_state == SFP_DEV_UP) sfp_sm_link_down(sfp); @@ -87,7 +87,7 @@ Signed-off-by: Russell King if (sfp->mod_phy) sfp_sm_phy_detach(sfp); sfp_module_tx_disable(sfp); -@@ -1985,6 +1989,10 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -1993,6 +1997,10 @@ static void sfp_sm_main(struct sfp *sfp, * clear. Probe for the PHY and check the LOS state. */ sfp_sm_probe_for_phy(sfp); diff --git a/target/linux/generic/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch b/target/linux/generic/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch index dcd1ba7ef3..f7c4bc1105 100644 --- a/target/linux/generic/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch +++ b/target/linux/generic/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch @@ -43,7 +43,7 @@ Signed-off-by: Russell King err = sfp_add_phy(sfp->sfp_bus, phy); if (err) { phy_device_remove(phy); -@@ -1503,10 +1510,32 @@ static void sfp_sm_fault(struct sfp *sfp +@@ -1511,10 +1518,32 @@ static void sfp_sm_fault(struct sfp *sfp } } @@ -78,7 +78,7 @@ Signed-off-by: Russell King } static int sfp_module_parse_power(struct sfp *sfp) -@@ -1566,6 +1595,13 @@ static int sfp_sm_mod_hpower(struct sfp +@@ -1574,6 +1603,13 @@ static int sfp_sm_mod_hpower(struct sfp return -EAGAIN; } diff --git a/target/linux/generic/pending-5.4/754-net-sfp-fix-unbind.patch b/target/linux/generic/pending-5.4/754-net-sfp-fix-unbind.patch index c31922e021..6872973385 100644 --- a/target/linux/generic/pending-5.4/754-net-sfp-fix-unbind.patch +++ b/target/linux/generic/pending-5.4/754-net-sfp-fix-unbind.patch @@ -15,7 +15,7 @@ Signed-off-by: Russell King --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c -@@ -2431,6 +2431,10 @@ static int sfp_remove(struct platform_de +@@ -2439,6 +2439,10 @@ static int sfp_remove(struct platform_de sfp_unregister_socket(sfp->sfp_bus); diff --git a/target/linux/generic/pending-5.4/755-net-sfp-fix-hwmon.patch b/target/linux/generic/pending-5.4/755-net-sfp-fix-hwmon.patch index a18e4801a2..be3b19b0ec 100644 --- a/target/linux/generic/pending-5.4/755-net-sfp-fix-hwmon.patch +++ b/target/linux/generic/pending-5.4/755-net-sfp-fix-hwmon.patch @@ -15,7 +15,7 @@ Signed-off-by: Russell King --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c -@@ -1883,6 +1883,10 @@ static void sfp_sm_module(struct sfp *sf +@@ -1891,6 +1891,10 @@ static void sfp_sm_module(struct sfp *sf break; } @@ -26,7 +26,7 @@ Signed-off-by: Russell King sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0); /* fall through */ case SFP_MOD_WAITDEV: -@@ -1932,15 +1936,6 @@ static void sfp_sm_module(struct sfp *sf +@@ -1940,15 +1944,6 @@ static void sfp_sm_module(struct sfp *sf case SFP_MOD_ERROR: break; } diff --git a/target/linux/generic/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch b/target/linux/generic/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch index ba4f8c40c4..c8e3cf5e4f 100644 --- a/target/linux/generic/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch +++ b/target/linux/generic/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch @@ -26,7 +26,7 @@ Signed-off-by: Russell King /* 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 * connect before the I2C bus on MOD DEF 1/2. -@@ -1972,7 +1980,7 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -1980,7 +1988,7 @@ static void sfp_sm_main(struct sfp *sfp, sfp_module_tx_enable(sfp); /* Initialise the fault clearance retries */ @@ -35,7 +35,7 @@ Signed-off-by: Russell King /* We need to check the TX_FAULT state, which is not defined * while TX_DISABLE is asserted. The earliest we want to do -@@ -2012,7 +2020,7 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -2020,7 +2028,7 @@ 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, @@ -44,7 +44,7 @@ Signed-off-by: Russell King } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { init_done: /* TX_FAULT deasserted or we timed out with TX_FAULT * clear. Probe for the PHY and check the LOS state. -@@ -2025,7 +2033,7 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -2033,7 +2041,7 @@ static void sfp_sm_main(struct sfp *sfp, sfp_sm_link_check_los(sfp); /* Reset the fault retry count */ diff --git a/target/linux/generic/pending-5.4/757-net-sfp-rename-sm_retries.patch b/target/linux/generic/pending-5.4/757-net-sfp-rename-sm_retries.patch index 13f3b6ccff..a8d3f32443 100644 --- a/target/linux/generic/pending-5.4/757-net-sfp-rename-sm_retries.patch +++ b/target/linux/generic/pending-5.4/757-net-sfp-rename-sm_retries.patch @@ -22,7 +22,7 @@ Signed-off-by: Russell King struct sfp_eeprom_id id; unsigned int module_power_mW; -@@ -1506,7 +1506,7 @@ static bool sfp_los_event_inactive(struc +@@ -1514,7 +1514,7 @@ static bool sfp_los_event_inactive(struc static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn) { @@ -31,7 +31,7 @@ Signed-off-by: Russell King dev_err(sfp->dev, "module persistently indicates fault, disabling\n"); sfp_sm_next(sfp, SFP_S_TX_DISABLE, 0); -@@ -1980,7 +1980,7 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -1988,7 +1988,7 @@ static void sfp_sm_main(struct sfp *sfp, sfp_module_tx_enable(sfp); /* Initialise the fault clearance retries */ @@ -40,7 +40,7 @@ Signed-off-by: Russell King /* We need to check the TX_FAULT state, which is not defined * while TX_DISABLE is asserted. The earliest we want to do -@@ -2020,7 +2020,7 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -2028,7 +2028,7 @@ 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, @@ -49,7 +49,7 @@ Signed-off-by: Russell King } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { init_done: /* TX_FAULT deasserted or we timed out with TX_FAULT * clear. Probe for the PHY and check the LOS state. -@@ -2033,7 +2033,7 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -2041,7 +2041,7 @@ static void sfp_sm_main(struct sfp *sfp, sfp_sm_link_check_los(sfp); /* Reset the fault retry count */ diff --git a/target/linux/generic/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch b/target/linux/generic/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch index dfa772dc72..5964ed5c5f 100644 --- a/target/linux/generic/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch +++ b/target/linux/generic/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch @@ -55,7 +55,7 @@ Signed-off-by: Russell King } static void sfp_sm_link_up(struct sfp *sfp) -@@ -1529,21 +1531,24 @@ static void sfp_sm_fault(struct sfp *sfp +@@ -1537,21 +1539,24 @@ static void sfp_sm_fault(struct sfp *sfp * Clause 45 copper SFP+ modules (10G) appear to switch their interface * mode according to the negotiated line speed. */ @@ -83,7 +83,7 @@ Signed-off-by: Russell King } static int sfp_module_parse_power(struct sfp *sfp) -@@ -2025,7 +2030,10 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -2033,7 +2038,10 @@ static void sfp_sm_main(struct sfp *sfp, init_done: /* TX_FAULT deasserted or we timed out with TX_FAULT * clear. Probe for the PHY and check the LOS state. */ diff --git a/target/linux/generic/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch b/target/linux/generic/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch index aebb6b0398..27e2187398 100644 --- a/target/linux/generic/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch +++ b/target/linux/generic/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch @@ -69,7 +69,7 @@ Signed-off-by: Russell King if (IS_ERR(phy)) { dev_err(sfp->dev, "mdiobus scan returned %ld\n", PTR_ERR(phy)); return PTR_ERR(phy); -@@ -1954,6 +1961,7 @@ static void sfp_sm_module(struct sfp *sf +@@ -1962,6 +1969,7 @@ static void sfp_sm_module(struct sfp *sf static void sfp_sm_main(struct sfp *sfp, unsigned int event) { unsigned long timeout; @@ -77,7 +77,7 @@ Signed-off-by: Russell King /* Some events are global */ if (sfp->sm_state != SFP_S_DOWN && -@@ -2027,22 +2035,39 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -2035,22 +2043,39 @@ static void sfp_sm_main(struct sfp *sfp, sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, sfp->sm_fault_retries == N_FAULT_INIT); } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { diff --git a/target/linux/generic/pending-5.4/771-net-sfp-add-mode-quirk-Ubiquiti-UFiber-Instant.patch b/target/linux/generic/pending-5.4/771-net-sfp-add-mode-quirk-Ubiquiti-UFiber-Instant.patch new file mode 100644 index 0000000000..e48b474472 --- /dev/null +++ b/target/linux/generic/pending-5.4/771-net-sfp-add-mode-quirk-Ubiquiti-UFiber-Instant.patch @@ -0,0 +1,93 @@ +From f0b4f847673299577c29b71d3f3acd3c313d81b7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Mon, 25 Jan 2021 16:02:28 +0100 +Subject: net: sfp: add mode quirk for GPON module Ubiquiti U-Fiber Instant +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The Ubiquiti U-Fiber Instant SFP GPON module has nonsensical information +stored in its EEPROM. It claims to support all transceiver types including +10G Ethernet. Clear all claimed modes and set only 1000baseX_Full, which is +the only one supported. + +This module has also phys_id set to SFF, and the SFP subsystem currently +does not allow to use SFP modules detected as SFFs. Add exception for this +module so it can be detected as supported. + +This change finally allows to detect and use SFP GPON module Ubiquiti +U-Fiber Instant on Linux system. + +EEPROM content of this SFP module is (where XX is serial number): + +00: 02 04 0b ff ff ff ff ff ff ff ff 03 0c 00 14 c8 ???........??.?? +10: 00 00 00 00 55 42 4e 54 20 20 20 20 20 20 20 20 ....UBNT +20: 20 20 20 20 00 18 e8 29 55 46 2d 49 4e 53 54 41 .??)UF-INSTA +30: 4e 54 20 20 20 20 20 20 34 20 20 20 05 1e 00 36 NT 4 ??.6 +40: 00 06 00 00 55 42 4e 54 XX XX XX XX XX XX XX XX .?..UBNTXXXXXXXX +50: 20 20 20 20 31 34 30 31 32 33 20 20 60 80 02 41 140123 `??A + +Signed-off-by: Pali Rohár +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/sfp-bus.c | 15 +++++++++++++++ + drivers/net/phy/sfp.c | 17 +++++++++++++++-- + 2 files changed, 30 insertions(+), 2 deletions(-) + +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -44,6 +44,17 @@ static void sfp_quirk_2500basex(const st + phylink_set(modes, 2500baseX_Full); + } + ++static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, ++ unsigned long *modes) ++{ ++ /* Ubiquiti U-Fiber Instant module claims that support all transceiver ++ * types including 10G Ethernet which is not truth. So clear all claimed ++ * modes and set only one mode which module supports: 1000baseX_Full. ++ */ ++ phylink_zero(modes); ++ phylink_set(modes, 1000baseX_Full); ++} ++ + static const struct sfp_quirk sfp_quirks[] = { + { + // Alcatel Lucent G-010S-P can operate at 2500base-X, but +@@ -63,6 +74,10 @@ static const struct sfp_quirk sfp_quirks + .vendor = "HUAWEI", + .part = "MA5671A", + .modes = sfp_quirk_2500basex, ++ }, { ++ .vendor = "UBNT", ++ .part = "UF-INSTANT", ++ .modes = sfp_quirk_ubnt_uf_instant, + }, + }; + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -273,8 +273,21 @@ static const struct sff_data sff_data = + + static bool sfp_module_supported(const struct sfp_eeprom_id *id) + { +- return id->base.phys_id == SFF8024_ID_SFP && +- id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP; ++ if (id->base.phys_id == SFF8024_ID_SFP && ++ id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP) ++ return true; ++ ++ /* SFP GPON module Ubiquiti U-Fiber Instant has in its EEPROM stored ++ * phys id SFF instead of SFP. Therefore mark this module explicitly ++ * as supported based on vendor name and pn match. ++ */ ++ if (id->base.phys_id == SFF8024_ID_SFF_8472 && ++ id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP && ++ !memcmp(id->base.vendor_name, "UBNT ", 16) && ++ !memcmp(id->base.vendor_pn, "UF-INSTANT ", 16)) ++ return true; ++ ++ return false; + } + + static const struct sff_data sfp_data = { diff --git a/target/linux/generic/pending-5.4/772-net-sfp-relax-bitrate-devided-check.patch b/target/linux/generic/pending-5.4/772-net-sfp-relax-bitrate-devided-check.patch new file mode 100644 index 0000000000..672d2d0b23 --- /dev/null +++ b/target/linux/generic/pending-5.4/772-net-sfp-relax-bitrate-devided-check.patch @@ -0,0 +1,44 @@ +From 7a77233ec6d114322e2c4f71b4e26dbecd9ea8a7 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Wed, 9 Dec 2020 11:22:54 +0000 +Subject: net: sfp: relax bitrate-derived mode check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Do not check the encoding when deriving 1000BASE-X from the bitrate +when no other modes are discovered. Some GPON modules (VSOL V2801F +and CarlitoxxPro CPGOS03-0490 v2.0) indicate NRZ encoding with a +1200Mbaud bitrate, but should be driven with 1000BASE-X on the host +side. + +Tested-by: Pali Rohár +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King +Signed-off-by: David S. Miller +--- + drivers/net/phy/sfp-bus.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -349,14 +349,13 @@ void sfp_parse_support(struct sfp_bus *b + } + + /* If we haven't discovered any modes that this module supports, try +- * the encoding and bitrate to determine supported modes. Some BiDi +- * modules (eg, 1310nm/1550nm) are not 1000BASE-BX compliant due to +- * the differing wavelengths, so do not set any transceiver bits. ++ * the bitrate to determine supported modes. Some BiDi modules (eg, ++ * 1310nm/1550nm) are not 1000BASE-BX compliant due to the differing ++ * wavelengths, so do not set any transceiver bits. + */ + if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS)) { +- /* If the encoding and bit rate allows 1000baseX */ +- if (id->base.encoding == SFF8024_ENCODING_8B10B && br_nom && +- br_min <= 1300 && br_max >= 1200) ++ /* If the bit rate allows 1000baseX */ ++ if (br_nom && br_min <= 1300 && br_max >= 1200) + phylink_set(modes, 1000baseX_Full); + } +