Add support for "preserve-boot-config" property that can be used to selectively (i.e. per host bridge) instruct the kernel to preserve the boot time configuration done by the platform firmware. Reported-by: kernel test robot <lkp@xxxxxxxxx> Signed-off-by: Vidya Sagar <vidyas@xxxxxxxxxx> --- V2: * Addressed issues reported by kernel test robot <lkp@xxxxxxxxx> drivers/pci/controller/pci-host-common.c | 5 ++++- drivers/pci/of.c | 18 ++++++++++++++++++ drivers/pci/probe.c | 2 +- include/linux/of_pci.h | 6 ++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c index 6be3266cd7b5..d3475dc9ec44 100644 --- a/drivers/pci/controller/pci-host-common.c +++ b/drivers/pci/controller/pci-host-common.c @@ -68,13 +68,16 @@ int pci_host_common_probe(struct platform_device *pdev) of_pci_check_probe_only(); + bridge->preserve_config = + of_pci_check_preserve_boot_config(dev->of_node); + /* Parse and map our Configuration Space windows */ cfg = gen_pci_init(dev, bridge, ops); if (IS_ERR(cfg)) return PTR_ERR(cfg); /* Do not reassign resources if probe only */ - if (!pci_has_flag(PCI_PROBE_ONLY)) + if (!(pci_has_flag(PCI_PROBE_ONLY) || bridge->preserve_config)) pci_add_flags(PCI_REASSIGN_ALL_BUS); bridge->sysdata = cfg; diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 51e3dd0ea5ab..ed3c0dd9804e 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -258,6 +258,24 @@ void of_pci_check_probe_only(void) } EXPORT_SYMBOL_GPL(of_pci_check_probe_only); +/** + * of_pci_check_preserve_boot_config - Return true if the boot configuration + * needs to be preserved + * @node: Device tree node with the domain information. + * + * This function looks for a property called "preserve-boot-config" for a given + * PCIe controller's node and returns true if found. Having this property + * for a PCIe controller ensures that the kernel doesn't re-enumerate and + * reconfigure the BAR resources that are already done by the platform firmware. + * + * Return: true if the property exists false otherwise. + */ +bool of_pci_check_preserve_boot_config(struct device_node *node) +{ + return of_property_read_bool(node, "preserve-boot-config"); +} +EXPORT_SYMBOL_GPL(of_pci_check_preserve_boot_config); + /** * devm_of_pci_get_host_bridge_resources() - Resource-managed parsing of PCI * host bridge resources from DT diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 795534589b98..79d0ac34f567 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -3085,7 +3085,7 @@ int pci_host_probe(struct pci_host_bridge *bridge) * ioport_resource trees in either pci_bus_claim_resources() * or pci_bus_assign_resources(). */ - if (pci_has_flag(PCI_PROBE_ONLY)) { + if (pci_has_flag(PCI_PROBE_ONLY) || bridge->preserve_config) { pci_bus_claim_resources(bus); } else { pci_bus_size_bridges(bus); diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index 29658c0ee71f..ba5532005125 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -13,6 +13,7 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, unsigned int devfn); int of_pci_get_devfn(struct device_node *np); void of_pci_check_probe_only(void); +bool of_pci_check_preserve_boot_config(struct device_node *node); #else static inline struct device_node *of_pci_find_child_device(struct device_node *parent, unsigned int devfn) @@ -26,6 +27,11 @@ static inline int of_pci_get_devfn(struct device_node *np) } static inline void of_pci_check_probe_only(void) { } + +static inline bool of_pci_check_preserve_boot_config(struct device_node *node) +{ + return false; +} #endif #if IS_ENABLED(CONFIG_OF_IRQ) -- 2.25.1