summaryrefslogtreecommitdiff
path: root/drivers/net/sfc
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2008-12-12 22:09:38 -0800
committerDavid S. Miller <davem@davemloft.net>2008-12-12 22:09:38 -0800
commit7dde596ef79982327d8992a579a137b4035ad599 (patch)
treed14cc58d0ea48dbece0f18b3c6823176969ecd74 /drivers/net/sfc
parent0c53d8c84047d86169bd4147bb8f5adf2772d2bb (diff)
downloadlwn-7dde596ef79982327d8992a579a137b4035ad599.tar.gz
lwn-7dde596ef79982327d8992a579a137b4035ad599.zip
sfc: Fix synchronisation of efx_mtd_{probe,rename,remove}
Currently efx_mtd_rename() can race with the probe() and remove() functions. Move probe() before device registration and remove() after unregistration. Move initialisation/update of all names based on the netdev name into a new function and call it under the RTNL immediately after registration. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r--drivers/net/sfc/efx.c33
1 files changed, 18 insertions, 15 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 8f832bf1e4d2..086629c0fe57 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1517,18 +1517,21 @@ static const struct net_device_ops efx_netdev_ops = {
#endif
};
+static void efx_update_name(struct efx_nic *efx)
+{
+ strcpy(efx->name, efx->net_dev->name);
+ efx_mtd_rename(efx);
+ efx_set_channel_names(efx);
+}
+
static int efx_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct net_device *net_dev = ptr;
- if (net_dev->netdev_ops == &efx_netdev_ops && event == NETDEV_CHANGENAME) {
- struct efx_nic *efx = netdev_priv(net_dev);
-
- strcpy(efx->name, net_dev->name);
- efx_mtd_rename(efx);
- efx_set_channel_names(efx);
- }
+ if (net_dev->netdev_ops == &efx_netdev_ops &&
+ event == NETDEV_CHANGENAME)
+ efx_update_name(netdev_priv(net_dev));
return NOTIFY_DONE;
}
@@ -1568,8 +1571,10 @@ static int efx_register_netdev(struct efx_nic *efx)
EFX_ERR(efx, "could not register net dev\n");
return rc;
}
- strcpy(efx->name, net_dev->name);
- efx_set_channel_names(efx);
+
+ rtnl_lock();
+ efx_update_name(efx);
+ rtnl_unlock();
rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
if (rc) {
@@ -1978,8 +1983,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
if (!efx)
return;
- efx_mtd_remove(efx);
-
/* Mark the NIC as fini, then stop the interface */
rtnl_lock();
efx->state = STATE_FINI;
@@ -1993,6 +1996,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_unregister_netdev(efx);
+ efx_mtd_remove(efx);
+
/* Wait for any scheduled resets to complete. No more will be
* scheduled from this point because efx_stop_all() has been
* called, we are no longer registered with driverlink, and
@@ -2146,17 +2151,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
/* Switch to the running state before we expose the device to
* the OS. This is to ensure that the initial gathering of
* MAC stats succeeds. */
- rtnl_lock();
efx->state = STATE_RUNNING;
- rtnl_unlock();
+
+ efx_mtd_probe(efx); /* allowed to fail */
rc = efx_register_netdev(efx);
if (rc)
goto fail5;
EFX_LOG(efx, "initialisation successful\n");
-
- efx_mtd_probe(efx); /* allowed to fail */
return 0;
fail5: