diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-07-18 14:01:20 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-07-22 19:44:13 -0400 |
commit | 8d9853d911b9d3fb767c3886066530c0e39b78ba (patch) | |
tree | ff27498e3d6b747bf07e21baa1b27d07be8f58ee /drivers/net | |
parent | 9dadae686fce02a02982fc9c0563f6b917217a66 (diff) |
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')
-rw-r--r-- | drivers/net/sfc/efx.c | 20 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 5 |
2 files changed, 21 insertions, 4 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) | |||
1762 | 1762 | ||
1763 | efx->reset_pending = method; | 1763 | efx->reset_pending = method; |
1764 | 1764 | ||
1765 | queue_work(efx->workqueue, &efx->reset_work); | 1765 | queue_work(efx->reset_workqueue, &efx->reset_work); |
1766 | } | 1766 | } |
1767 | 1767 | ||
1768 | /************************************************************************** | 1768 | /************************************************************************** |
@@ -1907,14 +1907,28 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, | |||
1907 | goto fail1; | 1907 | goto fail1; |
1908 | } | 1908 | } |
1909 | 1909 | ||
1910 | efx->reset_workqueue = create_singlethread_workqueue("sfc_reset"); | ||
1911 | if (!efx->reset_workqueue) { | ||
1912 | rc = -ENOMEM; | ||
1913 | goto fail2; | ||
1914 | } | ||
1915 | |||
1910 | return 0; | 1916 | return 0; |
1911 | 1917 | ||
1918 | fail2: | ||
1919 | destroy_workqueue(efx->workqueue); | ||
1920 | efx->workqueue = NULL; | ||
1921 | |||
1912 | fail1: | 1922 | fail1: |
1913 | return rc; | 1923 | return rc; |
1914 | } | 1924 | } |
1915 | 1925 | ||
1916 | static void efx_fini_struct(struct efx_nic *efx) | 1926 | static void efx_fini_struct(struct efx_nic *efx) |
1917 | { | 1927 | { |
1928 | if (efx->reset_workqueue) { | ||
1929 | destroy_workqueue(efx->reset_workqueue); | ||
1930 | efx->reset_workqueue = NULL; | ||
1931 | } | ||
1918 | if (efx->workqueue) { | 1932 | if (efx->workqueue) { |
1919 | destroy_workqueue(efx->workqueue); | 1933 | destroy_workqueue(efx->workqueue); |
1920 | efx->workqueue = NULL; | 1934 | efx->workqueue = NULL; |
@@ -1977,7 +1991,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev) | |||
1977 | * scheduled from this point because efx_stop_all() has been | 1991 | * scheduled from this point because efx_stop_all() has been |
1978 | * called, we are no longer registered with driverlink, and | 1992 | * called, we are no longer registered with driverlink, and |
1979 | * the net_device's have been removed. */ | 1993 | * the net_device's have been removed. */ |
1980 | flush_workqueue(efx->workqueue); | 1994 | flush_workqueue(efx->reset_workqueue); |
1981 | 1995 | ||
1982 | efx_pci_remove_main(efx); | 1996 | efx_pci_remove_main(efx); |
1983 | 1997 | ||
@@ -2098,7 +2112,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, | |||
2098 | * scheduled since efx_stop_all() has been called, and we | 2112 | * scheduled since efx_stop_all() has been called, and we |
2099 | * have not and never have been registered with either | 2113 | * have not and never have been registered with either |
2100 | * the rtnetlink or driverlink layers. */ | 2114 | * the rtnetlink or driverlink layers. */ |
2101 | cancel_work_sync(&efx->reset_work); | 2115 | flush_workqueue(efx->reset_workqueue); |
2102 | 2116 | ||
2103 | /* Retry if a recoverably reset event has been scheduled */ | 2117 | /* Retry if a recoverably reset event has been scheduled */ |
2104 | if ((efx->reset_pending != RESET_TYPE_INVISIBLE) && | 2118 | if ((efx->reset_pending != RESET_TYPE_INVISIBLE) && |
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index d803b86c647c..219c74a772c3 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -616,7 +616,9 @@ union efx_multicast_hash { | |||
616 | * @pci_dev: The PCI device | 616 | * @pci_dev: The PCI device |
617 | * @type: Controller type attributes | 617 | * @type: Controller type attributes |
618 | * @legacy_irq: IRQ number | 618 | * @legacy_irq: IRQ number |
619 | * @workqueue: Workqueue for resets, port reconfigures and the HW monitor | 619 | * @workqueue: Workqueue for port reconfigures and the HW monitor. |
620 | * Work items do not hold and must not acquire RTNL. | ||
621 | * @reset_workqueue: Workqueue for resets. Work item will acquire RTNL. | ||
620 | * @reset_work: Scheduled reset workitem | 622 | * @reset_work: Scheduled reset workitem |
621 | * @monitor_work: Hardware monitor workitem | 623 | * @monitor_work: Hardware monitor workitem |
622 | * @membase_phys: Memory BAR value as physical address | 624 | * @membase_phys: Memory BAR value as physical address |
@@ -684,6 +686,7 @@ struct efx_nic { | |||
684 | const struct efx_nic_type *type; | 686 | const struct efx_nic_type *type; |
685 | int legacy_irq; | 687 | int legacy_irq; |
686 | struct workqueue_struct *workqueue; | 688 | struct workqueue_struct *workqueue; |
689 | struct workqueue_struct *reset_workqueue; | ||
687 | struct work_struct reset_work; | 690 | struct work_struct reset_work; |
688 | struct delayed_work monitor_work; | 691 | struct delayed_work monitor_work; |
689 | resource_size_t membase_phys; | 692 | resource_size_t membase_phys; |