diff options
Diffstat (limited to 'drivers/pnp/pnpacpi/rsparser.c')
-rw-r--r-- | drivers/pnp/pnpacpi/rsparser.c | 296 |
1 files changed, 32 insertions, 264 deletions
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 5be4a392a3ae..b8f4ea7b27fc 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c | |||
@@ -28,37 +28,6 @@ | |||
28 | #include "../base.h" | 28 | #include "../base.h" |
29 | #include "pnpacpi.h" | 29 | #include "pnpacpi.h" |
30 | 30 | ||
31 | #ifdef CONFIG_IA64 | ||
32 | #define valid_IRQ(i) (1) | ||
33 | #else | ||
34 | #define valid_IRQ(i) (((i) != 0) && ((i) != 2)) | ||
35 | #endif | ||
36 | |||
37 | /* | ||
38 | * Allocated Resources | ||
39 | */ | ||
40 | static int irq_flags(int triggering, int polarity, int shareable) | ||
41 | { | ||
42 | int flags; | ||
43 | |||
44 | if (triggering == ACPI_LEVEL_SENSITIVE) { | ||
45 | if (polarity == ACPI_ACTIVE_LOW) | ||
46 | flags = IORESOURCE_IRQ_LOWLEVEL; | ||
47 | else | ||
48 | flags = IORESOURCE_IRQ_HIGHLEVEL; | ||
49 | } else { | ||
50 | if (polarity == ACPI_ACTIVE_LOW) | ||
51 | flags = IORESOURCE_IRQ_LOWEDGE; | ||
52 | else | ||
53 | flags = IORESOURCE_IRQ_HIGHEDGE; | ||
54 | } | ||
55 | |||
56 | if (shareable == ACPI_SHARED) | ||
57 | flags |= IORESOURCE_IRQ_SHAREABLE; | ||
58 | |||
59 | return flags; | ||
60 | } | ||
61 | |||
62 | static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, | 31 | static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, |
63 | int *polarity, int *shareable) | 32 | int *polarity, int *shareable) |
64 | { | 33 | { |
@@ -94,45 +63,6 @@ static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, | |||
94 | *shareable = ACPI_EXCLUSIVE; | 63 | *shareable = ACPI_EXCLUSIVE; |
95 | } | 64 | } |
96 | 65 | ||
97 | static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev, | ||
98 | u32 gsi, int triggering, | ||
99 | int polarity, int shareable) | ||
100 | { | ||
101 | int irq, flags; | ||
102 | int p, t; | ||
103 | |||
104 | if (!valid_IRQ(gsi)) { | ||
105 | pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED); | ||
106 | return; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * in IO-APIC mode, use overrided attribute. Two reasons: | ||
111 | * 1. BIOS bug in DSDT | ||
112 | * 2. BIOS uses IO-APIC mode Interrupt Source Override | ||
113 | */ | ||
114 | if (!acpi_get_override_irq(gsi, &t, &p)) { | ||
115 | t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; | ||
116 | p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; | ||
117 | |||
118 | if (triggering != t || polarity != p) { | ||
119 | dev_warn(&dev->dev, "IRQ %d override to %s, %s\n", | ||
120 | gsi, t ? "edge":"level", p ? "low":"high"); | ||
121 | triggering = t; | ||
122 | polarity = p; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | flags = irq_flags(triggering, polarity, shareable); | ||
127 | irq = acpi_register_gsi(&dev->dev, gsi, triggering, polarity); | ||
128 | if (irq >= 0) | ||
129 | pcibios_penalize_isa_irq(irq, 1); | ||
130 | else | ||
131 | flags |= IORESOURCE_DISABLED; | ||
132 | |||
133 | pnp_add_irq_resource(dev, irq, flags); | ||
134 | } | ||
135 | |||
136 | static int dma_flags(struct pnp_dev *dev, int type, int bus_master, | 66 | static int dma_flags(struct pnp_dev *dev, int type, int bus_master, |
137 | int transfer) | 67 | int transfer) |
138 | { | 68 | { |
@@ -177,21 +107,16 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master, | |||
177 | return flags; | 107 | return flags; |
178 | } | 108 | } |
179 | 109 | ||
180 | static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, | 110 | /* |
181 | u64 len, int io_decode, | 111 | * Allocated Resources |
182 | int window) | 112 | */ |
183 | { | ||
184 | int flags = 0; | ||
185 | u64 end = start + len - 1; | ||
186 | 113 | ||
187 | if (io_decode == ACPI_DECODE_16) | 114 | static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r) |
188 | flags |= IORESOURCE_IO_16BIT_ADDR; | 115 | { |
189 | if (len == 0 || end >= 0x10003) | 116 | if (!(r->flags & IORESOURCE_DISABLED)) |
190 | flags |= IORESOURCE_DISABLED; | 117 | pcibios_penalize_isa_irq(r->start, 1); |
191 | if (window) | ||
192 | flags |= IORESOURCE_WINDOW; | ||
193 | 118 | ||
194 | pnp_add_io_resource(dev, start, end, flags); | 119 | pnp_add_resource(dev, r); |
195 | } | 120 | } |
196 | 121 | ||
197 | /* | 122 | /* |
@@ -249,130 +174,49 @@ static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev, | |||
249 | } | 174 | } |
250 | } | 175 | } |
251 | 176 | ||
252 | static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, | ||
253 | u64 start, u64 len, | ||
254 | int write_protect, int window) | ||
255 | { | ||
256 | int flags = 0; | ||
257 | u64 end = start + len - 1; | ||
258 | |||
259 | if (len == 0) | ||
260 | flags |= IORESOURCE_DISABLED; | ||
261 | if (write_protect == ACPI_READ_WRITE_MEMORY) | ||
262 | flags |= IORESOURCE_MEM_WRITEABLE; | ||
263 | if (window) | ||
264 | flags |= IORESOURCE_WINDOW; | ||
265 | |||
266 | pnp_add_mem_resource(dev, start, end, flags); | ||
267 | } | ||
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 void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, | ||
278 | struct acpi_resource *res) | ||
279 | { | ||
280 | struct acpi_resource_address64 addr, *p = &addr; | ||
281 | acpi_status status; | ||
282 | int window; | ||
283 | u64 len; | ||
284 | |||
285 | status = acpi_resource_to_address64(res, p); | ||
286 | if (!ACPI_SUCCESS(status)) { | ||
287 | dev_warn(&dev->dev, "failed to convert resource type %d\n", | ||
288 | res->type); | ||
289 | return; | ||
290 | } | ||
291 | |||
292 | /* Windows apparently computes length rather than using _LEN */ | ||
293 | len = p->maximum - p->minimum + 1; | ||
294 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; | ||
295 | |||
296 | if (p->resource_type == ACPI_MEMORY_RANGE) | ||
297 | pnpacpi_parse_allocated_memresource(dev, p->minimum, len, | ||
298 | p->info.mem.write_protect, window); | ||
299 | else if (p->resource_type == ACPI_IO_RANGE) | ||
300 | pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, | ||
301 | p->granularity == 0xfff ? ACPI_DECODE_10 : | ||
302 | ACPI_DECODE_16, window); | ||
303 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) | ||
304 | pnpacpi_parse_allocated_busresource(dev, p->minimum, len); | ||
305 | } | ||
306 | |||
307 | static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev, | ||
308 | struct acpi_resource *res) | ||
309 | { | ||
310 | struct acpi_resource_extended_address64 *p = &res->data.ext_address64; | ||
311 | int window; | ||
312 | u64 len; | ||
313 | |||
314 | /* Windows apparently computes length rather than using _LEN */ | ||
315 | len = p->maximum - p->minimum + 1; | ||
316 | window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; | ||
317 | |||
318 | if (p->resource_type == ACPI_MEMORY_RANGE) | ||
319 | pnpacpi_parse_allocated_memresource(dev, p->minimum, len, | ||
320 | p->info.mem.write_protect, window); | ||
321 | else if (p->resource_type == ACPI_IO_RANGE) | ||
322 | pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, | ||
323 | p->granularity == 0xfff ? ACPI_DECODE_10 : | ||
324 | ACPI_DECODE_16, window); | ||
325 | else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) | ||
326 | pnpacpi_parse_allocated_busresource(dev, p->minimum, len); | ||
327 | } | ||
328 | |||
329 | static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | 177 | static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, |
330 | void *data) | 178 | void *data) |
331 | { | 179 | { |
332 | struct pnp_dev *dev = data; | 180 | struct pnp_dev *dev = data; |
333 | struct acpi_resource_irq *irq; | ||
334 | struct acpi_resource_dma *dma; | 181 | struct acpi_resource_dma *dma; |
335 | struct acpi_resource_io *io; | ||
336 | struct acpi_resource_fixed_io *fixed_io; | ||
337 | struct acpi_resource_vendor_typed *vendor_typed; | 182 | struct acpi_resource_vendor_typed *vendor_typed; |
338 | struct acpi_resource_memory24 *memory24; | 183 | struct resource r; |
339 | struct acpi_resource_memory32 *memory32; | ||
340 | struct acpi_resource_fixed_memory32 *fixed_memory32; | ||
341 | struct acpi_resource_extended_irq *extended_irq; | ||
342 | int i, flags; | 184 | int i, flags; |
343 | 185 | ||
344 | switch (res->type) { | 186 | if (acpi_dev_resource_memory(res, &r) |
345 | case ACPI_RESOURCE_TYPE_IRQ: | 187 | || acpi_dev_resource_io(res, &r) |
346 | /* | 188 | || acpi_dev_resource_address_space(res, &r) |
347 | * Per spec, only one interrupt per descriptor is allowed in | 189 | || acpi_dev_resource_ext_address_space(res, &r)) { |
348 | * _CRS, but some firmware violates this, so parse them all. | 190 | pnp_add_resource(dev, &r); |
349 | */ | 191 | return AE_OK; |
350 | irq = &res->data.irq; | 192 | } |
351 | if (irq->interrupt_count == 0) | ||
352 | pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); | ||
353 | else { | ||
354 | for (i = 0; i < irq->interrupt_count; i++) { | ||
355 | pnpacpi_parse_allocated_irqresource(dev, | ||
356 | irq->interrupts[i], | ||
357 | irq->triggering, | ||
358 | irq->polarity, | ||
359 | irq->sharable); | ||
360 | } | ||
361 | 193 | ||
194 | r.flags = 0; | ||
195 | if (acpi_dev_resource_interrupt(res, 0, &r)) { | ||
196 | pnpacpi_add_irqresource(dev, &r); | ||
197 | for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++) | ||
198 | pnpacpi_add_irqresource(dev, &r); | ||
199 | |||
200 | if (i > 1) { | ||
362 | /* | 201 | /* |
363 | * The IRQ encoder puts a single interrupt in each | 202 | * The IRQ encoder puts a single interrupt in each |
364 | * descriptor, so if a _CRS descriptor has more than | 203 | * descriptor, so if a _CRS descriptor has more than |
365 | * one interrupt, we won't be able to re-encode it. | 204 | * one interrupt, we won't be able to re-encode it. |
366 | */ | 205 | */ |
367 | if (pnp_can_write(dev) && irq->interrupt_count > 1) { | 206 | if (pnp_can_write(dev)) { |
368 | dev_warn(&dev->dev, "multiple interrupts in " | 207 | dev_warn(&dev->dev, "multiple interrupts in " |
369 | "_CRS descriptor; configuration can't " | 208 | "_CRS descriptor; configuration can't " |
370 | "be changed\n"); | 209 | "be changed\n"); |
371 | dev->capabilities &= ~PNP_WRITE; | 210 | dev->capabilities &= ~PNP_WRITE; |
372 | } | 211 | } |
373 | } | 212 | } |
374 | break; | 213 | return AE_OK; |
214 | } else if (r.flags & IORESOURCE_DISABLED) { | ||
215 | pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); | ||
216 | return AE_OK; | ||
217 | } | ||
375 | 218 | ||
219 | switch (res->type) { | ||
376 | case ACPI_RESOURCE_TYPE_DMA: | 220 | case ACPI_RESOURCE_TYPE_DMA: |
377 | dma = &res->data.dma; | 221 | dma = &res->data.dma; |
378 | if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) | 222 | if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) |
@@ -383,26 +227,10 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
383 | pnp_add_dma_resource(dev, dma->channels[0], flags); | 227 | pnp_add_dma_resource(dev, dma->channels[0], flags); |
384 | break; | 228 | break; |
385 | 229 | ||
386 | case ACPI_RESOURCE_TYPE_IO: | ||
387 | io = &res->data.io; | ||
388 | pnpacpi_parse_allocated_ioresource(dev, | ||
389 | io->minimum, | ||
390 | io->address_length, | ||
391 | io->io_decode, 0); | ||
392 | break; | ||
393 | |||
394 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: | 230 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
395 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: | 231 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: |
396 | break; | 232 | break; |
397 | 233 | ||
398 | case ACPI_RESOURCE_TYPE_FIXED_IO: | ||
399 | fixed_io = &res->data.fixed_io; | ||
400 | pnpacpi_parse_allocated_ioresource(dev, | ||
401 | fixed_io->address, | ||
402 | fixed_io->address_length, | ||
403 | ACPI_DECODE_10, 0); | ||
404 | break; | ||
405 | |||
406 | case ACPI_RESOURCE_TYPE_VENDOR: | 234 | case ACPI_RESOURCE_TYPE_VENDOR: |
407 | vendor_typed = &res->data.vendor_typed; | 235 | vendor_typed = &res->data.vendor_typed; |
408 | pnpacpi_parse_allocated_vendor(dev, vendor_typed); | 236 | pnpacpi_parse_allocated_vendor(dev, vendor_typed); |
@@ -411,66 +239,6 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
411 | case ACPI_RESOURCE_TYPE_END_TAG: | 239 | case ACPI_RESOURCE_TYPE_END_TAG: |
412 | break; | 240 | break; |
413 | 241 | ||
414 | case ACPI_RESOURCE_TYPE_MEMORY24: | ||
415 | memory24 = &res->data.memory24; | ||
416 | pnpacpi_parse_allocated_memresource(dev, | ||
417 | memory24->minimum, | ||
418 | memory24->address_length, | ||
419 | memory24->write_protect, 0); | ||
420 | break; | ||
421 | case ACPI_RESOURCE_TYPE_MEMORY32: | ||
422 | memory32 = &res->data.memory32; | ||
423 | pnpacpi_parse_allocated_memresource(dev, | ||
424 | memory32->minimum, | ||
425 | memory32->address_length, | ||
426 | memory32->write_protect, 0); | ||
427 | break; | ||
428 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | ||
429 | fixed_memory32 = &res->data.fixed_memory32; | ||
430 | pnpacpi_parse_allocated_memresource(dev, | ||
431 | fixed_memory32->address, | ||
432 | fixed_memory32->address_length, | ||
433 | fixed_memory32->write_protect, 0); | ||
434 | break; | ||
435 | case ACPI_RESOURCE_TYPE_ADDRESS16: | ||
436 | case ACPI_RESOURCE_TYPE_ADDRESS32: | ||
437 | case ACPI_RESOURCE_TYPE_ADDRESS64: | ||
438 | pnpacpi_parse_allocated_address_space(dev, res); | ||
439 | break; | ||
440 | |||
441 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: | ||
442 | pnpacpi_parse_allocated_ext_address_space(dev, res); | ||
443 | break; | ||
444 | |||
445 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: | ||
446 | extended_irq = &res->data.extended_irq; | ||
447 | |||
448 | if (extended_irq->interrupt_count == 0) | ||
449 | pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); | ||
450 | else { | ||
451 | for (i = 0; i < extended_irq->interrupt_count; i++) { | ||
452 | pnpacpi_parse_allocated_irqresource(dev, | ||
453 | extended_irq->interrupts[i], | ||
454 | extended_irq->triggering, | ||
455 | extended_irq->polarity, | ||
456 | extended_irq->sharable); | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * The IRQ encoder puts a single interrupt in each | ||
461 | * descriptor, so if a _CRS descriptor has more than | ||
462 | * one interrupt, we won't be able to re-encode it. | ||
463 | */ | ||
464 | if (pnp_can_write(dev) && | ||
465 | extended_irq->interrupt_count > 1) { | ||
466 | dev_warn(&dev->dev, "multiple interrupts in " | ||
467 | "_CRS descriptor; configuration can't " | ||
468 | "be changed\n"); | ||
469 | dev->capabilities &= ~PNP_WRITE; | ||
470 | } | ||
471 | } | ||
472 | break; | ||
473 | |||
474 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: | 242 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: |
475 | break; | 243 | break; |
476 | 244 | ||
@@ -531,7 +299,7 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, | |||
531 | if (p->interrupts[i]) | 299 | if (p->interrupts[i]) |
532 | __set_bit(p->interrupts[i], map.bits); | 300 | __set_bit(p->interrupts[i], map.bits); |
533 | 301 | ||
534 | flags = irq_flags(p->triggering, p->polarity, p->sharable); | 302 | flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable); |
535 | pnp_register_irq_resource(dev, option_flags, &map, flags); | 303 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
536 | } | 304 | } |
537 | 305 | ||
@@ -555,7 +323,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, | |||
555 | } | 323 | } |
556 | } | 324 | } |
557 | 325 | ||
558 | flags = irq_flags(p->triggering, p->polarity, p->sharable); | 326 | flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable); |
559 | pnp_register_irq_resource(dev, option_flags, &map, flags); | 327 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
560 | } | 328 | } |
561 | 329 | ||