aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/qlcnic
diff options
context:
space:
mode:
authorSucheta Chakraborty <sucheta.chakraborty@qlogic.com>2010-07-13 16:33:34 -0400
committerDavid S. Miller <davem@davemloft.net>2010-07-14 16:54:17 -0400
commit451724c821c1fe5af076a0def72362f947e1b6a0 (patch)
tree403ad8080b3cb6b5912c88dac63cdf8e1c3fcf9b /drivers/net/qlcnic
parent0cf3a14cb2b888a7efa055ff7354e97c59fd48fa (diff)
qlcnic: aer support
Pci error recovery support added. Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlcnic')
-rw-r--r--drivers/net/qlcnic/qlcnic.h1
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c137
2 files changed, 137 insertions, 1 deletions
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 02a50e60166d..064464201cbb 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -911,6 +911,7 @@ struct qlcnic_mac_req {
911#define __QLCNIC_DEV_UP 1 911#define __QLCNIC_DEV_UP 1
912#define __QLCNIC_RESETTING 2 912#define __QLCNIC_RESETTING 2
913#define __QLCNIC_START_FW 4 913#define __QLCNIC_START_FW 4
914#define __QLCNIC_AER 5
914 915
915#define QLCNIC_INTERRUPT_TEST 1 916#define QLCNIC_INTERRUPT_TEST 1
916#define QLCNIC_LOOPBACK_TEST 2 917#define QLCNIC_LOOPBACK_TEST 2
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 0995f90b0bac..d5c94a3364f7 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -34,6 +34,7 @@
34#include <linux/ipv6.h> 34#include <linux/ipv6.h>
35#include <linux/inetdevice.h> 35#include <linux/inetdevice.h>
36#include <linux/sysfs.h> 36#include <linux/sysfs.h>
37#include <linux/aer.h>
37 38
38MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver"); 39MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
39MODULE_LICENSE("GPL"); 40MODULE_LICENSE("GPL");
@@ -1306,6 +1307,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1306 goto err_out_disable_pdev; 1307 goto err_out_disable_pdev;
1307 1308
1308 pci_set_master(pdev); 1309 pci_set_master(pdev);
1310 pci_enable_pcie_error_reporting(pdev);
1309 1311
1310 netdev = alloc_etherdev(sizeof(struct qlcnic_adapter)); 1312 netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
1311 if (!netdev) { 1313 if (!netdev) {
@@ -1437,6 +1439,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
1437 1439
1438 qlcnic_release_firmware(adapter); 1440 qlcnic_release_firmware(adapter);
1439 1441
1442 pci_disable_pcie_error_reporting(pdev);
1440 pci_release_regions(pdev); 1443 pci_release_regions(pdev);
1441 pci_disable_device(pdev); 1444 pci_disable_device(pdev);
1442 pci_set_drvdata(pdev, NULL); 1445 pci_set_drvdata(pdev, NULL);
@@ -2521,6 +2524,9 @@ static void
2521qlcnic_schedule_work(struct qlcnic_adapter *adapter, 2524qlcnic_schedule_work(struct qlcnic_adapter *adapter,
2522 work_func_t func, int delay) 2525 work_func_t func, int delay)
2523{ 2526{
2527 if (test_bit(__QLCNIC_AER, &adapter->state))
2528 return;
2529
2524 INIT_DELAYED_WORK(&adapter->fw_work, func); 2530 INIT_DELAYED_WORK(&adapter->fw_work, func);
2525 schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay)); 2531 schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
2526} 2532}
@@ -2631,6 +2637,128 @@ reschedule:
2631 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); 2637 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
2632} 2638}
2633 2639
2640static int qlcnic_is_first_func(struct pci_dev *pdev)
2641{
2642 struct pci_dev *oth_pdev;
2643 int val = pdev->devfn;
2644
2645 while (val-- > 0) {
2646 oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr
2647 (pdev->bus), pdev->bus->number,
2648 PCI_DEVFN(PCI_SLOT(pdev->devfn), val));
2649
2650 if (oth_pdev && (oth_pdev->current_state != PCI_D3cold))
2651 return 0;
2652 }
2653 return 1;
2654}
2655
2656static int qlcnic_attach_func(struct pci_dev *pdev)
2657{
2658 int err, first_func;
2659 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
2660 struct net_device *netdev = adapter->netdev;
2661
2662 pdev->error_state = pci_channel_io_normal;
2663
2664 err = pci_enable_device(pdev);
2665 if (err)
2666 return err;
2667
2668 pci_set_power_state(pdev, PCI_D0);
2669 pci_set_master(pdev);
2670 pci_restore_state(pdev);
2671
2672 first_func = qlcnic_is_first_func(pdev);
2673
2674 if (qlcnic_api_lock(adapter))
2675 return -EINVAL;
2676
2677 if (first_func) {
2678 adapter->need_fw_reset = 1;
2679 set_bit(__QLCNIC_START_FW, &adapter->state);
2680 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
2681 QLCDB(adapter, DRV, "Restarting fw\n");
2682 }
2683 qlcnic_api_unlock(adapter);
2684
2685 err = adapter->nic_ops->start_firmware(adapter);
2686 if (err)
2687 return err;
2688
2689 qlcnic_clr_drv_state(adapter);
2690 qlcnic_setup_intr(adapter);
2691
2692 if (netif_running(netdev)) {
2693 err = qlcnic_attach(adapter);
2694 if (err) {
2695 qlcnic_clr_all_drv_state(adapter);
2696 clear_bit(__QLCNIC_AER, &adapter->state);
2697 netif_device_attach(netdev);
2698 return err;
2699 }
2700
2701 err = qlcnic_up(adapter, netdev);
2702 if (err)
2703 goto done;
2704
2705 qlcnic_config_indev_addr(netdev, NETDEV_UP);
2706 }
2707 done:
2708 netif_device_attach(netdev);
2709 return err;
2710}
2711
2712static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
2713 pci_channel_state_t state)
2714{
2715 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
2716 struct net_device *netdev = adapter->netdev;
2717
2718 if (state == pci_channel_io_perm_failure)
2719 return PCI_ERS_RESULT_DISCONNECT;
2720
2721 if (state == pci_channel_io_normal)
2722 return PCI_ERS_RESULT_RECOVERED;
2723
2724 set_bit(__QLCNIC_AER, &adapter->state);
2725 netif_device_detach(netdev);
2726
2727 cancel_delayed_work_sync(&adapter->fw_work);
2728
2729 if (netif_running(netdev))
2730 qlcnic_down(adapter, netdev);
2731
2732 qlcnic_detach(adapter);
2733 qlcnic_teardown_intr(adapter);
2734
2735 clear_bit(__QLCNIC_RESETTING, &adapter->state);
2736
2737 pci_save_state(pdev);
2738 pci_disable_device(pdev);
2739
2740 return PCI_ERS_RESULT_NEED_RESET;
2741}
2742
2743static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
2744{
2745 return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT :
2746 PCI_ERS_RESULT_RECOVERED;
2747}
2748
2749static void qlcnic_io_resume(struct pci_dev *pdev)
2750{
2751 struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
2752
2753 pci_cleanup_aer_uncorrect_error_status(pdev);
2754
2755 if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
2756 test_and_clear_bit(__QLCNIC_AER, &adapter->state))
2757 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
2758 FW_POLL_DELAY);
2759}
2760
2761
2634static int 2762static int
2635qlcnicvf_start_firmware(struct qlcnic_adapter *adapter) 2763qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
2636{ 2764{
@@ -3436,6 +3564,11 @@ static void
3436qlcnic_config_indev_addr(struct net_device *dev, unsigned long event) 3564qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
3437{ } 3565{ }
3438#endif 3566#endif
3567static struct pci_error_handlers qlcnic_err_handler = {
3568 .error_detected = qlcnic_io_error_detected,
3569 .slot_reset = qlcnic_io_slot_reset,
3570 .resume = qlcnic_io_resume,
3571};
3439 3572
3440static struct pci_driver qlcnic_driver = { 3573static struct pci_driver qlcnic_driver = {
3441 .name = qlcnic_driver_name, 3574 .name = qlcnic_driver_name,
@@ -3446,7 +3579,9 @@ static struct pci_driver qlcnic_driver = {
3446 .suspend = qlcnic_suspend, 3579 .suspend = qlcnic_suspend,
3447 .resume = qlcnic_resume, 3580 .resume = qlcnic_resume,
3448#endif 3581#endif
3449 .shutdown = qlcnic_shutdown 3582 .shutdown = qlcnic_shutdown,
3583 .err_handler = &qlcnic_err_handler
3584
3450}; 3585};
3451 3586
3452static int __init qlcnic_init_module(void) 3587static int __init qlcnic_init_module(void)