diff options
| -rw-r--r-- | drivers/pci/pci-sysfs.c | 3 | ||||
| -rw-r--r-- | drivers/pci/pci.c | 91 | ||||
| -rw-r--r-- | drivers/pci/pci.h | 2 |
3 files changed, 62 insertions, 34 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index aaf92195da32..a2f8a5d6190f 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -553,7 +553,6 @@ static ssize_t reset_subordinate_store(struct device *dev, const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); - struct pci_bus *bus = pdev->subordinate; unsigned long val; if (!capable(CAP_SYS_ADMIN)) @@ -563,7 +562,7 @@ static ssize_t reset_subordinate_store(struct device *dev, return -EINVAL; if (val) { - int ret = pci_try_reset_bus(bus); + int ret = pci_try_reset_bridge(pdev); if (ret) return ret; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4fd61d6cacff..5984ad9ef6c4 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5597,14 +5597,44 @@ static int pci_bus_reset(struct pci_bus *bus, bool probe) } /** - * pci_bus_error_reset - reset the bridge's subordinate bus - * @bridge: The parent device that connects to the bus to reset + * pci_try_reset_bus - Try to reset a PCI bus + * @bus: top level PCI bus to reset + * + * Same as above except return -EAGAIN if the bus cannot be locked + */ +static int pci_try_reset_bus(struct pci_bus *bus) +{ + int rc; + + rc = pci_bus_reset(bus, PCI_RESET_PROBE); + if (rc) + return rc; + + if (pci_bus_trylock(bus)) { + pci_bus_save_and_disable_locked(bus); + might_sleep(); + rc = pci_bridge_secondary_bus_reset(bus->self); + pci_bus_restore_locked(bus); + pci_bus_unlock(bus); + } else + rc = -EAGAIN; + + return rc; +} + +#define PCI_RESET_RESTORE true +#define PCI_RESET_NO_RESTORE false +/** + * pci_reset_bridge - reset a bridge's subordinate bus + * @bridge: bridge that connects to the bus to reset + * @restore: when true use a reset method that invokes pci_dev_restore() post + * reset for affected devices * * 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) +static int pci_reset_bridge(struct pci_dev *bridge, bool restore) { struct pci_bus *bus = bridge->subordinate; struct pci_slot *slot; @@ -5620,18 +5650,43 @@ int pci_bus_error_reset(struct pci_dev *bridge) if (pci_probe_reset_slot(slot)) goto bus_reset; - list_for_each_entry(slot, &bus->slots, list) - if (pci_slot_reset(slot, PCI_RESET_DO_RESET)) + list_for_each_entry(slot, &bus->slots, list) { + int ret; + + if (restore) + ret = pci_try_reset_slot(slot); + else + ret = pci_slot_reset(slot, PCI_RESET_DO_RESET); + + if (ret) goto bus_reset; + } mutex_unlock(&pci_slot_mutex); return 0; bus_reset: mutex_unlock(&pci_slot_mutex); + + if (restore) + return pci_try_reset_bus(bus); return pci_bus_reset(bridge->subordinate, PCI_RESET_DO_RESET); } /** + * pci_bus_error_reset - reset the bridge's subordinate bus + * @bridge: The parent device that connects to the bus to reset + */ +int pci_bus_error_reset(struct pci_dev *bridge) +{ + return pci_reset_bridge(bridge, PCI_RESET_NO_RESTORE); +} + +int pci_try_reset_bridge(struct pci_dev *bridge) +{ + return pci_reset_bridge(bridge, PCI_RESET_RESTORE); +} + +/** * pci_probe_reset_bus - probe whether a PCI bus can be reset * @bus: PCI bus to probe * @@ -5644,32 +5699,6 @@ int pci_probe_reset_bus(struct pci_bus *bus) EXPORT_SYMBOL_GPL(pci_probe_reset_bus); /** - * pci_try_reset_bus - Try to reset a PCI bus - * @bus: top level PCI bus to reset - * - * Same as above except return -EAGAIN if the bus cannot be locked - */ -int pci_try_reset_bus(struct pci_bus *bus) -{ - int rc; - - rc = pci_bus_reset(bus, PCI_RESET_PROBE); - if (rc) - return rc; - - if (pci_bus_trylock(bus)) { - pci_bus_save_and_disable_locked(bus); - might_sleep(); - rc = pci_bridge_secondary_bus_reset(bus->self); - pci_bus_restore_locked(bus); - pci_bus_unlock(bus); - } else - rc = -EAGAIN; - - return rc; -} - -/** * pci_reset_bus - Try to reset a PCI bus * @pdev: top level PCI device to reset via slot/bus * diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index e319417da5ca..a1d2ecb56207 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -231,7 +231,7 @@ bool pci_reset_supported(struct pci_dev *dev); void pci_init_reset_methods(struct pci_dev *dev); int pci_bridge_secondary_bus_reset(struct pci_dev *dev); int pci_bus_error_reset(struct pci_dev *dev); -int pci_try_reset_bus(struct pci_bus *bus); +int pci_try_reset_bridge(struct pci_dev *bridge); struct pci_cap_saved_data { u16 cap_nr; |
