Skip to content

Commit

Permalink
PCI/ERR: Use slot reset if available
Browse files Browse the repository at this point in the history
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 <[email protected]>
[bhelgaas: fold in
https://lore.kernel.org/linux-pci/[email protected]
for issue reported by Stephen Rothwell <[email protected]>]
Signed-off-by: Bjorn Helgaas <[email protected]>
Reviewed-by: Sinan Kaya <[email protected]>
  • Loading branch information
Keith Busch authored and bjorn-helgaas committed Sep 21, 2018
1 parent 9d938ea commit c4eed62
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 3 deletions.
37 changes: 37 additions & 0 deletions drivers/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
};
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion drivers/pci/pcie/aer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion drivers/pci/pcie/err.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 0 additions & 1 deletion drivers/pci/slot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit c4eed62

Please sign in to comment.