[RFC 2/2] ACPI, Add RAM mapping support to ACPI atomic IO support

Huang Ying
2011-08-30T06:28:36Z

Normally, ACPI atomic IO support is used to access IO memory. But in
EINJ, it may be used to access RAM to trigger the injected error.
This patch add RAM mapping support to satisfy EINJ requirement.

Signed-off-by: Huang Ying <ying.huang@intel.com>
Cc: Tony Luck <tony.luck@intel.com>
---
drivers/acpi/atomicio.c | 34 ++++++++++++++++++++++++++++++----
1 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c
index 7489b89..edf2f11 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,30 @@ static void __iomem *__acpi_try_ioremap(phys_addr_t paddr,
return NULL;
}

+static void __iomem *acpi_map(phys_addr_t pg_off, unsigned long pg_sz)
+{
+ unsigned long pfn;
+
+ pfn = pg_off >> PAGE_SHIFT;
+ if (page_is_ram(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 +145,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 +161,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 +170,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 +203,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);
}

--
1.7.5.4