diff options
| author | 2018-09-20 10:27:11 -0600 | |
|---|---|---|
| committer | 2018-09-21 12:18:10 -0500 | |
| commit | c4eed62a214330908eec11b0dc170d34fa50b412 (patch) | |
| tree | 8c8f5bfc802300f7aab110888fd25bce0d1bbae2 | |
| parent | PCI/AER: Don't read upstream ports below fatal errors (diff) | |
| download | wireguard-linux-c4eed62a214330908eec11b0dc170d34fa50b412.tar.xz wireguard-linux-c4eed62a214330908eec11b0dc170d34fa50b412.zip  | |
PCI/ERR: Use slot reset if available
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>
| -rw-r--r-- | drivers/pci/pci.c | 37 | ||||
| -rw-r--r-- | drivers/pci/pci.h | 2 | ||||
| -rw-r--r-- | drivers/pci/pcie/aer.c | 2 | ||||
| -rw-r--r-- | drivers/pci/pcie/err.c | 2 | ||||
| -rw-r--r-- | drivers/pci/slot.c | 1 | 
5 files changed, 41 insertions, 3 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d6bb56fbee6d..6916af269b19 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -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",  }; @@ -5156,6 +5158,41 @@ static int pci_bus_reset(struct pci_bus *bus, int probe)  }  /** + * 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   * diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b5af5642c6c9..b4ada8c383a8 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -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; diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 5c3ea7254c6a..1563e22600ec 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -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 */ diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index cac406b6e936..62ab665f0f03 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -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;  } diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 145cd953b518..c46d5e1ff536 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -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)  | 
