--- /dev/null
+From da5bc1832b325b15e4cca3b63861ecf48be870ef Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+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 <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/E1kyYQa-0004iR-CU@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ 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)
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;
}
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;
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 *
}
}
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;
}
}
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;
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;
}
/* 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 *
}
}
#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;
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) {
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) {
*/
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);
}
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);
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)
{
[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);
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);
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
}
}
}
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;
}
--- 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);
--- 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;
}
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;
}
/* 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 */
/* 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,
} 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 */
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)
{
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 */
/* 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,
} 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 */
}
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.
*/
}
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.
*/
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;
/* 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) {
--- /dev/null
+From f0b4f847673299577c29b71d3f3acd3c313d81b7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+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 <pali@kernel.org>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ 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 = {
--- /dev/null
+From 7a77233ec6d114322e2c4f71b4e26dbecd9ea8a7 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+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 <pali@kernel.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ 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);
+ }
+