When the movable BARs feature is enabled and a rescan has been requested, release all bridge windows and recalculate them from scratch, taking into account all kinds of BARs: fixed, movable, new. Comparing to simply trying to expand bridge windows, this also employs the PCI ability to shuffle BARs within a bridge, increasing the chances to find a memory space to fit BARs of newly hot-added devices, especially if no (or not enough) gaps were reserved. The last step of writing the recalculated windows to the bridges is done by the new pci_setup_bridges() function. Signed-off-by: Sergei Miroshnichenko <s.miroshnichenko@xxxxxxxxx> --- drivers/pci/pci.h | 1 + drivers/pci/probe.c | 22 ++++++++++++++++++++++ drivers/pci/setup-bus.c | 9 +++++++++ 3 files changed, 32 insertions(+) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index c962d0375074..dc7f40b42fa7 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -267,6 +267,7 @@ void __pci_bus_assign_resources(const struct pci_bus *bus, struct list_head *realloc_head, struct list_head *fail_head); bool pci_bus_clip_resource(struct pci_dev *dev, int idx); +void pci_bus_release_root_bridge_resources(struct pci_bus *bus); void pci_reassigndev_resource_alignment(struct pci_dev *dev); void pci_disable_bridge_window(struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 17dd1fa4a05a..47d28761339b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -3283,6 +3283,25 @@ static void pci_bus_rescan_done(struct pci_bus *bus) } } +static void pci_setup_bridges(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + struct pci_bus *child; + + if (!pci_dev_is_added(dev)) + continue; + + child = dev->subordinate; + if (child) + pci_setup_bridges(child); + } + + if (bus->self) + pci_setup_bridge(bus); +} + /** * pci_rescan_bus - Scan a PCI bus for devices * @bus: PCI bus to scan @@ -3304,8 +3323,11 @@ unsigned int pci_rescan_bus(struct pci_bus *bus) pci_bus_rescan_prepare(root); max = pci_scan_child_bus(root); + + pci_bus_release_root_bridge_resources(root); pci_assign_unassigned_root_bus_resources(root); + pci_setup_bridges(root); pci_bus_rescan_done(root); } else { max = pci_scan_child_bus(bus); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index a956f0179064..9eb982196422 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1673,6 +1673,15 @@ static void pci_bus_release_bridge_resources(struct pci_bus *bus, pci_bridge_release_resources(bus, type); } +void pci_bus_release_root_bridge_resources(struct pci_bus *root_bus) +{ + pci_bus_release_bridge_resources(root_bus, IORESOURCE_IO, whole_subtree); + pci_bus_release_bridge_resources(root_bus, IORESOURCE_MEM, whole_subtree); + pci_bus_release_bridge_resources(root_bus, + IORESOURCE_MEM_64 | IORESOURCE_PREFETCH, + whole_subtree); +} + static void pci_bus_dump_res(struct pci_bus *bus) { struct resource *res; -- 2.24.1