Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 327705
b: refs/heads/master
c: 7153f62
h: refs/heads/master
i:
  327703: 24481cd
v: v3
  • Loading branch information
Ben Hutchings committed Aug 24, 2012
1 parent 1ecd63a commit 9990ccb
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 42 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b812f8b7a9b657367eaacab8c34e6711a657a48b
refs/heads/master: 7153f623ea47f3feb54209d75b80ed09a497cd4a
84 changes: 43 additions & 41 deletions trunk/drivers/net/ethernet/sfc/efx.c
Original file line number Diff line number Diff line change
Expand Up @@ -2112,6 +2112,19 @@ static int efx_register_netdev(struct efx_nic *efx)

rtnl_lock();

/* Enable resets to be scheduled and check whether any were
* already requested. If so, the NIC is probably hosed so we
* abort.
*/
efx->state = STATE_READY;
smp_mb(); /* ensure we change state before checking reset_pending */
if (efx->reset_pending) {
netif_err(efx, probe, efx->net_dev,
"aborting probe due to scheduled reset\n");
rc = -EIO;
goto fail_locked;
}

rc = dev_alloc_name(net_dev, net_dev->name);
if (rc < 0)
goto fail_locked;
Expand Down Expand Up @@ -2141,14 +2154,14 @@ static int efx_register_netdev(struct efx_nic *efx)

return 0;

fail_registered:
rtnl_lock();
unregister_netdevice(net_dev);
fail_locked:
efx->state = STATE_UNINIT;
rtnl_unlock();
netif_err(efx, drv, efx->net_dev, "could not register net dev\n");
return rc;

fail_registered:
unregister_netdev(net_dev);
return rc;
}

static void efx_unregister_netdev(struct efx_nic *efx)
Expand All @@ -2171,7 +2184,11 @@ static void efx_unregister_netdev(struct efx_nic *efx)

strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type);
unregister_netdev(efx->net_dev);

rtnl_lock();
unregister_netdevice(efx->net_dev);
efx->state = STATE_UNINIT;
rtnl_unlock();
}

/**************************************************************************
Expand Down Expand Up @@ -2309,13 +2326,15 @@ static void efx_reset_work(struct work_struct *data)
if (!pending)
return;

/* If we're not READY then don't reset. Leave the reset_pending
* flags set so that efx_pci_probe_main will be retried */
if (efx->state != STATE_READY)
return;

rtnl_lock();
(void)efx_reset(efx, fls(pending) - 1);

/* We checked the state in efx_schedule_reset() but it may
* have changed by now. Now that we have the RTNL lock,
* it cannot change again.
*/
if (efx->state == STATE_READY)
(void)efx_reset(efx, fls(pending) - 1);

rtnl_unlock();
}

Expand All @@ -2341,6 +2360,13 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
}

set_bit(method, &efx->reset_pending);
smp_mb(); /* ensure we change reset_pending before checking state */

/* If we're not READY then just leave the flags set as the cue
* to abort probing or reschedule the reset later.
*/
if (ACCESS_ONCE(efx->state) != STATE_READY)
return;

/* efx_process_channel() will no longer read events once a
* reset is scheduled. So switch back to poll'd MCDI completions. */
Expand Down Expand Up @@ -2485,6 +2511,12 @@ static void efx_fini_struct(struct efx_nic *efx)
*/
static void efx_pci_remove_main(struct efx_nic *efx)
{
/* Flush reset_work. It can no longer be scheduled since we
* are not READY.
*/
BUG_ON(efx->state == STATE_READY);
cancel_work_sync(&efx->reset_work);

#ifdef CONFIG_RFS_ACCEL
free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap);
efx->net_dev->rx_cpu_rmap = NULL;
Expand All @@ -2510,24 +2542,15 @@ static void efx_pci_remove(struct pci_dev *pci_dev)

/* Mark the NIC as fini, then stop the interface */
rtnl_lock();
efx->state = STATE_UNINIT;
dev_close(efx->net_dev);
efx_stop_interrupts(efx, false);

/* Allow any queued efx_resets() to complete */
rtnl_unlock();

efx_sriov_fini(efx);
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
* the net_device's have been removed. */
cancel_work_sync(&efx->reset_work);

efx_pci_remove_main(efx);

efx_fini_io(efx);
Expand Down Expand Up @@ -2686,30 +2709,9 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
goto fail2;

rc = efx_pci_probe_main(efx);

/* Serialise against efx_reset(). No more resets will be
* scheduled since efx_stop_all() has been called, and we have
* not and never have been registered.
*/
cancel_work_sync(&efx->reset_work);

if (rc)
goto fail3;

/* If there was a scheduled reset during probe, the NIC is
* probably hosed anyway.
*/
if (efx->reset_pending) {
netif_err(efx, probe, efx->net_dev,
"aborting probe due to scheduled reset\n");
rc = -EIO;
goto fail4;
}

/* Switch to the READY state before we expose the device to the OS,
* so that dev_open()|efx_start_all() will actually start the device */
efx->state = STATE_READY;

rc = efx_register_netdev(efx);
if (rc)
goto fail4;
Expand Down

0 comments on commit 9990ccb

Please sign in to comment.