1
2
3
4#include <linux/vmalloc.h>
5#include <linux/io.h>
6#include <linux/mm.h>
7#include <asm/pgtable.h>
8
9void __iomem *ioremap(phys_addr_t phys_addr, size_t size);
10
11static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
12 void *caller)
13{
14 struct vm_struct *area;
15 unsigned long addr, offset, last_addr;
16 pgprot_t prot;
17
18
19 last_addr = phys_addr + size - 1;
20 if (!size || last_addr < phys_addr)
21 return NULL;
22
23
24
25
26 offset = phys_addr & ~PAGE_MASK;
27 phys_addr &= PAGE_MASK;
28 size = PAGE_ALIGN(last_addr + 1) - phys_addr;
29
30
31
32
33 area = get_vm_area_caller(size, VM_IOREMAP, caller);
34 if (!area)
35 return NULL;
36
37 area->phys_addr = phys_addr;
38 addr = (unsigned long)area->addr;
39 prot = __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D |
40 _PAGE_G | _PAGE_C_DEV);
41 if (ioremap_page_range(addr, addr + size, phys_addr, prot)) {
42 vunmap((void *)addr);
43 return NULL;
44 }
45 return (__force void __iomem *)(offset + (char *)addr);
46
47}
48
49void __iomem *ioremap(phys_addr_t phys_addr, size_t size)
50{
51 return __ioremap_caller(phys_addr, size,
52 __builtin_return_address(0));
53}
54
55EXPORT_SYMBOL(ioremap);
56
57void iounmap(volatile void __iomem * addr)
58{
59 vunmap((void *)(PAGE_MASK & (unsigned long)addr));
60}
61
62EXPORT_SYMBOL(iounmap);
63