[PATCH 03/10] x86: translate highmem /dev/mem pointers

From: Petr Tesarik
Date: Fri Jun 17 2011 - 04:59:42 EST


On 32-bit x86, it is necessary to kmap/kunmap /dev/mem pointers in
the high memory area.

Signed-off-by: Petr Tesarik <ptesarik@xxxxxxx>
---
arch/x86/include/asm/io.h | 4 ++--
arch/x86/mm/ioremap.c | 24 ++++++++++++++++++------
2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index d02804d..9b994dd 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -311,8 +311,8 @@ BUILDIO(b, b, char)
BUILDIO(w, w, short)
BUILDIO(l, , int)

-extern void *xlate_dev_mem_ptr(unsigned long phys);
-extern void unxlate_dev_mem_ptr(unsigned long phys, void *addr);
+extern void *xlate_dev_mem_ptr(phys_addr_t phys);
+extern void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr);

extern int ioremap_change_attr(unsigned long vaddr, unsigned long size,
unsigned long prot_val);
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index be1ef57..fb566d7 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -308,26 +308,38 @@ EXPORT_SYMBOL(iounmap);
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
* access
*/
-void *xlate_dev_mem_ptr(unsigned long phys)
+void *xlate_dev_mem_ptr(phys_addr_t phys)
{
void *addr;
- unsigned long start = phys & PAGE_MASK;
+ unsigned long pfn = phys >> PAGE_SHIFT;
+ phys_addr_t start = phys & ~((phys_addr_t)PAGE_SIZE-1);

/* If page is RAM, we can use __va. Otherwise ioremap and unmap. */
- if (page_is_ram(start >> PAGE_SHIFT))
+ if (page_is_ram(pfn)) {
+ if (phys >= __pa(high_memory))
+ return pfn_valid(pfn)
+ ? kmap(pfn_to_page(pfn))
+ : NULL;
return __va(phys);
+ }

addr = (void __force *)ioremap_cache(start, PAGE_SIZE);
if (addr)
- addr = (void *)((unsigned long)addr | (phys & ~PAGE_MASK));
+ addr = (void *)((unsigned long)addr |
+ ((unsigned long)phys & ~PAGE_MASK));

return addr;
}

-void unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
{
- if (page_is_ram(phys >> PAGE_SHIFT))
+ unsigned long pfn = phys >> PAGE_SHIFT;
+
+ if (page_is_ram(pfn)) {
+ if (phys >= __pa(high_memory))
+ kunmap(pfn_to_page(pfn));
return;
+ }

iounmap((void __iomem *)((unsigned long)addr & PAGE_MASK));
return;
--
1.7.3.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/