net/cxgb4: Avoid disabling PCI device for towice
authorGavin Shan <shangw@linux.vnet.ibm.com>
Thu, 23 Jan 2014 04:27:34 +0000 (12:27 +0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 23 Jan 2014 21:21:03 +0000 (13:21 -0800)
If we have EEH error happens to the adapter and we have to remove
it from the system for some reasons (e.g. more than 5 EEH errors
detected from the device in last hour), the adapter will be disabled
for towice separately by eeh_err_detected() and remove_one(), which
will incur following unexpected backtrace. The patch tries to avoid
it.

WARNING: at drivers/pci/pci.c:1431
CPU: 12 PID: 121 Comm: eehd Not tainted 3.13.0-rc7+ #1
task: c0000001823a3780 ti: c00000018240c000 task.ti: c00000018240c000
NIP: c0000000003c1e40 LR: c0000000003c1e3c CTR: 0000000001764c5c
REGS: c00000018240f470 TRAP: 0700   Not tainted  (3.13.0-rc7+)
MSR: 8000000000029032 <SF,EE,ME,IR,DR,RI>  CR: 28000024  XER: 00000004
CFAR: c000000000706528 SOFTE: 1
GPR00: c0000000003c1e3c c00000018240f6f0 c0000000010fe1f8 0000000000000035
GPR04: 0000000000000000 0000000000000000 00000000003ae509 0000000000000000
GPR08: 000000000000346f 0000000000000000 0000000000000000 0000000000003fef
GPR12: 0000000028000022 c00000000ec93000 c0000000000c11b0 c000000184ac3e40
GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
GPR24: 0000000000000000 c0000000009398d8 c00000000101f9c0 c0000001860ae000
GPR28: c000000182ba0000 00000000000001f0 c0000001860ae6f8 c0000001860ae000
NIP [c0000000003c1e40] .pci_disable_device+0xd0/0xf0
LR [c0000000003c1e3c] .pci_disable_device+0xcc/0xf0
Call Trace:
[c0000000003c1e3c] .pci_disable_device+0xcc/0xf0 (unreliable)
[d0000000073881c4] .remove_one+0x174/0x320 [cxgb4]
[c0000000003c57e0] .pci_device_remove+0x60/0x100
[c00000000046396c] .__device_release_driver+0x9c/0x120
[c000000000463a20] .device_release_driver+0x30/0x60
[c0000000003bcdb4] .pci_stop_bus_device+0x94/0xd0
[c0000000003bcf48] .pci_stop_and_remove_bus_device+0x18/0x30
[c00000000003f548] .pcibios_remove_pci_devices+0xa8/0x140
[c000000000035c00] .eeh_handle_normal_event+0xa0/0x3c0
[c000000000035f50] .eeh_handle_event+0x30/0x2b0
[c0000000000362c4] .eeh_event_handler+0xf4/0x1b0
[c0000000000c12b8] .kthread+0x108/0x130
[c00000000000a168] .ret_from_kernel_thread+0x5c/0x74

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c

index 16782b2cff495fcc508e5d3b96530f1a3386940c..1f4b9b30b9ed0bbaa969014e4bf6c1162d439d98 100644 (file)
@@ -387,8 +387,9 @@ struct work_struct;
 
 enum {                                 /* adapter flags */
        FULL_INIT_DONE     = (1 << 0),
-       USING_MSI          = (1 << 1),
-       USING_MSIX         = (1 << 2),
+       DEV_ENABLED        = (1 << 1),
+       USING_MSI          = (1 << 2),
+       USING_MSIX         = (1 << 3),
        FW_OK              = (1 << 4),
        RSS_TNLALLLOOKUP   = (1 << 5),
        USING_SOFT_PARAMS  = (1 << 6),
index fff02ed1295e5ef7bab408cbe19c46dbd5eedd52..c8eafbf1f51d26c56659f940987f05078f8acb5d 100644 (file)
@@ -5505,7 +5505,10 @@ static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev,
        if (adap->flags & FULL_INIT_DONE)
                cxgb_down(adap);
        rtnl_unlock();
-       pci_disable_device(pdev);
+       if ((adap->flags & DEV_ENABLED)) {
+               pci_disable_device(pdev);
+               adap->flags &= ~DEV_ENABLED;
+       }
 out:   return state == pci_channel_io_perm_failure ?
                PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
 }
@@ -5522,9 +5525,13 @@ static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
                return PCI_ERS_RESULT_RECOVERED;
        }
 
-       if (pci_enable_device(pdev)) {
-               dev_err(&pdev->dev, "cannot reenable PCI device after reset\n");
-               return PCI_ERS_RESULT_DISCONNECT;
+       if (!(adap->flags & DEV_ENABLED)) {
+               if (pci_enable_device(pdev)) {
+                       dev_err(&pdev->dev, "Cannot reenable PCI "
+                                           "device after reset\n");
+                       return PCI_ERS_RESULT_DISCONNECT;
+               }
+               adap->flags |= DEV_ENABLED;
        }
 
        pci_set_master(pdev);
@@ -5910,6 +5917,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto out_disable_device;
        }
 
+       /* PCI device has been enabled */
+       adapter->flags |= DEV_ENABLED;
+
        adapter->regs = pci_ioremap_bar(pdev, 0);
        if (!adapter->regs) {
                dev_err(&pdev->dev, "cannot map device registers\n");
@@ -6145,7 +6155,10 @@ static void remove_one(struct pci_dev *pdev)
                        iounmap(adapter->bar2);
                kfree(adapter);
                pci_disable_pcie_error_reporting(pdev);
-               pci_disable_device(pdev);
+               if ((adapter->flags & DEV_ENABLED)) {
+                       pci_disable_device(pdev);
+                       adapter->flags &= ~DEV_ENABLED;
+               }
                pci_release_regions(pdev);
        } else
                pci_release_regions(pdev);