diff options
author | Dhananjay Phadke <dhananjay@netxen.com> | 2009-07-17 11:27:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-07-20 11:23:31 -0400 |
commit | b2af9cb06d4de1b507ec0fd779ec2ecedee1480a (patch) | |
tree | 15967d7eaee2636e6c29d15d96dd57e99c0a6ee9 /drivers/net/netxen/netxen_nic_main.c | |
parent | cf981ffb31e8f41f4899a56560f81322f94f22d1 (diff) |
netxen: fix deadlock on dev close
netxen: fix deadlock on dev close
The tx ring accounting fix in commit cb2107be43d2fc5eadec58b92b
("netxen: fix tx ring accounting") introduced intermittent
deadlock when inteface is going down.
This was possibly combined effect of speculative tx pause,
calling netif_tx_lock instead of queue lock and unclean
synchronization with napi which could end up unmasking
interrupt.
Signed-off-by: Dhananjay Phadke <dhananjay@netxen.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/netxen/netxen_nic_main.c')
-rw-r--r-- | drivers/net/netxen/netxen_nic_main.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 9a7c4c8029de..370c52f27760 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c | |||
@@ -215,9 +215,9 @@ netxen_napi_disable(struct netxen_adapter *adapter) | |||
215 | 215 | ||
216 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { | 216 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { |
217 | sds_ring = &recv_ctx->sds_rings[ring]; | 217 | sds_ring = &recv_ctx->sds_rings[ring]; |
218 | napi_disable(&sds_ring->napi); | ||
219 | netxen_nic_disable_int(sds_ring); | 218 | netxen_nic_disable_int(sds_ring); |
220 | synchronize_irq(sds_ring->irq); | 219 | napi_synchronize(&sds_ring->napi); |
220 | napi_disable(&sds_ring->napi); | ||
221 | } | 221 | } |
222 | } | 222 | } |
223 | 223 | ||
@@ -833,11 +833,11 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) | |||
833 | 833 | ||
834 | adapter->ahw.linkup = 0; | 834 | adapter->ahw.linkup = 0; |
835 | 835 | ||
836 | netxen_napi_enable(adapter); | ||
837 | |||
838 | if (adapter->max_sds_rings > 1) | 836 | if (adapter->max_sds_rings > 1) |
839 | netxen_config_rss(adapter, 1); | 837 | netxen_config_rss(adapter, 1); |
840 | 838 | ||
839 | netxen_napi_enable(adapter); | ||
840 | |||
841 | if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION) | 841 | if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION) |
842 | netxen_linkevent_request(adapter, 1); | 842 | netxen_linkevent_request(adapter, 1); |
843 | else | 843 | else |
@@ -851,8 +851,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) | |||
851 | static void | 851 | static void |
852 | netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) | 852 | netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) |
853 | { | 853 | { |
854 | spin_lock(&adapter->tx_clean_lock); | ||
854 | netif_carrier_off(netdev); | 855 | netif_carrier_off(netdev); |
855 | netif_stop_queue(netdev); | 856 | netif_tx_disable(netdev); |
856 | 857 | ||
857 | if (adapter->stop_port) | 858 | if (adapter->stop_port) |
858 | adapter->stop_port(adapter); | 859 | adapter->stop_port(adapter); |
@@ -863,9 +864,10 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) | |||
863 | netxen_napi_disable(adapter); | 864 | netxen_napi_disable(adapter); |
864 | 865 | ||
865 | netxen_release_tx_buffers(adapter); | 866 | netxen_release_tx_buffers(adapter); |
867 | spin_unlock(&adapter->tx_clean_lock); | ||
866 | 868 | ||
867 | FLUSH_SCHEDULED_WORK(); | ||
868 | del_timer_sync(&adapter->watchdog_timer); | 869 | del_timer_sync(&adapter->watchdog_timer); |
870 | FLUSH_SCHEDULED_WORK(); | ||
869 | } | 871 | } |
870 | 872 | ||
871 | 873 | ||
@@ -1645,6 +1647,9 @@ static void netxen_tx_timeout_task(struct work_struct *work) | |||
1645 | struct netxen_adapter *adapter = | 1647 | struct netxen_adapter *adapter = |
1646 | container_of(work, struct netxen_adapter, tx_timeout_task); | 1648 | container_of(work, struct netxen_adapter, tx_timeout_task); |
1647 | 1649 | ||
1650 | if (!netif_running(adapter->netdev)) | ||
1651 | return; | ||
1652 | |||
1648 | printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", | 1653 | printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", |
1649 | netxen_nic_driver_name, adapter->netdev->name); | 1654 | netxen_nic_driver_name, adapter->netdev->name); |
1650 | 1655 | ||
@@ -1757,7 +1762,8 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget) | |||
1757 | 1762 | ||
1758 | if ((work_done < budget) && tx_complete) { | 1763 | if ((work_done < budget) && tx_complete) { |
1759 | napi_complete(&sds_ring->napi); | 1764 | napi_complete(&sds_ring->napi); |
1760 | netxen_nic_enable_int(sds_ring); | 1765 | if (netif_running(adapter->netdev)) |
1766 | netxen_nic_enable_int(sds_ring); | ||
1761 | } | 1767 | } |
1762 | 1768 | ||
1763 | return work_done; | 1769 | return work_done; |