Skip to content

Commit 451724c

Browse files
Sucheta Chakrabortydavem330
authored andcommitted
qlcnic: aer support
Pci error recovery support added. Signed-off-by: Sucheta Chakraborty <[email protected]> Signed-off-by: Amit Kumar Salecha <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0cf3a14 commit 451724c

File tree

2 files changed

+137
-1
lines changed

2 files changed

+137
-1
lines changed

drivers/net/qlcnic/qlcnic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ struct qlcnic_mac_req {
911911
#define __QLCNIC_DEV_UP 1
912912
#define __QLCNIC_RESETTING 2
913913
#define __QLCNIC_START_FW 4
914+
#define __QLCNIC_AER 5
914915

915916
#define QLCNIC_INTERRUPT_TEST 1
916917
#define QLCNIC_LOOPBACK_TEST 2

drivers/net/qlcnic/qlcnic_main.c

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <linux/ipv6.h>
3535
#include <linux/inetdevice.h>
3636
#include <linux/sysfs.h>
37+
#include <linux/aer.h>
3738

3839
MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
3940
MODULE_LICENSE("GPL");
@@ -1306,6 +1307,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
13061307
goto err_out_disable_pdev;
13071308

13081309
pci_set_master(pdev);
1310+
pci_enable_pcie_error_reporting(pdev);
13091311

13101312
netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
13111313
if (!netdev) {
@@ -1437,6 +1439,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
14371439

14381440
qlcnic_release_firmware(adapter);
14391441

1442+
pci_disable_pcie_error_reporting(pdev);
14401443
pci_release_regions(pdev);
14411444
pci_disable_device(pdev);
14421445
pci_set_drvdata(pdev, NULL);
@@ -2521,6 +2524,9 @@ static void
25212524
qlcnic_schedule_work(struct qlcnic_adapter *adapter,
25222525
work_func_t func, int delay)
25232526
{
2527+
if (test_bit(__QLCNIC_AER, &adapter->state))
2528+
return;
2529+
25242530
INIT_DELAYED_WORK(&adapter->fw_work, func);
25252531
schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
25262532
}
@@ -2631,6 +2637,128 @@ qlcnic_fw_poll_work(struct work_struct *work)
26312637
qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
26322638
}
26332639

2640+
static 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+
2656+
static 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+
2712+
static 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+
2743+
static 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+
2749+
static 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+
26342762
static int
26352763
qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
26362764
{
@@ -3436,6 +3564,11 @@ static void
34363564
qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
34373565
{ }
34383566
#endif
3567+
static 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+
};
34393572

34403573
static struct pci_driver qlcnic_driver = {
34413574
.name = qlcnic_driver_name,
@@ -3446,7 +3579,9 @@ static struct pci_driver qlcnic_driver = {
34463579
.suspend = qlcnic_suspend,
34473580
.resume = qlcnic_resume,
34483581
#endif
3449-
.shutdown = qlcnic_shutdown
3582+
.shutdown = qlcnic_shutdown,
3583+
.err_handler = &qlcnic_err_handler
3584+
34503585
};
34513586

34523587
static int __init qlcnic_init_module(void)

0 commit comments

Comments
 (0)