aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2010-10-26 14:50:56 -0400
committerLen Brown <len.brown@intel.com>2010-10-26 14:50:56 -0400
commit1bd64d42abdd4f9d44f77011a31f0292112f4c3b (patch)
tree6eae9454b9a30813b75cfa55680b7fc13a5e110c /drivers/acpi
parent4895ae6f9f81011bf3a6fea70d46bab08d58fd8c (diff)
parent4a3cba5e72a5232842ff7c1ca691ec3450af64b9 (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.c280
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 {
95static LIST_HEAD(resource_list_head); 95static LIST_HEAD(resource_list_head);
96static DEFINE_SPINLOCK(acpi_res_lock); 96static 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 */
102struct 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
110static LIST_HEAD(acpi_ioremaps);
111static DEFINE_SPINLOCK(acpi_ioremap_lock);
112
98#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ 113#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
99static char osi_setup_string[OSI_STRING_LENGTH_MAX]; 114static char osi_setup_string[OSI_STRING_LENGTH_MAX];
100 115
@@ -201,38 +216,6 @@ static int __init acpi_reserve_resources(void)
201} 216}
202device_initcall(acpi_reserve_resources); 217device_initcall(acpi_reserve_resources);
203 218
204acpi_status __init acpi_os_initialize(void)
205{
206 return AE_OK;
207}
208
209acpi_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
222acpi_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
236void acpi_os_printf(const char *fmt, ...) 219void 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. */
265static struct acpi_ioremap *
266acpi_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. */
279static void __iomem *
280acpi_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. */
292static struct acpi_ioremap *
293acpi_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
281void __iomem *__init_refok 305void __iomem *__init_refok
282acpi_os_map_memory(acpi_physical_address phys, acpi_size size) 306acpi_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}
296EXPORT_SYMBOL_GPL(acpi_os_map_memory); 354EXPORT_SYMBOL_GPL(acpi_os_map_memory);
297 355
356static 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
298void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) 364void __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}
305EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); 394EXPORT_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
402int 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}
418EXPORT_SYMBOL_GPL(acpi_os_map_generic_address);
419
420void 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}
438EXPORT_SYMBOL_GPL(acpi_os_unmap_generic_address);
439
313#ifdef ACPI_FUTURE_USAGE 440#ifdef ACPI_FUTURE_USAGE
314acpi_status 441acpi_status
315acpi_os_get_physical_address(void *virt, acpi_physical_address * phys) 442acpi_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
541acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) 676acpi_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
1548acpi_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
1558acpi_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
1571acpi_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}