diff options
author | Len Brown <len.brown@intel.com> | 2010-10-26 14:50:56 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2010-10-26 14:50:56 -0400 |
commit | 1bd64d42abdd4f9d44f77011a31f0292112f4c3b (patch) | |
tree | 6eae9454b9a30813b75cfa55680b7fc13a5e110c /drivers/acpi | |
parent | 4895ae6f9f81011bf3a6fea70d46bab08d58fd8c (diff) | |
parent | 4a3cba5e72a5232842ff7c1ca691ec3450af64b9 (diff) |
Merge branch 'acpi-mmio' into release
Conflicts:
drivers/acpi/osl.c
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/osl.c | 280 |
1 files changed, 232 insertions, 48 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index d3bed219c44..0c2e445410a 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -95,6 +95,21 @@ 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 | /* | ||
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 | struct kref ref; | ||
108 | }; | ||
109 | |||
110 | static LIST_HEAD(acpi_ioremaps); | ||
111 | static DEFINE_SPINLOCK(acpi_ioremap_lock); | ||
112 | |||
98 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ | 113 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ |
99 | static char osi_setup_string[OSI_STRING_LENGTH_MAX]; | 114 | static char osi_setup_string[OSI_STRING_LENGTH_MAX]; |
100 | 115 | ||
@@ -201,38 +216,6 @@ static int __init acpi_reserve_resources(void) | |||
201 | } | 216 | } |
202 | device_initcall(acpi_reserve_resources); | 217 | device_initcall(acpi_reserve_resources); |
203 | 218 | ||
204 | acpi_status __init acpi_os_initialize(void) | ||
205 | { | ||
206 | return AE_OK; | ||
207 | } | ||
208 | |||
209 | acpi_status acpi_os_initialize1(void) | ||
210 | { | ||
211 | kacpid_wq = create_workqueue("kacpid"); | ||
212 | kacpi_notify_wq = create_workqueue("kacpi_notify"); | ||
213 | kacpi_hotplug_wq = create_workqueue("kacpi_hotplug"); | ||
214 | BUG_ON(!kacpid_wq); | ||
215 | BUG_ON(!kacpi_notify_wq); | ||
216 | BUG_ON(!kacpi_hotplug_wq); | ||
217 | acpi_install_interface_handler(acpi_osi_handler); | ||
218 | acpi_osi_setup_late(); | ||
219 | return AE_OK; | ||
220 | } | ||
221 | |||
222 | acpi_status acpi_os_terminate(void) | ||
223 | { | ||
224 | if (acpi_irq_handler) { | ||
225 | acpi_os_remove_interrupt_handler(acpi_irq_irq, | ||
226 | acpi_irq_handler); | ||
227 | } | ||
228 | |||
229 | destroy_workqueue(kacpid_wq); | ||
230 | destroy_workqueue(kacpi_notify_wq); | ||
231 | destroy_workqueue(kacpi_hotplug_wq); | ||
232 | |||
233 | return AE_OK; | ||
234 | } | ||
235 | |||
236 | void acpi_os_printf(const char *fmt, ...) | 219 | void acpi_os_printf(const char *fmt, ...) |
237 | { | 220 | { |
238 | va_list args; | 221 | va_list args; |
@@ -278,29 +261,135 @@ acpi_physical_address __init acpi_os_get_root_pointer(void) | |||
278 | } | 261 | } |
279 | } | 262 | } |
280 | 263 | ||
264 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ | ||
265 | static struct acpi_ioremap * | ||
266 | acpi_map_lookup(acpi_physical_address phys, acpi_size size) | ||
267 | { | ||
268 | struct acpi_ioremap *map; | ||
269 | |||
270 | list_for_each_entry_rcu(map, &acpi_ioremaps, list) | ||
271 | if (map->phys <= phys && | ||
272 | phys + size <= map->phys + map->size) | ||
273 | return map; | ||
274 | |||
275 | return NULL; | ||
276 | } | ||
277 | |||
278 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ | ||
279 | static void __iomem * | ||
280 | acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size) | ||
281 | { | ||
282 | struct acpi_ioremap *map; | ||
283 | |||
284 | map = acpi_map_lookup(phys, size); | ||
285 | if (map) | ||
286 | return map->virt + (phys - map->phys); | ||
287 | |||
288 | return NULL; | ||
289 | } | ||
290 | |||
291 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ | ||
292 | static struct acpi_ioremap * | ||
293 | acpi_map_lookup_virt(void __iomem *virt, acpi_size size) | ||
294 | { | ||
295 | struct acpi_ioremap *map; | ||
296 | |||
297 | list_for_each_entry_rcu(map, &acpi_ioremaps, list) | ||
298 | if (map->virt <= virt && | ||
299 | virt + size <= map->virt + map->size) | ||
300 | return map; | ||
301 | |||
302 | return NULL; | ||
303 | } | ||
304 | |||
281 | void __iomem *__init_refok | 305 | void __iomem *__init_refok |
282 | acpi_os_map_memory(acpi_physical_address phys, acpi_size size) | 306 | acpi_os_map_memory(acpi_physical_address phys, acpi_size size) |
283 | { | 307 | { |
308 | struct acpi_ioremap *map, *tmp_map; | ||
309 | unsigned long flags, pg_sz; | ||
310 | void __iomem *virt; | ||
311 | phys_addr_t pg_off; | ||
312 | |||
284 | if (phys > ULONG_MAX) { | 313 | if (phys > ULONG_MAX) { |
285 | printk(KERN_ERR PREFIX "Cannot map memory that high\n"); | 314 | printk(KERN_ERR PREFIX "Cannot map memory that high\n"); |
286 | return NULL; | 315 | return NULL; |
287 | } | 316 | } |
288 | if (acpi_gbl_permanent_mmap) | 317 | |
289 | /* | 318 | if (!acpi_gbl_permanent_mmap) |
290 | * ioremap checks to ensure this is in reserved space | ||
291 | */ | ||
292 | return ioremap((unsigned long)phys, size); | ||
293 | else | ||
294 | return __acpi_map_table((unsigned long)phys, size); | 319 | return __acpi_map_table((unsigned long)phys, size); |
320 | |||
321 | map = kzalloc(sizeof(*map), GFP_KERNEL); | ||
322 | if (!map) | ||
323 | return NULL; | ||
324 | |||
325 | pg_off = round_down(phys, PAGE_SIZE); | ||
326 | pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; | ||
327 | virt = ioremap(pg_off, pg_sz); | ||
328 | if (!virt) { | ||
329 | kfree(map); | ||
330 | return NULL; | ||
331 | } | ||
332 | |||
333 | INIT_LIST_HEAD(&map->list); | ||
334 | map->virt = virt; | ||
335 | map->phys = pg_off; | ||
336 | map->size = pg_sz; | ||
337 | kref_init(&map->ref); | ||
338 | |||
339 | spin_lock_irqsave(&acpi_ioremap_lock, flags); | ||
340 | /* Check if page has already been mapped. */ | ||
341 | tmp_map = acpi_map_lookup(phys, size); | ||
342 | if (tmp_map) { | ||
343 | kref_get(&tmp_map->ref); | ||
344 | spin_unlock_irqrestore(&acpi_ioremap_lock, flags); | ||
345 | iounmap(map->virt); | ||
346 | kfree(map); | ||
347 | return tmp_map->virt + (phys - tmp_map->phys); | ||
348 | } | ||
349 | list_add_tail_rcu(&map->list, &acpi_ioremaps); | ||
350 | spin_unlock_irqrestore(&acpi_ioremap_lock, flags); | ||
351 | |||
352 | return map->virt + (phys - map->phys); | ||
295 | } | 353 | } |
296 | EXPORT_SYMBOL_GPL(acpi_os_map_memory); | 354 | EXPORT_SYMBOL_GPL(acpi_os_map_memory); |
297 | 355 | ||
356 | static void acpi_kref_del_iomap(struct kref *ref) | ||
357 | { | ||
358 | struct acpi_ioremap *map; | ||
359 | |||
360 | map = container_of(ref, struct acpi_ioremap, ref); | ||
361 | list_del_rcu(&map->list); | ||
362 | } | ||
363 | |||
298 | void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) | 364 | void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) |
299 | { | 365 | { |
300 | if (acpi_gbl_permanent_mmap) | 366 | struct acpi_ioremap *map; |
301 | iounmap(virt); | 367 | unsigned long flags; |
302 | else | 368 | int del; |
369 | |||
370 | if (!acpi_gbl_permanent_mmap) { | ||
303 | __acpi_unmap_table(virt, size); | 371 | __acpi_unmap_table(virt, size); |
372 | return; | ||
373 | } | ||
374 | |||
375 | spin_lock_irqsave(&acpi_ioremap_lock, flags); | ||
376 | map = acpi_map_lookup_virt(virt, size); | ||
377 | if (!map) { | ||
378 | spin_unlock_irqrestore(&acpi_ioremap_lock, flags); | ||
379 | printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt); | ||
380 | dump_stack(); | ||
381 | return; | ||
382 | } | ||
383 | |||
384 | del = kref_put(&map->ref, acpi_kref_del_iomap); | ||
385 | spin_unlock_irqrestore(&acpi_ioremap_lock, flags); | ||
386 | |||
387 | if (!del) | ||
388 | return; | ||
389 | |||
390 | synchronize_rcu(); | ||
391 | iounmap(map->virt); | ||
392 | kfree(map); | ||
304 | } | 393 | } |
305 | EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); | 394 | EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); |
306 | 395 | ||
@@ -310,6 +399,44 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) | |||
310 | __acpi_unmap_table(virt, size); | 399 | __acpi_unmap_table(virt, size); |
311 | } | 400 | } |
312 | 401 | ||
402 | int acpi_os_map_generic_address(struct acpi_generic_address *addr) | ||
403 | { | ||
404 | void __iomem *virt; | ||
405 | |||
406 | if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) | ||
407 | return 0; | ||
408 | |||
409 | if (!addr->address || !addr->bit_width) | ||
410 | return -EINVAL; | ||
411 | |||
412 | virt = acpi_os_map_memory(addr->address, addr->bit_width / 8); | ||
413 | if (!virt) | ||
414 | return -EIO; | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | EXPORT_SYMBOL_GPL(acpi_os_map_generic_address); | ||
419 | |||
420 | void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) | ||
421 | { | ||
422 | void __iomem *virt; | ||
423 | unsigned long flags; | ||
424 | acpi_size size = addr->bit_width / 8; | ||
425 | |||
426 | if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) | ||
427 | return; | ||
428 | |||
429 | if (!addr->address || !addr->bit_width) | ||
430 | return; | ||
431 | |||
432 | spin_lock_irqsave(&acpi_ioremap_lock, flags); | ||
433 | virt = acpi_map_vaddr_lookup(addr->address, size); | ||
434 | spin_unlock_irqrestore(&acpi_ioremap_lock, flags); | ||
435 | |||
436 | acpi_os_unmap_memory(virt, size); | ||
437 | } | ||
438 | EXPORT_SYMBOL_GPL(acpi_os_unmap_generic_address); | ||
439 | |||
313 | #ifdef ACPI_FUTURE_USAGE | 440 | #ifdef ACPI_FUTURE_USAGE |
314 | acpi_status | 441 | acpi_status |
315 | acpi_os_get_physical_address(void *virt, acpi_physical_address * phys) | 442 | acpi_os_get_physical_address(void *virt, acpi_physical_address * phys) |
@@ -513,8 +640,15 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) | |||
513 | { | 640 | { |
514 | u32 dummy; | 641 | u32 dummy; |
515 | void __iomem *virt_addr; | 642 | void __iomem *virt_addr; |
516 | 643 | int size = width / 8, unmap = 0; | |
517 | virt_addr = ioremap(phys_addr, width); | 644 | |
645 | rcu_read_lock(); | ||
646 | virt_addr = acpi_map_vaddr_lookup(phys_addr, size); | ||
647 | rcu_read_unlock(); | ||
648 | if (!virt_addr) { | ||
649 | virt_addr = ioremap(phys_addr, size); | ||
650 | unmap = 1; | ||
651 | } | ||
518 | if (!value) | 652 | if (!value) |
519 | value = &dummy; | 653 | value = &dummy; |
520 | 654 | ||
@@ -532,7 +666,8 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) | |||
532 | BUG(); | 666 | BUG(); |
533 | } | 667 | } |
534 | 668 | ||
535 | iounmap(virt_addr); | 669 | if (unmap) |
670 | iounmap(virt_addr); | ||
536 | 671 | ||
537 | return AE_OK; | 672 | return AE_OK; |
538 | } | 673 | } |
@@ -541,8 +676,15 @@ acpi_status | |||
541 | acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) | 676 | acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) |
542 | { | 677 | { |
543 | void __iomem *virt_addr; | 678 | void __iomem *virt_addr; |
544 | 679 | int size = width / 8, unmap = 0; | |
545 | virt_addr = ioremap(phys_addr, width); | 680 | |
681 | rcu_read_lock(); | ||
682 | virt_addr = acpi_map_vaddr_lookup(phys_addr, size); | ||
683 | rcu_read_unlock(); | ||
684 | if (!virt_addr) { | ||
685 | virt_addr = ioremap(phys_addr, size); | ||
686 | unmap = 1; | ||
687 | } | ||
546 | 688 | ||
547 | switch (width) { | 689 | switch (width) { |
548 | case 8: | 690 | case 8: |
@@ -558,7 +700,8 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) | |||
558 | BUG(); | 700 | BUG(); |
559 | } | 701 | } |
560 | 702 | ||
561 | iounmap(virt_addr); | 703 | if (unmap) |
704 | iounmap(virt_addr); | ||
562 | 705 | ||
563 | return AE_OK; | 706 | return AE_OK; |
564 | } | 707 | } |
@@ -1400,5 +1543,46 @@ acpi_os_validate_address ( | |||
1400 | } | 1543 | } |
1401 | return AE_OK; | 1544 | return AE_OK; |
1402 | } | 1545 | } |
1403 | |||
1404 | #endif | 1546 | #endif |
1547 | |||
1548 | acpi_status __init acpi_os_initialize(void) | ||
1549 | { | ||
1550 | acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block); | ||
1551 | acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block); | ||
1552 | acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block); | ||
1553 | acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block); | ||
1554 | |||
1555 | return AE_OK; | ||
1556 | } | ||
1557 | |||
1558 | acpi_status acpi_os_initialize1(void) | ||
1559 | { | ||
1560 | kacpid_wq = create_workqueue("kacpid"); | ||
1561 | kacpi_notify_wq = create_workqueue("kacpi_notify"); | ||
1562 | kacpi_hotplug_wq = create_workqueue("kacpi_hotplug"); | ||
1563 | BUG_ON(!kacpid_wq); | ||
1564 | BUG_ON(!kacpi_notify_wq); | ||
1565 | BUG_ON(!kacpi_hotplug_wq); | ||
1566 | acpi_install_interface_handler(acpi_osi_handler); | ||
1567 | acpi_osi_setup_late(); | ||
1568 | return AE_OK; | ||
1569 | } | ||
1570 | |||
1571 | acpi_status acpi_os_terminate(void) | ||
1572 | { | ||
1573 | if (acpi_irq_handler) { | ||
1574 | acpi_os_remove_interrupt_handler(acpi_irq_irq, | ||
1575 | acpi_irq_handler); | ||
1576 | } | ||
1577 | |||
1578 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe1_block); | ||
1579 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block); | ||
1580 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block); | ||
1581 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block); | ||
1582 | |||
1583 | destroy_workqueue(kacpid_wq); | ||
1584 | destroy_workqueue(kacpi_notify_wq); | ||
1585 | destroy_workqueue(kacpi_hotplug_wq); | ||
1586 | |||
1587 | return AE_OK; | ||
1588 | } | ||