diff options
| author | Bjorn Helgaas <bjorn.helgaas@hp.com> | 2010-03-25 12:32:49 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2010-04-04 01:33:43 -0400 |
| commit | 3162b6f0c5e1fcad372d64194fb3cb968941b428 (patch) | |
| tree | 31cde2251d3fc28c4e77c8dd213bca0a5a2fedfd | |
| parent | 2eaa9cfdf33b8d7fb7aff27792192e0019ae8fc6 (diff) | |
PNPACPI: truncate _CRS windows with _LEN > _MAX - _MIN + 1
The ACPI spec (sec 6.4.3.5 in v4.0) requires that for Address Space Resource
Descriptors, _LEN <= _MAX - _MIN + 1 in all cases, but there are BIOSes that
violate this. We experimentally determined that Windows truncates the
resource so it doesn't extend past _MAX, so let's do the same thing in
Linux.
http://bugzilla.kernel.org/show_bug.cgi?id=15480
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Acked-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | drivers/pnp/pnpacpi/rsparser.c | 42 |
1 files changed, 30 insertions, 12 deletions
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 54514aa35b09..fe5bfa998f59 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c | |||
| @@ -273,12 +273,33 @@ static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev, | |||
| 273 | pnp_add_bus_resource(dev, start, end); | 273 | pnp_add_bus_resource(dev, start, end); |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | static u64 addr_space_length(struct pnp_dev *dev, u64 min, u64 max, u64 len) | ||
| 277 | { | ||
| 278 | u64 max_len; | ||
| 279 | |||
| 280 | max_len = max - min + 1; | ||
| 281 | if (len <= max_len) | ||
| 282 | return len; | ||
| 283 | |||
| 284 | /* | ||
| 285 | * Per 6.4.3.5, _LEN cannot exceed _MAX - _MIN + 1, but some BIOSes | ||
| 286 | * don't do this correctly, e.g., | ||
| 287 | * https://bugzilla.kernel.org/show_bug.cgi?id=15480 | ||
| 288 | */ | ||
| 289 | dev_info(&dev->dev, | ||
| 290 | "resource length %#llx doesn't fit in %#llx-%#llx, trimming\n", | ||
| 291 | (unsigned long long) len, (unsigned long long) min, | ||
| 292 | (unsigned long long) max); | ||
| 293 | return max_len; | ||
| 294 | } | ||
| 295 | |||
| 276 | static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, | 296 | static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, |
| 277 | struct acpi_resource *res) | 297 | struct acpi_resource *res) |
| 278 | { | 298 | { |
| 279 | struct acpi_resource_address64 addr, *p = &addr; | 299 | struct acpi_resource_address64 addr, *p = &addr; |
| 280 | acpi_status status; | 300 | acpi_status status; |
| 281 | int window; | 301 | int window; |
| 302 | u64 len; | ||
| 282 | 303 | ||
| 283 | status = acpi_resource_to_address64(res, p); | 304 | status = acpi_resource_to_address64(res, p); |
| 284 | if (!ACPI_SUCCESS(status)) { | 305 | if (!ACPI_SUCCESS(status)) { |
| @@ -287,20 +308,18 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, | |||
| 287 | return; | 308 | return; |
| 288 | } | 309 | } |
| 289 | 310 | ||
| 311 | len = addr_space_length(dev, p->minimum, p->maximum, p->address_length); | ||
| 290 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; | 312 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; |
| 291 | 313 | ||
| 292 | if (p->resource_type == ACPI_MEMORY_RANGE) | 314 | if (p->resource_type == ACPI_MEMORY_RANGE) |
| 293 | pnpacpi_parse_allocated_memresource(dev, | 315 | pnpacpi_parse_allocated_memresource(dev, p->minimum, len, |
| 294 | p->minimum, p->address_length, | ||
| 295 | p->info.mem.write_protect, window); | 316 | p->info.mem.write_protect, window); |
| 296 | else if (p->resource_type == ACPI_IO_RANGE) | 317 | else if (p->resource_type == ACPI_IO_RANGE) |
| 297 | pnpacpi_parse_allocated_ioresource(dev, | 318 | pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, |
| 298 | p->minimum, p->address_length, | ||
| 299 | p->granularity == 0xfff ? ACPI_DECODE_10 : | 319 | p->granularity == 0xfff ? ACPI_DECODE_10 : |
| 300 | ACPI_DECODE_16, window); | 320 | ACPI_DECODE_16, window); |
| 301 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) | 321 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) |
| 302 | pnpacpi_parse_allocated_busresource(dev, p->minimum, | 322 | pnpacpi_parse_allocated_busresource(dev, p->minimum, len); |
| 303 | p->address_length); | ||
| 304 | } | 323 | } |
| 305 | 324 | ||
| 306 | static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev, | 325 | static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev, |
| @@ -308,21 +327,20 @@ static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev, | |||
| 308 | { | 327 | { |
| 309 | struct acpi_resource_extended_address64 *p = &res->data.ext_address64; | 328 | struct acpi_resource_extended_address64 *p = &res->data.ext_address64; |
| 310 | int window; | 329 | int window; |
| 330 | u64 len; | ||
| 311 | 331 | ||
| 332 | len = addr_space_length(dev, p->minimum, p->maximum, p->address_length); | ||
| 312 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; | 333 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; |
| 313 | 334 | ||
| 314 | if (p->resource_type == ACPI_MEMORY_RANGE) | 335 | if (p->resource_type == ACPI_MEMORY_RANGE) |
| 315 | pnpacpi_parse_allocated_memresource(dev, | 336 | pnpacpi_parse_allocated_memresource(dev, p->minimum, len, |
| 316 | p->minimum, p->address_length, | ||
| 317 | p->info.mem.write_protect, window); | 337 | p->info.mem.write_protect, window); |
| 318 | else if (p->resource_type == ACPI_IO_RANGE) | 338 | else if (p->resource_type == ACPI_IO_RANGE) |
| 319 | pnpacpi_parse_allocated_ioresource(dev, | 339 | pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, |
| 320 | p->minimum, p->address_length, | ||
| 321 | p->granularity == 0xfff ? ACPI_DECODE_10 : | 340 | p->granularity == 0xfff ? ACPI_DECODE_10 : |
| 322 | ACPI_DECODE_16, window); | 341 | ACPI_DECODE_16, window); |
| 323 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) | 342 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) |
| 324 | pnpacpi_parse_allocated_busresource(dev, p->minimum, | 343 | pnpacpi_parse_allocated_busresource(dev, p->minimum, len); |
| 325 | p->address_length); | ||
| 326 | } | 344 | } |
| 327 | 345 | ||
| 328 | static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | 346 | static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, |
