Commit e117be74 authored by Russell King's avatar Russell King Committed by David S. Miller

net: sfp: allow sfp to probe slow to initialise GPON modules

Some GPON modules (e.g. Huawei MA5671A) take a significant amount of
time to start responding on the I2C bus, contary to the SFF
specifications.

Work around this by implementing a two-level timeout strategy, where
we initially quickly retry for the module, and then use a slower retry
after we exceed a maximum number of quick attempts.
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 73f5e847
...@@ -169,7 +169,10 @@ static const enum gpiod_flags gpio_flags[] = { ...@@ -169,7 +169,10 @@ static const enum gpiod_flags gpio_flags[] = {
*/ */
#define T_SERIAL msecs_to_jiffies(300) #define T_SERIAL msecs_to_jiffies(300)
#define T_HPOWER_LEVEL msecs_to_jiffies(300) #define T_HPOWER_LEVEL msecs_to_jiffies(300)
#define T_PROBE_RETRY msecs_to_jiffies(100) #define T_PROBE_RETRY_INIT msecs_to_jiffies(100)
#define R_PROBE_RETRY_INIT 10
#define T_PROBE_RETRY_SLOW msecs_to_jiffies(5000)
#define R_PROBE_RETRY_SLOW 12
/* SFP modules appear to always have their PHY configured for bus address /* SFP modules appear to always have their PHY configured for bus address
* 0x56 (which with mdio-i2c, translates to a PHY address of 22). * 0x56 (which with mdio-i2c, translates to a PHY address of 22).
...@@ -204,6 +207,8 @@ struct sfp { ...@@ -204,6 +207,8 @@ struct sfp {
struct delayed_work timeout; struct delayed_work timeout;
struct mutex sm_mutex; /* Protects state machine */ struct mutex sm_mutex; /* Protects state machine */
unsigned char sm_mod_state; unsigned char sm_mod_state;
unsigned char sm_mod_tries_init;
unsigned char sm_mod_tries;
unsigned char sm_dev_state; unsigned char sm_dev_state;
unsigned short sm_state; unsigned short sm_state;
unsigned int sm_retries; unsigned int sm_retries;
...@@ -1457,7 +1462,7 @@ static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable) ...@@ -1457,7 +1462,7 @@ static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
return 0; return 0;
} }
static int sfp_sm_mod_probe(struct sfp *sfp) static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
{ {
/* SFP module inserted - read I2C data */ /* SFP module inserted - read I2C data */
struct sfp_eeprom_id id; struct sfp_eeprom_id id;
...@@ -1467,6 +1472,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp) ...@@ -1467,6 +1472,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp)
ret = sfp_read(sfp, false, 0, &id, sizeof(id)); ret = sfp_read(sfp, false, 0, &id, sizeof(id));
if (ret < 0) { if (ret < 0) {
if (report)
dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret); dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
return -EAGAIN; return -EAGAIN;
} }
...@@ -1614,8 +1620,11 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) ...@@ -1614,8 +1620,11 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
switch (sfp->sm_mod_state) { switch (sfp->sm_mod_state) {
default: default:
if (event == SFP_E_INSERT) if (event == SFP_E_INSERT) {
sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL); sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
sfp->sm_mod_tries_init = R_PROBE_RETRY_INIT;
sfp->sm_mod_tries = R_PROBE_RETRY_SLOW;
}
break; break;
case SFP_MOD_PROBE: case SFP_MOD_PROBE:
...@@ -1623,11 +1632,20 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) ...@@ -1623,11 +1632,20 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
if (event != SFP_E_TIMEOUT) if (event != SFP_E_TIMEOUT)
break; break;
err = sfp_sm_mod_probe(sfp); err = sfp_sm_mod_probe(sfp, sfp->sm_mod_tries == 1);
if (err == -EAGAIN) { if (err == -EAGAIN) {
sfp_sm_set_timer(sfp, T_PROBE_RETRY); if (sfp->sm_mod_tries_init &&
--sfp->sm_mod_tries_init) {
sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT);
break;
} else if (sfp->sm_mod_tries && --sfp->sm_mod_tries) {
if (sfp->sm_mod_tries == R_PROBE_RETRY_SLOW - 1)
dev_warn(sfp->dev,
"please wait, module slow to respond\n");
sfp_sm_set_timer(sfp, T_PROBE_RETRY_SLOW);
break; break;
} }
}
if (err < 0) { if (err < 0) {
sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
break; break;
...@@ -1661,7 +1679,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) ...@@ -1661,7 +1679,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
sfp_module_remove(sfp->sfp_bus); sfp_module_remove(sfp->sfp_bus);
sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
} else { } else {
sfp_sm_set_timer(sfp, T_PROBE_RETRY); sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT);
} }
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment