Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * arch/parisc/mm/ioremap.c | |
3 | * | |
1da177e4 | 4 | * (C) Copyright 1995 1996 Linus Torvalds |
b2d6b9fb | 5 | * (C) Copyright 2001-2006 Helge Deller <deller@gmx.de> |
e0565a1c | 6 | * (C) Copyright 2005 Kyle McMartin <kyle@parisc-linux.org> |
1da177e4 LT |
7 | */ |
8 | ||
9 | #include <linux/vmalloc.h> | |
10 | #include <linux/errno.h> | |
11 | #include <linux/module.h> | |
e34067fd | 12 | #include <linux/io.h> |
1da177e4 | 13 | #include <asm/pgalloc.h> |
1da177e4 | 14 | |
1da177e4 LT |
15 | /* |
16 | * Generic mapping function (not visible outside): | |
17 | */ | |
18 | ||
19 | /* | |
20 | * Remap an arbitrary physical address space into the kernel virtual | |
e0565a1c | 21 | * address space. |
1da177e4 LT |
22 | * |
23 | * NOTE! We need to allow non-page-aligned mappings too: we will obviously | |
24 | * have to convert them into an offset in a page-aligned mapping, but the | |
25 | * caller shouldn't need to know that small detail. | |
26 | */ | |
27 | void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) | |
28 | { | |
e51ec241 | 29 | void __iomem *addr; |
cb4ab59c HD |
30 | struct vm_struct *area; |
31 | unsigned long offset, last_addr; | |
e34067fd | 32 | pgprot_t pgprot; |
cb4ab59c | 33 | |
29ef8295 | 34 | #ifdef CONFIG_EISA |
1da177e4 LT |
35 | unsigned long end = phys_addr + size - 1; |
36 | /* Support EISA addresses */ | |
10267cdd HD |
37 | if ((phys_addr >= 0x00080000 && end < 0x000fffff) || |
38 | (phys_addr >= 0x00500000 && end < 0x03bfffff)) { | |
39 | phys_addr |= F_EXTEND(0xfc000000); | |
b2d6b9fb | 40 | flags |= _PAGE_NO_CACHE; |
1da177e4 | 41 | } |
1da177e4 LT |
42 | #endif |
43 | ||
1da177e4 LT |
44 | /* Don't allow wraparound or zero size */ |
45 | last_addr = phys_addr + size - 1; | |
46 | if (!size || last_addr < phys_addr) | |
47 | return NULL; | |
48 | ||
49 | /* | |
50 | * Don't allow anybody to remap normal RAM that we're using.. | |
51 | */ | |
52 | if (phys_addr < virt_to_phys(high_memory)) { | |
53 | char *t_addr, *t_end; | |
54 | struct page *page; | |
55 | ||
56 | t_addr = __va(phys_addr); | |
57 | t_end = t_addr + (size - 1); | |
58 | ||
e0565a1c KM |
59 | for (page = virt_to_page(t_addr); |
60 | page <= virt_to_page(t_end); page++) { | |
1da177e4 LT |
61 | if(!PageReserved(page)) |
62 | return NULL; | |
e0565a1c | 63 | } |
1da177e4 LT |
64 | } |
65 | ||
e34067fd HS |
66 | pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | |
67 | _PAGE_ACCESSED | flags); | |
68 | ||
1da177e4 LT |
69 | /* |
70 | * Mappings have to be page-aligned | |
71 | */ | |
72 | offset = phys_addr & ~PAGE_MASK; | |
73 | phys_addr &= PAGE_MASK; | |
a292dfa0 | 74 | size = PAGE_ALIGN(last_addr + 1) - phys_addr; |
1da177e4 LT |
75 | |
76 | /* | |
77 | * Ok, go for it.. | |
78 | */ | |
79 | area = get_vm_area(size, VM_IOREMAP); | |
80 | if (!area) | |
81 | return NULL; | |
e0565a1c | 82 | |
e51ec241 | 83 | addr = (void __iomem *) area->addr; |
e34067fd HS |
84 | if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, |
85 | phys_addr, pgprot)) { | |
1da177e4 LT |
86 | vfree(addr); |
87 | return NULL; | |
88 | } | |
e0565a1c | 89 | |
e51ec241 | 90 | return (void __iomem *) (offset + (char __iomem *)addr); |
1da177e4 | 91 | } |
d345fd36 | 92 | EXPORT_SYMBOL(__ioremap); |
1da177e4 | 93 | |
01232e93 | 94 | void iounmap(const volatile void __iomem *addr) |
1da177e4 | 95 | { |
1da177e4 LT |
96 | if (addr > high_memory) |
97 | return vfree((void *) (PAGE_MASK & (unsigned long __force) addr)); | |
1da177e4 | 98 | } |
d345fd36 | 99 | EXPORT_SYMBOL(iounmap); |