diff options
author | Amit Kumar Salecha <amit.salecha@qlogic.com> | 2009-12-08 15:40:56 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-23 17:13:27 -0500 |
commit | e87ad5539343366e7c634c940a930157b6fa2aae (patch) | |
tree | 53eacf4e7a62498e76463adafd0e43f4808d188d /drivers/net | |
parent | 6a808c6c02fb9f0ffa24ac7cca6cfc323cf98b21 (diff) |
netxen: support pci error handlers
o Support pci error detection and recovery.
o Refactor suspend and resume code, to share with io_error_detected,
and slot_reset callbacks
o NX_NEED_AER device state added, to synchronize with firmware
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')
-rw-r--r-- | drivers/net/netxen/netxen_nic_hdr.h | 3 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_main.c | 193 |
2 files changed, 150 insertions, 46 deletions
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index d138fc22927a..638369024908 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h | |||
@@ -969,7 +969,8 @@ enum { | |||
969 | #define NX_DEV_READY 3 | 969 | #define NX_DEV_READY 3 |
970 | #define NX_DEV_NEED_RESET 4 | 970 | #define NX_DEV_NEED_RESET 4 |
971 | #define NX_DEV_NEED_QUISCENT 5 | 971 | #define NX_DEV_NEED_QUISCENT 5 |
972 | #define NX_DEV_FAILED 6 | 972 | #define NX_DEV_NEED_AER 6 |
973 | #define NX_DEV_FAILED 7 | ||
973 | 974 | ||
974 | #define NX_RCODE_DRIVER_INFO 0x20000000 | 975 | #define NX_RCODE_DRIVER_INFO 0x20000000 |
975 | #define NX_RCODE_DRIVER_CAN_RELOAD 0x40000000 | 976 | #define NX_RCODE_DRIVER_CAN_RELOAD 0x40000000 |
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 1aca6260909a..f13a07f717c7 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/ipv6.h> | 35 | #include <linux/ipv6.h> |
36 | #include <linux/inetdevice.h> | 36 | #include <linux/inetdevice.h> |
37 | #include <linux/sysfs.h> | 37 | #include <linux/sysfs.h> |
38 | #include <linux/aer.h> | ||
38 | 39 | ||
39 | MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver"); | 40 | MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver"); |
40 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
@@ -84,6 +85,7 @@ static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter); | |||
84 | static void netxen_create_diag_entries(struct netxen_adapter *adapter); | 85 | static void netxen_create_diag_entries(struct netxen_adapter *adapter); |
85 | static void netxen_remove_diag_entries(struct netxen_adapter *adapter); | 86 | static void netxen_remove_diag_entries(struct netxen_adapter *adapter); |
86 | 87 | ||
88 | static int nx_dev_request_aer(struct netxen_adapter *adapter); | ||
87 | static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter); | 89 | static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter); |
88 | static int netxen_can_start_firmware(struct netxen_adapter *adapter); | 90 | static int netxen_can_start_firmware(struct netxen_adapter *adapter); |
89 | 91 | ||
@@ -1262,6 +1264,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1262 | if ((err = pci_request_regions(pdev, netxen_nic_driver_name))) | 1264 | if ((err = pci_request_regions(pdev, netxen_nic_driver_name))) |
1263 | goto err_out_disable_pdev; | 1265 | goto err_out_disable_pdev; |
1264 | 1266 | ||
1267 | if (NX_IS_REVISION_P3(pdev->revision)) | ||
1268 | pci_enable_pcie_error_reporting(pdev); | ||
1269 | |||
1265 | pci_set_master(pdev); | 1270 | pci_set_master(pdev); |
1266 | 1271 | ||
1267 | netdev = alloc_etherdev(sizeof(struct netxen_adapter)); | 1272 | netdev = alloc_etherdev(sizeof(struct netxen_adapter)); |
@@ -1409,17 +1414,19 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) | |||
1409 | 1414 | ||
1410 | netxen_release_firmware(adapter); | 1415 | netxen_release_firmware(adapter); |
1411 | 1416 | ||
1417 | if (NX_IS_REVISION_P3(pdev->revision)) | ||
1418 | pci_disable_pcie_error_reporting(pdev); | ||
1419 | |||
1412 | pci_release_regions(pdev); | 1420 | pci_release_regions(pdev); |
1413 | pci_disable_device(pdev); | 1421 | pci_disable_device(pdev); |
1414 | pci_set_drvdata(pdev, NULL); | 1422 | pci_set_drvdata(pdev, NULL); |
1415 | 1423 | ||
1416 | free_netdev(netdev); | 1424 | free_netdev(netdev); |
1417 | } | 1425 | } |
1418 | static int __netxen_nic_shutdown(struct pci_dev *pdev) | 1426 | |
1427 | static void netxen_nic_detach_func(struct netxen_adapter *adapter) | ||
1419 | { | 1428 | { |
1420 | struct netxen_adapter *adapter = pci_get_drvdata(pdev); | ||
1421 | struct net_device *netdev = adapter->netdev; | 1429 | struct net_device *netdev = adapter->netdev; |
1422 | int retval; | ||
1423 | 1430 | ||
1424 | netif_device_detach(netdev); | 1431 | netif_device_detach(netdev); |
1425 | 1432 | ||
@@ -1438,43 +1445,9 @@ static int __netxen_nic_shutdown(struct pci_dev *pdev) | |||
1438 | nx_decr_dev_ref_cnt(adapter); | 1445 | nx_decr_dev_ref_cnt(adapter); |
1439 | 1446 | ||
1440 | clear_bit(__NX_RESETTING, &adapter->state); | 1447 | clear_bit(__NX_RESETTING, &adapter->state); |
1441 | |||
1442 | retval = pci_save_state(pdev); | ||
1443 | if (retval) | ||
1444 | return retval; | ||
1445 | |||
1446 | if (netxen_nic_wol_supported(adapter)) { | ||
1447 | pci_enable_wake(pdev, PCI_D3cold, 1); | ||
1448 | pci_enable_wake(pdev, PCI_D3hot, 1); | ||
1449 | } | ||
1450 | |||
1451 | return 0; | ||
1452 | } | ||
1453 | static void netxen_nic_shutdown(struct pci_dev *pdev) | ||
1454 | { | ||
1455 | if (__netxen_nic_shutdown(pdev)) | ||
1456 | return; | ||
1457 | |||
1458 | pci_disable_device(pdev); | ||
1459 | } | ||
1460 | #ifdef CONFIG_PM | ||
1461 | static int | ||
1462 | netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) | ||
1463 | { | ||
1464 | int retval; | ||
1465 | |||
1466 | retval = __netxen_nic_shutdown(pdev); | ||
1467 | if (retval) | ||
1468 | return retval; | ||
1469 | |||
1470 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
1471 | |||
1472 | pci_disable_device(pdev); | ||
1473 | return 0; | ||
1474 | } | 1448 | } |
1475 | 1449 | ||
1476 | static int | 1450 | static int netxen_nic_attach_func(struct pci_dev *pdev) |
1477 | netxen_nic_resume(struct pci_dev *pdev) | ||
1478 | { | 1451 | { |
1479 | struct netxen_adapter *adapter = pci_get_drvdata(pdev); | 1452 | struct netxen_adapter *adapter = pci_get_drvdata(pdev); |
1480 | struct net_device *netdev = adapter->netdev; | 1453 | struct net_device *netdev = adapter->netdev; |
@@ -1519,6 +1492,85 @@ err_out: | |||
1519 | nx_decr_dev_ref_cnt(adapter); | 1492 | nx_decr_dev_ref_cnt(adapter); |
1520 | return err; | 1493 | return err; |
1521 | } | 1494 | } |
1495 | |||
1496 | static pci_ers_result_t netxen_io_error_detected(struct pci_dev *pdev, | ||
1497 | pci_channel_state_t state) | ||
1498 | { | ||
1499 | struct netxen_adapter *adapter = pci_get_drvdata(pdev); | ||
1500 | |||
1501 | if (state == pci_channel_io_perm_failure) | ||
1502 | return PCI_ERS_RESULT_DISCONNECT; | ||
1503 | |||
1504 | if (nx_dev_request_aer(adapter)) | ||
1505 | return PCI_ERS_RESULT_RECOVERED; | ||
1506 | |||
1507 | netxen_nic_detach_func(adapter); | ||
1508 | |||
1509 | pci_disable_device(pdev); | ||
1510 | |||
1511 | return PCI_ERS_RESULT_NEED_RESET; | ||
1512 | } | ||
1513 | |||
1514 | static pci_ers_result_t netxen_io_slot_reset(struct pci_dev *pdev) | ||
1515 | { | ||
1516 | int err = 0; | ||
1517 | |||
1518 | err = netxen_nic_attach_func(pdev); | ||
1519 | |||
1520 | return err ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; | ||
1521 | } | ||
1522 | |||
1523 | static void netxen_io_resume(struct pci_dev *pdev) | ||
1524 | { | ||
1525 | pci_cleanup_aer_uncorrect_error_status(pdev); | ||
1526 | } | ||
1527 | |||
1528 | static void netxen_nic_shutdown(struct pci_dev *pdev) | ||
1529 | { | ||
1530 | struct netxen_adapter *adapter = pci_get_drvdata(pdev); | ||
1531 | |||
1532 | netxen_nic_detach_func(adapter); | ||
1533 | |||
1534 | if (pci_save_state(pdev)) | ||
1535 | return; | ||
1536 | |||
1537 | if (netxen_nic_wol_supported(adapter)) { | ||
1538 | pci_enable_wake(pdev, PCI_D3cold, 1); | ||
1539 | pci_enable_wake(pdev, PCI_D3hot, 1); | ||
1540 | } | ||
1541 | |||
1542 | pci_disable_device(pdev); | ||
1543 | } | ||
1544 | |||
1545 | #ifdef CONFIG_PM | ||
1546 | static int | ||
1547 | netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) | ||
1548 | { | ||
1549 | struct netxen_adapter *adapter = pci_get_drvdata(pdev); | ||
1550 | int retval; | ||
1551 | |||
1552 | netxen_nic_detach_func(adapter); | ||
1553 | |||
1554 | retval = pci_save_state(pdev); | ||
1555 | if (retval) | ||
1556 | return retval; | ||
1557 | |||
1558 | if (netxen_nic_wol_supported(adapter)) { | ||
1559 | pci_enable_wake(pdev, PCI_D3cold, 1); | ||
1560 | pci_enable_wake(pdev, PCI_D3hot, 1); | ||
1561 | } | ||
1562 | |||
1563 | pci_disable_device(pdev); | ||
1564 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
1565 | |||
1566 | return 0; | ||
1567 | } | ||
1568 | |||
1569 | static int | ||
1570 | netxen_nic_resume(struct pci_dev *pdev) | ||
1571 | { | ||
1572 | return netxen_nic_attach_func(pdev); | ||
1573 | } | ||
1522 | #endif | 1574 | #endif |
1523 | 1575 | ||
1524 | static int netxen_nic_open(struct net_device *netdev) | 1576 | static int netxen_nic_open(struct net_device *netdev) |
@@ -2110,20 +2162,49 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter) | |||
2110 | return count; | 2162 | return count; |
2111 | } | 2163 | } |
2112 | 2164 | ||
2113 | static void | 2165 | static int |
2166 | nx_dev_request_aer(struct netxen_adapter *adapter) | ||
2167 | { | ||
2168 | u32 state; | ||
2169 | int ret = -EINVAL; | ||
2170 | |||
2171 | if (netxen_api_lock(adapter)) | ||
2172 | return ret; | ||
2173 | |||
2174 | state = NXRD32(adapter, NX_CRB_DEV_STATE); | ||
2175 | |||
2176 | if (state == NX_DEV_NEED_AER) | ||
2177 | ret = 0; | ||
2178 | else if (state == NX_DEV_READY) { | ||
2179 | NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_AER); | ||
2180 | ret = 0; | ||
2181 | } | ||
2182 | |||
2183 | netxen_api_unlock(adapter); | ||
2184 | return ret; | ||
2185 | } | ||
2186 | |||
2187 | static int | ||
2114 | nx_dev_request_reset(struct netxen_adapter *adapter) | 2188 | nx_dev_request_reset(struct netxen_adapter *adapter) |
2115 | { | 2189 | { |
2116 | u32 state; | 2190 | u32 state; |
2191 | int ret = -EINVAL; | ||
2117 | 2192 | ||
2118 | if (netxen_api_lock(adapter)) | 2193 | if (netxen_api_lock(adapter)) |
2119 | return; | 2194 | return ret; |
2120 | 2195 | ||
2121 | state = NXRD32(adapter, NX_CRB_DEV_STATE); | 2196 | state = NXRD32(adapter, NX_CRB_DEV_STATE); |
2122 | 2197 | ||
2123 | if (state != NX_DEV_INITALIZING) | 2198 | if (state == NX_DEV_NEED_RESET) |
2199 | ret = 0; | ||
2200 | else if (state != NX_DEV_INITALIZING && state != NX_DEV_NEED_AER) { | ||
2124 | NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET); | 2201 | NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET); |
2202 | ret = 0; | ||
2203 | } | ||
2125 | 2204 | ||
2126 | netxen_api_unlock(adapter); | 2205 | netxen_api_unlock(adapter); |
2206 | |||
2207 | return ret; | ||
2127 | } | 2208 | } |
2128 | 2209 | ||
2129 | static int | 2210 | static int |
@@ -2275,18 +2356,28 @@ netxen_check_health(struct netxen_adapter *adapter) | |||
2275 | u32 state, heartbit; | 2356 | u32 state, heartbit; |
2276 | struct net_device *netdev = adapter->netdev; | 2357 | struct net_device *netdev = adapter->netdev; |
2277 | 2358 | ||
2359 | state = NXRD32(adapter, NX_CRB_DEV_STATE); | ||
2360 | if (state == NX_DEV_NEED_AER) | ||
2361 | return 0; | ||
2362 | |||
2278 | if (netxen_nic_check_temp(adapter)) | 2363 | if (netxen_nic_check_temp(adapter)) |
2279 | goto detach; | 2364 | goto detach; |
2280 | 2365 | ||
2281 | if (adapter->need_fw_reset) { | 2366 | if (adapter->need_fw_reset) { |
2282 | nx_dev_request_reset(adapter); | 2367 | if (nx_dev_request_reset(adapter)) |
2368 | return 0; | ||
2283 | goto detach; | 2369 | goto detach; |
2284 | } | 2370 | } |
2285 | 2371 | ||
2286 | state = NXRD32(adapter, NX_CRB_DEV_STATE); | 2372 | /* NX_DEV_NEED_RESET, this state can be marked in two cases |
2373 | * 1. Tx timeout 2. Fw hang | ||
2374 | * Send request to destroy context in case of tx timeout only | ||
2375 | * and doesn't required in case of Fw hang | ||
2376 | */ | ||
2287 | if (state == NX_DEV_NEED_RESET) { | 2377 | if (state == NX_DEV_NEED_RESET) { |
2288 | adapter->need_fw_reset = 1; | 2378 | adapter->need_fw_reset = 1; |
2289 | goto detach; | 2379 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) |
2380 | goto detach; | ||
2290 | } | 2381 | } |
2291 | 2382 | ||
2292 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) | 2383 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) |
@@ -2296,12 +2387,17 @@ netxen_check_health(struct netxen_adapter *adapter) | |||
2296 | if (heartbit != adapter->heartbit) { | 2387 | if (heartbit != adapter->heartbit) { |
2297 | adapter->heartbit = heartbit; | 2388 | adapter->heartbit = heartbit; |
2298 | adapter->fw_fail_cnt = 0; | 2389 | adapter->fw_fail_cnt = 0; |
2390 | if (adapter->need_fw_reset) | ||
2391 | goto detach; | ||
2299 | return 0; | 2392 | return 0; |
2300 | } | 2393 | } |
2301 | 2394 | ||
2302 | if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) | 2395 | if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) |
2303 | return 0; | 2396 | return 0; |
2304 | 2397 | ||
2398 | if (nx_dev_request_reset(adapter)) | ||
2399 | return 0; | ||
2400 | |||
2305 | clear_bit(__NX_FW_ATTACHED, &adapter->state); | 2401 | clear_bit(__NX_FW_ATTACHED, &adapter->state); |
2306 | 2402 | ||
2307 | dev_info(&netdev->dev, "firmware hang detected\n"); | 2403 | dev_info(&netdev->dev, "firmware hang detected\n"); |
@@ -2731,6 +2827,12 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event) | |||
2731 | { } | 2827 | { } |
2732 | #endif | 2828 | #endif |
2733 | 2829 | ||
2830 | static struct pci_error_handlers netxen_err_handler = { | ||
2831 | .error_detected = netxen_io_error_detected, | ||
2832 | .slot_reset = netxen_io_slot_reset, | ||
2833 | .resume = netxen_io_resume, | ||
2834 | }; | ||
2835 | |||
2734 | static struct pci_driver netxen_driver = { | 2836 | static struct pci_driver netxen_driver = { |
2735 | .name = netxen_nic_driver_name, | 2837 | .name = netxen_nic_driver_name, |
2736 | .id_table = netxen_pci_tbl, | 2838 | .id_table = netxen_pci_tbl, |
@@ -2740,7 +2842,8 @@ static struct pci_driver netxen_driver = { | |||
2740 | .suspend = netxen_nic_suspend, | 2842 | .suspend = netxen_nic_suspend, |
2741 | .resume = netxen_nic_resume, | 2843 | .resume = netxen_nic_resume, |
2742 | #endif | 2844 | #endif |
2743 | .shutdown = netxen_nic_shutdown | 2845 | .shutdown = netxen_nic_shutdown, |
2846 | .err_handler = &netxen_err_handler | ||
2744 | }; | 2847 | }; |
2745 | 2848 | ||
2746 | static int __init netxen_init_module(void) | 2849 | static int __init netxen_init_module(void) |