summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlpo Järvinen <ilpo.jarvinen@linux.intel.com>2024-08-08 15:17:07 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-10-04 16:33:05 +0200
commitfe5a1e8d80ad7778b39b3fa146e183f3671eeb94 (patch)
treec528e0c6512f382772157a4f0545ed49f007777f
parent7fd6aae7e53b94f4035b1bfce28b8dfa0d0ae470 (diff)
downloadlinux-stable-fe5a1e8d80ad7778b39b3fa146e183f3671eeb94.tar.gz
linux-stable-fe5a1e8d80ad7778b39b3fa146e183f3671eeb94.tar.bz2
linux-stable-fe5a1e8d80ad7778b39b3fa146e183f3671eeb94.zip
PCI: Wait for Link before restoring Downstream Buses
[ Upstream commit 3e40aa29d47e231a54640addf6a09c1f64c5b63f ] __pci_reset_bus() calls pci_bridge_secondary_bus_reset() to perform the reset and also waits for the Secondary Bus to become again accessible. __pci_reset_bus() then calls pci_bus_restore_locked() that restores the PCI devices connected to the bus, and if necessary, recursively restores also the subordinate buses and their devices. The logic in pci_bus_restore_locked() does not take into account that after restoring a device on one level, there might be another Link Downstream that can only start to come up after restore has been performed for its Downstream Port device. That is, the Link may require additional wait until it becomes accessible. Similarly, pci_slot_restore_locked() lacks wait. Amend pci_bus_restore_locked() and pci_slot_restore_locked() to wait for the Secondary Bus before recursively performing the restore of that bus. Fixes: 090a3c5322e9 ("PCI: Add pci_reset_slot() and pci_reset_bus()") Link: https://lore.kernel.org/r/20240808121708.2523-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--drivers/pci/pci.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8db214d4b1d4..c20ce49eecc9 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5598,8 +5598,10 @@ static void pci_bus_restore_locked(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
pci_dev_restore(dev);
- if (dev->subordinate)
+ if (dev->subordinate) {
+ pci_bridge_wait_for_secondary_bus(dev, "bus reset");
pci_bus_restore_locked(dev->subordinate);
+ }
}
}
@@ -5633,8 +5635,10 @@ static void pci_slot_restore_locked(struct pci_slot *slot)
if (!dev->slot || dev->slot != slot)
continue;
pci_dev_restore(dev);
- if (dev->subordinate)
+ if (dev->subordinate) {
+ pci_bridge_wait_for_secondary_bus(dev, "slot reset");
pci_bus_restore_locked(dev->subordinate);
+ }
}
}