diff options
Diffstat (limited to 'drivers/pnp/pnpacpi')
-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 c6c552f681b7..35bb44af49b3 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c | |||
@@ -274,12 +274,33 @@ static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev, | |||
274 | pnp_add_bus_resource(dev, start, end); | 274 | pnp_add_bus_resource(dev, start, end); |
275 | } | 275 | } |
276 | 276 | ||
277 | static u64 addr_space_length(struct pnp_dev *dev, u64 min, u64 max, u64 len) | ||
278 | { | ||
279 | u64 max_len; | ||
280 | |||
281 | max_len = max - min + 1; | ||
282 | if (len <= max_len) | ||
283 | return len; | ||
284 | |||
285 | /* | ||
286 | * Per 6.4.3.5, _LEN cannot exceed _MAX - _MIN + 1, but some BIOSes | ||
287 | * don't do this correctly, e.g., | ||
288 | * https://bugzilla.kernel.org/show_bug.cgi?id=15480 | ||
289 | */ | ||
290 | dev_info(&dev->dev, | ||
291 | "resource length %#llx doesn't fit in %#llx-%#llx, trimming\n", | ||
292 | (unsigned long long) len, (unsigned long long) min, | ||
293 | (unsigned long long) max); | ||
294 | return max_len; | ||
295 | } | ||
296 | |||
277 | static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, | 297 | static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, |
278 | struct acpi_resource *res) | 298 | struct acpi_resource *res) |
279 | { | 299 | { |
280 | struct acpi_resource_address64 addr, *p = &addr; | 300 | struct acpi_resource_address64 addr, *p = &addr; |
281 | acpi_status status; | 301 | acpi_status status; |
282 | int window; | 302 | int window; |
303 | u64 len; | ||
283 | 304 | ||
284 | status = acpi_resource_to_address64(res, p); | 305 | status = acpi_resource_to_address64(res, p); |
285 | if (!ACPI_SUCCESS(status)) { | 306 | if (!ACPI_SUCCESS(status)) { |
@@ -288,20 +309,18 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, | |||
288 | return; | 309 | return; |
289 | } | 310 | } |
290 | 311 | ||
312 | len = addr_space_length(dev, p->minimum, p->maximum, p->address_length); | ||
291 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; | 313 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; |
292 | 314 | ||
293 | if (p->resource_type == ACPI_MEMORY_RANGE) | 315 | if (p->resource_type == ACPI_MEMORY_RANGE) |
294 | pnpacpi_parse_allocated_memresource(dev, | 316 | pnpacpi_parse_allocated_memresource(dev, p->minimum, len, |
295 | p->minimum, p->address_length, | ||
296 | p->info.mem.write_protect, window); | 317 | p->info.mem.write_protect, window); |
297 | else if (p->resource_type == ACPI_IO_RANGE) | 318 | else if (p->resource_type == ACPI_IO_RANGE) |
298 | pnpacpi_parse_allocated_ioresource(dev, | 319 | pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, |
299 | p->minimum, p->address_length, | ||
300 | p->granularity == 0xfff ? ACPI_DECODE_10 : | 320 | p->granularity == 0xfff ? ACPI_DECODE_10 : |
301 | ACPI_DECODE_16, window); | 321 | ACPI_DECODE_16, window); |
302 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) | 322 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) |
303 | pnpacpi_parse_allocated_busresource(dev, p->minimum, | 323 | pnpacpi_parse_allocated_busresource(dev, p->minimum, len); |
304 | p->address_length); | ||
305 | } | 324 | } |
306 | 325 | ||
307 | static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev, | 326 | static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev, |
@@ -309,21 +328,20 @@ static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev, | |||
309 | { | 328 | { |
310 | struct acpi_resource_extended_address64 *p = &res->data.ext_address64; | 329 | struct acpi_resource_extended_address64 *p = &res->data.ext_address64; |
311 | int window; | 330 | int window; |
331 | u64 len; | ||
312 | 332 | ||
333 | len = addr_space_length(dev, p->minimum, p->maximum, p->address_length); | ||
313 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; | 334 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; |
314 | 335 | ||
315 | if (p->resource_type == ACPI_MEMORY_RANGE) | 336 | if (p->resource_type == ACPI_MEMORY_RANGE) |
316 | pnpacpi_parse_allocated_memresource(dev, | 337 | pnpacpi_parse_allocated_memresource(dev, p->minimum, len, |
317 | p->minimum, p->address_length, | ||
318 | p->info.mem.write_protect, window); | 338 | p->info.mem.write_protect, window); |
319 | else if (p->resource_type == ACPI_IO_RANGE) | 339 | else if (p->resource_type == ACPI_IO_RANGE) |
320 | pnpacpi_parse_allocated_ioresource(dev, | 340 | pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, |
321 | p->minimum, p->address_length, | ||
322 | p->granularity == 0xfff ? ACPI_DECODE_10 : | 341 | p->granularity == 0xfff ? ACPI_DECODE_10 : |
323 | ACPI_DECODE_16, window); | 342 | ACPI_DECODE_16, window); |
324 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) | 343 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) |
325 | pnpacpi_parse_allocated_busresource(dev, p->minimum, | 344 | pnpacpi_parse_allocated_busresource(dev, p->minimum, len); |
326 | p->address_length); | ||
327 | } | 345 | } |
328 | 346 | ||
329 | static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | 347 | static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, |