diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2011-04-25 08:42:48 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-26 03:07:03 -0400 |
commit | b45aa2f6192e34a837ebdbb3548039c24440bc04 (patch) | |
tree | a6f9be41c6a91c612b0e63f123b799dfd512f311 /drivers/net/tg3.c | |
parent | bb158d696489244f79fd4c3abd47968a06b48c79 (diff) |
tg3: Add EEH support
This patch adds EEH support to the tg3 driver.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Reviewed-by: Michael Chan <mchan@broadcom.com>
Reviewed-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r-- | drivers/net/tg3.c | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index fb2139a80700..6bc43ed172b5 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -15395,6 +15395,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, | |||
15395 | pdev->dma_mask == DMA_BIT_MASK(32) ? 32 : | 15395 | pdev->dma_mask == DMA_BIT_MASK(32) ? 32 : |
15396 | ((u64)pdev->dma_mask) == DMA_BIT_MASK(40) ? 40 : 64); | 15396 | ((u64)pdev->dma_mask) == DMA_BIT_MASK(40) ? 40 : 64); |
15397 | 15397 | ||
15398 | pci_save_state(pdev); | ||
15399 | |||
15398 | return 0; | 15400 | return 0; |
15399 | 15401 | ||
15400 | err_out_apeunmap: | 15402 | err_out_apeunmap: |
@@ -15551,11 +15553,156 @@ static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume); | |||
15551 | 15553 | ||
15552 | #endif /* CONFIG_PM_SLEEP */ | 15554 | #endif /* CONFIG_PM_SLEEP */ |
15553 | 15555 | ||
15556 | /** | ||
15557 | * tg3_io_error_detected - called when PCI error is detected | ||
15558 | * @pdev: Pointer to PCI device | ||
15559 | * @state: The current pci connection state | ||
15560 | * | ||
15561 | * This function is called after a PCI bus error affecting | ||
15562 | * this device has been detected. | ||
15563 | */ | ||
15564 | static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, | ||
15565 | pci_channel_state_t state) | ||
15566 | { | ||
15567 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
15568 | struct tg3 *tp = netdev_priv(netdev); | ||
15569 | pci_ers_result_t err = PCI_ERS_RESULT_NEED_RESET; | ||
15570 | |||
15571 | netdev_info(netdev, "PCI I/O error detected\n"); | ||
15572 | |||
15573 | rtnl_lock(); | ||
15574 | |||
15575 | if (!netif_running(netdev)) | ||
15576 | goto done; | ||
15577 | |||
15578 | tg3_phy_stop(tp); | ||
15579 | |||
15580 | tg3_netif_stop(tp); | ||
15581 | |||
15582 | del_timer_sync(&tp->timer); | ||
15583 | tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; | ||
15584 | |||
15585 | /* Want to make sure that the reset task doesn't run */ | ||
15586 | cancel_work_sync(&tp->reset_task); | ||
15587 | tp->tg3_flags &= ~TG3_FLAG_TX_RECOVERY_PENDING; | ||
15588 | tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; | ||
15589 | |||
15590 | netif_device_detach(netdev); | ||
15591 | |||
15592 | /* Clean up software state, even if MMIO is blocked */ | ||
15593 | tg3_full_lock(tp, 0); | ||
15594 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); | ||
15595 | tg3_full_unlock(tp); | ||
15596 | |||
15597 | done: | ||
15598 | if (state == pci_channel_io_perm_failure) | ||
15599 | err = PCI_ERS_RESULT_DISCONNECT; | ||
15600 | else | ||
15601 | pci_disable_device(pdev); | ||
15602 | |||
15603 | rtnl_unlock(); | ||
15604 | |||
15605 | return err; | ||
15606 | } | ||
15607 | |||
15608 | /** | ||
15609 | * tg3_io_slot_reset - called after the pci bus has been reset. | ||
15610 | * @pdev: Pointer to PCI device | ||
15611 | * | ||
15612 | * Restart the card from scratch, as if from a cold-boot. | ||
15613 | * At this point, the card has exprienced a hard reset, | ||
15614 | * followed by fixups by BIOS, and has its config space | ||
15615 | * set up identically to what it was at cold boot. | ||
15616 | */ | ||
15617 | static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev) | ||
15618 | { | ||
15619 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
15620 | struct tg3 *tp = netdev_priv(netdev); | ||
15621 | pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; | ||
15622 | int err; | ||
15623 | |||
15624 | rtnl_lock(); | ||
15625 | |||
15626 | if (pci_enable_device(pdev)) { | ||
15627 | netdev_err(netdev, "Cannot re-enable PCI device after reset.\n"); | ||
15628 | goto done; | ||
15629 | } | ||
15630 | |||
15631 | pci_set_master(pdev); | ||
15632 | pci_restore_state(pdev); | ||
15633 | pci_save_state(pdev); | ||
15634 | |||
15635 | if (!netif_running(netdev)) { | ||
15636 | rc = PCI_ERS_RESULT_RECOVERED; | ||
15637 | goto done; | ||
15638 | } | ||
15639 | |||
15640 | err = tg3_power_up(tp); | ||
15641 | if (err) { | ||
15642 | netdev_err(netdev, "Failed to restore register access.\n"); | ||
15643 | goto done; | ||
15644 | } | ||
15645 | |||
15646 | rc = PCI_ERS_RESULT_RECOVERED; | ||
15647 | |||
15648 | done: | ||
15649 | rtnl_unlock(); | ||
15650 | |||
15651 | return rc; | ||
15652 | } | ||
15653 | |||
15654 | /** | ||
15655 | * tg3_io_resume - called when traffic can start flowing again. | ||
15656 | * @pdev: Pointer to PCI device | ||
15657 | * | ||
15658 | * This callback is called when the error recovery driver tells | ||
15659 | * us that its OK to resume normal operation. | ||
15660 | */ | ||
15661 | static void tg3_io_resume(struct pci_dev *pdev) | ||
15662 | { | ||
15663 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
15664 | struct tg3 *tp = netdev_priv(netdev); | ||
15665 | int err; | ||
15666 | |||
15667 | rtnl_lock(); | ||
15668 | |||
15669 | if (!netif_running(netdev)) | ||
15670 | goto done; | ||
15671 | |||
15672 | tg3_full_lock(tp, 0); | ||
15673 | tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; | ||
15674 | err = tg3_restart_hw(tp, 1); | ||
15675 | tg3_full_unlock(tp); | ||
15676 | if (err) { | ||
15677 | netdev_err(netdev, "Cannot restart hardware after reset.\n"); | ||
15678 | goto done; | ||
15679 | } | ||
15680 | |||
15681 | netif_device_attach(netdev); | ||
15682 | |||
15683 | tp->timer.expires = jiffies + tp->timer_offset; | ||
15684 | add_timer(&tp->timer); | ||
15685 | |||
15686 | tg3_netif_start(tp); | ||
15687 | |||
15688 | tg3_phy_start(tp); | ||
15689 | |||
15690 | done: | ||
15691 | rtnl_unlock(); | ||
15692 | } | ||
15693 | |||
15694 | static struct pci_error_handlers tg3_err_handler = { | ||
15695 | .error_detected = tg3_io_error_detected, | ||
15696 | .slot_reset = tg3_io_slot_reset, | ||
15697 | .resume = tg3_io_resume | ||
15698 | }; | ||
15699 | |||
15554 | static struct pci_driver tg3_driver = { | 15700 | static struct pci_driver tg3_driver = { |
15555 | .name = DRV_MODULE_NAME, | 15701 | .name = DRV_MODULE_NAME, |
15556 | .id_table = tg3_pci_tbl, | 15702 | .id_table = tg3_pci_tbl, |
15557 | .probe = tg3_init_one, | 15703 | .probe = tg3_init_one, |
15558 | .remove = __devexit_p(tg3_remove_one), | 15704 | .remove = __devexit_p(tg3_remove_one), |
15705 | .err_handler = &tg3_err_handler, | ||
15559 | .driver.pm = TG3_PM_OPS, | 15706 | .driver.pm = TG3_PM_OPS, |
15560 | }; | 15707 | }; |
15561 | 15708 | ||