kernel: sfp: add Nokia SFP fix from net-next

Add Nokia GPON ONT SFP fix for tx_fault in net-next.

Signed-off-by: Scott Roberts <ttocsr@gmail.com>
master
Scott Roberts 4 years ago committed by Hauke Mehrtens
parent 996f02e5ba
commit a461f984c4

@ -0,0 +1,108 @@
From 283b211aa01bdae94dffb3121655dbb20bf237f4 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Tue, 3 Dec 2019 15:22:05 +0000
Subject: net: sfp: avoid tx-fault with Nokia GPON module
The Nokia GPON module can hold tx-fault active while it is initialising
which can take up to 60s. Avoid this causing the module to be declared
faulty after the SFP MSA defined non-cooled module timeout.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp.c | 42 ++++++++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 12 deletions(-)
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -153,10 +153,20 @@ static const enum gpiod_flags gpio_flags
GPIOD_ASIS,
};
-#define T_WAIT msecs_to_jiffies(50)
-#define T_INIT_JIFFIES msecs_to_jiffies(300)
-#define T_RESET_US 10
-#define T_FAULT_RECOVER msecs_to_jiffies(1000)
+/* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a
+ * non-cooled module to initialise its laser safety circuitry. We wait
+ * an initial T_WAIT period before we check the tx fault to give any PHY
+ * on board (for a copper SFP) time to initialise.
+ */
+#define T_WAIT msecs_to_jiffies(50)
+#define T_START_UP msecs_to_jiffies(300)
+#define T_START_UP_BAD_GPON msecs_to_jiffies(60000)
+
+/* t_reset is the time required to assert the TX_DISABLE signal to reset
+ * an indicated TX_FAULT.
+ */
+#define T_RESET_US 10
+#define T_FAULT_RECOVER msecs_to_jiffies(1000)
/* 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
@@ -216,6 +226,7 @@ struct sfp {
struct sfp_eeprom_id id;
unsigned int module_power_mW;
+ unsigned int module_t_start_up;
#if IS_ENABLED(CONFIG_HWMON)
struct sfp_diag diag;
@@ -1590,6 +1601,12 @@ static int sfp_sm_mod_probe(struct sfp *
if (ret < 0)
return ret;
+ if (!memcmp(id.base.vendor_name, "ALCATELLUCENT ", 16) &&
+ !memcmp(id.base.vendor_pn, "3FE46541AA ", 16))
+ sfp->module_t_start_up = T_START_UP_BAD_GPON;
+ else
+ sfp->module_t_start_up = T_START_UP;
+
return 0;
}
@@ -1795,11 +1812,12 @@ static void sfp_sm_main(struct sfp *sfp,
break;
if (sfp->state & SFP_F_TX_FAULT) {
- /* Wait t_init before indicating that the link is up,
- * provided the current state indicates no TX_FAULT. If
- * TX_FAULT clears before this time, that's fine too.
+ /* Wait up to t_init (SFF-8472) or t_start_up (SFF-8431)
+ * from the TX_DISABLE deassertion for the module to
+ * initialise, which is indicated by TX_FAULT
+ * deasserting.
*/
- timeout = T_INIT_JIFFIES;
+ timeout = sfp->module_t_start_up;
if (timeout > T_WAIT)
timeout -= T_WAIT;
else
@@ -1816,8 +1834,8 @@ static void sfp_sm_main(struct sfp *sfp,
case SFP_S_INIT:
if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
- /* TX_FAULT is still asserted after t_init, so assume
- * there is a fault.
+ /* TX_FAULT is still asserted after t_init or
+ * or t_start_up, so assume there is a fault.
*/
sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
sfp->sm_retries == 5);
@@ -1836,7 +1854,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);
- sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
+ sfp_sm_next(sfp, SFP_S_INIT, sfp->module_t_start_up);
}
break;
@@ -1860,7 +1878,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);
- sfp_sm_next(sfp, SFP_S_REINIT, T_INIT_JIFFIES);
+ sfp_sm_next(sfp, SFP_S_REINIT, sfp->module_t_start_up);
}
break;

@ -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
@@ -1413,18 +1413,7 @@ static void sfp_sm_fault(struct sfp *sfp
@@ -1424,18 +1424,7 @@ static void sfp_sm_fault(struct sfp *sfp
static void sfp_sm_probe_for_phy(struct sfp *sfp)
{

@ -132,7 +132,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
if (phylink_test(link_modes, 2500baseX_Full))
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -229,7 +229,7 @@ struct sfp {
@@ -240,7 +240,7 @@ struct sfp {
static bool sff_module_supported(const struct sfp_eeprom_id *id)
{
@ -141,7 +141,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP;
}
@@ -240,7 +240,7 @@ static const struct sff_data sff_data =
@@ -251,7 +251,7 @@ static const struct sff_data sff_data =
static bool sfp_module_supported(const struct sfp_eeprom_id *id)
{

@ -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",
@@ -1749,6 +1751,8 @@ static void sfp_sm_main(struct sfp *sfp,
@@ -1766,6 +1768,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);
@@ -1815,6 +1819,10 @@ static void sfp_sm_main(struct sfp *sfp,
@@ -1833,6 +1837,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);

@ -54,7 +54,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
.connect_phy = phylink_sfp_connect_phy,
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -1320,7 +1320,6 @@ static void sfp_sm_mod_next(struct sfp *
@@ -1331,7 +1331,6 @@ static void sfp_sm_mod_next(struct sfp *
static void sfp_sm_phy_detach(struct sfp *sfp)
{
@ -62,7 +62,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
sfp_remove_phy(sfp->sfp_bus);
phy_device_remove(sfp->mod_phy);
phy_device_free(sfp->mod_phy);
@@ -1351,7 +1350,6 @@ static void sfp_sm_probe_phy(struct sfp
@@ -1362,7 +1361,6 @@ static void sfp_sm_probe_phy(struct sfp
}
sfp->mod_phy = phy;

@ -14,7 +14,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -1326,12 +1326,12 @@ static void sfp_sm_phy_detach(struct sfp
@@ -1337,12 +1337,12 @@ static void sfp_sm_phy_detach(struct sfp
sfp->mod_phy = NULL;
}
@ -29,7 +29,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
if (phy == ERR_PTR(-ENODEV)) {
dev_info(sfp->dev, "no PHY detected\n");
return;
@@ -1341,6 +1341,13 @@ static void sfp_sm_probe_phy(struct sfp
@@ -1352,6 +1352,13 @@ static void sfp_sm_probe_phy(struct sfp
return;
}
@ -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);
@@ -1411,10 +1418,32 @@ static void sfp_sm_fault(struct sfp *sfp
@@ -1422,10 +1429,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)
@@ -1474,6 +1503,13 @@ static int sfp_sm_mod_hpower(struct sfp
@@ -1485,6 +1514,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
@@ -2242,6 +2242,10 @@ static int sfp_remove(struct platform_de
@@ -2260,6 +2260,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
@@ -1714,6 +1714,10 @@ static void sfp_sm_module(struct sfp *sf
@@ -1731,6 +1731,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:
@@ -1763,15 +1767,6 @@ static void sfp_sm_module(struct sfp *sf
@@ -1780,15 +1784,6 @@ static void sfp_sm_module(struct sfp *sf
case SFP_MOD_ERROR:
break;
}

@ -11,9 +11,9 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -160,6 +160,14 @@ static const enum gpiod_flags gpio_flags
#define T_RESET_US 10
#define T_FAULT_RECOVER msecs_to_jiffies(1000)
@@ -170,6 +170,14 @@ static const enum gpiod_flags gpio_flags
#define T_RESET_US 10
#define T_FAULT_RECOVER msecs_to_jiffies(1000)
+/* N_FAULT_INIT is the number of recovery attempts at module initialisation
+ * time. If the TX_FAULT signal is not deasserted after this number of
@ -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.
@@ -1803,7 +1811,7 @@ static void sfp_sm_main(struct sfp *sfp,
@@ -1820,7 +1828,7 @@ static void sfp_sm_main(struct sfp *sfp,
sfp_module_tx_enable(sfp);
/* Initialise the fault clearance retries */
@ -35,8 +35,8 @@ 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
@@ -1842,7 +1850,7 @@ static void sfp_sm_main(struct sfp *sfp,
* there is a fault.
@@ -1860,7 +1868,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,
- sfp->sm_retries == 5);
@ -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.
@@ -1855,7 +1863,7 @@ static void sfp_sm_main(struct sfp *sfp,
@@ -1873,7 +1881,7 @@ static void sfp_sm_main(struct sfp *sfp,
sfp_sm_link_check_los(sfp);
/* Reset the fault retry count */

@ -13,7 +13,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -222,7 +222,7 @@ struct sfp {
@@ -232,7 +232,7 @@ struct sfp {
unsigned char sm_mod_tries;
unsigned char sm_dev_state;
unsigned short sm_state;
@ -22,7 +22,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
struct sfp_eeprom_id id;
unsigned int module_power_mW;
@@ -1414,7 +1414,7 @@ static bool sfp_los_event_inactive(struc
@@ -1425,7 +1425,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);
@@ -1811,7 +1811,7 @@ static void sfp_sm_main(struct sfp *sfp,
@@ -1828,7 +1828,7 @@ static void sfp_sm_main(struct sfp *sfp,
sfp_module_tx_enable(sfp);
/* Initialise the fault clearance retries */
@ -40,8 +40,8 @@ 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
@@ -1850,7 +1850,7 @@ static void sfp_sm_main(struct sfp *sfp,
* there is a fault.
@@ -1868,7 +1868,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,
- sfp->sm_retries == N_FAULT_INIT);
@ -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.
@@ -1863,7 +1863,7 @@ static void sfp_sm_main(struct sfp *sfp,
@@ -1881,7 +1881,7 @@ static void sfp_sm_main(struct sfp *sfp,
sfp_sm_link_check_los(sfp);
/* Reset the fault retry count */

@ -10,7 +10,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -1334,7 +1334,7 @@ static void sfp_sm_phy_detach(struct sfp
@@ -1345,7 +1345,7 @@ static void sfp_sm_phy_detach(struct sfp
sfp->mod_phy = NULL;
}
@ -19,7 +19,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
{
struct phy_device *phy;
int err;
@@ -1342,18 +1342,18 @@ static void sfp_sm_probe_phy(struct sfp
@@ -1353,18 +1353,18 @@ static void sfp_sm_probe_phy(struct sfp
phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45);
if (phy == ERR_PTR(-ENODEV)) {
dev_info(sfp->dev, "no PHY detected\n");
@ -41,7 +41,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
}
err = sfp_add_phy(sfp->sfp_bus, phy);
@@ -1361,10 +1361,12 @@ static void sfp_sm_probe_phy(struct sfp
@@ -1372,10 +1372,12 @@ static void sfp_sm_probe_phy(struct sfp
phy_device_remove(phy);
phy_device_free(phy);
dev_err(sfp->dev, "sfp_add_phy failed: %d\n", err);
@ -55,7 +55,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
}
static void sfp_sm_link_up(struct sfp *sfp)
@@ -1437,21 +1439,24 @@ static void sfp_sm_fault(struct sfp *sfp
@@ -1448,21 +1450,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)
@@ -1855,7 +1860,10 @@ static void sfp_sm_main(struct sfp *sfp,
@@ -1873,7 +1878,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.
*/

@ -35,7 +35,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
[SFP_S_INIT_TX_FAULT] = "init_tx_fault",
[SFP_S_WAIT_LOS] = "wait_los",
[SFP_S_LINK_UP] = "link_up",
@@ -168,6 +170,12 @@ static const enum gpiod_flags gpio_flags
@@ -178,6 +180,12 @@ static const enum gpiod_flags gpio_flags
#define N_FAULT_INIT 5
#define N_FAULT 5
@ -48,7 +48,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.
@@ -223,6 +231,7 @@ struct sfp {
@@ -233,6 +241,7 @@ struct sfp {
unsigned char sm_dev_state;
unsigned short sm_state;
unsigned char sm_fault_retries;
@ -56,7 +56,7 @@ Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
struct sfp_eeprom_id id;
unsigned int module_power_mW;
@@ -1340,10 +1349,8 @@ static int sfp_sm_probe_phy(struct sfp *
@@ -1351,10 +1360,8 @@ static int sfp_sm_probe_phy(struct sfp *
int err;
phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45);
@ -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);
@@ -1785,6 +1792,7 @@ static void sfp_sm_module(struct sfp *sf
@@ -1802,6 +1809,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 &&
@@ -1857,22 +1865,39 @@ static void sfp_sm_main(struct sfp *sfp,
@@ -1875,22 +1883,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) {

Loading…
Cancel
Save