diff options
author | Amit Kumar Salecha <amit.salecha@qlogic.com> | 2010-06-21 23:19:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-23 16:16:31 -0400 |
commit | 68bf1c68a4b3d9ad0a98f3310f2f79dca075a035 (patch) | |
tree | 8e29abda3a579c252076eab1b79718d0702a008e /drivers/net/qlcnic | |
parent | 52486a3ac86eabe5a2f283eb9682a69c14347213 (diff) |
qlcnic: offload tx timeout recovery
Offload tx timeout recovery to fw recovery func(check_health).
In check_health, first check health of device, if it its ok, then
do tx timeout recovery otherwise device recovery.
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlcnic')
-rw-r--r-- | drivers/net/qlcnic/qlcnic.h | 3 | ||||
-rw-r--r-- | drivers/net/qlcnic/qlcnic_main.c | 65 |
2 files changed, 32 insertions, 36 deletions
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 5c7d474e560b..6ec34a7fba65 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h | |||
@@ -934,6 +934,7 @@ struct qlcnic_adapter { | |||
934 | u8 rx_csum; | 934 | u8 rx_csum; |
935 | u8 portnum; | 935 | u8 portnum; |
936 | u8 physical_port; | 936 | u8 physical_port; |
937 | u8 reset_context; | ||
937 | 938 | ||
938 | u8 mc_enabled; | 939 | u8 mc_enabled; |
939 | u8 max_mc_count; | 940 | u8 max_mc_count; |
@@ -1001,8 +1002,6 @@ struct qlcnic_adapter { | |||
1001 | 1002 | ||
1002 | struct delayed_work fw_work; | 1003 | struct delayed_work fw_work; |
1003 | 1004 | ||
1004 | struct work_struct tx_timeout_task; | ||
1005 | |||
1006 | struct qlcnic_nic_intr_coalesce coal; | 1005 | struct qlcnic_nic_intr_coalesce coal; |
1007 | 1006 | ||
1008 | unsigned long state; | 1007 | unsigned long state; |
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index c4602fa866d4..3b71dfcd6d44 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c | |||
@@ -75,7 +75,6 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev); | |||
75 | static int qlcnic_open(struct net_device *netdev); | 75 | static int qlcnic_open(struct net_device *netdev); |
76 | static int qlcnic_close(struct net_device *netdev); | 76 | static int qlcnic_close(struct net_device *netdev); |
77 | static void qlcnic_tx_timeout(struct net_device *netdev); | 77 | static void qlcnic_tx_timeout(struct net_device *netdev); |
78 | static void qlcnic_tx_timeout_task(struct work_struct *work); | ||
79 | static void qlcnic_attach_work(struct work_struct *work); | 78 | static void qlcnic_attach_work(struct work_struct *work); |
80 | static void qlcnic_fwinit_work(struct work_struct *work); | 79 | static void qlcnic_fwinit_work(struct work_struct *work); |
81 | static void qlcnic_fw_poll_work(struct work_struct *work); | 80 | static void qlcnic_fw_poll_work(struct work_struct *work); |
@@ -911,6 +910,7 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) | |||
911 | 910 | ||
912 | qlcnic_linkevent_request(adapter, 1); | 911 | qlcnic_linkevent_request(adapter, 1); |
913 | 912 | ||
913 | adapter->reset_context = 0; | ||
914 | set_bit(__QLCNIC_DEV_UP, &adapter->state); | 914 | set_bit(__QLCNIC_DEV_UP, &adapter->state); |
915 | return 0; | 915 | return 0; |
916 | } | 916 | } |
@@ -1110,6 +1110,27 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) | |||
1110 | return 0; | 1110 | return 0; |
1111 | } | 1111 | } |
1112 | 1112 | ||
1113 | /* Reset context in hardware only */ | ||
1114 | static int | ||
1115 | qlcnic_reset_hw_context(struct qlcnic_adapter *adapter) | ||
1116 | { | ||
1117 | struct net_device *netdev = adapter->netdev; | ||
1118 | |||
1119 | if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) | ||
1120 | return -EBUSY; | ||
1121 | |||
1122 | netif_device_detach(netdev); | ||
1123 | |||
1124 | qlcnic_down(adapter, netdev); | ||
1125 | |||
1126 | qlcnic_up(adapter, netdev); | ||
1127 | |||
1128 | netif_device_attach(netdev); | ||
1129 | |||
1130 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | ||
1131 | return 0; | ||
1132 | } | ||
1133 | |||
1113 | int | 1134 | int |
1114 | qlcnic_reset_context(struct qlcnic_adapter *adapter) | 1135 | qlcnic_reset_context(struct qlcnic_adapter *adapter) |
1115 | { | 1136 | { |
@@ -1178,8 +1199,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, | |||
1178 | 1199 | ||
1179 | netdev->irq = adapter->msix_entries[0].vector; | 1200 | netdev->irq = adapter->msix_entries[0].vector; |
1180 | 1201 | ||
1181 | INIT_WORK(&adapter->tx_timeout_task, qlcnic_tx_timeout_task); | ||
1182 | |||
1183 | if (qlcnic_read_mac_addr(adapter)) | 1202 | if (qlcnic_read_mac_addr(adapter)) |
1184 | dev_warn(&pdev->dev, "failed to read mac addr\n"); | 1203 | dev_warn(&pdev->dev, "failed to read mac addr\n"); |
1185 | 1204 | ||
@@ -1350,8 +1369,6 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev) | |||
1350 | 1369 | ||
1351 | unregister_netdev(netdev); | 1370 | unregister_netdev(netdev); |
1352 | 1371 | ||
1353 | cancel_work_sync(&adapter->tx_timeout_task); | ||
1354 | |||
1355 | qlcnic_detach(adapter); | 1372 | qlcnic_detach(adapter); |
1356 | 1373 | ||
1357 | if (adapter->npars != NULL) | 1374 | if (adapter->npars != NULL) |
@@ -1390,8 +1407,6 @@ static int __qlcnic_shutdown(struct pci_dev *pdev) | |||
1390 | if (netif_running(netdev)) | 1407 | if (netif_running(netdev)) |
1391 | qlcnic_down(adapter, netdev); | 1408 | qlcnic_down(adapter, netdev); |
1392 | 1409 | ||
1393 | cancel_work_sync(&adapter->tx_timeout_task); | ||
1394 | |||
1395 | qlcnic_clr_all_drv_state(adapter); | 1410 | qlcnic_clr_all_drv_state(adapter); |
1396 | 1411 | ||
1397 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | 1412 | clear_bit(__QLCNIC_RESETTING, &adapter->state); |
@@ -1854,35 +1869,11 @@ static void qlcnic_tx_timeout(struct net_device *netdev) | |||
1854 | return; | 1869 | return; |
1855 | 1870 | ||
1856 | dev_err(&netdev->dev, "transmit timeout, resetting.\n"); | 1871 | dev_err(&netdev->dev, "transmit timeout, resetting.\n"); |
1857 | schedule_work(&adapter->tx_timeout_task); | ||
1858 | } | ||
1859 | |||
1860 | static void qlcnic_tx_timeout_task(struct work_struct *work) | ||
1861 | { | ||
1862 | struct qlcnic_adapter *adapter = | ||
1863 | container_of(work, struct qlcnic_adapter, tx_timeout_task); | ||
1864 | |||
1865 | if (!netif_running(adapter->netdev)) | ||
1866 | return; | ||
1867 | |||
1868 | if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) | ||
1869 | return; | ||
1870 | 1872 | ||
1871 | if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS) | 1873 | if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS) |
1872 | goto request_reset; | 1874 | adapter->need_fw_reset = 1; |
1873 | 1875 | else | |
1874 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | 1876 | adapter->reset_context = 1; |
1875 | if (!qlcnic_reset_context(adapter)) { | ||
1876 | adapter->netdev->trans_start = jiffies; | ||
1877 | return; | ||
1878 | |||
1879 | /* context reset failed, fall through for fw reset */ | ||
1880 | } | ||
1881 | |||
1882 | request_reset: | ||
1883 | adapter->need_fw_reset = 1; | ||
1884 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | ||
1885 | QLCDB(adapter, DRV, "Resetting adapter\n"); | ||
1886 | } | 1877 | } |
1887 | 1878 | ||
1888 | static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) | 1879 | static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) |
@@ -2540,6 +2531,12 @@ qlcnic_check_health(struct qlcnic_adapter *adapter) | |||
2540 | adapter->fw_fail_cnt = 0; | 2531 | adapter->fw_fail_cnt = 0; |
2541 | if (adapter->need_fw_reset) | 2532 | if (adapter->need_fw_reset) |
2542 | goto detach; | 2533 | goto detach; |
2534 | |||
2535 | if (adapter->reset_context) { | ||
2536 | qlcnic_reset_hw_context(adapter); | ||
2537 | adapter->netdev->trans_start = jiffies; | ||
2538 | } | ||
2539 | |||
2543 | return 0; | 2540 | return 0; |
2544 | } | 2541 | } |
2545 | 2542 | ||