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

net: sfp: do not probe SFP module before we're attached

When we probe a SFP module, we expect to be able to call the upstream
device's module_insert() function so that the upstream link can be
configured.  However, when the upstream device is delayed, we currently
may end up probing the module before the upstream device is available,
and lose the module_insert() call.

Avoid this by holding off probing the module until the SFP bus is
properly connected to both the SFP socket driver and the upstream
driver.
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 27b4ad62
...@@ -347,6 +347,7 @@ static int sfp_register_bus(struct sfp_bus *bus) ...@@ -347,6 +347,7 @@ static int sfp_register_bus(struct sfp_bus *bus)
return ret; return ret;
} }
} }
bus->socket_ops->attach(bus->sfp);
if (bus->started) if (bus->started)
bus->socket_ops->start(bus->sfp); bus->socket_ops->start(bus->sfp);
bus->netdev->sfp_bus = bus; bus->netdev->sfp_bus = bus;
...@@ -362,6 +363,7 @@ static void sfp_unregister_bus(struct sfp_bus *bus) ...@@ -362,6 +363,7 @@ static void sfp_unregister_bus(struct sfp_bus *bus)
if (bus->registered) { if (bus->registered) {
if (bus->started) if (bus->started)
bus->socket_ops->stop(bus->sfp); bus->socket_ops->stop(bus->sfp);
bus->socket_ops->detach(bus->sfp);
if (bus->phydev && ops && ops->disconnect_phy) if (bus->phydev && ops && ops->disconnect_phy)
ops->disconnect_phy(bus->upstream); ops->disconnect_phy(bus->upstream);
} }
......
...@@ -184,6 +184,7 @@ struct sfp { ...@@ -184,6 +184,7 @@ struct sfp {
struct gpio_desc *gpio[GPIO_MAX]; struct gpio_desc *gpio[GPIO_MAX];
bool attached;
unsigned int state; unsigned int state;
struct delayed_work poll; struct delayed_work poll;
struct delayed_work timeout; struct delayed_work timeout;
...@@ -1475,7 +1476,7 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event) ...@@ -1475,7 +1476,7 @@ static void sfp_sm_event(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->attached) {
sfp_module_tx_disable(sfp); sfp_module_tx_disable(sfp);
sfp_sm_ins_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT); sfp_sm_ins_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT);
} }
...@@ -1607,6 +1608,19 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event) ...@@ -1607,6 +1608,19 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event)
mutex_unlock(&sfp->sm_mutex); mutex_unlock(&sfp->sm_mutex);
} }
static void sfp_attach(struct sfp *sfp)
{
sfp->attached = true;
if (sfp->state & SFP_F_PRESENT)
sfp_sm_event(sfp, SFP_E_INSERT);
}
static void sfp_detach(struct sfp *sfp)
{
sfp->attached = false;
sfp_sm_event(sfp, SFP_E_REMOVE);
}
static void sfp_start(struct sfp *sfp) static void sfp_start(struct sfp *sfp)
{ {
sfp_sm_event(sfp, SFP_E_DEV_UP); sfp_sm_event(sfp, SFP_E_DEV_UP);
...@@ -1667,6 +1681,8 @@ static int sfp_module_eeprom(struct sfp *sfp, struct ethtool_eeprom *ee, ...@@ -1667,6 +1681,8 @@ static int sfp_module_eeprom(struct sfp *sfp, struct ethtool_eeprom *ee,
} }
static const struct sfp_socket_ops sfp_module_ops = { static const struct sfp_socket_ops sfp_module_ops = {
.attach = sfp_attach,
.detach = sfp_detach,
.start = sfp_start, .start = sfp_start,
.stop = sfp_stop, .stop = sfp_stop,
.module_info = sfp_module_info, .module_info = sfp_module_info,
...@@ -1834,10 +1850,6 @@ static int sfp_probe(struct platform_device *pdev) ...@@ -1834,10 +1850,6 @@ static int sfp_probe(struct platform_device *pdev)
dev_info(sfp->dev, "Host maximum power %u.%uW\n", dev_info(sfp->dev, "Host maximum power %u.%uW\n",
sfp->max_power_mW / 1000, (sfp->max_power_mW / 100) % 10); sfp->max_power_mW / 1000, (sfp->max_power_mW / 100) % 10);
sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops);
if (!sfp->sfp_bus)
return -ENOMEM;
/* Get the initial state, and always signal TX disable, /* Get the initial state, and always signal TX disable,
* since the network interface will not be up. * since the network interface will not be up.
*/ */
...@@ -1848,10 +1860,6 @@ static int sfp_probe(struct platform_device *pdev) ...@@ -1848,10 +1860,6 @@ static int sfp_probe(struct platform_device *pdev)
sfp->state |= SFP_F_RATE_SELECT; sfp->state |= SFP_F_RATE_SELECT;
sfp_set_state(sfp, sfp->state); sfp_set_state(sfp, sfp->state);
sfp_module_tx_disable(sfp); sfp_module_tx_disable(sfp);
rtnl_lock();
if (sfp->state & SFP_F_PRESENT)
sfp_sm_event(sfp, SFP_E_INSERT);
rtnl_unlock();
for (i = 0; i < GPIO_MAX; i++) { for (i = 0; i < GPIO_MAX; i++) {
if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i]) if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
...@@ -1884,6 +1892,10 @@ static int sfp_probe(struct platform_device *pdev) ...@@ -1884,6 +1892,10 @@ static int sfp_probe(struct platform_device *pdev)
dev_warn(sfp->dev, dev_warn(sfp->dev,
"No tx_disable pin: SFP modules will always be emitting.\n"); "No tx_disable pin: SFP modules will always be emitting.\n");
sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops);
if (!sfp->sfp_bus)
return -ENOMEM;
return 0; return 0;
} }
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
struct sfp; struct sfp;
struct sfp_socket_ops { struct sfp_socket_ops {
void (*attach)(struct sfp *sfp);
void (*detach)(struct sfp *sfp);
void (*start)(struct sfp *sfp); void (*start)(struct sfp *sfp);
void (*stop)(struct sfp *sfp); void (*stop)(struct sfp *sfp);
int (*module_info)(struct sfp *sfp, struct ethtool_modinfo *modinfo); int (*module_info)(struct sfp *sfp, struct ethtool_modinfo *modinfo);
......
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