diff options
-rw-r--r-- | drivers/acpi/atomicio.c | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c index 1016f186c17c..d4a5b3d3657b 100644 --- a/drivers/acpi/atomicio.c +++ b/drivers/acpi/atomicio.c @@ -32,6 +32,8 @@ #include <linux/rculist.h> #include <linux/interrupt.h> #include <linux/slab.h> +#include <linux/mm.h> +#include <linux/highmem.h> #include <acpi/atomicio.h> #define ACPI_PFX "ACPI: " @@ -97,6 +99,37 @@ static void __iomem *__acpi_try_ioremap(phys_addr_t paddr, return NULL; } +#ifndef CONFIG_IA64 +#define should_use_kmap(pfn) page_is_ram(pfn) +#else +/* ioremap will take care of cache attributes */ +#define should_use_kmap(pfn) 0 +#endif + +static void __iomem *acpi_map(phys_addr_t pg_off, unsigned long pg_sz) +{ + unsigned long pfn; + + pfn = pg_off >> PAGE_SHIFT; + if (should_use_kmap(pfn)) { + if (pg_sz > PAGE_SIZE) + return NULL; + return (void __iomem __force *)kmap(pfn_to_page(pfn)); + } else + return ioremap(pg_off, pg_sz); +} + +static void acpi_unmap(phys_addr_t pg_off, void __iomem *vaddr) +{ + unsigned long pfn; + + pfn = pg_off >> PAGE_SHIFT; + if (page_is_ram(pfn)) + kunmap(pfn_to_page(pfn)); + else + iounmap(vaddr); +} + /* * Used to pre-map the specified IO memory area. First try to find * whether the area is already pre-mapped, if it is, increase the @@ -119,7 +152,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr, pg_off = paddr & PAGE_MASK; pg_sz = ((paddr + size + PAGE_SIZE - 1) & PAGE_MASK) - pg_off; - vaddr = ioremap(pg_off, pg_sz); + vaddr = acpi_map(pg_off, pg_sz); if (!vaddr) return NULL; map = kmalloc(sizeof(*map), GFP_KERNEL); @@ -135,7 +168,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr, vaddr = __acpi_try_ioremap(paddr, size); if (vaddr) { spin_unlock_irqrestore(&acpi_iomaps_lock, flags); - iounmap(map->vaddr); + acpi_unmap(pg_off, map->vaddr); kfree(map); return vaddr; } @@ -144,7 +177,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr, return map->vaddr + (paddr - map->paddr); err_unmap: - iounmap(vaddr); + acpi_unmap(pg_off, vaddr); return NULL; } @@ -177,7 +210,7 @@ static void acpi_post_unmap(phys_addr_t paddr, unsigned long size) return; synchronize_rcu(); - iounmap(map->vaddr); + acpi_unmap(map->paddr, map->vaddr); kfree(map); } |