mirror of
https://github.com/immortalwrt/immortalwrt
synced 2025-01-09 04:29:03 +08:00
mvebu: SFP backports for GPON modules
This backports the following upstream Linux patches net: sfp: add mode quirk for GPON module Ubiquiti U-Fiber Instant net: sfp: relax bitrate-derived mode check net: sfp: cope with SFPs that set both LOS normal and LOS inverted for 5.4 for mvebu platform. This fixes GPON modules: Ubiquiti U-Fiber Instant SFP GPON VSOL V2801F CarlitoxxPro CPGOS03-0490 v2.0 Signed-off-by: Marek Behún <marek.behun@nic.cz>
This commit is contained in:
parent
52de8bf86e
commit
0e5350db43
@ -0,0 +1,94 @@
|
||||
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)
|
@ -68,7 +68,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
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 <davem@davemloft.net>
|
||||
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 <davem@davemloft.net>
|
||||
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 *
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
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 <kuba@kernel.org>
|
||||
}
|
||||
|
||||
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 <kuba@kernel.org>
|
||||
|
||||
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 <kuba@kernel.org>
|
||||
/* 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 *
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
|
||||
#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 <rmk+kernel@armlinux.org.uk>
|
||||
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 <rmk+kernel@armlinux.org.uk>
|
||||
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 <rmk+kernel@armlinux.org.uk>
|
||||
*/
|
||||
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 <rmk+kernel@armlinux.org.uk>
|
||||
}
|
||||
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);
|
||||
|
@ -30,7 +30,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
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)
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
[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 <rmk+kernel@armlinux.org.uk>
|
||||
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);
|
||||
|
@ -43,7 +43,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
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 <rmk+kernel@armlinux.org.uk>
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
|
||||
--- 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);
|
||||
|
||||
|
@ -15,7 +15,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
|
||||
--- 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 <rmk+kernel@armlinux.org.uk>
|
||||
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;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
/* 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 <rmk+kernel@armlinux.org.uk>
|
||||
|
||||
/* 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 <rmk+kernel@armlinux.org.uk>
|
||||
} 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 */
|
||||
|
@ -22,7 +22,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
|
||||
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 <rmk+kernel@armlinux.org.uk>
|
||||
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 <rmk+kernel@armlinux.org.uk>
|
||||
|
||||
/* 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 <rmk+kernel@armlinux.org.uk>
|
||||
} 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 */
|
||||
|
@ -55,7 +55,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
}
|
||||
|
||||
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 <rmk+kernel@armlinux.org.uk>
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
|
@ -69,7 +69,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
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 <rmk+kernel@armlinux.org.uk>
|
||||
|
||||
/* 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) {
|
||||
|
@ -0,0 +1,93 @@
|
||||
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 = {
|
@ -0,0 +1,44 @@
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user