diff options
author | Padmanabh Ratnakar <padmanabh.ratnakar@emulex.com> | 2011-11-25 00:48:23 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-11-26 14:52:29 -0500 |
commit | d8110f62c020ebc49108de57510a1482bfcbe86a (patch) | |
tree | 1aa4e4223ffd5bf0554c782f649576f3251a2a58 /drivers/net/ethernet/emulex | |
parent | 3bb62f4f95ba004048bafb460179b5db33aff787 (diff) |
be2net: Add error handling for Lancer
Detect error in Lancer by polling a HW register and
recover from this error if it is recoverable.
Signed-off-by: Padmanabh Ratnakar <padmanabh.ratnakar@emulex.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/emulex')
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 155 |
1 files changed, 106 insertions, 49 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index a1b8ebc6c5f2..66429ea60bb2 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c | |||
@@ -2044,52 +2044,6 @@ void be_detect_dump_ue(struct be_adapter *adapter) | |||
2044 | } | 2044 | } |
2045 | } | 2045 | } |
2046 | 2046 | ||
2047 | static void be_worker(struct work_struct *work) | ||
2048 | { | ||
2049 | struct be_adapter *adapter = | ||
2050 | container_of(work, struct be_adapter, work.work); | ||
2051 | struct be_rx_obj *rxo; | ||
2052 | int i; | ||
2053 | |||
2054 | be_detect_dump_ue(adapter); | ||
2055 | |||
2056 | /* when interrupts are not yet enabled, just reap any pending | ||
2057 | * mcc completions */ | ||
2058 | if (!netif_running(adapter->netdev)) { | ||
2059 | int mcc_compl, status = 0; | ||
2060 | |||
2061 | mcc_compl = be_process_mcc(adapter, &status); | ||
2062 | |||
2063 | if (mcc_compl) { | ||
2064 | struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; | ||
2065 | be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); | ||
2066 | } | ||
2067 | |||
2068 | goto reschedule; | ||
2069 | } | ||
2070 | |||
2071 | if (!adapter->stats_cmd_sent) { | ||
2072 | if (lancer_chip(adapter)) | ||
2073 | lancer_cmd_get_pport_stats(adapter, | ||
2074 | &adapter->stats_cmd); | ||
2075 | else | ||
2076 | be_cmd_get_stats(adapter, &adapter->stats_cmd); | ||
2077 | } | ||
2078 | |||
2079 | for_all_rx_queues(adapter, rxo, i) { | ||
2080 | be_rx_eqd_update(adapter, rxo); | ||
2081 | |||
2082 | if (rxo->rx_post_starved) { | ||
2083 | rxo->rx_post_starved = false; | ||
2084 | be_post_rx_frags(rxo, GFP_KERNEL); | ||
2085 | } | ||
2086 | } | ||
2087 | |||
2088 | reschedule: | ||
2089 | adapter->work_counter++; | ||
2090 | schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); | ||
2091 | } | ||
2092 | |||
2093 | static void be_msix_disable(struct be_adapter *adapter) | 2047 | static void be_msix_disable(struct be_adapter *adapter) |
2094 | { | 2048 | { |
2095 | if (msix_enabled(adapter)) { | 2049 | if (msix_enabled(adapter)) { |
@@ -3328,7 +3282,7 @@ static int be_dev_family_check(struct be_adapter *adapter) | |||
3328 | 3282 | ||
3329 | static int lancer_wait_ready(struct be_adapter *adapter) | 3283 | static int lancer_wait_ready(struct be_adapter *adapter) |
3330 | { | 3284 | { |
3331 | #define SLIPORT_READY_TIMEOUT 500 | 3285 | #define SLIPORT_READY_TIMEOUT 30 |
3332 | u32 sliport_status; | 3286 | u32 sliport_status; |
3333 | int status = 0, i; | 3287 | int status = 0, i; |
3334 | 3288 | ||
@@ -3337,7 +3291,7 @@ static int lancer_wait_ready(struct be_adapter *adapter) | |||
3337 | if (sliport_status & SLIPORT_STATUS_RDY_MASK) | 3291 | if (sliport_status & SLIPORT_STATUS_RDY_MASK) |
3338 | break; | 3292 | break; |
3339 | 3293 | ||
3340 | msleep(20); | 3294 | msleep(1000); |
3341 | } | 3295 | } |
3342 | 3296 | ||
3343 | if (i == SLIPORT_READY_TIMEOUT) | 3297 | if (i == SLIPORT_READY_TIMEOUT) |
@@ -3374,6 +3328,104 @@ static int lancer_test_and_set_rdy_state(struct be_adapter *adapter) | |||
3374 | return status; | 3328 | return status; |
3375 | } | 3329 | } |
3376 | 3330 | ||
3331 | static void lancer_test_and_recover_fn_err(struct be_adapter *adapter) | ||
3332 | { | ||
3333 | int status; | ||
3334 | u32 sliport_status; | ||
3335 | |||
3336 | if (adapter->eeh_err || adapter->ue_detected) | ||
3337 | return; | ||
3338 | |||
3339 | sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); | ||
3340 | |||
3341 | if (sliport_status & SLIPORT_STATUS_ERR_MASK) { | ||
3342 | dev_err(&adapter->pdev->dev, | ||
3343 | "Adapter in error state." | ||
3344 | "Trying to recover.\n"); | ||
3345 | |||
3346 | status = lancer_test_and_set_rdy_state(adapter); | ||
3347 | if (status) | ||
3348 | goto err; | ||
3349 | |||
3350 | netif_device_detach(adapter->netdev); | ||
3351 | |||
3352 | if (netif_running(adapter->netdev)) | ||
3353 | be_close(adapter->netdev); | ||
3354 | |||
3355 | be_clear(adapter); | ||
3356 | |||
3357 | adapter->fw_timeout = false; | ||
3358 | |||
3359 | status = be_setup(adapter); | ||
3360 | if (status) | ||
3361 | goto err; | ||
3362 | |||
3363 | if (netif_running(adapter->netdev)) { | ||
3364 | status = be_open(adapter->netdev); | ||
3365 | if (status) | ||
3366 | goto err; | ||
3367 | } | ||
3368 | |||
3369 | netif_device_attach(adapter->netdev); | ||
3370 | |||
3371 | dev_err(&adapter->pdev->dev, | ||
3372 | "Adapter error recovery succeeded\n"); | ||
3373 | } | ||
3374 | return; | ||
3375 | err: | ||
3376 | dev_err(&adapter->pdev->dev, | ||
3377 | "Adapter error recovery failed\n"); | ||
3378 | } | ||
3379 | |||
3380 | static void be_worker(struct work_struct *work) | ||
3381 | { | ||
3382 | struct be_adapter *adapter = | ||
3383 | container_of(work, struct be_adapter, work.work); | ||
3384 | struct be_rx_obj *rxo; | ||
3385 | int i; | ||
3386 | |||
3387 | if (lancer_chip(adapter)) | ||
3388 | lancer_test_and_recover_fn_err(adapter); | ||
3389 | |||
3390 | be_detect_dump_ue(adapter); | ||
3391 | |||
3392 | /* when interrupts are not yet enabled, just reap any pending | ||
3393 | * mcc completions */ | ||
3394 | if (!netif_running(adapter->netdev)) { | ||
3395 | int mcc_compl, status = 0; | ||
3396 | |||
3397 | mcc_compl = be_process_mcc(adapter, &status); | ||
3398 | |||
3399 | if (mcc_compl) { | ||
3400 | struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; | ||
3401 | be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); | ||
3402 | } | ||
3403 | |||
3404 | goto reschedule; | ||
3405 | } | ||
3406 | |||
3407 | if (!adapter->stats_cmd_sent) { | ||
3408 | if (lancer_chip(adapter)) | ||
3409 | lancer_cmd_get_pport_stats(adapter, | ||
3410 | &adapter->stats_cmd); | ||
3411 | else | ||
3412 | be_cmd_get_stats(adapter, &adapter->stats_cmd); | ||
3413 | } | ||
3414 | |||
3415 | for_all_rx_queues(adapter, rxo, i) { | ||
3416 | be_rx_eqd_update(adapter, rxo); | ||
3417 | |||
3418 | if (rxo->rx_post_starved) { | ||
3419 | rxo->rx_post_starved = false; | ||
3420 | be_post_rx_frags(rxo, GFP_KERNEL); | ||
3421 | } | ||
3422 | } | ||
3423 | |||
3424 | reschedule: | ||
3425 | adapter->work_counter++; | ||
3426 | schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); | ||
3427 | } | ||
3428 | |||
3377 | static int __devinit be_probe(struct pci_dev *pdev, | 3429 | static int __devinit be_probe(struct pci_dev *pdev, |
3378 | const struct pci_device_id *pdev_id) | 3430 | const struct pci_device_id *pdev_id) |
3379 | { | 3431 | { |
@@ -3426,7 +3478,12 @@ static int __devinit be_probe(struct pci_dev *pdev, | |||
3426 | goto disable_sriov; | 3478 | goto disable_sriov; |
3427 | 3479 | ||
3428 | if (lancer_chip(adapter)) { | 3480 | if (lancer_chip(adapter)) { |
3429 | status = lancer_test_and_set_rdy_state(adapter); | 3481 | status = lancer_wait_ready(adapter); |
3482 | if (!status) { | ||
3483 | iowrite32(SLI_PORT_CONTROL_IP_MASK, | ||
3484 | adapter->db + SLIPORT_CONTROL_OFFSET); | ||
3485 | status = lancer_test_and_set_rdy_state(adapter); | ||
3486 | } | ||
3430 | if (status) { | 3487 | if (status) { |
3431 | dev_err(&pdev->dev, "Adapter in non recoverable error\n"); | 3488 | dev_err(&pdev->dev, "Adapter in non recoverable error\n"); |
3432 | goto ctrl_clean; | 3489 | goto ctrl_clean; |