Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 48728e07 authored by Bjorn Helgaas's avatar Bjorn Helgaas Committed by Jesse Barnes
Browse files

x86/PCI: compute Address Space length rather than using _LEN

ACPI _CRS Address Space Descriptors have _MIN, _MAX, and _LEN.  Linux has
been computing Address Spaces as [_MIN to _MIN + _LEN - 1].  Based on the
tests in the bug reports below, Windows apparently uses [_MIN to _MAX].

Per spec (ACPI 4.0, Table 6-40), for _CRS fixed-size, fixed location
descriptors, "_LEN must be (_MAX - _MIN + 1)", and when that's true, it
doesn't matter which way we compute the end.  But of course, there are
BIOSes that don't follow this rule, and we're better off if Linux handles
those exceptions the same way as Windows.

This patch makes Linux use [_MIN to _MAX], as Windows seems to do.  This
effectively reverts d558b483 and 03db42ad and replaces them with
simpler code.

    https://bugzilla.kernel.org/show_bug.cgi?id=14337 (round)
    https://bugzilla.kernel.org/show_bug.cgi?id=15480

 (truncate)

Signed-off-by: default avatarBjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 55051feb
Loading
Loading
Loading
Loading
+2 −38
Original line number Original line Diff line number Diff line
@@ -121,30 +121,6 @@ count_resource(struct acpi_resource *acpi_res, void *data)
	return AE_OK;
	return AE_OK;
}
}


static void
align_resource(struct acpi_device *bridge, struct resource *res)
{
	int align = (res->flags & IORESOURCE_MEM) ? 16 : 4;

	/*
	 * Host bridge windows are not BARs, but the decoders on the PCI side
	 * that claim this address space have starting alignment and length
	 * constraints, so fix any obvious BIOS goofs.
	 */
	if (!IS_ALIGNED(res->start, align)) {
		dev_printk(KERN_DEBUG, &bridge->dev,
			   "host bridge window %pR invalid; "
			   "aligning start to %d-byte boundary\n", res, align);
		res->start &= ~(align - 1);
	}
	if (!IS_ALIGNED(res->end + 1, align)) {
		dev_printk(KERN_DEBUG, &bridge->dev,
			   "host bridge window %pR invalid; "
			   "aligning end to %d-byte boundary\n", res, align);
		res->end = ALIGN(res->end, align) - 1;
	}
}

static acpi_status
static acpi_status
setup_resource(struct acpi_resource *acpi_res, void *data)
setup_resource(struct acpi_resource *acpi_res, void *data)
{
{
@@ -154,7 +130,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
	acpi_status status;
	acpi_status status;
	unsigned long flags;
	unsigned long flags;
	struct resource *root, *conflict;
	struct resource *root, *conflict;
	u64 start, end, max_len;
	u64 start, end;


	status = resource_to_addr(acpi_res, &addr);
	status = resource_to_addr(acpi_res, &addr);
	if (!ACPI_SUCCESS(status))
	if (!ACPI_SUCCESS(status))
@@ -171,19 +147,8 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
	} else
	} else
		return AE_OK;
		return AE_OK;


	max_len = addr.maximum - addr.minimum + 1;
	if (addr.address_length > max_len) {
		dev_printk(KERN_DEBUG, &info->bridge->dev,
			   "host bridge window length %#llx doesn't fit in "
			   "%#llx-%#llx, trimming\n",
			   (unsigned long long) addr.address_length,
			   (unsigned long long) addr.minimum,
			   (unsigned long long) addr.maximum);
		addr.address_length = max_len;
	}

	start = addr.minimum + addr.translation_offset;
	start = addr.minimum + addr.translation_offset;
	end = start + addr.address_length - 1;
	end = addr.maximum + addr.translation_offset;


	res = &info->res[info->res_num];
	res = &info->res[info->res_num];
	res->name = info->name;
	res->name = info->name;
@@ -191,7 +156,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
	res->start = start;
	res->start = start;
	res->end = end;
	res->end = end;
	res->child = NULL;
	res->child = NULL;
	align_resource(info->bridge, res);


	if (!pci_use_crs) {
	if (!pci_use_crs) {
		dev_printk(KERN_DEBUG, &info->bridge->dev,
		dev_printk(KERN_DEBUG, &info->bridge->dev,