If the static enumeration profile reserves memory behind a bridge, and that memory was already assigned to a device's BAR by the BIOS, then invalidate those BAR resources. The core PCI subsystem will then reassign those BARs to a different, not-conflicting location. Signed-off-by: Jason Tang <jason.tang2@xxxxxxx> --- drivers/pci/pci_static_enum.c | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/pci/pci_static_enum.c b/drivers/pci/pci_static_enum.c index 8d479a9..f000c7f 100644 --- a/drivers/pci/pci_static_enum.c +++ b/drivers/pci/pci_static_enum.c @@ -259,6 +259,41 @@ int pci_static_enum_get_busnr(struct pci_bus *bus, struct pci_dev *dev, } /** + * pci_static_enum_invalidate() - callback invoked while invalidating + * bridge resources + * @dev: device to examine + * @data: overridden bridge memory + * + * For each of @dev's BARs, if it conflicts with the memory being + * reserved for a bridge then invalidate it. + * + * Return: 0 + */ +static int pci_static_enum_invalidate(struct pci_dev *dev, void *data) +{ + struct pci_static_enum_setting *setting = + (struct pci_static_enum_setting *)(data); + int i; + struct resource *r; + resource_size_t start, end; + + for (i = 0; i < PCI_STD_RESOURCE_END; i++) { + r = &dev->resource[i]; + if (!(r->flags & IORESOURCE_MEM) + || (r->flags & IORESOURCE_UNSET)) + continue; + start = max(r->start, setting->bridgemem_start); + end = min(r->end, setting->bridgemem_end); + if (start >= end) + continue; /* no overlap */ + dev_info(&dev->dev, "Invalidating res %d %pR\n", i, r); + r->flags |= IORESOURCE_UNSET; + } + + return 0; +} + +/** * pci_static_enum_set_bridge_memory() - override a PCI bridge's * memory base and limit registers, according to its static * enumeration profile @@ -270,6 +305,7 @@ static void pci_static_enum_set_bridge_memory(struct pci_dev *dev, struct pci_st { u16 mem_base_lo, mem_limit_lo; struct pci_dev *parent; + struct pci_bus *root = dev->bus; struct resource *res; u16 parent_base_lo, parent_limit_lo; unsigned long base, limit; @@ -311,8 +347,14 @@ static void pci_static_enum_set_bridge_memory(struct pci_dev *dev, struct pci_st pci_write_config_word(parent, PCI_MEMORY_LIMIT, mem_limit_lo); } + root = parent->bus; parent = pci_upstream_bridge(parent); } + + /* invalidate any other resource that is using this bridge + memory */ + if (root) + pci_walk_bus(root, pci_static_enum_invalidate, setting); } /** -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html