diff options
author | Sathya Perla <sathyap@serverengines.com> | 2010-02-14 16:22:01 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-16 00:49:51 -0500 |
commit | cf588477a3fbf085426e5c0b6205984ebb7e2187 (patch) | |
tree | 3c5cf63269e443fa5c0518581526017774fa5888 /drivers/net/benet | |
parent | 0dca3a843632c2fbb6e358734fb08fc23e800f50 (diff) |
be2net: implement EEH pci error recovery handlers
The code has been tested on IBM pSeries server.
Signed-off-by: Sathya Perla <sathyap@serverengines.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/benet')
-rw-r--r-- | drivers/net/benet/be.h | 1 | ||||
-rw-r--r-- | drivers/net/benet/be_cmds.c | 23 | ||||
-rw-r--r-- | drivers/net/benet/be_main.c | 103 |
3 files changed, 125 insertions, 2 deletions
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index b39b38542623..5038c16bfe9b 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h | |||
@@ -265,6 +265,7 @@ struct be_adapter { | |||
265 | u32 if_handle; /* Used to configure filtering */ | 265 | u32 if_handle; /* Used to configure filtering */ |
266 | u32 pmac_id; /* MAC addr handle used by BE card */ | 266 | u32 pmac_id; /* MAC addr handle used by BE card */ |
267 | 267 | ||
268 | bool eeh_err; | ||
268 | bool link_up; | 269 | bool link_up; |
269 | u32 port_num; | 270 | u32 port_num; |
270 | bool promiscuous; | 271 | bool promiscuous; |
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index d1a0e5ede4b3..3397ee327e1f 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c | |||
@@ -167,7 +167,14 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) | |||
167 | u32 ready; | 167 | u32 ready; |
168 | 168 | ||
169 | do { | 169 | do { |
170 | ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK; | 170 | ready = ioread32(db); |
171 | if (ready == 0xffffffff) { | ||
172 | dev_err(&adapter->pdev->dev, | ||
173 | "pci slot disconnected\n"); | ||
174 | return -1; | ||
175 | } | ||
176 | |||
177 | ready &= MPU_MAILBOX_DB_RDY_MASK; | ||
171 | if (ready) | 178 | if (ready) |
172 | break; | 179 | break; |
173 | 180 | ||
@@ -198,6 +205,11 @@ static int be_mbox_notify_wait(struct be_adapter *adapter) | |||
198 | struct be_mcc_mailbox *mbox = mbox_mem->va; | 205 | struct be_mcc_mailbox *mbox = mbox_mem->va; |
199 | struct be_mcc_compl *compl = &mbox->compl; | 206 | struct be_mcc_compl *compl = &mbox->compl; |
200 | 207 | ||
208 | /* wait for ready to be set */ | ||
209 | status = be_mbox_db_ready_wait(adapter, db); | ||
210 | if (status != 0) | ||
211 | return status; | ||
212 | |||
201 | val |= MPU_MAILBOX_DB_HI_MASK; | 213 | val |= MPU_MAILBOX_DB_HI_MASK; |
202 | /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ | 214 | /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ |
203 | val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; | 215 | val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; |
@@ -396,6 +408,9 @@ int be_cmd_fw_clean(struct be_adapter *adapter) | |||
396 | u8 *wrb; | 408 | u8 *wrb; |
397 | int status; | 409 | int status; |
398 | 410 | ||
411 | if (adapter->eeh_err) | ||
412 | return -EIO; | ||
413 | |||
399 | spin_lock(&adapter->mbox_lock); | 414 | spin_lock(&adapter->mbox_lock); |
400 | 415 | ||
401 | wrb = (u8 *)wrb_from_mbox(adapter); | 416 | wrb = (u8 *)wrb_from_mbox(adapter); |
@@ -768,6 +783,9 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, | |||
768 | u8 subsys = 0, opcode = 0; | 783 | u8 subsys = 0, opcode = 0; |
769 | int status; | 784 | int status; |
770 | 785 | ||
786 | if (adapter->eeh_err) | ||
787 | return -EIO; | ||
788 | |||
771 | spin_lock(&adapter->mbox_lock); | 789 | spin_lock(&adapter->mbox_lock); |
772 | 790 | ||
773 | wrb = wrb_from_mbox(adapter); | 791 | wrb = wrb_from_mbox(adapter); |
@@ -856,6 +874,9 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) | |||
856 | struct be_cmd_req_if_destroy *req; | 874 | struct be_cmd_req_if_destroy *req; |
857 | int status; | 875 | int status; |
858 | 876 | ||
877 | if (adapter->eeh_err) | ||
878 | return -EIO; | ||
879 | |||
859 | spin_lock(&adapter->mbox_lock); | 880 | spin_lock(&adapter->mbox_lock); |
860 | 881 | ||
861 | wrb = wrb_from_mbox(adapter); | 882 | wrb = wrb_from_mbox(adapter); |
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 92c55f679466..cbfaa3feb7c4 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c | |||
@@ -68,6 +68,9 @@ static void be_intr_set(struct be_adapter *adapter, bool enable) | |||
68 | u32 reg = ioread32(addr); | 68 | u32 reg = ioread32(addr); |
69 | u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; | 69 | u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; |
70 | 70 | ||
71 | if (adapter->eeh_err) | ||
72 | return; | ||
73 | |||
71 | if (!enabled && enable) | 74 | if (!enabled && enable) |
72 | reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; | 75 | reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; |
73 | else if (enabled && !enable) | 76 | else if (enabled && !enable) |
@@ -99,6 +102,10 @@ static void be_eq_notify(struct be_adapter *adapter, u16 qid, | |||
99 | { | 102 | { |
100 | u32 val = 0; | 103 | u32 val = 0; |
101 | val |= qid & DB_EQ_RING_ID_MASK; | 104 | val |= qid & DB_EQ_RING_ID_MASK; |
105 | |||
106 | if (adapter->eeh_err) | ||
107 | return; | ||
108 | |||
102 | if (arm) | 109 | if (arm) |
103 | val |= 1 << DB_EQ_REARM_SHIFT; | 110 | val |= 1 << DB_EQ_REARM_SHIFT; |
104 | if (clear_int) | 111 | if (clear_int) |
@@ -112,6 +119,10 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped) | |||
112 | { | 119 | { |
113 | u32 val = 0; | 120 | u32 val = 0; |
114 | val |= qid & DB_CQ_RING_ID_MASK; | 121 | val |= qid & DB_CQ_RING_ID_MASK; |
122 | |||
123 | if (adapter->eeh_err) | ||
124 | return; | ||
125 | |||
115 | if (arm) | 126 | if (arm) |
116 | val |= 1 << DB_CQ_REARM_SHIFT; | 127 | val |= 1 << DB_CQ_REARM_SHIFT; |
117 | val |= num_popped << DB_CQ_NUM_POPPED_SHIFT; | 128 | val |= num_popped << DB_CQ_NUM_POPPED_SHIFT; |
@@ -2154,6 +2165,7 @@ static int be_ctrl_init(struct be_adapter *adapter) | |||
2154 | spin_lock_init(&adapter->mcc_lock); | 2165 | spin_lock_init(&adapter->mcc_lock); |
2155 | spin_lock_init(&adapter->mcc_cq_lock); | 2166 | spin_lock_init(&adapter->mcc_cq_lock); |
2156 | 2167 | ||
2168 | pci_save_state(adapter->pdev); | ||
2157 | return 0; | 2169 | return 0; |
2158 | 2170 | ||
2159 | free_mbox: | 2171 | free_mbox: |
@@ -2417,13 +2429,102 @@ static int be_resume(struct pci_dev *pdev) | |||
2417 | return 0; | 2429 | return 0; |
2418 | } | 2430 | } |
2419 | 2431 | ||
2432 | static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev, | ||
2433 | pci_channel_state_t state) | ||
2434 | { | ||
2435 | struct be_adapter *adapter = pci_get_drvdata(pdev); | ||
2436 | struct net_device *netdev = adapter->netdev; | ||
2437 | |||
2438 | dev_err(&adapter->pdev->dev, "EEH error detected\n"); | ||
2439 | |||
2440 | adapter->eeh_err = true; | ||
2441 | |||
2442 | netif_device_detach(netdev); | ||
2443 | |||
2444 | if (netif_running(netdev)) { | ||
2445 | rtnl_lock(); | ||
2446 | be_close(netdev); | ||
2447 | rtnl_unlock(); | ||
2448 | } | ||
2449 | be_clear(adapter); | ||
2450 | |||
2451 | if (state == pci_channel_io_perm_failure) | ||
2452 | return PCI_ERS_RESULT_DISCONNECT; | ||
2453 | |||
2454 | pci_disable_device(pdev); | ||
2455 | |||
2456 | return PCI_ERS_RESULT_NEED_RESET; | ||
2457 | } | ||
2458 | |||
2459 | static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) | ||
2460 | { | ||
2461 | struct be_adapter *adapter = pci_get_drvdata(pdev); | ||
2462 | int status; | ||
2463 | |||
2464 | dev_info(&adapter->pdev->dev, "EEH reset\n"); | ||
2465 | adapter->eeh_err = false; | ||
2466 | |||
2467 | status = pci_enable_device(pdev); | ||
2468 | if (status) | ||
2469 | return PCI_ERS_RESULT_DISCONNECT; | ||
2470 | |||
2471 | pci_set_master(pdev); | ||
2472 | pci_set_power_state(pdev, 0); | ||
2473 | pci_restore_state(pdev); | ||
2474 | |||
2475 | /* Check if card is ok and fw is ready */ | ||
2476 | status = be_cmd_POST(adapter); | ||
2477 | if (status) | ||
2478 | return PCI_ERS_RESULT_DISCONNECT; | ||
2479 | |||
2480 | return PCI_ERS_RESULT_RECOVERED; | ||
2481 | } | ||
2482 | |||
2483 | static void be_eeh_resume(struct pci_dev *pdev) | ||
2484 | { | ||
2485 | int status = 0; | ||
2486 | struct be_adapter *adapter = pci_get_drvdata(pdev); | ||
2487 | struct net_device *netdev = adapter->netdev; | ||
2488 | |||
2489 | dev_info(&adapter->pdev->dev, "EEH resume\n"); | ||
2490 | |||
2491 | pci_save_state(pdev); | ||
2492 | |||
2493 | /* tell fw we're ready to fire cmds */ | ||
2494 | status = be_cmd_fw_init(adapter); | ||
2495 | if (status) | ||
2496 | goto err; | ||
2497 | |||
2498 | status = be_setup(adapter); | ||
2499 | if (status) | ||
2500 | goto err; | ||
2501 | |||
2502 | if (netif_running(netdev)) { | ||
2503 | status = be_open(netdev); | ||
2504 | if (status) | ||
2505 | goto err; | ||
2506 | } | ||
2507 | netif_device_attach(netdev); | ||
2508 | return; | ||
2509 | err: | ||
2510 | dev_err(&adapter->pdev->dev, "EEH resume failed\n"); | ||
2511 | return; | ||
2512 | } | ||
2513 | |||
2514 | static struct pci_error_handlers be_eeh_handlers = { | ||
2515 | .error_detected = be_eeh_err_detected, | ||
2516 | .slot_reset = be_eeh_reset, | ||
2517 | .resume = be_eeh_resume, | ||
2518 | }; | ||
2519 | |||
2420 | static struct pci_driver be_driver = { | 2520 | static struct pci_driver be_driver = { |
2421 | .name = DRV_NAME, | 2521 | .name = DRV_NAME, |
2422 | .id_table = be_dev_ids, | 2522 | .id_table = be_dev_ids, |
2423 | .probe = be_probe, | 2523 | .probe = be_probe, |
2424 | .remove = be_remove, | 2524 | .remove = be_remove, |
2425 | .suspend = be_suspend, | 2525 | .suspend = be_suspend, |
2426 | .resume = be_resume | 2526 | .resume = be_resume, |
2527 | .err_handler = &be_eeh_handlers | ||
2427 | }; | 2528 | }; |
2428 | 2529 | ||
2429 | static int __init be_init_module(void) | 2530 | static int __init be_init_module(void) |