Re: [PATCH] x86/PCI: coalesce overlapping host bridge windows

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux