diff options
Diffstat (limited to 'drivers/pnp/pnpacpi/rsparser.c')
-rw-r--r-- | drivers/pnp/pnpacpi/rsparser.c | 84 |
1 files changed, 61 insertions, 23 deletions
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 5702b2c8691f..35bb44af49b3 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/acpi.h> | 24 | #include <linux/acpi.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/pnp.h> | 26 | #include <linux/pnp.h> |
27 | #include <linux/slab.h> | ||
27 | #include "../base.h" | 28 | #include "../base.h" |
28 | #include "pnpacpi.h" | 29 | #include "pnpacpi.h" |
29 | 30 | ||
@@ -177,7 +178,8 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master, | |||
177 | } | 178 | } |
178 | 179 | ||
179 | static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, | 180 | static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, |
180 | u64 len, int io_decode) | 181 | u64 len, int io_decode, |
182 | int window) | ||
181 | { | 183 | { |
182 | int flags = 0; | 184 | int flags = 0; |
183 | u64 end = start + len - 1; | 185 | u64 end = start + len - 1; |
@@ -186,6 +188,8 @@ static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, | |||
186 | flags |= IORESOURCE_IO_16BIT_ADDR; | 188 | flags |= IORESOURCE_IO_16BIT_ADDR; |
187 | if (len == 0 || end >= 0x10003) | 189 | if (len == 0 || end >= 0x10003) |
188 | flags |= IORESOURCE_DISABLED; | 190 | flags |= IORESOURCE_DISABLED; |
191 | if (window) | ||
192 | flags |= IORESOURCE_WINDOW; | ||
189 | 193 | ||
190 | pnp_add_io_resource(dev, start, end, flags); | 194 | pnp_add_io_resource(dev, start, end, flags); |
191 | } | 195 | } |
@@ -247,7 +251,7 @@ static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev, | |||
247 | 251 | ||
248 | static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, | 252 | static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, |
249 | u64 start, u64 len, | 253 | u64 start, u64 len, |
250 | int write_protect) | 254 | int write_protect, int window) |
251 | { | 255 | { |
252 | int flags = 0; | 256 | int flags = 0; |
253 | u64 end = start + len - 1; | 257 | u64 end = start + len - 1; |
@@ -256,15 +260,47 @@ static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, | |||
256 | flags |= IORESOURCE_DISABLED; | 260 | flags |= IORESOURCE_DISABLED; |
257 | if (write_protect == ACPI_READ_WRITE_MEMORY) | 261 | if (write_protect == ACPI_READ_WRITE_MEMORY) |
258 | flags |= IORESOURCE_MEM_WRITEABLE; | 262 | flags |= IORESOURCE_MEM_WRITEABLE; |
263 | if (window) | ||
264 | flags |= IORESOURCE_WINDOW; | ||
259 | 265 | ||
260 | pnp_add_mem_resource(dev, start, end, flags); | 266 | pnp_add_mem_resource(dev, start, end, flags); |
261 | } | 267 | } |
262 | 268 | ||
269 | static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev, | ||
270 | u64 start, u64 len) | ||
271 | { | ||
272 | u64 end = start + len - 1; | ||
273 | |||
274 | pnp_add_bus_resource(dev, start, end); | ||
275 | } | ||
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 | |||
263 | static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, | 297 | static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, |
264 | struct acpi_resource *res) | 298 | struct acpi_resource *res) |
265 | { | 299 | { |
266 | struct acpi_resource_address64 addr, *p = &addr; | 300 | struct acpi_resource_address64 addr, *p = &addr; |
267 | acpi_status status; | 301 | acpi_status status; |
302 | int window; | ||
303 | u64 len; | ||
268 | 304 | ||
269 | status = acpi_resource_to_address64(res, p); | 305 | status = acpi_resource_to_address64(res, p); |
270 | if (!ACPI_SUCCESS(status)) { | 306 | if (!ACPI_SUCCESS(status)) { |
@@ -273,37 +309,39 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, | |||
273 | return; | 309 | return; |
274 | } | 310 | } |
275 | 311 | ||
276 | if (p->producer_consumer == ACPI_PRODUCER) | 312 | len = addr_space_length(dev, p->minimum, p->maximum, p->address_length); |
277 | return; | 313 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; |
278 | 314 | ||
279 | if (p->resource_type == ACPI_MEMORY_RANGE) | 315 | if (p->resource_type == ACPI_MEMORY_RANGE) |
280 | pnpacpi_parse_allocated_memresource(dev, | 316 | pnpacpi_parse_allocated_memresource(dev, p->minimum, len, |
281 | p->minimum, p->address_length, | 317 | p->info.mem.write_protect, window); |
282 | p->info.mem.write_protect); | ||
283 | else if (p->resource_type == ACPI_IO_RANGE) | 318 | else if (p->resource_type == ACPI_IO_RANGE) |
284 | pnpacpi_parse_allocated_ioresource(dev, | 319 | pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, |
285 | p->minimum, p->address_length, | ||
286 | p->granularity == 0xfff ? ACPI_DECODE_10 : | 320 | p->granularity == 0xfff ? ACPI_DECODE_10 : |
287 | ACPI_DECODE_16); | 321 | ACPI_DECODE_16, window); |
322 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) | ||
323 | pnpacpi_parse_allocated_busresource(dev, p->minimum, len); | ||
288 | } | 324 | } |
289 | 325 | ||
290 | 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, |
291 | struct acpi_resource *res) | 327 | struct acpi_resource *res) |
292 | { | 328 | { |
293 | struct acpi_resource_extended_address64 *p = &res->data.ext_address64; | 329 | struct acpi_resource_extended_address64 *p = &res->data.ext_address64; |
330 | int window; | ||
331 | u64 len; | ||
294 | 332 | ||
295 | if (p->producer_consumer == ACPI_PRODUCER) | 333 | len = addr_space_length(dev, p->minimum, p->maximum, p->address_length); |
296 | return; | 334 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; |
297 | 335 | ||
298 | if (p->resource_type == ACPI_MEMORY_RANGE) | 336 | if (p->resource_type == ACPI_MEMORY_RANGE) |
299 | pnpacpi_parse_allocated_memresource(dev, | 337 | pnpacpi_parse_allocated_memresource(dev, p->minimum, len, |
300 | p->minimum, p->address_length, | 338 | p->info.mem.write_protect, window); |
301 | p->info.mem.write_protect); | ||
302 | else if (p->resource_type == ACPI_IO_RANGE) | 339 | else if (p->resource_type == ACPI_IO_RANGE) |
303 | pnpacpi_parse_allocated_ioresource(dev, | 340 | pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, |
304 | p->minimum, p->address_length, | ||
305 | p->granularity == 0xfff ? ACPI_DECODE_10 : | 341 | p->granularity == 0xfff ? ACPI_DECODE_10 : |
306 | ACPI_DECODE_16); | 342 | ACPI_DECODE_16, window); |
343 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) | ||
344 | pnpacpi_parse_allocated_busresource(dev, p->minimum, len); | ||
307 | } | 345 | } |
308 | 346 | ||
309 | static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | 347 | static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, |
@@ -368,7 +406,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
368 | pnpacpi_parse_allocated_ioresource(dev, | 406 | pnpacpi_parse_allocated_ioresource(dev, |
369 | io->minimum, | 407 | io->minimum, |
370 | io->address_length, | 408 | io->address_length, |
371 | io->io_decode); | 409 | io->io_decode, 0); |
372 | break; | 410 | break; |
373 | 411 | ||
374 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: | 412 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
@@ -380,7 +418,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
380 | pnpacpi_parse_allocated_ioresource(dev, | 418 | pnpacpi_parse_allocated_ioresource(dev, |
381 | fixed_io->address, | 419 | fixed_io->address, |
382 | fixed_io->address_length, | 420 | fixed_io->address_length, |
383 | ACPI_DECODE_10); | 421 | ACPI_DECODE_10, 0); |
384 | break; | 422 | break; |
385 | 423 | ||
386 | case ACPI_RESOURCE_TYPE_VENDOR: | 424 | case ACPI_RESOURCE_TYPE_VENDOR: |
@@ -396,21 +434,21 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
396 | pnpacpi_parse_allocated_memresource(dev, | 434 | pnpacpi_parse_allocated_memresource(dev, |
397 | memory24->minimum, | 435 | memory24->minimum, |
398 | memory24->address_length, | 436 | memory24->address_length, |
399 | memory24->write_protect); | 437 | memory24->write_protect, 0); |
400 | break; | 438 | break; |
401 | case ACPI_RESOURCE_TYPE_MEMORY32: | 439 | case ACPI_RESOURCE_TYPE_MEMORY32: |
402 | memory32 = &res->data.memory32; | 440 | memory32 = &res->data.memory32; |
403 | pnpacpi_parse_allocated_memresource(dev, | 441 | pnpacpi_parse_allocated_memresource(dev, |
404 | memory32->minimum, | 442 | memory32->minimum, |
405 | memory32->address_length, | 443 | memory32->address_length, |
406 | memory32->write_protect); | 444 | memory32->write_protect, 0); |
407 | break; | 445 | break; |
408 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | 446 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
409 | fixed_memory32 = &res->data.fixed_memory32; | 447 | fixed_memory32 = &res->data.fixed_memory32; |
410 | pnpacpi_parse_allocated_memresource(dev, | 448 | pnpacpi_parse_allocated_memresource(dev, |
411 | fixed_memory32->address, | 449 | fixed_memory32->address, |
412 | fixed_memory32->address_length, | 450 | fixed_memory32->address_length, |
413 | fixed_memory32->write_protect); | 451 | fixed_memory32->write_protect, 0); |
414 | break; | 452 | break; |
415 | case ACPI_RESOURCE_TYPE_ADDRESS16: | 453 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
416 | case ACPI_RESOURCE_TYPE_ADDRESS32: | 454 | case ACPI_RESOURCE_TYPE_ADDRESS32: |