]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PCI: Wait for Link before restoring Downstream Buses
authorIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Thu, 8 Aug 2024 12:17:07 +0000 (15:17 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 4 Oct 2024 14:29:28 +0000 (16:29 +0200)
[ 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>
drivers/pci/pci.c

index 53e9e9788bd54d6c92edaf2f9fa277e37e92a973..da52f98d8f7f3297b3d7ca1f1b72b091d5fb6194 100644 (file)
@@ -5875,8 +5875,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);
+               }
        }
 }
 
@@ -5910,8 +5912,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);
+               }
        }
 }