}
/**
- * 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;
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
}
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