PCI/ERR: Use slot reset if available
authorKeith Busch <keith.busch@intel.com>
Thu, 20 Sep 2018 16:27:11 +0000 (10:27 -0600)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 21 Sep 2018 17:18:10 +0000 (12:18 -0500)
The secondary bus reset may have link side effects that a hotplug capable
port may incorrectly react to.  Use the slot specific reset for hotplug
ports, fixing the undesirable link down-up handling during error
recovering.

Signed-off-by: Keith Busch <keith.busch@intel.com>
[bhelgaas: fold in
https://lore.kernel.org/linux-pci/20180926152326.14821-1-keith.busch@intel.com
for issue reported by Stephen Rothwell <sfr@canb.auug.org.au>]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Sinan Kaya <okaya@kernel.org>
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer.c
drivers/pci/pcie/err.c
drivers/pci/slot.c

index d6bb56fbee6dfa4ff12cb6329aafc5daff242cdc..6916af269b19739cbc6b4aafc28d16d2c3dd01c4 100644 (file)
@@ -35,6 +35,8 @@
 #include <linux/aer.h>
 #include "pci.h"
 
+DEFINE_MUTEX(pci_slot_mutex);
+
 const char *pci_power_names[] = {
        "error", "D0", "D1", "D2", "D3hot", "D3cold", "unknown",
 };
@@ -5155,6 +5157,41 @@ static int pci_bus_reset(struct pci_bus *bus, int probe)
        return ret;
 }
 
+/**
+ * pci_bus_error_reset - reset the bridge's subordinate bus
+ * @bridge: The parent device that connects to the bus to reset
+ *
+ * This function will first try to reset the slots on this bus if the method is
+ * available. If slot reset fails or is not available, this will fall back to a
+ * secondary bus reset.
+ */
+int pci_bus_error_reset(struct pci_dev *bridge)
+{
+       struct pci_bus *bus = bridge->subordinate;
+       struct pci_slot *slot;
+
+       if (!bus)
+               return -ENOTTY;
+
+       mutex_lock(&pci_slot_mutex);
+       if (list_empty(&bus->slots))
+               goto bus_reset;
+
+       list_for_each_entry(slot, &bus->slots, list)
+               if (pci_probe_reset_slot(slot))
+                       goto bus_reset;
+
+       list_for_each_entry(slot, &bus->slots, list)
+               if (pci_slot_reset(slot, 0))
+                       goto bus_reset;
+
+       mutex_unlock(&pci_slot_mutex);
+       return 0;
+bus_reset:
+       mutex_unlock(&pci_slot_mutex);
+       return pci_bus_reset(bridge->subordinate, 0);
+}
+
 /**
  * pci_probe_reset_bus - probe whether a PCI bus can be reset
  * @bus: PCI bus to probe
index b5af5642c6c9d139f5ae728b5a3645632ce94d0b..b4ada8c383a83d6e3be5226779137f395e3606c7 100644 (file)
@@ -35,6 +35,7 @@ int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vmai,
 
 int pci_probe_reset_function(struct pci_dev *dev);
 int pci_bridge_secondary_bus_reset(struct pci_dev *dev);
+int pci_bus_error_reset(struct pci_dev *dev);
 
 /**
  * struct pci_platform_pm_ops - Firmware PM callbacks
@@ -136,6 +137,7 @@ static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; }
 
 /* Lock for read/write access to pci device and bus lists */
 extern struct rw_semaphore pci_bus_sem;
+extern struct mutex pci_slot_mutex;
 
 extern raw_spinlock_t pci_lock;
 
index 5c3ea7254c6aee26c701f82f4e9b8642531ff450..1563e22600ecab220306d7d616b093b9ef9b7355 100644 (file)
@@ -1528,7 +1528,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
        reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 
-       rc = pci_bridge_secondary_bus_reset(dev);
+       rc = pci_bus_error_reset(dev);
        pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n");
 
        /* Clear Root Error Status */
index cac406b6e9360b8d2d6899975a08e94dbdf488f8..62ab665f0f037af70f9e021058d2c72937b3ddb6 100644 (file)
@@ -177,7 +177,7 @@ static pci_ers_result_t default_reset_link(struct pci_dev *dev)
 {
        int rc;
 
-       rc = pci_bridge_secondary_bus_reset(dev);
+       rc = pci_bus_error_reset(dev);
        pci_printk(KERN_DEBUG, dev, "downstream link has been reset\n");
        return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
 }
index 145cd953b51835e2a8749db588e556163765e1e2..c46d5e1ff53692ebeafaee1d4e745d4743a4c78a 100644 (file)
@@ -14,7 +14,6 @@
 
 struct kset *pci_slots_kset;
 EXPORT_SYMBOL_GPL(pci_slots_kset);
-static DEFINE_MUTEX(pci_slot_mutex);
 
 static ssize_t pci_slot_attr_show(struct kobject *kobj,
                                        struct attribute *attr, char *buf)