diff options
Diffstat (limited to 'drivers/net/netxen/netxen_nic_main.c')
-rw-r--r-- | drivers/net/netxen/netxen_nic_main.c | 213 |
1 files changed, 160 insertions, 53 deletions
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 9f9d6081959b..076f826d5a50 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c | |||
@@ -19,7 +19,7 @@ | |||
19 | * MA 02111-1307, USA. | 19 | * MA 02111-1307, USA. |
20 | * | 20 | * |
21 | * The full GNU General Public License is included in this distribution | 21 | * The full GNU General Public License is included in this distribution |
22 | * in the file called LICENSE. | 22 | * in the file called "COPYING". |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
@@ -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 | ||
@@ -98,7 +100,7 @@ static void netxen_config_indev_addr(struct net_device *dev, unsigned long); | |||
98 | {PCI_DEVICE(PCI_VENDOR_ID_NETXEN, (device)), \ | 100 | {PCI_DEVICE(PCI_VENDOR_ID_NETXEN, (device)), \ |
99 | .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0} | 101 | .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0} |
100 | 102 | ||
101 | static struct pci_device_id netxen_pci_tbl[] __devinitdata = { | 103 | static DEFINE_PCI_DEVICE_TABLE(netxen_pci_tbl) = { |
102 | ENTRY(PCI_DEVICE_ID_NX2031_10GXSR), | 104 | ENTRY(PCI_DEVICE_ID_NX2031_10GXSR), |
103 | ENTRY(PCI_DEVICE_ID_NX2031_10GCX4), | 105 | ENTRY(PCI_DEVICE_ID_NX2031_10GCX4), |
104 | ENTRY(PCI_DEVICE_ID_NX2031_4GCU), | 106 | ENTRY(PCI_DEVICE_ID_NX2031_4GCU), |
@@ -430,7 +432,7 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) | |||
430 | { | 432 | { |
431 | int i; | 433 | int i; |
432 | unsigned char *p; | 434 | unsigned char *p; |
433 | __le64 mac_addr; | 435 | u64 mac_addr; |
434 | struct net_device *netdev = adapter->netdev; | 436 | struct net_device *netdev = adapter->netdev; |
435 | struct pci_dev *pdev = adapter->pdev; | 437 | struct pci_dev *pdev = adapter->pdev; |
436 | 438 | ||
@@ -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,53 +1445,22 @@ 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 | pci_disable_device(pdev); | ||
1452 | |||
1453 | return 0; | ||
1454 | } | 1448 | } |
1455 | static void netxen_nic_shutdown(struct pci_dev *pdev) | ||
1456 | { | ||
1457 | if (__netxen_nic_shutdown(pdev)) | ||
1458 | return; | ||
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 | 1449 | ||
1470 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | 1450 | static int netxen_nic_attach_func(struct pci_dev *pdev) |
1471 | return 0; | ||
1472 | } | ||
1473 | |||
1474 | static int | ||
1475 | netxen_nic_resume(struct pci_dev *pdev) | ||
1476 | { | 1451 | { |
1477 | struct netxen_adapter *adapter = pci_get_drvdata(pdev); | 1452 | struct netxen_adapter *adapter = pci_get_drvdata(pdev); |
1478 | struct net_device *netdev = adapter->netdev; | 1453 | struct net_device *netdev = adapter->netdev; |
1479 | int err; | 1454 | int err; |
1480 | 1455 | ||
1481 | pci_set_power_state(pdev, PCI_D0); | ||
1482 | pci_restore_state(pdev); | ||
1483 | |||
1484 | err = pci_enable_device(pdev); | 1456 | err = pci_enable_device(pdev); |
1485 | if (err) | 1457 | if (err) |
1486 | return err; | 1458 | return err; |
1487 | 1459 | ||
1460 | pci_set_power_state(pdev, PCI_D0); | ||
1461 | pci_set_master(pdev); | ||
1462 | pci_restore_state(pdev); | ||
1463 | |||
1488 | adapter->ahw.crb_win = -1; | 1464 | adapter->ahw.crb_win = -1; |
1489 | adapter->ahw.ocm_win = -1; | 1465 | adapter->ahw.ocm_win = -1; |
1490 | 1466 | ||
@@ -1503,11 +1479,10 @@ netxen_nic_resume(struct pci_dev *pdev) | |||
1503 | if (err) | 1479 | if (err) |
1504 | goto err_out_detach; | 1480 | goto err_out_detach; |
1505 | 1481 | ||
1506 | netif_device_attach(netdev); | ||
1507 | |||
1508 | netxen_config_indev_addr(netdev, NETDEV_UP); | 1482 | netxen_config_indev_addr(netdev, NETDEV_UP); |
1509 | } | 1483 | } |
1510 | 1484 | ||
1485 | netif_device_attach(netdev); | ||
1511 | netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); | 1486 | netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); |
1512 | return 0; | 1487 | return 0; |
1513 | 1488 | ||
@@ -1517,6 +1492,85 @@ err_out: | |||
1517 | nx_decr_dev_ref_cnt(adapter); | 1492 | nx_decr_dev_ref_cnt(adapter); |
1518 | return err; | 1493 | return err; |
1519 | } | 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 | } | ||
1520 | #endif | 1574 | #endif |
1521 | 1575 | ||
1522 | static int netxen_nic_open(struct net_device *netdev) | 1576 | static int netxen_nic_open(struct net_device *netdev) |
@@ -2104,20 +2158,49 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter) | |||
2104 | return count; | 2158 | return count; |
2105 | } | 2159 | } |
2106 | 2160 | ||
2107 | static void | 2161 | static int |
2162 | nx_dev_request_aer(struct netxen_adapter *adapter) | ||
2163 | { | ||
2164 | u32 state; | ||
2165 | int ret = -EINVAL; | ||
2166 | |||
2167 | if (netxen_api_lock(adapter)) | ||
2168 | return ret; | ||
2169 | |||
2170 | state = NXRD32(adapter, NX_CRB_DEV_STATE); | ||
2171 | |||
2172 | if (state == NX_DEV_NEED_AER) | ||
2173 | ret = 0; | ||
2174 | else if (state == NX_DEV_READY) { | ||
2175 | NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_AER); | ||
2176 | ret = 0; | ||
2177 | } | ||
2178 | |||
2179 | netxen_api_unlock(adapter); | ||
2180 | return ret; | ||
2181 | } | ||
2182 | |||
2183 | static int | ||
2108 | nx_dev_request_reset(struct netxen_adapter *adapter) | 2184 | nx_dev_request_reset(struct netxen_adapter *adapter) |
2109 | { | 2185 | { |
2110 | u32 state; | 2186 | u32 state; |
2187 | int ret = -EINVAL; | ||
2111 | 2188 | ||
2112 | if (netxen_api_lock(adapter)) | 2189 | if (netxen_api_lock(adapter)) |
2113 | return; | 2190 | return ret; |
2114 | 2191 | ||
2115 | state = NXRD32(adapter, NX_CRB_DEV_STATE); | 2192 | state = NXRD32(adapter, NX_CRB_DEV_STATE); |
2116 | 2193 | ||
2117 | if (state != NX_DEV_INITALIZING) | 2194 | if (state == NX_DEV_NEED_RESET) |
2195 | ret = 0; | ||
2196 | else if (state != NX_DEV_INITALIZING && state != NX_DEV_NEED_AER) { | ||
2118 | NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET); | 2197 | NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET); |
2198 | ret = 0; | ||
2199 | } | ||
2119 | 2200 | ||
2120 | netxen_api_unlock(adapter); | 2201 | netxen_api_unlock(adapter); |
2202 | |||
2203 | return ret; | ||
2121 | } | 2204 | } |
2122 | 2205 | ||
2123 | static int | 2206 | static int |
@@ -2269,17 +2352,29 @@ netxen_check_health(struct netxen_adapter *adapter) | |||
2269 | u32 state, heartbit; | 2352 | u32 state, heartbit; |
2270 | struct net_device *netdev = adapter->netdev; | 2353 | struct net_device *netdev = adapter->netdev; |
2271 | 2354 | ||
2355 | state = NXRD32(adapter, NX_CRB_DEV_STATE); | ||
2356 | if (state == NX_DEV_NEED_AER) | ||
2357 | return 0; | ||
2358 | |||
2272 | if (netxen_nic_check_temp(adapter)) | 2359 | if (netxen_nic_check_temp(adapter)) |
2273 | goto detach; | 2360 | goto detach; |
2274 | 2361 | ||
2275 | if (adapter->need_fw_reset) { | 2362 | if (adapter->need_fw_reset) { |
2276 | nx_dev_request_reset(adapter); | 2363 | if (nx_dev_request_reset(adapter)) |
2364 | return 0; | ||
2277 | goto detach; | 2365 | goto detach; |
2278 | } | 2366 | } |
2279 | 2367 | ||
2280 | state = NXRD32(adapter, NX_CRB_DEV_STATE); | 2368 | /* NX_DEV_NEED_RESET, this state can be marked in two cases |
2281 | if (state == NX_DEV_NEED_RESET) | 2369 | * 1. Tx timeout 2. Fw hang |
2282 | goto detach; | 2370 | * Send request to destroy context in case of tx timeout only |
2371 | * and doesn't required in case of Fw hang | ||
2372 | */ | ||
2373 | if (state == NX_DEV_NEED_RESET) { | ||
2374 | adapter->need_fw_reset = 1; | ||
2375 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) | ||
2376 | goto detach; | ||
2377 | } | ||
2283 | 2378 | ||
2284 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) | 2379 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) |
2285 | return 0; | 2380 | return 0; |
@@ -2288,12 +2383,17 @@ netxen_check_health(struct netxen_adapter *adapter) | |||
2288 | if (heartbit != adapter->heartbit) { | 2383 | if (heartbit != adapter->heartbit) { |
2289 | adapter->heartbit = heartbit; | 2384 | adapter->heartbit = heartbit; |
2290 | adapter->fw_fail_cnt = 0; | 2385 | adapter->fw_fail_cnt = 0; |
2386 | if (adapter->need_fw_reset) | ||
2387 | goto detach; | ||
2291 | return 0; | 2388 | return 0; |
2292 | } | 2389 | } |
2293 | 2390 | ||
2294 | if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) | 2391 | if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) |
2295 | return 0; | 2392 | return 0; |
2296 | 2393 | ||
2394 | if (nx_dev_request_reset(adapter)) | ||
2395 | return 0; | ||
2396 | |||
2297 | clear_bit(__NX_FW_ATTACHED, &adapter->state); | 2397 | clear_bit(__NX_FW_ATTACHED, &adapter->state); |
2298 | 2398 | ||
2299 | dev_info(&netdev->dev, "firmware hang detected\n"); | 2399 | dev_info(&netdev->dev, "firmware hang detected\n"); |
@@ -2496,7 +2596,7 @@ netxen_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr, | |||
2496 | return size; | 2596 | return size; |
2497 | } | 2597 | } |
2498 | 2598 | ||
2499 | ssize_t netxen_sysfs_write_mem(struct kobject *kobj, | 2599 | static ssize_t netxen_sysfs_write_mem(struct kobject *kobj, |
2500 | struct bin_attribute *attr, char *buf, | 2600 | struct bin_attribute *attr, char *buf, |
2501 | loff_t offset, size_t size) | 2601 | loff_t offset, size_t size) |
2502 | { | 2602 | { |
@@ -2723,6 +2823,12 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event) | |||
2723 | { } | 2823 | { } |
2724 | #endif | 2824 | #endif |
2725 | 2825 | ||
2826 | static struct pci_error_handlers netxen_err_handler = { | ||
2827 | .error_detected = netxen_io_error_detected, | ||
2828 | .slot_reset = netxen_io_slot_reset, | ||
2829 | .resume = netxen_io_resume, | ||
2830 | }; | ||
2831 | |||
2726 | static struct pci_driver netxen_driver = { | 2832 | static struct pci_driver netxen_driver = { |
2727 | .name = netxen_nic_driver_name, | 2833 | .name = netxen_nic_driver_name, |
2728 | .id_table = netxen_pci_tbl, | 2834 | .id_table = netxen_pci_tbl, |
@@ -2732,7 +2838,8 @@ static struct pci_driver netxen_driver = { | |||
2732 | .suspend = netxen_nic_suspend, | 2838 | .suspend = netxen_nic_suspend, |
2733 | .resume = netxen_nic_resume, | 2839 | .resume = netxen_nic_resume, |
2734 | #endif | 2840 | #endif |
2735 | .shutdown = netxen_nic_shutdown | 2841 | .shutdown = netxen_nic_shutdown, |
2842 | .err_handler = &netxen_err_handler | ||
2736 | }; | 2843 | }; |
2737 | 2844 | ||
2738 | static int __init netxen_init_module(void) | 2845 | static int __init netxen_init_module(void) |