diff options
Diffstat (limited to 'drivers/pnp/pnpacpi/rsparser.c')
-rw-r--r-- | drivers/pnp/pnpacpi/rsparser.c | 492 |
1 files changed, 287 insertions, 205 deletions
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 46c791adb894..d7e9f2152df0 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c | |||
@@ -3,6 +3,8 @@ | |||
3 | * | 3 | * |
4 | * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr> | 4 | * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr> |
5 | * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com> | 5 | * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com> |
6 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
7 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | ||
6 | * | 8 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is free software; you can redistribute it and/or modify it |
8 | * under the terms of the GNU General Public License as published by the | 10 | * under the terms of the GNU General Public License as published by the |
@@ -98,8 +100,10 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev, | |||
98 | int irq, flags; | 100 | int irq, flags; |
99 | int p, t; | 101 | int p, t; |
100 | 102 | ||
101 | if (!valid_IRQ(gsi)) | 103 | if (!valid_IRQ(gsi)) { |
104 | pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED); | ||
102 | return; | 105 | return; |
106 | } | ||
103 | 107 | ||
104 | /* | 108 | /* |
105 | * in IO-APIC mode, use overrided attribute. Two reasons: | 109 | * in IO-APIC mode, use overrided attribute. Two reasons: |
@@ -178,13 +182,68 @@ static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, | |||
178 | u64 end = start + len - 1; | 182 | u64 end = start + len - 1; |
179 | 183 | ||
180 | if (io_decode == ACPI_DECODE_16) | 184 | if (io_decode == ACPI_DECODE_16) |
181 | flags |= PNP_PORT_FLAG_16BITADDR; | 185 | flags |= IORESOURCE_IO_16BIT_ADDR; |
182 | if (len == 0 || end >= 0x10003) | 186 | if (len == 0 || end >= 0x10003) |
183 | flags |= IORESOURCE_DISABLED; | 187 | flags |= IORESOURCE_DISABLED; |
184 | 188 | ||
185 | pnp_add_io_resource(dev, start, end, flags); | 189 | pnp_add_io_resource(dev, start, end, flags); |
186 | } | 190 | } |
187 | 191 | ||
192 | /* | ||
193 | * Device CSRs that do not appear in PCI config space should be described | ||
194 | * via ACPI. This would normally be done with Address Space Descriptors | ||
195 | * marked as "consumer-only," but old versions of Windows and Linux ignore | ||
196 | * the producer/consumer flag, so HP invented a vendor-defined resource to | ||
197 | * describe the location and size of CSR space. | ||
198 | */ | ||
199 | static struct acpi_vendor_uuid hp_ccsr_uuid = { | ||
200 | .subtype = 2, | ||
201 | .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a, | ||
202 | 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad }, | ||
203 | }; | ||
204 | |||
205 | static int vendor_resource_matches(struct pnp_dev *dev, | ||
206 | struct acpi_resource_vendor_typed *vendor, | ||
207 | struct acpi_vendor_uuid *match, | ||
208 | int expected_len) | ||
209 | { | ||
210 | int uuid_len = sizeof(vendor->uuid); | ||
211 | u8 uuid_subtype = vendor->uuid_subtype; | ||
212 | u8 *uuid = vendor->uuid; | ||
213 | int actual_len; | ||
214 | |||
215 | /* byte_length includes uuid_subtype and uuid */ | ||
216 | actual_len = vendor->byte_length - uuid_len - 1; | ||
217 | |||
218 | if (uuid_subtype == match->subtype && | ||
219 | uuid_len == sizeof(match->data) && | ||
220 | memcmp(uuid, match->data, uuid_len) == 0) { | ||
221 | if (expected_len && expected_len != actual_len) { | ||
222 | dev_err(&dev->dev, "wrong vendor descriptor size; " | ||
223 | "expected %d, found %d bytes\n", | ||
224 | expected_len, actual_len); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | return 1; | ||
229 | } | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev, | ||
235 | struct acpi_resource_vendor_typed *vendor) | ||
236 | { | ||
237 | if (vendor_resource_matches(dev, vendor, &hp_ccsr_uuid, 16)) { | ||
238 | u64 start, length; | ||
239 | |||
240 | memcpy(&start, vendor->byte_data, sizeof(start)); | ||
241 | memcpy(&length, vendor->byte_data + 8, sizeof(length)); | ||
242 | |||
243 | pnp_add_mem_resource(dev, start, start + length - 1, 0); | ||
244 | } | ||
245 | } | ||
246 | |||
188 | static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, | 247 | static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, |
189 | u64 start, u64 len, | 248 | u64 start, u64 len, |
190 | int write_protect) | 249 | int write_protect) |
@@ -235,6 +294,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
235 | struct acpi_resource_dma *dma; | 294 | struct acpi_resource_dma *dma; |
236 | struct acpi_resource_io *io; | 295 | struct acpi_resource_io *io; |
237 | struct acpi_resource_fixed_io *fixed_io; | 296 | struct acpi_resource_fixed_io *fixed_io; |
297 | struct acpi_resource_vendor_typed *vendor_typed; | ||
238 | struct acpi_resource_memory24 *memory24; | 298 | struct acpi_resource_memory24 *memory24; |
239 | struct acpi_resource_memory32 *memory32; | 299 | struct acpi_resource_memory32 *memory32; |
240 | struct acpi_resource_fixed_memory32 *fixed_memory32; | 300 | struct acpi_resource_fixed_memory32 *fixed_memory32; |
@@ -248,24 +308,39 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
248 | * _CRS, but some firmware violates this, so parse them all. | 308 | * _CRS, but some firmware violates this, so parse them all. |
249 | */ | 309 | */ |
250 | irq = &res->data.irq; | 310 | irq = &res->data.irq; |
251 | for (i = 0; i < irq->interrupt_count; i++) { | 311 | if (irq->interrupt_count == 0) |
252 | pnpacpi_parse_allocated_irqresource(dev, | 312 | pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); |
253 | irq->interrupts[i], | 313 | else { |
254 | irq->triggering, | 314 | for (i = 0; i < irq->interrupt_count; i++) { |
255 | irq->polarity, | 315 | pnpacpi_parse_allocated_irqresource(dev, |
256 | irq->sharable); | 316 | irq->interrupts[i], |
317 | irq->triggering, | ||
318 | irq->polarity, | ||
319 | irq->sharable); | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * The IRQ encoder puts a single interrupt in each | ||
324 | * descriptor, so if a _CRS descriptor has more than | ||
325 | * one interrupt, we won't be able to re-encode it. | ||
326 | */ | ||
327 | if (pnp_can_write(dev) && irq->interrupt_count > 1) { | ||
328 | dev_warn(&dev->dev, "multiple interrupts in " | ||
329 | "_CRS descriptor; configuration can't " | ||
330 | "be changed\n"); | ||
331 | dev->capabilities &= ~PNP_WRITE; | ||
332 | } | ||
257 | } | 333 | } |
258 | break; | 334 | break; |
259 | 335 | ||
260 | case ACPI_RESOURCE_TYPE_DMA: | 336 | case ACPI_RESOURCE_TYPE_DMA: |
261 | dma = &res->data.dma; | 337 | dma = &res->data.dma; |
262 | if (dma->channel_count > 0) { | 338 | if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) |
263 | flags = dma_flags(dma->type, dma->bus_master, | 339 | flags = dma_flags(dma->type, dma->bus_master, |
264 | dma->transfer); | 340 | dma->transfer); |
265 | if (dma->channels[0] == (u8) -1) | 341 | else |
266 | flags |= IORESOURCE_DISABLED; | 342 | flags = IORESOURCE_DISABLED; |
267 | pnp_add_dma_resource(dev, dma->channels[0], flags); | 343 | pnp_add_dma_resource(dev, dma->channels[0], flags); |
268 | } | ||
269 | break; | 344 | break; |
270 | 345 | ||
271 | case ACPI_RESOURCE_TYPE_IO: | 346 | case ACPI_RESOURCE_TYPE_IO: |
@@ -289,6 +364,8 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
289 | break; | 364 | break; |
290 | 365 | ||
291 | case ACPI_RESOURCE_TYPE_VENDOR: | 366 | case ACPI_RESOURCE_TYPE_VENDOR: |
367 | vendor_typed = &res->data.vendor_typed; | ||
368 | pnpacpi_parse_allocated_vendor(dev, vendor_typed); | ||
292 | break; | 369 | break; |
293 | 370 | ||
294 | case ACPI_RESOURCE_TYPE_END_TAG: | 371 | case ACPI_RESOURCE_TYPE_END_TAG: |
@@ -331,12 +408,29 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
331 | if (extended_irq->producer_consumer == ACPI_PRODUCER) | 408 | if (extended_irq->producer_consumer == ACPI_PRODUCER) |
332 | return AE_OK; | 409 | return AE_OK; |
333 | 410 | ||
334 | for (i = 0; i < extended_irq->interrupt_count; i++) { | 411 | if (extended_irq->interrupt_count == 0) |
335 | pnpacpi_parse_allocated_irqresource(dev, | 412 | pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); |
336 | extended_irq->interrupts[i], | 413 | else { |
337 | extended_irq->triggering, | 414 | for (i = 0; i < extended_irq->interrupt_count; i++) { |
338 | extended_irq->polarity, | 415 | pnpacpi_parse_allocated_irqresource(dev, |
339 | extended_irq->sharable); | 416 | extended_irq->interrupts[i], |
417 | extended_irq->triggering, | ||
418 | extended_irq->polarity, | ||
419 | extended_irq->sharable); | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * The IRQ encoder puts a single interrupt in each | ||
424 | * descriptor, so if a _CRS descriptor has more than | ||
425 | * one interrupt, we won't be able to re-encode it. | ||
426 | */ | ||
427 | if (pnp_can_write(dev) && | ||
428 | extended_irq->interrupt_count > 1) { | ||
429 | dev_warn(&dev->dev, "multiple interrupts in " | ||
430 | "_CRS descriptor; configuration can't " | ||
431 | "be changed\n"); | ||
432 | dev->capabilities &= ~PNP_WRITE; | ||
433 | } | ||
340 | } | 434 | } |
341 | break; | 435 | break; |
342 | 436 | ||
@@ -373,179 +467,147 @@ int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) | |||
373 | } | 467 | } |
374 | 468 | ||
375 | static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, | 469 | static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, |
376 | struct pnp_option *option, | 470 | unsigned int option_flags, |
377 | struct acpi_resource_dma *p) | 471 | struct acpi_resource_dma *p) |
378 | { | 472 | { |
379 | int i; | 473 | int i; |
380 | struct pnp_dma *dma; | 474 | unsigned char map = 0, flags; |
381 | 475 | ||
382 | if (p->channel_count == 0) | 476 | if (p->channel_count == 0) |
383 | return; | 477 | return; |
384 | dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL); | ||
385 | if (!dma) | ||
386 | return; | ||
387 | 478 | ||
388 | for (i = 0; i < p->channel_count; i++) | 479 | for (i = 0; i < p->channel_count; i++) |
389 | dma->map |= 1 << p->channels[i]; | 480 | map |= 1 << p->channels[i]; |
390 | |||
391 | dma->flags = dma_flags(p->type, p->bus_master, p->transfer); | ||
392 | 481 | ||
393 | pnp_register_dma_resource(dev, option, dma); | 482 | flags = dma_flags(p->type, p->bus_master, p->transfer); |
483 | pnp_register_dma_resource(dev, option_flags, map, flags); | ||
394 | } | 484 | } |
395 | 485 | ||
396 | static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, | 486 | static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, |
397 | struct pnp_option *option, | 487 | unsigned int option_flags, |
398 | struct acpi_resource_irq *p) | 488 | struct acpi_resource_irq *p) |
399 | { | 489 | { |
400 | int i; | 490 | int i; |
401 | struct pnp_irq *irq; | 491 | pnp_irq_mask_t map; |
492 | unsigned char flags; | ||
402 | 493 | ||
403 | if (p->interrupt_count == 0) | 494 | if (p->interrupt_count == 0) |
404 | return; | 495 | return; |
405 | irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL); | ||
406 | if (!irq) | ||
407 | return; | ||
408 | 496 | ||
497 | bitmap_zero(map.bits, PNP_IRQ_NR); | ||
409 | for (i = 0; i < p->interrupt_count; i++) | 498 | for (i = 0; i < p->interrupt_count; i++) |
410 | if (p->interrupts[i]) | 499 | if (p->interrupts[i]) |
411 | __set_bit(p->interrupts[i], irq->map); | 500 | __set_bit(p->interrupts[i], map.bits); |
412 | irq->flags = irq_flags(p->triggering, p->polarity, p->sharable); | ||
413 | 501 | ||
414 | pnp_register_irq_resource(dev, option, irq); | 502 | flags = irq_flags(p->triggering, p->polarity, p->sharable); |
503 | pnp_register_irq_resource(dev, option_flags, &map, flags); | ||
415 | } | 504 | } |
416 | 505 | ||
417 | static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, | 506 | static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, |
418 | struct pnp_option *option, | 507 | unsigned int option_flags, |
419 | struct acpi_resource_extended_irq *p) | 508 | struct acpi_resource_extended_irq *p) |
420 | { | 509 | { |
421 | int i; | 510 | int i; |
422 | struct pnp_irq *irq; | 511 | pnp_irq_mask_t map; |
512 | unsigned char flags; | ||
423 | 513 | ||
424 | if (p->interrupt_count == 0) | 514 | if (p->interrupt_count == 0) |
425 | return; | 515 | return; |
426 | irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL); | ||
427 | if (!irq) | ||
428 | return; | ||
429 | 516 | ||
430 | for (i = 0; i < p->interrupt_count; i++) | 517 | bitmap_zero(map.bits, PNP_IRQ_NR); |
431 | if (p->interrupts[i]) | 518 | for (i = 0; i < p->interrupt_count; i++) { |
432 | __set_bit(p->interrupts[i], irq->map); | 519 | if (p->interrupts[i]) { |
433 | irq->flags = irq_flags(p->triggering, p->polarity, p->sharable); | 520 | if (p->interrupts[i] < PNP_IRQ_NR) |
521 | __set_bit(p->interrupts[i], map.bits); | ||
522 | else | ||
523 | dev_err(&dev->dev, "ignoring IRQ %d option " | ||
524 | "(too large for %d entry bitmap)\n", | ||
525 | p->interrupts[i], PNP_IRQ_NR); | ||
526 | } | ||
527 | } | ||
434 | 528 | ||
435 | pnp_register_irq_resource(dev, option, irq); | 529 | flags = irq_flags(p->triggering, p->polarity, p->sharable); |
530 | pnp_register_irq_resource(dev, option_flags, &map, flags); | ||
436 | } | 531 | } |
437 | 532 | ||
438 | static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, | 533 | static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, |
439 | struct pnp_option *option, | 534 | unsigned int option_flags, |
440 | struct acpi_resource_io *io) | 535 | struct acpi_resource_io *io) |
441 | { | 536 | { |
442 | struct pnp_port *port; | 537 | unsigned char flags = 0; |
443 | 538 | ||
444 | if (io->address_length == 0) | 539 | if (io->address_length == 0) |
445 | return; | 540 | return; |
446 | port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); | 541 | |
447 | if (!port) | 542 | if (io->io_decode == ACPI_DECODE_16) |
448 | return; | 543 | flags = IORESOURCE_IO_16BIT_ADDR; |
449 | port->min = io->minimum; | 544 | pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, |
450 | port->max = io->maximum; | 545 | io->alignment, io->address_length, flags); |
451 | port->align = io->alignment; | ||
452 | port->size = io->address_length; | ||
453 | port->flags = ACPI_DECODE_16 == io->io_decode ? | ||
454 | PNP_PORT_FLAG_16BITADDR : 0; | ||
455 | pnp_register_port_resource(dev, option, port); | ||
456 | } | 546 | } |
457 | 547 | ||
458 | static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, | 548 | static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, |
459 | struct pnp_option *option, | 549 | unsigned int option_flags, |
460 | struct acpi_resource_fixed_io *io) | 550 | struct acpi_resource_fixed_io *io) |
461 | { | 551 | { |
462 | struct pnp_port *port; | ||
463 | |||
464 | if (io->address_length == 0) | 552 | if (io->address_length == 0) |
465 | return; | 553 | return; |
466 | port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); | 554 | |
467 | if (!port) | 555 | pnp_register_port_resource(dev, option_flags, io->address, io->address, |
468 | return; | 556 | 0, io->address_length, IORESOURCE_IO_FIXED); |
469 | port->min = port->max = io->address; | ||
470 | port->size = io->address_length; | ||
471 | port->align = 0; | ||
472 | port->flags = PNP_PORT_FLAG_FIXED; | ||
473 | pnp_register_port_resource(dev, option, port); | ||
474 | } | 557 | } |
475 | 558 | ||
476 | static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, | 559 | static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, |
477 | struct pnp_option *option, | 560 | unsigned int option_flags, |
478 | struct acpi_resource_memory24 *p) | 561 | struct acpi_resource_memory24 *p) |
479 | { | 562 | { |
480 | struct pnp_mem *mem; | 563 | unsigned char flags = 0; |
481 | 564 | ||
482 | if (p->address_length == 0) | 565 | if (p->address_length == 0) |
483 | return; | 566 | return; |
484 | mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); | ||
485 | if (!mem) | ||
486 | return; | ||
487 | mem->min = p->minimum; | ||
488 | mem->max = p->maximum; | ||
489 | mem->align = p->alignment; | ||
490 | mem->size = p->address_length; | ||
491 | |||
492 | mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ? | ||
493 | IORESOURCE_MEM_WRITEABLE : 0; | ||
494 | 567 | ||
495 | pnp_register_mem_resource(dev, option, mem); | 568 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
569 | flags = IORESOURCE_MEM_WRITEABLE; | ||
570 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, | ||
571 | p->alignment, p->address_length, flags); | ||
496 | } | 572 | } |
497 | 573 | ||
498 | static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, | 574 | static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, |
499 | struct pnp_option *option, | 575 | unsigned int option_flags, |
500 | struct acpi_resource_memory32 *p) | 576 | struct acpi_resource_memory32 *p) |
501 | { | 577 | { |
502 | struct pnp_mem *mem; | 578 | unsigned char flags = 0; |
503 | 579 | ||
504 | if (p->address_length == 0) | 580 | if (p->address_length == 0) |
505 | return; | 581 | return; |
506 | mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); | ||
507 | if (!mem) | ||
508 | return; | ||
509 | mem->min = p->minimum; | ||
510 | mem->max = p->maximum; | ||
511 | mem->align = p->alignment; | ||
512 | mem->size = p->address_length; | ||
513 | |||
514 | mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ? | ||
515 | IORESOURCE_MEM_WRITEABLE : 0; | ||
516 | 582 | ||
517 | pnp_register_mem_resource(dev, option, mem); | 583 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
584 | flags = IORESOURCE_MEM_WRITEABLE; | ||
585 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, | ||
586 | p->alignment, p->address_length, flags); | ||
518 | } | 587 | } |
519 | 588 | ||
520 | static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, | 589 | static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, |
521 | struct pnp_option *option, | 590 | unsigned int option_flags, |
522 | struct acpi_resource_fixed_memory32 *p) | 591 | struct acpi_resource_fixed_memory32 *p) |
523 | { | 592 | { |
524 | struct pnp_mem *mem; | 593 | unsigned char flags = 0; |
525 | 594 | ||
526 | if (p->address_length == 0) | 595 | if (p->address_length == 0) |
527 | return; | 596 | return; |
528 | mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); | ||
529 | if (!mem) | ||
530 | return; | ||
531 | mem->min = mem->max = p->address; | ||
532 | mem->size = p->address_length; | ||
533 | mem->align = 0; | ||
534 | |||
535 | mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ? | ||
536 | IORESOURCE_MEM_WRITEABLE : 0; | ||
537 | 597 | ||
538 | pnp_register_mem_resource(dev, option, mem); | 598 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
599 | flags = IORESOURCE_MEM_WRITEABLE; | ||
600 | pnp_register_mem_resource(dev, option_flags, p->address, p->address, | ||
601 | 0, p->address_length, flags); | ||
539 | } | 602 | } |
540 | 603 | ||
541 | static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, | 604 | static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, |
542 | struct pnp_option *option, | 605 | unsigned int option_flags, |
543 | struct acpi_resource *r) | 606 | struct acpi_resource *r) |
544 | { | 607 | { |
545 | struct acpi_resource_address64 addr, *p = &addr; | 608 | struct acpi_resource_address64 addr, *p = &addr; |
546 | acpi_status status; | 609 | acpi_status status; |
547 | struct pnp_mem *mem; | 610 | unsigned char flags = 0; |
548 | struct pnp_port *port; | ||
549 | 611 | ||
550 | status = acpi_resource_to_address64(r, p); | 612 | status = acpi_resource_to_address64(r, p); |
551 | if (!ACPI_SUCCESS(status)) { | 613 | if (!ACPI_SUCCESS(status)) { |
@@ -558,49 +620,37 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, | |||
558 | return; | 620 | return; |
559 | 621 | ||
560 | if (p->resource_type == ACPI_MEMORY_RANGE) { | 622 | if (p->resource_type == ACPI_MEMORY_RANGE) { |
561 | mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); | 623 | if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) |
562 | if (!mem) | 624 | flags = IORESOURCE_MEM_WRITEABLE; |
563 | return; | 625 | pnp_register_mem_resource(dev, option_flags, p->minimum, |
564 | mem->min = mem->max = p->minimum; | 626 | p->minimum, 0, p->address_length, |
565 | mem->size = p->address_length; | 627 | flags); |
566 | mem->align = 0; | 628 | } else if (p->resource_type == ACPI_IO_RANGE) |
567 | mem->flags = (p->info.mem.write_protect == | 629 | pnp_register_port_resource(dev, option_flags, p->minimum, |
568 | ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE | 630 | p->minimum, 0, p->address_length, |
569 | : 0; | 631 | IORESOURCE_IO_FIXED); |
570 | pnp_register_mem_resource(dev, option, mem); | ||
571 | } else if (p->resource_type == ACPI_IO_RANGE) { | ||
572 | port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); | ||
573 | if (!port) | ||
574 | return; | ||
575 | port->min = port->max = p->minimum; | ||
576 | port->size = p->address_length; | ||
577 | port->align = 0; | ||
578 | port->flags = PNP_PORT_FLAG_FIXED; | ||
579 | pnp_register_port_resource(dev, option, port); | ||
580 | } | ||
581 | } | 632 | } |
582 | 633 | ||
583 | struct acpipnp_parse_option_s { | 634 | struct acpipnp_parse_option_s { |
584 | struct pnp_option *option; | ||
585 | struct pnp_option *option_independent; | ||
586 | struct pnp_dev *dev; | 635 | struct pnp_dev *dev; |
636 | unsigned int option_flags; | ||
587 | }; | 637 | }; |
588 | 638 | ||
589 | static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, | 639 | static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, |
590 | void *data) | 640 | void *data) |
591 | { | 641 | { |
592 | int priority = 0; | 642 | int priority; |
593 | struct acpipnp_parse_option_s *parse_data = data; | 643 | struct acpipnp_parse_option_s *parse_data = data; |
594 | struct pnp_dev *dev = parse_data->dev; | 644 | struct pnp_dev *dev = parse_data->dev; |
595 | struct pnp_option *option = parse_data->option; | 645 | unsigned int option_flags = parse_data->option_flags; |
596 | 646 | ||
597 | switch (res->type) { | 647 | switch (res->type) { |
598 | case ACPI_RESOURCE_TYPE_IRQ: | 648 | case ACPI_RESOURCE_TYPE_IRQ: |
599 | pnpacpi_parse_irq_option(dev, option, &res->data.irq); | 649 | pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq); |
600 | break; | 650 | break; |
601 | 651 | ||
602 | case ACPI_RESOURCE_TYPE_DMA: | 652 | case ACPI_RESOURCE_TYPE_DMA: |
603 | pnpacpi_parse_dma_option(dev, option, &res->data.dma); | 653 | pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma); |
604 | break; | 654 | break; |
605 | 655 | ||
606 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: | 656 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
@@ -620,31 +670,19 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, | |||
620 | priority = PNP_RES_PRIORITY_INVALID; | 670 | priority = PNP_RES_PRIORITY_INVALID; |
621 | break; | 671 | break; |
622 | } | 672 | } |
623 | /* TBD: Consider performance/robustness bits */ | 673 | parse_data->option_flags = pnp_new_dependent_set(dev, priority); |
624 | option = pnp_register_dependent_option(dev, priority); | ||
625 | if (!option) | ||
626 | return AE_ERROR; | ||
627 | parse_data->option = option; | ||
628 | break; | 674 | break; |
629 | 675 | ||
630 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: | 676 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: |
631 | /*only one EndDependentFn is allowed */ | 677 | parse_data->option_flags = 0; |
632 | if (!parse_data->option_independent) { | ||
633 | dev_warn(&dev->dev, "more than one EndDependentFn " | ||
634 | "in _PRS\n"); | ||
635 | return AE_ERROR; | ||
636 | } | ||
637 | parse_data->option = parse_data->option_independent; | ||
638 | parse_data->option_independent = NULL; | ||
639 | dev_dbg(&dev->dev, "end dependent options\n"); | ||
640 | break; | 678 | break; |
641 | 679 | ||
642 | case ACPI_RESOURCE_TYPE_IO: | 680 | case ACPI_RESOURCE_TYPE_IO: |
643 | pnpacpi_parse_port_option(dev, option, &res->data.io); | 681 | pnpacpi_parse_port_option(dev, option_flags, &res->data.io); |
644 | break; | 682 | break; |
645 | 683 | ||
646 | case ACPI_RESOURCE_TYPE_FIXED_IO: | 684 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
647 | pnpacpi_parse_fixed_port_option(dev, option, | 685 | pnpacpi_parse_fixed_port_option(dev, option_flags, |
648 | &res->data.fixed_io); | 686 | &res->data.fixed_io); |
649 | break; | 687 | break; |
650 | 688 | ||
@@ -653,29 +691,31 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, | |||
653 | break; | 691 | break; |
654 | 692 | ||
655 | case ACPI_RESOURCE_TYPE_MEMORY24: | 693 | case ACPI_RESOURCE_TYPE_MEMORY24: |
656 | pnpacpi_parse_mem24_option(dev, option, &res->data.memory24); | 694 | pnpacpi_parse_mem24_option(dev, option_flags, |
695 | &res->data.memory24); | ||
657 | break; | 696 | break; |
658 | 697 | ||
659 | case ACPI_RESOURCE_TYPE_MEMORY32: | 698 | case ACPI_RESOURCE_TYPE_MEMORY32: |
660 | pnpacpi_parse_mem32_option(dev, option, &res->data.memory32); | 699 | pnpacpi_parse_mem32_option(dev, option_flags, |
700 | &res->data.memory32); | ||
661 | break; | 701 | break; |
662 | 702 | ||
663 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | 703 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
664 | pnpacpi_parse_fixed_mem32_option(dev, option, | 704 | pnpacpi_parse_fixed_mem32_option(dev, option_flags, |
665 | &res->data.fixed_memory32); | 705 | &res->data.fixed_memory32); |
666 | break; | 706 | break; |
667 | 707 | ||
668 | case ACPI_RESOURCE_TYPE_ADDRESS16: | 708 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
669 | case ACPI_RESOURCE_TYPE_ADDRESS32: | 709 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
670 | case ACPI_RESOURCE_TYPE_ADDRESS64: | 710 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
671 | pnpacpi_parse_address_option(dev, option, res); | 711 | pnpacpi_parse_address_option(dev, option_flags, res); |
672 | break; | 712 | break; |
673 | 713 | ||
674 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: | 714 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: |
675 | break; | 715 | break; |
676 | 716 | ||
677 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: | 717 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
678 | pnpacpi_parse_ext_irq_option(dev, option, | 718 | pnpacpi_parse_ext_irq_option(dev, option_flags, |
679 | &res->data.extended_irq); | 719 | &res->data.extended_irq); |
680 | break; | 720 | break; |
681 | 721 | ||
@@ -699,12 +739,9 @@ int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) | |||
699 | 739 | ||
700 | dev_dbg(&dev->dev, "parse resource options\n"); | 740 | dev_dbg(&dev->dev, "parse resource options\n"); |
701 | 741 | ||
702 | parse_data.option = pnp_register_independent_option(dev); | ||
703 | if (!parse_data.option) | ||
704 | return -ENOMEM; | ||
705 | |||
706 | parse_data.option_independent = parse_data.option; | ||
707 | parse_data.dev = dev; | 742 | parse_data.dev = dev; |
743 | parse_data.option_flags = 0; | ||
744 | |||
708 | status = acpi_walk_resources(handle, METHOD_NAME__PRS, | 745 | status = acpi_walk_resources(handle, METHOD_NAME__PRS, |
709 | pnpacpi_option_resource, &parse_data); | 746 | pnpacpi_option_resource, &parse_data); |
710 | 747 | ||
@@ -806,6 +843,13 @@ static void pnpacpi_encode_irq(struct pnp_dev *dev, | |||
806 | struct acpi_resource_irq *irq = &resource->data.irq; | 843 | struct acpi_resource_irq *irq = &resource->data.irq; |
807 | int triggering, polarity, shareable; | 844 | int triggering, polarity, shareable; |
808 | 845 | ||
846 | if (!pnp_resource_enabled(p)) { | ||
847 | irq->interrupt_count = 0; | ||
848 | dev_dbg(&dev->dev, " encode irq (%s)\n", | ||
849 | p ? "disabled" : "missing"); | ||
850 | return; | ||
851 | } | ||
852 | |||
809 | decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); | 853 | decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); |
810 | irq->triggering = triggering; | 854 | irq->triggering = triggering; |
811 | irq->polarity = polarity; | 855 | irq->polarity = polarity; |
@@ -828,6 +872,13 @@ static void pnpacpi_encode_ext_irq(struct pnp_dev *dev, | |||
828 | struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq; | 872 | struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq; |
829 | int triggering, polarity, shareable; | 873 | int triggering, polarity, shareable; |
830 | 874 | ||
875 | if (!pnp_resource_enabled(p)) { | ||
876 | extended_irq->interrupt_count = 0; | ||
877 | dev_dbg(&dev->dev, " encode extended irq (%s)\n", | ||
878 | p ? "disabled" : "missing"); | ||
879 | return; | ||
880 | } | ||
881 | |||
831 | decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); | 882 | decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); |
832 | extended_irq->producer_consumer = ACPI_CONSUMER; | 883 | extended_irq->producer_consumer = ACPI_CONSUMER; |
833 | extended_irq->triggering = triggering; | 884 | extended_irq->triggering = triggering; |
@@ -848,6 +899,13 @@ static void pnpacpi_encode_dma(struct pnp_dev *dev, | |||
848 | { | 899 | { |
849 | struct acpi_resource_dma *dma = &resource->data.dma; | 900 | struct acpi_resource_dma *dma = &resource->data.dma; |
850 | 901 | ||
902 | if (!pnp_resource_enabled(p)) { | ||
903 | dma->channel_count = 0; | ||
904 | dev_dbg(&dev->dev, " encode dma (%s)\n", | ||
905 | p ? "disabled" : "missing"); | ||
906 | return; | ||
907 | } | ||
908 | |||
851 | /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */ | 909 | /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */ |
852 | switch (p->flags & IORESOURCE_DMA_SPEED_MASK) { | 910 | switch (p->flags & IORESOURCE_DMA_SPEED_MASK) { |
853 | case IORESOURCE_DMA_TYPEA: | 911 | case IORESOURCE_DMA_TYPEA: |
@@ -889,17 +947,21 @@ static void pnpacpi_encode_io(struct pnp_dev *dev, | |||
889 | { | 947 | { |
890 | struct acpi_resource_io *io = &resource->data.io; | 948 | struct acpi_resource_io *io = &resource->data.io; |
891 | 949 | ||
892 | /* Note: pnp_assign_port will copy pnp_port->flags into p->flags */ | 950 | if (pnp_resource_enabled(p)) { |
893 | io->io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ? | 951 | /* Note: pnp_assign_port copies pnp_port->flags into p->flags */ |
894 | ACPI_DECODE_16 : ACPI_DECODE_10; | 952 | io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ? |
895 | io->minimum = p->start; | 953 | ACPI_DECODE_16 : ACPI_DECODE_10; |
896 | io->maximum = p->end; | 954 | io->minimum = p->start; |
897 | io->alignment = 0; /* Correct? */ | 955 | io->maximum = p->end; |
898 | io->address_length = p->end - p->start + 1; | 956 | io->alignment = 0; /* Correct? */ |
899 | 957 | io->address_length = p->end - p->start + 1; | |
900 | dev_dbg(&dev->dev, " encode io %#llx-%#llx decode %#x\n", | 958 | } else { |
901 | (unsigned long long) p->start, (unsigned long long) p->end, | 959 | io->minimum = 0; |
902 | io->io_decode); | 960 | io->address_length = 0; |
961 | } | ||
962 | |||
963 | dev_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum, | ||
964 | io->minimum + io->address_length - 1, io->io_decode); | ||
903 | } | 965 | } |
904 | 966 | ||
905 | static void pnpacpi_encode_fixed_io(struct pnp_dev *dev, | 967 | static void pnpacpi_encode_fixed_io(struct pnp_dev *dev, |
@@ -908,11 +970,16 @@ static void pnpacpi_encode_fixed_io(struct pnp_dev *dev, | |||
908 | { | 970 | { |
909 | struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io; | 971 | struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io; |
910 | 972 | ||
911 | fixed_io->address = p->start; | 973 | if (pnp_resource_enabled(p)) { |
912 | fixed_io->address_length = p->end - p->start + 1; | 974 | fixed_io->address = p->start; |
975 | fixed_io->address_length = p->end - p->start + 1; | ||
976 | } else { | ||
977 | fixed_io->address = 0; | ||
978 | fixed_io->address_length = 0; | ||
979 | } | ||
913 | 980 | ||
914 | dev_dbg(&dev->dev, " encode fixed_io %#llx-%#llx\n", | 981 | dev_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address, |
915 | (unsigned long long) p->start, (unsigned long long) p->end); | 982 | fixed_io->address + fixed_io->address_length - 1); |
916 | } | 983 | } |
917 | 984 | ||
918 | static void pnpacpi_encode_mem24(struct pnp_dev *dev, | 985 | static void pnpacpi_encode_mem24(struct pnp_dev *dev, |
@@ -921,17 +988,22 @@ static void pnpacpi_encode_mem24(struct pnp_dev *dev, | |||
921 | { | 988 | { |
922 | struct acpi_resource_memory24 *memory24 = &resource->data.memory24; | 989 | struct acpi_resource_memory24 *memory24 = &resource->data.memory24; |
923 | 990 | ||
924 | /* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */ | 991 | if (pnp_resource_enabled(p)) { |
925 | memory24->write_protect = | 992 | /* Note: pnp_assign_mem copies pnp_mem->flags into p->flags */ |
926 | (p->flags & IORESOURCE_MEM_WRITEABLE) ? | 993 | memory24->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ? |
927 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; | 994 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; |
928 | memory24->minimum = p->start; | 995 | memory24->minimum = p->start; |
929 | memory24->maximum = p->end; | 996 | memory24->maximum = p->end; |
930 | memory24->alignment = 0; | 997 | memory24->alignment = 0; |
931 | memory24->address_length = p->end - p->start + 1; | 998 | memory24->address_length = p->end - p->start + 1; |
932 | 999 | } else { | |
933 | dev_dbg(&dev->dev, " encode mem24 %#llx-%#llx write_protect %#x\n", | 1000 | memory24->minimum = 0; |
934 | (unsigned long long) p->start, (unsigned long long) p->end, | 1001 | memory24->address_length = 0; |
1002 | } | ||
1003 | |||
1004 | dev_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n", | ||
1005 | memory24->minimum, | ||
1006 | memory24->minimum + memory24->address_length - 1, | ||
935 | memory24->write_protect); | 1007 | memory24->write_protect); |
936 | } | 1008 | } |
937 | 1009 | ||
@@ -941,16 +1013,21 @@ static void pnpacpi_encode_mem32(struct pnp_dev *dev, | |||
941 | { | 1013 | { |
942 | struct acpi_resource_memory32 *memory32 = &resource->data.memory32; | 1014 | struct acpi_resource_memory32 *memory32 = &resource->data.memory32; |
943 | 1015 | ||
944 | memory32->write_protect = | 1016 | if (pnp_resource_enabled(p)) { |
945 | (p->flags & IORESOURCE_MEM_WRITEABLE) ? | 1017 | memory32->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ? |
946 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; | 1018 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; |
947 | memory32->minimum = p->start; | 1019 | memory32->minimum = p->start; |
948 | memory32->maximum = p->end; | 1020 | memory32->maximum = p->end; |
949 | memory32->alignment = 0; | 1021 | memory32->alignment = 0; |
950 | memory32->address_length = p->end - p->start + 1; | 1022 | memory32->address_length = p->end - p->start + 1; |
1023 | } else { | ||
1024 | memory32->minimum = 0; | ||
1025 | memory32->alignment = 0; | ||
1026 | } | ||
951 | 1027 | ||
952 | dev_dbg(&dev->dev, " encode mem32 %#llx-%#llx write_protect %#x\n", | 1028 | dev_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n", |
953 | (unsigned long long) p->start, (unsigned long long) p->end, | 1029 | memory32->minimum, |
1030 | memory32->minimum + memory32->address_length - 1, | ||
954 | memory32->write_protect); | 1031 | memory32->write_protect); |
955 | } | 1032 | } |
956 | 1033 | ||
@@ -960,15 +1037,20 @@ static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev, | |||
960 | { | 1037 | { |
961 | struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32; | 1038 | struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32; |
962 | 1039 | ||
963 | fixed_memory32->write_protect = | 1040 | if (pnp_resource_enabled(p)) { |
964 | (p->flags & IORESOURCE_MEM_WRITEABLE) ? | 1041 | fixed_memory32->write_protect = |
965 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; | 1042 | p->flags & IORESOURCE_MEM_WRITEABLE ? |
966 | fixed_memory32->address = p->start; | 1043 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; |
967 | fixed_memory32->address_length = p->end - p->start + 1; | 1044 | fixed_memory32->address = p->start; |
1045 | fixed_memory32->address_length = p->end - p->start + 1; | ||
1046 | } else { | ||
1047 | fixed_memory32->address = 0; | ||
1048 | fixed_memory32->address_length = 0; | ||
1049 | } | ||
968 | 1050 | ||
969 | dev_dbg(&dev->dev, " encode fixed_mem32 %#llx-%#llx " | 1051 | dev_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n", |
970 | "write_protect %#x\n", | 1052 | fixed_memory32->address, |
971 | (unsigned long long) p->start, (unsigned long long) p->end, | 1053 | fixed_memory32->address + fixed_memory32->address_length - 1, |
972 | fixed_memory32->write_protect); | 1054 | fixed_memory32->write_protect); |
973 | } | 1055 | } |
974 | 1056 | ||