aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMyron Stowe <myron.stowe@hp.com>2010-10-21 16:23:53 -0400
committerLen Brown <len.brown@intel.com>2010-10-24 23:25:52 -0400
commit620242ae8c3d9c0b1a77451744fb2d855d1e7342 (patch)
tree33271319c7628aa51998fadf5df0f492c36abb4f /drivers
parentb3ba1efec2a58f4dc0647f4c0099c27d6ab92595 (diff)
ACPI: Maintain a list of ACPI memory mapped I/O remappings
For memory mapped I/O (MMIO) remappings, add a list to maintain the remappings and augment the corresponding mapping and unmapping interface routines (acpi_os_map_memory() and acpi_os_unmap_memory()) to dynamically add to, and delete from, the list. The current ACPI I/O accessing methods - acpi_read() and acpi_write() - end up calling ioremap() when accessing MMIO. This prevents use of these methods within interrupt context (IRQ and/or NMI), since ioremap() may block to allocate memory. Maintaining a list of MMIO remappings enables accesses to such areas from within interrupt context provided they have been pre-mapped. Signed-off-by: Myron Stowe <myron.stowe@hp.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/osl.c128
1 files changed, 113 insertions, 15 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 58842fb9fd90..bd72129e35f2 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -95,6 +95,20 @@ 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};
108
109static LIST_HEAD(acpi_ioremaps);
110static DEFINE_SPINLOCK(acpi_ioremap_lock);
111
98#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ 112#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
99static char osi_additional_string[OSI_STRING_LENGTH_MAX]; 113static char osi_additional_string[OSI_STRING_LENGTH_MAX];
100 114
@@ -260,29 +274,95 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
260 } 274 }
261} 275}
262 276
277/* Must be called with 'acpi_ioremap_lock' lock held. */
278static void __iomem *
279acpi_map_vaddr_lookup(acpi_physical_address phys, acpi_size size)
280{
281 struct acpi_ioremap *map;
282
283 list_for_each_entry(map, &acpi_ioremaps, list)
284 if (map->phys <= phys &&
285 phys + size <= map->phys + map->size)
286 return map->virt + (phys - map->phys);
287
288 return NULL;
289}
290
291/* Must be called with 'acpi_ioremap_lock' 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(map, &acpi_ioremaps, list)
298 if (map->virt == virt && map->size == size)
299 return map;
300
301 return NULL;
302}
303
263void __iomem *__init_refok 304void __iomem *__init_refok
264acpi_os_map_memory(acpi_physical_address phys, acpi_size size) 305acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
265{ 306{
307 struct acpi_ioremap *map;
308 unsigned long flags;
309 void __iomem *virt;
310
266 if (phys > ULONG_MAX) { 311 if (phys > ULONG_MAX) {
267 printk(KERN_ERR PREFIX "Cannot map memory that high\n"); 312 printk(KERN_ERR PREFIX "Cannot map memory that high\n");
268 return NULL; 313 return NULL;
269 } 314 }
270 if (acpi_gbl_permanent_mmap) 315
271 /* 316 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); 317 return __acpi_map_table((unsigned long)phys, size);
318
319 map = kzalloc(sizeof(*map), GFP_KERNEL);
320 if (!map)
321 return NULL;
322
323 virt = ioremap(phys, size);
324 if (!virt) {
325 kfree(map);
326 return NULL;
327 }
328
329 INIT_LIST_HEAD(&map->list);
330 map->virt = virt;
331 map->phys = phys;
332 map->size = size;
333
334 spin_lock_irqsave(&acpi_ioremap_lock, flags);
335 list_add_tail(&map->list, &acpi_ioremaps);
336 spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
337
338 return virt;
277} 339}
278EXPORT_SYMBOL_GPL(acpi_os_map_memory); 340EXPORT_SYMBOL_GPL(acpi_os_map_memory);
279 341
280void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) 342void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
281{ 343{
282 if (acpi_gbl_permanent_mmap) 344 struct acpi_ioremap *map;
283 iounmap(virt); 345 unsigned long flags;
284 else 346
347 if (!acpi_gbl_permanent_mmap) {
285 __acpi_unmap_table(virt, size); 348 __acpi_unmap_table(virt, size);
349 return;
350 }
351
352 spin_lock_irqsave(&acpi_ioremap_lock, flags);
353 map = acpi_map_lookup_virt(virt, size);
354 if (!map) {
355 spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
356 printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt);
357 dump_stack();
358 return;
359 }
360
361 list_del(&map->list);
362 spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
363
364 iounmap(map->virt);
365 kfree(map);
286} 366}
287EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); 367EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
288 368
@@ -495,8 +575,16 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
495{ 575{
496 u32 dummy; 576 u32 dummy;
497 void __iomem *virt_addr; 577 void __iomem *virt_addr;
498 578 int size = width / 8, unmap = 0;
499 virt_addr = ioremap(phys_addr, width / 8); 579 unsigned long flags;
580
581 spin_lock_irqsave(&acpi_ioremap_lock, flags);
582 virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
583 spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
584 if (!virt_addr) {
585 virt_addr = ioremap(phys_addr, size);
586 unmap = 1;
587 }
500 if (!value) 588 if (!value)
501 value = &dummy; 589 value = &dummy;
502 590
@@ -514,7 +602,8 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
514 BUG(); 602 BUG();
515 } 603 }
516 604
517 iounmap(virt_addr); 605 if (unmap)
606 iounmap(virt_addr);
518 607
519 return AE_OK; 608 return AE_OK;
520} 609}
@@ -523,8 +612,16 @@ acpi_status
523acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) 612acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
524{ 613{
525 void __iomem *virt_addr; 614 void __iomem *virt_addr;
526 615 int size = width / 8, unmap = 0;
527 virt_addr = ioremap(phys_addr, width / 8); 616 unsigned long flags;
617
618 spin_lock_irqsave(&acpi_ioremap_lock, flags);
619 virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
620 spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
621 if (!virt_addr) {
622 virt_addr = ioremap(phys_addr, size);
623 unmap = 1;
624 }
528 625
529 switch (width) { 626 switch (width) {
530 case 8: 627 case 8:
@@ -540,7 +637,8 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
540 BUG(); 637 BUG();
541 } 638 }
542 639
543 iounmap(virt_addr); 640 if (unmap)
641 iounmap(virt_addr);
544 642
545 return AE_OK; 643 return AE_OK;
546} 644}