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[] = {
*/
#define T_SERIAL 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
* 0x56 (which with mdio-i2c, translates to a PHY address of 22).
......@@ -204,6 +207,8 @@ struct sfp {
struct delayed_work timeout;
struct mutex sm_mutex; /* Protects state machine */
unsigned char sm_mod_state;
unsigned char sm_mod_tries_init;
unsigned char sm_mod_tries;
unsigned char sm_dev_state;
unsigned short sm_state;
unsigned int sm_retries;
......@@ -1457,7 +1462,7 @@ static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
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 */
struct sfp_eeprom_id id;
......@@ -1467,6 +1472,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp)
ret = sfp_read(sfp, false, 0, &id, sizeof(id));
if (ret < 0) {
if (report)
dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
return -EAGAIN;
}
......@@ -1614,8 +1620,11 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
switch (sfp->sm_mod_state) {
default:
if (event == SFP_E_INSERT)
if (event == SFP_E_INSERT) {
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;
case SFP_MOD_PROBE:
......@@ -1623,11 +1632,20 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
if (event != SFP_E_TIMEOUT)
break;
err = sfp_sm_mod_probe(sfp);
err = sfp_sm_mod_probe(sfp, sfp->sm_mod_tries == 1);
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;
}
}
if (err < 0) {
sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
break;
......@@ -1661,7 +1679,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
sfp_module_remove(sfp->sfp_bus);
sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
} else {
sfp_sm_set_timer(sfp, T_PROBE_RETRY);
sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT);
}
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