diff options
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r-- | drivers/acpi/osl.c | 621 |
1 files changed, 397 insertions, 224 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 65b25a303b86..372f9b70f7f4 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/workqueue.h> | 38 | #include <linux/workqueue.h> |
39 | #include <linux/nmi.h> | 39 | #include <linux/nmi.h> |
40 | #include <linux/acpi.h> | 40 | #include <linux/acpi.h> |
41 | #include <linux/acpi_io.h> | ||
41 | #include <linux/efi.h> | 42 | #include <linux/efi.h> |
42 | #include <linux/ioport.h> | 43 | #include <linux/ioport.h> |
43 | #include <linux/list.h> | 44 | #include <linux/list.h> |
@@ -75,7 +76,6 @@ EXPORT_SYMBOL(acpi_in_debugger); | |||
75 | extern char line_buf[80]; | 76 | extern char line_buf[80]; |
76 | #endif /*ENABLE_DEBUGGER */ | 77 | #endif /*ENABLE_DEBUGGER */ |
77 | 78 | ||
78 | static unsigned int acpi_irq_irq; | ||
79 | static acpi_osd_handler acpi_irq_handler; | 79 | static acpi_osd_handler acpi_irq_handler; |
80 | static void *acpi_irq_context; | 80 | static void *acpi_irq_context; |
81 | static struct workqueue_struct *kacpid_wq; | 81 | static struct workqueue_struct *kacpid_wq; |
@@ -95,8 +95,22 @@ struct acpi_res_list { | |||
95 | static LIST_HEAD(resource_list_head); | 95 | static LIST_HEAD(resource_list_head); |
96 | static DEFINE_SPINLOCK(acpi_res_lock); | 96 | static DEFINE_SPINLOCK(acpi_res_lock); |
97 | 97 | ||
98 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ | 98 | /* |
99 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; | 99 | * This list of permanent mappings is for memory that may be accessed from |
100 | * interrupt context, where we can't do the ioremap(). | ||
101 | */ | ||
102 | struct acpi_ioremap { | ||
103 | struct list_head list; | ||
104 | void __iomem *virt; | ||
105 | acpi_physical_address phys; | ||
106 | acpi_size size; | ||
107 | unsigned long refcount; | ||
108 | }; | ||
109 | |||
110 | static LIST_HEAD(acpi_ioremaps); | ||
111 | static DEFINE_MUTEX(acpi_ioremap_lock); | ||
112 | |||
113 | static void __init acpi_osi_setup_late(void); | ||
100 | 114 | ||
101 | /* | 115 | /* |
102 | * The story of _OSI(Linux) | 116 | * The story of _OSI(Linux) |
@@ -135,8 +149,21 @@ static struct osi_linux { | |||
135 | unsigned int enable:1; | 149 | unsigned int enable:1; |
136 | unsigned int dmi:1; | 150 | unsigned int dmi:1; |
137 | unsigned int cmdline:1; | 151 | unsigned int cmdline:1; |
138 | unsigned int known:1; | 152 | } osi_linux = {0, 0, 0}; |
139 | } osi_linux = { 0, 0, 0, 0}; | 153 | |
154 | static u32 acpi_osi_handler(acpi_string interface, u32 supported) | ||
155 | { | ||
156 | if (!strcmp("Linux", interface)) { | ||
157 | |||
158 | printk(KERN_NOTICE FW_BUG PREFIX | ||
159 | "BIOS _OSI(Linux) query %s%s\n", | ||
160 | osi_linux.enable ? "honored" : "ignored", | ||
161 | osi_linux.cmdline ? " via cmdline" : | ||
162 | osi_linux.dmi ? " via DMI" : ""); | ||
163 | } | ||
164 | |||
165 | return supported; | ||
166 | } | ||
140 | 167 | ||
141 | static void __init acpi_request_region (struct acpi_generic_address *addr, | 168 | static void __init acpi_request_region (struct acpi_generic_address *addr, |
142 | unsigned int length, char *desc) | 169 | unsigned int length, char *desc) |
@@ -185,36 +212,6 @@ static int __init acpi_reserve_resources(void) | |||
185 | } | 212 | } |
186 | device_initcall(acpi_reserve_resources); | 213 | device_initcall(acpi_reserve_resources); |
187 | 214 | ||
188 | acpi_status __init acpi_os_initialize(void) | ||
189 | { | ||
190 | return AE_OK; | ||
191 | } | ||
192 | |||
193 | acpi_status acpi_os_initialize1(void) | ||
194 | { | ||
195 | kacpid_wq = create_workqueue("kacpid"); | ||
196 | kacpi_notify_wq = create_workqueue("kacpi_notify"); | ||
197 | kacpi_hotplug_wq = create_workqueue("kacpi_hotplug"); | ||
198 | BUG_ON(!kacpid_wq); | ||
199 | BUG_ON(!kacpi_notify_wq); | ||
200 | BUG_ON(!kacpi_hotplug_wq); | ||
201 | return AE_OK; | ||
202 | } | ||
203 | |||
204 | acpi_status acpi_os_terminate(void) | ||
205 | { | ||
206 | if (acpi_irq_handler) { | ||
207 | acpi_os_remove_interrupt_handler(acpi_irq_irq, | ||
208 | acpi_irq_handler); | ||
209 | } | ||
210 | |||
211 | destroy_workqueue(kacpid_wq); | ||
212 | destroy_workqueue(kacpi_notify_wq); | ||
213 | destroy_workqueue(kacpi_hotplug_wq); | ||
214 | |||
215 | return AE_OK; | ||
216 | } | ||
217 | |||
218 | void acpi_os_printf(const char *fmt, ...) | 215 | void acpi_os_printf(const char *fmt, ...) |
219 | { | 216 | { |
220 | va_list args; | 217 | va_list args; |
@@ -260,29 +257,151 @@ acpi_physical_address __init acpi_os_get_root_pointer(void) | |||
260 | } | 257 | } |
261 | } | 258 | } |
262 | 259 | ||
260 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ | ||
261 | static struct acpi_ioremap * | ||
262 | acpi_map_lookup(acpi_physical_address phys, acpi_size size) | ||
263 | { | ||
264 | struct acpi_ioremap *map; | ||
265 | |||
266 | list_for_each_entry_rcu(map, &acpi_ioremaps, list) | ||
267 | if (map->phys <= phys && | ||
268 | phys + size <= map->phys + map->size) | ||
269 | return map; | ||
270 | |||
271 | return NULL; | ||
272 | } | ||
273 | |||
274 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ | ||
275 | static void __iomem * | ||
276 | acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size) | ||
277 | { | ||
278 | struct acpi_ioremap *map; | ||
279 | |||
280 | map = acpi_map_lookup(phys, size); | ||
281 | if (map) | ||
282 | return map->virt + (phys - map->phys); | ||
283 | |||
284 | return NULL; | ||
285 | } | ||
286 | |||
287 | void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size) | ||
288 | { | ||
289 | struct acpi_ioremap *map; | ||
290 | void __iomem *virt = NULL; | ||
291 | |||
292 | mutex_lock(&acpi_ioremap_lock); | ||
293 | map = acpi_map_lookup(phys, size); | ||
294 | if (map) { | ||
295 | virt = map->virt + (phys - map->phys); | ||
296 | map->refcount++; | ||
297 | } | ||
298 | mutex_unlock(&acpi_ioremap_lock); | ||
299 | return virt; | ||
300 | } | ||
301 | EXPORT_SYMBOL_GPL(acpi_os_get_iomem); | ||
302 | |||
303 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ | ||
304 | static struct acpi_ioremap * | ||
305 | acpi_map_lookup_virt(void __iomem *virt, acpi_size size) | ||
306 | { | ||
307 | struct acpi_ioremap *map; | ||
308 | |||
309 | list_for_each_entry_rcu(map, &acpi_ioremaps, list) | ||
310 | if (map->virt <= virt && | ||
311 | virt + size <= map->virt + map->size) | ||
312 | return map; | ||
313 | |||
314 | return NULL; | ||
315 | } | ||
316 | |||
263 | void __iomem *__init_refok | 317 | void __iomem *__init_refok |
264 | acpi_os_map_memory(acpi_physical_address phys, acpi_size size) | 318 | acpi_os_map_memory(acpi_physical_address phys, acpi_size size) |
265 | { | 319 | { |
320 | struct acpi_ioremap *map; | ||
321 | void __iomem *virt; | ||
322 | acpi_physical_address pg_off; | ||
323 | acpi_size pg_sz; | ||
324 | |||
266 | if (phys > ULONG_MAX) { | 325 | if (phys > ULONG_MAX) { |
267 | printk(KERN_ERR PREFIX "Cannot map memory that high\n"); | 326 | printk(KERN_ERR PREFIX "Cannot map memory that high\n"); |
268 | return NULL; | 327 | return NULL; |
269 | } | 328 | } |
270 | if (acpi_gbl_permanent_mmap) | 329 | |
271 | /* | 330 | if (!acpi_gbl_permanent_mmap) |
272 | * ioremap checks to ensure this is in reserved space | ||
273 | */ | ||
274 | return ioremap((unsigned long)phys, size); | ||
275 | else | ||
276 | return __acpi_map_table((unsigned long)phys, size); | 331 | return __acpi_map_table((unsigned long)phys, size); |
332 | |||
333 | mutex_lock(&acpi_ioremap_lock); | ||
334 | /* Check if there's a suitable mapping already. */ | ||
335 | map = acpi_map_lookup(phys, size); | ||
336 | if (map) { | ||
337 | map->refcount++; | ||
338 | goto out; | ||
339 | } | ||
340 | |||
341 | map = kzalloc(sizeof(*map), GFP_KERNEL); | ||
342 | if (!map) { | ||
343 | mutex_unlock(&acpi_ioremap_lock); | ||
344 | return NULL; | ||
345 | } | ||
346 | |||
347 | pg_off = round_down(phys, PAGE_SIZE); | ||
348 | pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; | ||
349 | virt = acpi_os_ioremap(pg_off, pg_sz); | ||
350 | if (!virt) { | ||
351 | mutex_unlock(&acpi_ioremap_lock); | ||
352 | kfree(map); | ||
353 | return NULL; | ||
354 | } | ||
355 | |||
356 | INIT_LIST_HEAD(&map->list); | ||
357 | map->virt = virt; | ||
358 | map->phys = pg_off; | ||
359 | map->size = pg_sz; | ||
360 | map->refcount = 1; | ||
361 | |||
362 | list_add_tail_rcu(&map->list, &acpi_ioremaps); | ||
363 | |||
364 | out: | ||
365 | mutex_unlock(&acpi_ioremap_lock); | ||
366 | return map->virt + (phys - map->phys); | ||
277 | } | 367 | } |
278 | EXPORT_SYMBOL_GPL(acpi_os_map_memory); | 368 | EXPORT_SYMBOL_GPL(acpi_os_map_memory); |
279 | 369 | ||
370 | static void acpi_os_drop_map_ref(struct acpi_ioremap *map) | ||
371 | { | ||
372 | if (!--map->refcount) | ||
373 | list_del_rcu(&map->list); | ||
374 | } | ||
375 | |||
376 | static void acpi_os_map_cleanup(struct acpi_ioremap *map) | ||
377 | { | ||
378 | if (!map->refcount) { | ||
379 | synchronize_rcu(); | ||
380 | iounmap(map->virt); | ||
381 | kfree(map); | ||
382 | } | ||
383 | } | ||
384 | |||
280 | void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) | 385 | void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) |
281 | { | 386 | { |
282 | if (acpi_gbl_permanent_mmap) | 387 | struct acpi_ioremap *map; |
283 | iounmap(virt); | 388 | |
284 | else | 389 | if (!acpi_gbl_permanent_mmap) { |
285 | __acpi_unmap_table(virt, size); | 390 | __acpi_unmap_table(virt, size); |
391 | return; | ||
392 | } | ||
393 | |||
394 | mutex_lock(&acpi_ioremap_lock); | ||
395 | map = acpi_map_lookup_virt(virt, size); | ||
396 | if (!map) { | ||
397 | mutex_unlock(&acpi_ioremap_lock); | ||
398 | WARN(true, PREFIX "%s: bad address %p\n", __func__, virt); | ||
399 | return; | ||
400 | } | ||
401 | acpi_os_drop_map_ref(map); | ||
402 | mutex_unlock(&acpi_ioremap_lock); | ||
403 | |||
404 | acpi_os_map_cleanup(map); | ||
286 | } | 405 | } |
287 | EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); | 406 | EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); |
288 | 407 | ||
@@ -292,6 +411,45 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) | |||
292 | __acpi_unmap_table(virt, size); | 411 | __acpi_unmap_table(virt, size); |
293 | } | 412 | } |
294 | 413 | ||
414 | static int acpi_os_map_generic_address(struct acpi_generic_address *addr) | ||
415 | { | ||
416 | void __iomem *virt; | ||
417 | |||
418 | if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) | ||
419 | return 0; | ||
420 | |||
421 | if (!addr->address || !addr->bit_width) | ||
422 | return -EINVAL; | ||
423 | |||
424 | virt = acpi_os_map_memory(addr->address, addr->bit_width / 8); | ||
425 | if (!virt) | ||
426 | return -EIO; | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) | ||
432 | { | ||
433 | struct acpi_ioremap *map; | ||
434 | |||
435 | if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) | ||
436 | return; | ||
437 | |||
438 | if (!addr->address || !addr->bit_width) | ||
439 | return; | ||
440 | |||
441 | mutex_lock(&acpi_ioremap_lock); | ||
442 | map = acpi_map_lookup(addr->address, addr->bit_width / 8); | ||
443 | if (!map) { | ||
444 | mutex_unlock(&acpi_ioremap_lock); | ||
445 | return; | ||
446 | } | ||
447 | acpi_os_drop_map_ref(map); | ||
448 | mutex_unlock(&acpi_ioremap_lock); | ||
449 | |||
450 | acpi_os_map_cleanup(map); | ||
451 | } | ||
452 | |||
295 | #ifdef ACPI_FUTURE_USAGE | 453 | #ifdef ACPI_FUTURE_USAGE |
296 | acpi_status | 454 | acpi_status |
297 | acpi_os_get_physical_address(void *virt, acpi_physical_address * phys) | 455 | acpi_os_get_physical_address(void *virt, acpi_physical_address * phys) |
@@ -373,11 +531,15 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, | |||
373 | acpi_irq_stats_init(); | 531 | acpi_irq_stats_init(); |
374 | 532 | ||
375 | /* | 533 | /* |
376 | * Ignore the GSI from the core, and use the value in our copy of the | 534 | * ACPI interrupts different from the SCI in our copy of the FADT are |
377 | * FADT. It may not be the same if an interrupt source override exists | 535 | * not supported. |
378 | * for the SCI. | ||
379 | */ | 536 | */ |
380 | gsi = acpi_gbl_FADT.sci_interrupt; | 537 | if (gsi != acpi_gbl_FADT.sci_interrupt) |
538 | return AE_BAD_PARAMETER; | ||
539 | |||
540 | if (acpi_irq_handler) | ||
541 | return AE_ALREADY_ACQUIRED; | ||
542 | |||
381 | if (acpi_gsi_to_irq(gsi, &irq) < 0) { | 543 | if (acpi_gsi_to_irq(gsi, &irq) < 0) { |
382 | printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", | 544 | printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", |
383 | gsi); | 545 | gsi); |
@@ -388,20 +550,20 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, | |||
388 | acpi_irq_context = context; | 550 | acpi_irq_context = context; |
389 | if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { | 551 | if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { |
390 | printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); | 552 | printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); |
553 | acpi_irq_handler = NULL; | ||
391 | return AE_NOT_ACQUIRED; | 554 | return AE_NOT_ACQUIRED; |
392 | } | 555 | } |
393 | acpi_irq_irq = irq; | ||
394 | 556 | ||
395 | return AE_OK; | 557 | return AE_OK; |
396 | } | 558 | } |
397 | 559 | ||
398 | acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) | 560 | acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) |
399 | { | 561 | { |
400 | if (irq) { | 562 | if (irq != acpi_gbl_FADT.sci_interrupt) |
401 | free_irq(irq, acpi_irq); | 563 | return AE_BAD_PARAMETER; |
402 | acpi_irq_handler = NULL; | 564 | |
403 | acpi_irq_irq = 0; | 565 | free_irq(irq, acpi_irq); |
404 | } | 566 | acpi_irq_handler = NULL; |
405 | 567 | ||
406 | return AE_OK; | 568 | return AE_OK; |
407 | } | 569 | } |
@@ -493,10 +655,21 @@ EXPORT_SYMBOL(acpi_os_write_port); | |||
493 | acpi_status | 655 | acpi_status |
494 | acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) | 656 | acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) |
495 | { | 657 | { |
496 | u32 dummy; | ||
497 | void __iomem *virt_addr; | 658 | void __iomem *virt_addr; |
659 | unsigned int size = width / 8; | ||
660 | bool unmap = false; | ||
661 | u32 dummy; | ||
662 | |||
663 | rcu_read_lock(); | ||
664 | virt_addr = acpi_map_vaddr_lookup(phys_addr, size); | ||
665 | if (!virt_addr) { | ||
666 | rcu_read_unlock(); | ||
667 | virt_addr = acpi_os_ioremap(phys_addr, size); | ||
668 | if (!virt_addr) | ||
669 | return AE_BAD_ADDRESS; | ||
670 | unmap = true; | ||
671 | } | ||
498 | 672 | ||
499 | virt_addr = ioremap(phys_addr, width); | ||
500 | if (!value) | 673 | if (!value) |
501 | value = &dummy; | 674 | value = &dummy; |
502 | 675 | ||
@@ -514,7 +687,10 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) | |||
514 | BUG(); | 687 | BUG(); |
515 | } | 688 | } |
516 | 689 | ||
517 | iounmap(virt_addr); | 690 | if (unmap) |
691 | iounmap(virt_addr); | ||
692 | else | ||
693 | rcu_read_unlock(); | ||
518 | 694 | ||
519 | return AE_OK; | 695 | return AE_OK; |
520 | } | 696 | } |
@@ -523,8 +699,18 @@ acpi_status | |||
523 | acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) | 699 | acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) |
524 | { | 700 | { |
525 | void __iomem *virt_addr; | 701 | void __iomem *virt_addr; |
526 | 702 | unsigned int size = width / 8; | |
527 | virt_addr = ioremap(phys_addr, width); | 703 | bool unmap = false; |
704 | |||
705 | rcu_read_lock(); | ||
706 | virt_addr = acpi_map_vaddr_lookup(phys_addr, size); | ||
707 | if (!virt_addr) { | ||
708 | rcu_read_unlock(); | ||
709 | virt_addr = acpi_os_ioremap(phys_addr, size); | ||
710 | if (!virt_addr) | ||
711 | return AE_BAD_ADDRESS; | ||
712 | unmap = true; | ||
713 | } | ||
528 | 714 | ||
529 | switch (width) { | 715 | switch (width) { |
530 | case 8: | 716 | case 8: |
@@ -540,16 +726,20 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) | |||
540 | BUG(); | 726 | BUG(); |
541 | } | 727 | } |
542 | 728 | ||
543 | iounmap(virt_addr); | 729 | if (unmap) |
730 | iounmap(virt_addr); | ||
731 | else | ||
732 | rcu_read_unlock(); | ||
544 | 733 | ||
545 | return AE_OK; | 734 | return AE_OK; |
546 | } | 735 | } |
547 | 736 | ||
548 | acpi_status | 737 | acpi_status |
549 | acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, | 738 | acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, |
550 | u32 *value, u32 width) | 739 | u64 *value, u32 width) |
551 | { | 740 | { |
552 | int result, size; | 741 | int result, size; |
742 | u32 value32; | ||
553 | 743 | ||
554 | if (!value) | 744 | if (!value) |
555 | return AE_BAD_PARAMETER; | 745 | return AE_BAD_PARAMETER; |
@@ -570,7 +760,8 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, | |||
570 | 760 | ||
571 | result = raw_pci_read(pci_id->segment, pci_id->bus, | 761 | result = raw_pci_read(pci_id->segment, pci_id->bus, |
572 | PCI_DEVFN(pci_id->device, pci_id->function), | 762 | PCI_DEVFN(pci_id->device, pci_id->function), |
573 | reg, size, value); | 763 | reg, size, &value32); |
764 | *value = value32; | ||
574 | 765 | ||
575 | return (result ? AE_ERROR : AE_OK); | 766 | return (result ? AE_ERROR : AE_OK); |
576 | } | 767 | } |
@@ -602,74 +793,6 @@ acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, | |||
602 | return (result ? AE_ERROR : AE_OK); | 793 | return (result ? AE_ERROR : AE_OK); |
603 | } | 794 | } |
604 | 795 | ||
605 | /* TODO: Change code to take advantage of driver model more */ | ||
606 | static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */ | ||
607 | acpi_handle chandle, /* current node */ | ||
608 | struct acpi_pci_id **id, | ||
609 | int *is_bridge, u8 * bus_number) | ||
610 | { | ||
611 | acpi_handle handle; | ||
612 | struct acpi_pci_id *pci_id = *id; | ||
613 | acpi_status status; | ||
614 | unsigned long long temp; | ||
615 | acpi_object_type type; | ||
616 | |||
617 | acpi_get_parent(chandle, &handle); | ||
618 | if (handle != rhandle) { | ||
619 | acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge, | ||
620 | bus_number); | ||
621 | |||
622 | status = acpi_get_type(handle, &type); | ||
623 | if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE)) | ||
624 | return; | ||
625 | |||
626 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, | ||
627 | &temp); | ||
628 | if (ACPI_SUCCESS(status)) { | ||
629 | u32 val; | ||
630 | pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp)); | ||
631 | pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp)); | ||
632 | |||
633 | if (*is_bridge) | ||
634 | pci_id->bus = *bus_number; | ||
635 | |||
636 | /* any nicer way to get bus number of bridge ? */ | ||
637 | status = | ||
638 | acpi_os_read_pci_configuration(pci_id, 0x0e, &val, | ||
639 | 8); | ||
640 | if (ACPI_SUCCESS(status) | ||
641 | && ((val & 0x7f) == 1 || (val & 0x7f) == 2)) { | ||
642 | status = | ||
643 | acpi_os_read_pci_configuration(pci_id, 0x18, | ||
644 | &val, 8); | ||
645 | if (!ACPI_SUCCESS(status)) { | ||
646 | /* Certainly broken... FIX ME */ | ||
647 | return; | ||
648 | } | ||
649 | *is_bridge = 1; | ||
650 | pci_id->bus = val; | ||
651 | status = | ||
652 | acpi_os_read_pci_configuration(pci_id, 0x19, | ||
653 | &val, 8); | ||
654 | if (ACPI_SUCCESS(status)) { | ||
655 | *bus_number = val; | ||
656 | } | ||
657 | } else | ||
658 | *is_bridge = 0; | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | |||
663 | void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */ | ||
664 | acpi_handle chandle, /* current node */ | ||
665 | struct acpi_pci_id **id) | ||
666 | { | ||
667 | int is_bridge = 1; | ||
668 | u8 bus_number = (*id)->bus; | ||
669 | |||
670 | acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number); | ||
671 | } | ||
672 | |||
673 | static void acpi_os_execute_deferred(struct work_struct *work) | 796 | static void acpi_os_execute_deferred(struct work_struct *work) |
674 | { | 797 | { |
675 | struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); | 798 | struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); |
@@ -779,24 +902,6 @@ void acpi_os_wait_events_complete(void *context) | |||
779 | 902 | ||
780 | EXPORT_SYMBOL(acpi_os_wait_events_complete); | 903 | EXPORT_SYMBOL(acpi_os_wait_events_complete); |
781 | 904 | ||
782 | /* | ||
783 | * Allocate the memory for a spinlock and initialize it. | ||
784 | */ | ||
785 | acpi_status acpi_os_create_lock(acpi_spinlock * handle) | ||
786 | { | ||
787 | spin_lock_init(*handle); | ||
788 | |||
789 | return AE_OK; | ||
790 | } | ||
791 | |||
792 | /* | ||
793 | * Deallocate the memory for a spinlock. | ||
794 | */ | ||
795 | void acpi_os_delete_lock(acpi_spinlock handle) | ||
796 | { | ||
797 | return; | ||
798 | } | ||
799 | |||
800 | acpi_status | 905 | acpi_status |
801 | acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) | 906 | acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) |
802 | { | 907 | { |
@@ -970,19 +1075,66 @@ static int __init acpi_os_name_setup(char *str) | |||
970 | 1075 | ||
971 | __setup("acpi_os_name=", acpi_os_name_setup); | 1076 | __setup("acpi_os_name=", acpi_os_name_setup); |
972 | 1077 | ||
1078 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ | ||
1079 | #define OSI_STRING_ENTRIES_MAX 16 /* arbitrary */ | ||
1080 | |||
1081 | struct osi_setup_entry { | ||
1082 | char string[OSI_STRING_LENGTH_MAX]; | ||
1083 | bool enable; | ||
1084 | }; | ||
1085 | |||
1086 | static struct osi_setup_entry __initdata osi_setup_entries[OSI_STRING_ENTRIES_MAX]; | ||
1087 | |||
1088 | void __init acpi_osi_setup(char *str) | ||
1089 | { | ||
1090 | struct osi_setup_entry *osi; | ||
1091 | bool enable = true; | ||
1092 | int i; | ||
1093 | |||
1094 | if (!acpi_gbl_create_osi_method) | ||
1095 | return; | ||
1096 | |||
1097 | if (str == NULL || *str == '\0') { | ||
1098 | printk(KERN_INFO PREFIX "_OSI method disabled\n"); | ||
1099 | acpi_gbl_create_osi_method = FALSE; | ||
1100 | return; | ||
1101 | } | ||
1102 | |||
1103 | if (*str == '!') { | ||
1104 | str++; | ||
1105 | enable = false; | ||
1106 | } | ||
1107 | |||
1108 | for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { | ||
1109 | osi = &osi_setup_entries[i]; | ||
1110 | if (!strcmp(osi->string, str)) { | ||
1111 | osi->enable = enable; | ||
1112 | break; | ||
1113 | } else if (osi->string[0] == '\0') { | ||
1114 | osi->enable = enable; | ||
1115 | strncpy(osi->string, str, OSI_STRING_LENGTH_MAX); | ||
1116 | break; | ||
1117 | } | ||
1118 | } | ||
1119 | } | ||
1120 | |||
973 | static void __init set_osi_linux(unsigned int enable) | 1121 | static void __init set_osi_linux(unsigned int enable) |
974 | { | 1122 | { |
975 | if (osi_linux.enable != enable) { | 1123 | if (osi_linux.enable != enable) |
976 | osi_linux.enable = enable; | 1124 | osi_linux.enable = enable; |
977 | printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n", | 1125 | |
978 | enable ? "Add": "Delet"); | 1126 | if (osi_linux.enable) |
979 | } | 1127 | acpi_osi_setup("Linux"); |
1128 | else | ||
1129 | acpi_osi_setup("!Linux"); | ||
1130 | |||
980 | return; | 1131 | return; |
981 | } | 1132 | } |
982 | 1133 | ||
983 | static void __init acpi_cmdline_osi_linux(unsigned int enable) | 1134 | static void __init acpi_cmdline_osi_linux(unsigned int enable) |
984 | { | 1135 | { |
985 | osi_linux.cmdline = 1; /* cmdline set the default */ | 1136 | osi_linux.cmdline = 1; /* cmdline set the default and override DMI */ |
1137 | osi_linux.dmi = 0; | ||
986 | set_osi_linux(enable); | 1138 | set_osi_linux(enable); |
987 | 1139 | ||
988 | return; | 1140 | return; |
@@ -990,15 +1142,12 @@ static void __init acpi_cmdline_osi_linux(unsigned int enable) | |||
990 | 1142 | ||
991 | void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d) | 1143 | void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d) |
992 | { | 1144 | { |
993 | osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */ | ||
994 | |||
995 | printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); | 1145 | printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); |
996 | 1146 | ||
997 | if (enable == -1) | 1147 | if (enable == -1) |
998 | return; | 1148 | return; |
999 | 1149 | ||
1000 | osi_linux.known = 1; /* DMI knows which OSI(Linux) default needed */ | 1150 | osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */ |
1001 | |||
1002 | set_osi_linux(enable); | 1151 | set_osi_linux(enable); |
1003 | 1152 | ||
1004 | return; | 1153 | return; |
@@ -1011,27 +1160,46 @@ void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d) | |||
1011 | * string starting with '!' disables that string | 1160 | * string starting with '!' disables that string |
1012 | * otherwise string is added to list, augmenting built-in strings | 1161 | * otherwise string is added to list, augmenting built-in strings |
1013 | */ | 1162 | */ |
1014 | int __init acpi_osi_setup(char *str) | 1163 | static void __init acpi_osi_setup_late(void) |
1015 | { | 1164 | { |
1016 | if (str == NULL || *str == '\0') { | 1165 | struct osi_setup_entry *osi; |
1017 | printk(KERN_INFO PREFIX "_OSI method disabled\n"); | 1166 | char *str; |
1018 | acpi_gbl_create_osi_method = FALSE; | 1167 | int i; |
1019 | } else if (!strcmp("!Linux", str)) { | 1168 | acpi_status status; |
1020 | acpi_cmdline_osi_linux(0); /* !enable */ | 1169 | |
1021 | } else if (*str == '!') { | 1170 | for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { |
1022 | if (acpi_osi_invalidate(++str) == AE_OK) | 1171 | osi = &osi_setup_entries[i]; |
1023 | printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); | 1172 | str = osi->string; |
1024 | } else if (!strcmp("Linux", str)) { | 1173 | |
1025 | acpi_cmdline_osi_linux(1); /* enable */ | 1174 | if (*str == '\0') |
1026 | } else if (*osi_additional_string == '\0') { | 1175 | break; |
1027 | strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX); | 1176 | if (osi->enable) { |
1028 | printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); | 1177 | status = acpi_install_interface(str); |
1178 | |||
1179 | if (ACPI_SUCCESS(status)) | ||
1180 | printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); | ||
1181 | } else { | ||
1182 | status = acpi_remove_interface(str); | ||
1183 | |||
1184 | if (ACPI_SUCCESS(status)) | ||
1185 | printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); | ||
1186 | } | ||
1029 | } | 1187 | } |
1188 | } | ||
1189 | |||
1190 | static int __init osi_setup(char *str) | ||
1191 | { | ||
1192 | if (str && !strcmp("Linux", str)) | ||
1193 | acpi_cmdline_osi_linux(1); | ||
1194 | else if (str && !strcmp("!Linux", str)) | ||
1195 | acpi_cmdline_osi_linux(0); | ||
1196 | else | ||
1197 | acpi_osi_setup(str); | ||
1030 | 1198 | ||
1031 | return 1; | 1199 | return 1; |
1032 | } | 1200 | } |
1033 | 1201 | ||
1034 | __setup("acpi_osi=", acpi_osi_setup); | 1202 | __setup("acpi_osi=", osi_setup); |
1035 | 1203 | ||
1036 | /* enable serialization to combat AE_ALREADY_EXISTS errors */ | 1204 | /* enable serialization to combat AE_ALREADY_EXISTS errors */ |
1037 | static int __init acpi_serialize_setup(char *str) | 1205 | static int __init acpi_serialize_setup(char *str) |
@@ -1089,8 +1257,7 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); | |||
1089 | int acpi_check_resource_conflict(const struct resource *res) | 1257 | int acpi_check_resource_conflict(const struct resource *res) |
1090 | { | 1258 | { |
1091 | struct acpi_res_list *res_list_elem; | 1259 | struct acpi_res_list *res_list_elem; |
1092 | int ioport; | 1260 | int ioport = 0, clash = 0; |
1093 | int clash = 0; | ||
1094 | 1261 | ||
1095 | if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) | 1262 | if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) |
1096 | return 0; | 1263 | return 0; |
@@ -1120,9 +1287,13 @@ int acpi_check_resource_conflict(const struct resource *res) | |||
1120 | if (clash) { | 1287 | if (clash) { |
1121 | if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { | 1288 | if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { |
1122 | printk(KERN_WARNING "ACPI: resource %s %pR" | 1289 | printk(KERN_WARNING "ACPI: resource %s %pR" |
1123 | " conflicts with ACPI region %s %pR\n", | 1290 | " conflicts with ACPI region %s " |
1291 | "[%s 0x%zx-0x%zx]\n", | ||
1124 | res->name, res, res_list_elem->name, | 1292 | res->name, res, res_list_elem->name, |
1125 | res_list_elem); | 1293 | (res_list_elem->resource_type == |
1294 | ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem", | ||
1295 | (size_t) res_list_elem->start, | ||
1296 | (size_t) res_list_elem->end); | ||
1126 | if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) | 1297 | if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) |
1127 | printk(KERN_NOTICE "ACPI: This conflict may" | 1298 | printk(KERN_NOTICE "ACPI: This conflict may" |
1128 | " cause random problems and system" | 1299 | " cause random problems and system" |
@@ -1152,21 +1323,6 @@ int acpi_check_region(resource_size_t start, resource_size_t n, | |||
1152 | } | 1323 | } |
1153 | EXPORT_SYMBOL(acpi_check_region); | 1324 | EXPORT_SYMBOL(acpi_check_region); |
1154 | 1325 | ||
1155 | int acpi_check_mem_region(resource_size_t start, resource_size_t n, | ||
1156 | const char *name) | ||
1157 | { | ||
1158 | struct resource res = { | ||
1159 | .start = start, | ||
1160 | .end = start + n - 1, | ||
1161 | .name = name, | ||
1162 | .flags = IORESOURCE_MEM, | ||
1163 | }; | ||
1164 | |||
1165 | return acpi_check_resource_conflict(&res); | ||
1166 | |||
1167 | } | ||
1168 | EXPORT_SYMBOL(acpi_check_mem_region); | ||
1169 | |||
1170 | /* | 1326 | /* |
1171 | * Let drivers know whether the resource checks are effective | 1327 | * Let drivers know whether the resource checks are effective |
1172 | */ | 1328 | */ |
@@ -1177,6 +1333,14 @@ int acpi_resources_are_enforced(void) | |||
1177 | EXPORT_SYMBOL(acpi_resources_are_enforced); | 1333 | EXPORT_SYMBOL(acpi_resources_are_enforced); |
1178 | 1334 | ||
1179 | /* | 1335 | /* |
1336 | * Deallocate the memory for a spinlock. | ||
1337 | */ | ||
1338 | void acpi_os_delete_lock(acpi_spinlock handle) | ||
1339 | { | ||
1340 | ACPI_FREE(handle); | ||
1341 | } | ||
1342 | |||
1343 | /* | ||
1180 | * Acquire a spinlock. | 1344 | * Acquire a spinlock. |
1181 | * | 1345 | * |
1182 | * handle is a pointer to the spinlock_t. | 1346 | * handle is a pointer to the spinlock_t. |
@@ -1282,38 +1446,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) | |||
1282 | return (AE_OK); | 1446 | return (AE_OK); |
1283 | } | 1447 | } |
1284 | 1448 | ||
1285 | /****************************************************************************** | ||
1286 | * | ||
1287 | * FUNCTION: acpi_os_validate_interface | ||
1288 | * | ||
1289 | * PARAMETERS: interface - Requested interface to be validated | ||
1290 | * | ||
1291 | * RETURN: AE_OK if interface is supported, AE_SUPPORT otherwise | ||
1292 | * | ||
1293 | * DESCRIPTION: Match an interface string to the interfaces supported by the | ||
1294 | * host. Strings originate from an AML call to the _OSI method. | ||
1295 | * | ||
1296 | *****************************************************************************/ | ||
1297 | |||
1298 | acpi_status | ||
1299 | acpi_os_validate_interface (char *interface) | ||
1300 | { | ||
1301 | if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX)) | ||
1302 | return AE_OK; | ||
1303 | if (!strcmp("Linux", interface)) { | ||
1304 | |||
1305 | printk(KERN_NOTICE PREFIX | ||
1306 | "BIOS _OSI(Linux) query %s%s\n", | ||
1307 | osi_linux.enable ? "honored" : "ignored", | ||
1308 | osi_linux.cmdline ? " via cmdline" : | ||
1309 | osi_linux.dmi ? " via DMI" : ""); | ||
1310 | |||
1311 | if (osi_linux.enable) | ||
1312 | return AE_OK; | ||
1313 | } | ||
1314 | return AE_SUPPORT; | ||
1315 | } | ||
1316 | |||
1317 | static inline int acpi_res_list_add(struct acpi_res_list *res) | 1449 | static inline int acpi_res_list_add(struct acpi_res_list *res) |
1318 | { | 1450 | { |
1319 | struct acpi_res_list *res_list_elem; | 1451 | struct acpi_res_list *res_list_elem; |
@@ -1462,5 +1594,46 @@ acpi_os_validate_address ( | |||
1462 | } | 1594 | } |
1463 | return AE_OK; | 1595 | return AE_OK; |
1464 | } | 1596 | } |
1465 | |||
1466 | #endif | 1597 | #endif |
1598 | |||
1599 | acpi_status __init acpi_os_initialize(void) | ||
1600 | { | ||
1601 | acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block); | ||
1602 | acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block); | ||
1603 | acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block); | ||
1604 | acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block); | ||
1605 | |||
1606 | return AE_OK; | ||
1607 | } | ||
1608 | |||
1609 | acpi_status __init acpi_os_initialize1(void) | ||
1610 | { | ||
1611 | kacpid_wq = alloc_workqueue("kacpid", 0, 1); | ||
1612 | kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); | ||
1613 | kacpi_hotplug_wq = alloc_workqueue("kacpi_hotplug", 0, 1); | ||
1614 | BUG_ON(!kacpid_wq); | ||
1615 | BUG_ON(!kacpi_notify_wq); | ||
1616 | BUG_ON(!kacpi_hotplug_wq); | ||
1617 | acpi_install_interface_handler(acpi_osi_handler); | ||
1618 | acpi_osi_setup_late(); | ||
1619 | return AE_OK; | ||
1620 | } | ||
1621 | |||
1622 | acpi_status acpi_os_terminate(void) | ||
1623 | { | ||
1624 | if (acpi_irq_handler) { | ||
1625 | acpi_os_remove_interrupt_handler(acpi_gbl_FADT.sci_interrupt, | ||
1626 | acpi_irq_handler); | ||
1627 | } | ||
1628 | |||
1629 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe1_block); | ||
1630 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block); | ||
1631 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block); | ||
1632 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block); | ||
1633 | |||
1634 | destroy_workqueue(kacpid_wq); | ||
1635 | destroy_workqueue(kacpi_notify_wq); | ||
1636 | destroy_workqueue(kacpi_hotplug_wq); | ||
1637 | |||
1638 | return AE_OK; | ||
1639 | } | ||