Skip to content

Commit

Permalink
ACPI, Add RAM mapping support to ACPI atomic IO support
Browse files Browse the repository at this point in the history
On one of our testing machine, the following EINJ command lines:

  # echo 0x10000000 > param1
  # echo 0xfffffffffffff000 > param2
  # echo 0x8 > error_type
  # echo 1 > error_inject

Will get:

  echo: write error: Input/output error

The EIO comes from:

    rc = apei_exec_pre_map_gars(&trigger_ctx);

The root cause is as follow.  Normally, ACPI atomic IO support is used
to access IO memory.  But in EINJ of that machine, it is used to
access RAM to trigger the injected error.  And the ioremap() called by
apei_exec_pre_map_gars() can not map the RAM.

This patch add RAM mapping support to ACPI atomic IO support to
satisfy EINJ requirement.

Signed-off-by: Huang Ying <[email protected]>
Tested-by: Tony Luck <[email protected]>
Signed-off-by: Len Brown <[email protected]>
  • Loading branch information
yhuang-intel authored and lenb committed Jan 17, 2012
1 parent 46d12f0 commit 76da3fb
Showing 1 changed file with 37 additions and 4 deletions.
41 changes: 37 additions & 4 deletions drivers/acpi/atomicio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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: "
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -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;
}
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit 76da3fb

Please sign in to comment.