summaryrefslogtreecommitdiff
path: root/drivers/net/sfc/efx.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2008-07-18 19:01:20 +0100
committerJeff Garzik <jgarzik@redhat.com>2008-07-22 19:44:13 -0400
commit8d9853d911b9d3fb767c3886066530c0e39b78ba (patch)
treeff27498e3d6b747bf07e21baa1b27d07be8f58ee /drivers/net/sfc/efx.c
parent9dadae686fce02a02982fc9c0563f6b917217a66 (diff)
downloadlwn-8d9853d911b9d3fb767c3886066530c0e39b78ba.tar.gz
lwn-8d9853d911b9d3fb767c3886066530c0e39b78ba.zip
sfc: Use a separate workqueue for resets
This avoids deadlock in case a reset is triggered during self-test. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/sfc/efx.c')
-rw-r--r--drivers/net/sfc/efx.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 7b2015f9e469..7b2a81866232 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1762,7 +1762,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
efx->reset_pending = method;
- queue_work(efx->workqueue, &efx->reset_work);
+ queue_work(efx->reset_workqueue, &efx->reset_work);
}
/**************************************************************************
@@ -1907,14 +1907,28 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
goto fail1;
}
+ efx->reset_workqueue = create_singlethread_workqueue("sfc_reset");
+ if (!efx->reset_workqueue) {
+ rc = -ENOMEM;
+ goto fail2;
+ }
+
return 0;
+ fail2:
+ destroy_workqueue(efx->workqueue);
+ efx->workqueue = NULL;
+
fail1:
return rc;
}
static void efx_fini_struct(struct efx_nic *efx)
{
+ if (efx->reset_workqueue) {
+ destroy_workqueue(efx->reset_workqueue);
+ efx->reset_workqueue = NULL;
+ }
if (efx->workqueue) {
destroy_workqueue(efx->workqueue);
efx->workqueue = NULL;
@@ -1977,7 +1991,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
* 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. */
- flush_workqueue(efx->workqueue);
+ flush_workqueue(efx->reset_workqueue);
efx_pci_remove_main(efx);
@@ -2098,7 +2112,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
* scheduled since efx_stop_all() has been called, and we
* have not and never have been registered with either
* the rtnetlink or driverlink layers. */
- cancel_work_sync(&efx->reset_work);
+ flush_workqueue(efx->reset_workqueue);
/* Retry if a recoverably reset event has been scheduled */
if ((efx->reset_pending != RESET_TYPE_INVISIBLE) &&