Added cc: stable@xxxxxxxxxx See: https://patchwork.kernel.org/patch/199952/ On Wednesday, September 22, 2010 11:09:19 am Bjorn Helgaas wrote: > > Some BIOSes provide PCI host bridge windows that overlap, e.g., > > pci_root PNP0A03:00: host bridge window [mem 0xb0000000-0xffffffff] > pci_root PNP0A03:00: host bridge window [mem 0xafffffff-0xdfffffff] > pci_root PNP0A03:00: host bridge window [mem 0xf0000000-0xffffffff] > > If we simply insert these as children of iomem_resource, the second window > fails because it conflicts with the first, and the third is inserted as a > child of the first, i.e., > > b0000000-ffffffff PCI Bus 0000:00 > f0000000-ffffffff PCI Bus 0000:00 > > When we claim PCI device resources, this can cause collisions like this > if we put them in the first window: > > pci 0000:00:01.0: address space collision: [mem 0xff300000-0xff4fffff] conflicts with PCI Bus 0000:00 [mem 0xf0000000-0xffffffff] > > Host bridge windows are top-level resources by definition, so it doesn't > make sense to make the third window a child of the first. This patch > coalesces any host bridge windows that overlap. For the example above, > the result is this single window: > > pci_root PNP0A03:00: host bridge window [mem 0xafffffff-0xffffffff] > > This fixes a 2.6.34 regression. > > Reference: https://bugzilla.kernel.org/show_bug.cgi?id=17011 > Reported-and-tested-by: Anisse Astier <anisse@xxxxxxxxx> > Reported-and-tested-by: Pramod Dematagoda <pmd.lotr.gandalf@xxxxxxxxx> > Signed-off-by: Bjorn Helgaas <bjorn.helgaas@xxxxxx> > --- > > arch/x86/pci/acpi.c | 103 +++++++++++++++++++++++++++++++++++++++++---------- > 1 files changed, 83 insertions(+), 20 deletions(-) > > > diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c > index 15466c0..0972315 100644 > --- a/arch/x86/pci/acpi.c > +++ b/arch/x86/pci/acpi.c > @@ -138,7 +138,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data) > struct acpi_resource_address64 addr; > acpi_status status; > unsigned long flags; > - struct resource *root, *conflict; > u64 start, end; > > status = resource_to_addr(acpi_res, &addr); > @@ -146,12 +145,10 @@ setup_resource(struct acpi_resource *acpi_res, void *data) > return AE_OK; > > if (addr.resource_type == ACPI_MEMORY_RANGE) { > - root = &iomem_resource; > flags = IORESOURCE_MEM; > if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY) > flags |= IORESOURCE_PREFETCH; > } else if (addr.resource_type == ACPI_IO_RANGE) { > - root = &ioport_resource; > flags = IORESOURCE_IO; > } else > return AE_OK; > @@ -172,25 +169,90 @@ setup_resource(struct acpi_resource *acpi_res, void *data) > return AE_OK; > } > > - conflict = insert_resource_conflict(root, res); > - if (conflict) { > - dev_err(&info->bridge->dev, > - "address space collision: host bridge window %pR " > - "conflicts with %s %pR\n", > - res, conflict->name, conflict); > - } else { > - pci_bus_add_resource(info->bus, res, 0); > - info->res_num++; > - if (addr.translation_offset) > - dev_info(&info->bridge->dev, "host bridge window %pR " > - "(PCI address [%#llx-%#llx])\n", > - res, res->start - addr.translation_offset, > - res->end - addr.translation_offset); > + info->res_num++; > + if (addr.translation_offset) > + dev_info(&info->bridge->dev, "host bridge window %pR " > + "(PCI address [%#llx-%#llx])\n", > + res, res->start - addr.translation_offset, > + res->end - addr.translation_offset); > + else > + dev_info(&info->bridge->dev, "host bridge window %pR\n", res); > + > + return AE_OK; > +} > + > +static bool resource_contains(struct resource *res, resource_size_t point) > +{ > + if (res->start <= point && point <= res->end) > + return true; > + return false; > +} > + > +static void coalesce_windows(struct pci_root_info *info, int type) > +{ > + int i, j; > + struct resource *res1, *res2; > + > + for (i = 0; i < info->res_num; i++) { > + res1 = &info->res[i]; > + if (!(res1->flags & type)) > + continue; > + > + for (j = i + 1; j < info->res_num; j++) { > + res2 = &info->res[j]; > + if (!(res2->flags & type)) > + continue; > + > + /* > + * I don't like throwing away windows because then > + * our resources no longer match the ACPI _CRS, but > + * the kernel resource tree doesn't allow overlaps. > + */ > + if (resource_contains(res1, res2->start) || > + resource_contains(res1, res2->end) || > + resource_contains(res2, res1->start) || > + resource_contains(res2, res1->end)) { > + res1->start = min(res1->start, res2->start); > + res1->end = max(res1->end, res2->end); > + dev_info(&info->bridge->dev, > + "host bridge window expanded to %pR; %pR ignored\n", > + res1, res2); > + res2->flags = 0; > + } > + } > + } > +} > + > +static void add_resources(struct pci_root_info *info) > +{ > + int i; > + struct resource *res, *root, *conflict; > + > + if (!pci_use_crs) > + return; > + > + coalesce_windows(info, IORESOURCE_MEM); > + coalesce_windows(info, IORESOURCE_IO); > + > + for (i = 0; i < info->res_num; i++) { > + res = &info->res[i]; > + > + if (res->flags & IORESOURCE_MEM) > + root = &iomem_resource; > + else if (res->flags & IORESOURCE_IO) > + root = &ioport_resource; > else > - dev_info(&info->bridge->dev, > - "host bridge window %pR\n", res); > + continue; > + > + conflict = insert_resource_conflict(root, res); > + if (conflict) > + dev_err(&info->bridge->dev, > + "address space collision: host bridge window %pR " > + "conflicts with %s %pR\n", > + res, conflict->name, conflict); > + else > + pci_bus_add_resource(info->bus, res, 0); > } > - return AE_OK; > } > > static void > @@ -224,6 +286,7 @@ get_current_resources(struct acpi_device *device, int busnum, > acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, > &info); > > + add_resources(&info); > return; > > name_alloc_fail: > > -- 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