Add pcibios_root_bus_rescan_prepare()/_done() hooks for the powerpc, so it can reassign the PE numbers (which depend on BAR sizes and locations) and update the EEH address cache during a PCI rescan. New PE numbers are assigned during pci_setup_bridges(root) after the rescan is done. CC: Oliver O'Halloran <oohall@xxxxxxxxx> CC: Sam Bobroff <sbobroff@xxxxxxxxxxxxx> Signed-off-by: Sergey Miroshnichenko <s.miroshnichenko@xxxxxxxxx> --- arch/powerpc/kernel/pci-hotplug.c | 43 +++++++++++++++++++++++++++++++ drivers/pci/probe.c | 10 +++++++ include/linux/pci.h | 3 +++ 3 files changed, 56 insertions(+) diff --git a/arch/powerpc/kernel/pci-hotplug.c b/arch/powerpc/kernel/pci-hotplug.c index fc62c4bc47b1..42847f5b0f08 100644 --- a/arch/powerpc/kernel/pci-hotplug.c +++ b/arch/powerpc/kernel/pci-hotplug.c @@ -16,6 +16,7 @@ #include <asm/ppc-pci.h> #include <asm/firmware.h> #include <asm/eeh.h> +#include <asm/iommu.h> static struct pci_bus *find_bus_among_children(struct pci_bus *bus, struct device_node *dn) @@ -151,3 +152,45 @@ void pci_hp_add_devices(struct pci_bus *bus) pcibios_finish_adding_to_bus(bus); } EXPORT_SYMBOL_GPL(pci_hp_add_devices); + +static void pci_hp_bus_rescan_prepare(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + struct pci_bus *child = dev->subordinate; + + if (child) + pci_hp_bus_rescan_prepare(child); + + iommu_del_device(&dev->dev); + } + + list_for_each_entry(dev, &bus->devices, bus_list) { + pcibios_release_device(dev); + } +} + +static void pci_hp_bus_rescan_done(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + struct pci_bus *child = dev->subordinate; + + pcibios_bus_add_device(dev); + + if (child) + pci_hp_bus_rescan_done(child); + } +} + +void pcibios_root_bus_rescan_prepare(struct pci_bus *root) +{ + pci_hp_bus_rescan_prepare(root); +} + +void pcibios_root_bus_rescan_done(struct pci_bus *root) +{ + pci_hp_bus_rescan_done(root); +} diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 73452aa81417..539f5d39bb6d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -3235,6 +3235,14 @@ static void pci_bus_rescan_done(struct pci_bus *bus) pci_config_pm_runtime_put(bus->self); } +void __weak pcibios_root_bus_rescan_prepare(struct pci_bus *root) +{ +} + +void __weak pcibios_root_bus_rescan_done(struct pci_bus *root) +{ +} + static void pci_setup_bridges(struct pci_bus *bus) { struct pci_dev *dev; @@ -3430,6 +3438,7 @@ unsigned int pci_rescan_bus(struct pci_bus *bus) root = root->parent; if (pci_can_move_bars) { + pcibios_root_bus_rescan_prepare(root); pci_bus_rescan_prepare(root); pci_bus_update_immovable_range(root); pci_bus_release_root_bridge_resources(root); @@ -3440,6 +3449,7 @@ unsigned int pci_rescan_bus(struct pci_bus *bus) pci_setup_bridges(root); pci_bus_rescan_done(root); + pcibios_root_bus_rescan_done(root); } else { max = pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); diff --git a/include/linux/pci.h b/include/linux/pci.h index e1edcb3fad31..b5821134bdae 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1275,6 +1275,9 @@ unsigned int pci_rescan_bus(struct pci_bus *bus); void pci_lock_rescan_remove(void); void pci_unlock_rescan_remove(void); +void pcibios_root_bus_rescan_prepare(struct pci_bus *root); +void pcibios_root_bus_rescan_done(struct pci_bus *root); + /* Vital Product Data routines */ ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf); ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); -- 2.23.0