diff options
author | Divy Le Ray <divy@chelsio.com> | 2008-10-08 20:36:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-10-08 20:36:03 -0400 |
commit | 20d3fc11505a2706a33b4c9a932af036d836727f (patch) | |
tree | 8c72b6673ac62166225d30a409b09c2354f5286b /drivers/net/cxgb3/cxgb3_main.c | |
parent | 45cec1bac0719c904bb5f4405c2937f7e715888c (diff) |
cxgb3: reset the adapter on fatal error
when a fatal error occurs, bring ports down, reset the chip,
and bring ports back up.
Factorize code used for both EEH and fatal error recovery.
Fix timer usage when bringing up/resetting sge queue sets.
Signed-off-by: Divy Le Ray <divy@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/cxgb3/cxgb3_main.c')
-rw-r--r-- | drivers/net/cxgb3/cxgb3_main.c | 164 |
1 files changed, 111 insertions, 53 deletions
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index d355c826b9b..0e51d49842f 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c | |||
@@ -892,6 +892,13 @@ static int cxgb_up(struct adapter *adap) | |||
892 | goto out; | 892 | goto out; |
893 | } | 893 | } |
894 | 894 | ||
895 | /* | ||
896 | * Clear interrupts now to catch errors if t3_init_hw fails. | ||
897 | * We clear them again later as initialization may trigger | ||
898 | * conditions that can interrupt. | ||
899 | */ | ||
900 | t3_intr_clear(adap); | ||
901 | |||
895 | err = t3_init_hw(adap, 0); | 902 | err = t3_init_hw(adap, 0); |
896 | if (err) | 903 | if (err) |
897 | goto out; | 904 | goto out; |
@@ -1101,9 +1108,9 @@ static int cxgb_close(struct net_device *dev) | |||
1101 | netif_carrier_off(dev); | 1108 | netif_carrier_off(dev); |
1102 | t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); | 1109 | t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); |
1103 | 1110 | ||
1104 | spin_lock(&adapter->work_lock); /* sync with update task */ | 1111 | spin_lock_irq(&adapter->work_lock); /* sync with update task */ |
1105 | clear_bit(pi->port_id, &adapter->open_device_map); | 1112 | clear_bit(pi->port_id, &adapter->open_device_map); |
1106 | spin_unlock(&adapter->work_lock); | 1113 | spin_unlock_irq(&adapter->work_lock); |
1107 | 1114 | ||
1108 | if (!(adapter->open_device_map & PORT_MASK)) | 1115 | if (!(adapter->open_device_map & PORT_MASK)) |
1109 | cancel_rearming_delayed_workqueue(cxgb3_wq, | 1116 | cancel_rearming_delayed_workqueue(cxgb3_wq, |
@@ -2356,10 +2363,10 @@ static void t3_adap_check_task(struct work_struct *work) | |||
2356 | check_t3b2_mac(adapter); | 2363 | check_t3b2_mac(adapter); |
2357 | 2364 | ||
2358 | /* Schedule the next check update if any port is active. */ | 2365 | /* Schedule the next check update if any port is active. */ |
2359 | spin_lock(&adapter->work_lock); | 2366 | spin_lock_irq(&adapter->work_lock); |
2360 | if (adapter->open_device_map & PORT_MASK) | 2367 | if (adapter->open_device_map & PORT_MASK) |
2361 | schedule_chk_task(adapter); | 2368 | schedule_chk_task(adapter); |
2362 | spin_unlock(&adapter->work_lock); | 2369 | spin_unlock_irq(&adapter->work_lock); |
2363 | } | 2370 | } |
2364 | 2371 | ||
2365 | /* | 2372 | /* |
@@ -2404,6 +2411,96 @@ void t3_os_ext_intr_handler(struct adapter *adapter) | |||
2404 | spin_unlock(&adapter->work_lock); | 2411 | spin_unlock(&adapter->work_lock); |
2405 | } | 2412 | } |
2406 | 2413 | ||
2414 | static int t3_adapter_error(struct adapter *adapter, int reset) | ||
2415 | { | ||
2416 | int i, ret = 0; | ||
2417 | |||
2418 | /* Stop all ports */ | ||
2419 | for_each_port(adapter, i) { | ||
2420 | struct net_device *netdev = adapter->port[i]; | ||
2421 | |||
2422 | if (netif_running(netdev)) | ||
2423 | cxgb_close(netdev); | ||
2424 | } | ||
2425 | |||
2426 | if (is_offload(adapter) && | ||
2427 | test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) | ||
2428 | offload_close(&adapter->tdev); | ||
2429 | |||
2430 | /* Stop SGE timers */ | ||
2431 | t3_stop_sge_timers(adapter); | ||
2432 | |||
2433 | adapter->flags &= ~FULL_INIT_DONE; | ||
2434 | |||
2435 | if (reset) | ||
2436 | ret = t3_reset_adapter(adapter); | ||
2437 | |||
2438 | pci_disable_device(adapter->pdev); | ||
2439 | |||
2440 | return ret; | ||
2441 | } | ||
2442 | |||
2443 | static int t3_reenable_adapter(struct adapter *adapter) | ||
2444 | { | ||
2445 | if (pci_enable_device(adapter->pdev)) { | ||
2446 | dev_err(&adapter->pdev->dev, | ||
2447 | "Cannot re-enable PCI device after reset.\n"); | ||
2448 | goto err; | ||
2449 | } | ||
2450 | pci_set_master(adapter->pdev); | ||
2451 | pci_restore_state(adapter->pdev); | ||
2452 | |||
2453 | /* Free sge resources */ | ||
2454 | t3_free_sge_resources(adapter); | ||
2455 | |||
2456 | if (t3_replay_prep_adapter(adapter)) | ||
2457 | goto err; | ||
2458 | |||
2459 | return 0; | ||
2460 | err: | ||
2461 | return -1; | ||
2462 | } | ||
2463 | |||
2464 | static void t3_resume_ports(struct adapter *adapter) | ||
2465 | { | ||
2466 | int i; | ||
2467 | |||
2468 | /* Restart the ports */ | ||
2469 | for_each_port(adapter, i) { | ||
2470 | struct net_device *netdev = adapter->port[i]; | ||
2471 | |||
2472 | if (netif_running(netdev)) { | ||
2473 | if (cxgb_open(netdev)) { | ||
2474 | dev_err(&adapter->pdev->dev, | ||
2475 | "can't bring device back up" | ||
2476 | " after reset\n"); | ||
2477 | continue; | ||
2478 | } | ||
2479 | } | ||
2480 | } | ||
2481 | } | ||
2482 | |||
2483 | /* | ||
2484 | * processes a fatal error. | ||
2485 | * Bring the ports down, reset the chip, bring the ports back up. | ||
2486 | */ | ||
2487 | static void fatal_error_task(struct work_struct *work) | ||
2488 | { | ||
2489 | struct adapter *adapter = container_of(work, struct adapter, | ||
2490 | fatal_error_handler_task); | ||
2491 | int err = 0; | ||
2492 | |||
2493 | rtnl_lock(); | ||
2494 | err = t3_adapter_error(adapter, 1); | ||
2495 | if (!err) | ||
2496 | err = t3_reenable_adapter(adapter); | ||
2497 | if (!err) | ||
2498 | t3_resume_ports(adapter); | ||
2499 | |||
2500 | CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded"); | ||
2501 | rtnl_unlock(); | ||
2502 | } | ||
2503 | |||
2407 | void t3_fatal_err(struct adapter *adapter) | 2504 | void t3_fatal_err(struct adapter *adapter) |
2408 | { | 2505 | { |
2409 | unsigned int fw_status[4]; | 2506 | unsigned int fw_status[4]; |
@@ -2414,7 +2511,11 @@ void t3_fatal_err(struct adapter *adapter) | |||
2414 | t3_write_reg(adapter, A_XGM_RX_CTRL, 0); | 2511 | t3_write_reg(adapter, A_XGM_RX_CTRL, 0); |
2415 | t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0); | 2512 | t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0); |
2416 | t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0); | 2513 | t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0); |
2514 | |||
2515 | spin_lock(&adapter->work_lock); | ||
2417 | t3_intr_disable(adapter); | 2516 | t3_intr_disable(adapter); |
2517 | queue_work(cxgb3_wq, &adapter->fatal_error_handler_task); | ||
2518 | spin_unlock(&adapter->work_lock); | ||
2418 | } | 2519 | } |
2419 | CH_ALERT(adapter, "encountered fatal error, operation suspended\n"); | 2520 | CH_ALERT(adapter, "encountered fatal error, operation suspended\n"); |
2420 | if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status)) | 2521 | if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status)) |
@@ -2436,26 +2537,9 @@ static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev, | |||
2436 | pci_channel_state_t state) | 2537 | pci_channel_state_t state) |
2437 | { | 2538 | { |
2438 | struct adapter *adapter = pci_get_drvdata(pdev); | 2539 | struct adapter *adapter = pci_get_drvdata(pdev); |
2439 | int i; | 2540 | int ret; |
2440 | |||
2441 | /* Stop all ports */ | ||
2442 | for_each_port(adapter, i) { | ||
2443 | struct net_device *netdev = adapter->port[i]; | ||
2444 | |||
2445 | if (netif_running(netdev)) | ||
2446 | cxgb_close(netdev); | ||
2447 | } | ||
2448 | |||
2449 | if (is_offload(adapter) && | ||
2450 | test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) | ||
2451 | offload_close(&adapter->tdev); | ||
2452 | |||
2453 | /* Stop SGE timers */ | ||
2454 | t3_stop_sge_timers(adapter); | ||
2455 | |||
2456 | adapter->flags &= ~FULL_INIT_DONE; | ||
2457 | 2541 | ||
2458 | pci_disable_device(pdev); | 2542 | ret = t3_adapter_error(adapter, 0); |
2459 | 2543 | ||
2460 | /* Request a slot reset. */ | 2544 | /* Request a slot reset. */ |
2461 | return PCI_ERS_RESULT_NEED_RESET; | 2545 | return PCI_ERS_RESULT_NEED_RESET; |
@@ -2471,22 +2555,9 @@ static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev) | |||
2471 | { | 2555 | { |
2472 | struct adapter *adapter = pci_get_drvdata(pdev); | 2556 | struct adapter *adapter = pci_get_drvdata(pdev); |
2473 | 2557 | ||
2474 | if (pci_enable_device(pdev)) { | 2558 | if (!t3_reenable_adapter(adapter)) |
2475 | dev_err(&pdev->dev, | 2559 | return PCI_ERS_RESULT_RECOVERED; |
2476 | "Cannot re-enable PCI device after reset.\n"); | ||
2477 | goto err; | ||
2478 | } | ||
2479 | pci_set_master(pdev); | ||
2480 | pci_restore_state(pdev); | ||
2481 | |||
2482 | /* Free sge resources */ | ||
2483 | t3_free_sge_resources(adapter); | ||
2484 | |||
2485 | if (t3_replay_prep_adapter(adapter)) | ||
2486 | goto err; | ||
2487 | 2560 | ||
2488 | return PCI_ERS_RESULT_RECOVERED; | ||
2489 | err: | ||
2490 | return PCI_ERS_RESULT_DISCONNECT; | 2561 | return PCI_ERS_RESULT_DISCONNECT; |
2491 | } | 2562 | } |
2492 | 2563 | ||
@@ -2500,22 +2571,8 @@ err: | |||
2500 | static void t3_io_resume(struct pci_dev *pdev) | 2571 | static void t3_io_resume(struct pci_dev *pdev) |
2501 | { | 2572 | { |
2502 | struct adapter *adapter = pci_get_drvdata(pdev); | 2573 | struct adapter *adapter = pci_get_drvdata(pdev); |
2503 | int i; | ||
2504 | |||
2505 | /* Restart the ports */ | ||
2506 | for_each_port(adapter, i) { | ||
2507 | struct net_device *netdev = adapter->port[i]; | ||
2508 | 2574 | ||
2509 | if (netif_running(netdev)) { | 2575 | t3_resume_ports(adapter); |
2510 | if (cxgb_open(netdev)) { | ||
2511 | dev_err(&pdev->dev, | ||
2512 | "can't bring device back up" | ||
2513 | " after reset\n"); | ||
2514 | continue; | ||
2515 | } | ||
2516 | netif_device_attach(netdev); | ||
2517 | } | ||
2518 | } | ||
2519 | } | 2576 | } |
2520 | 2577 | ||
2521 | static struct pci_error_handlers t3_err_handler = { | 2578 | static struct pci_error_handlers t3_err_handler = { |
@@ -2664,6 +2721,7 @@ static int __devinit init_one(struct pci_dev *pdev, | |||
2664 | 2721 | ||
2665 | INIT_LIST_HEAD(&adapter->adapter_list); | 2722 | INIT_LIST_HEAD(&adapter->adapter_list); |
2666 | INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); | 2723 | INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); |
2724 | INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task); | ||
2667 | INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); | 2725 | INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); |
2668 | 2726 | ||
2669 | for (i = 0; i < ai->nports; ++i) { | 2727 | for (i = 0; i < ai->nports; ++i) { |