Commit | Line | Data |
---|---|---|
1162b070 VG |
1 | /* |
2 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 as | |
6 | * published by the Free Software Foundation. | |
7 | */ | |
8 | ||
9 | #include <linux/vmalloc.h> | |
10 | #include <linux/init.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/io.h> | |
13 | #include <linux/mm.h> | |
14 | #include <linux/slab.h> | |
1ec9db10 | 15 | #include <linux/cache.h> |
1162b070 VG |
16 | |
17 | void __iomem *ioremap(unsigned long paddr, unsigned long size) | |
18 | { | |
4368902b | 19 | unsigned long end; |
1162b070 VG |
20 | |
21 | /* Don't allow wraparound or zero size */ | |
22 | end = paddr + size - 1; | |
23 | if (!size || (end < paddr)) | |
24 | return NULL; | |
25 | ||
4368902b | 26 | /* If the region is h/w uncached, avoid MMU mappings */ |
1162b070 VG |
27 | if (paddr >= ARC_UNCACHED_ADDR_SPACE) |
28 | return (void __iomem *)paddr; | |
29 | ||
4368902b GBY |
30 | return ioremap_prot(paddr, size, PAGE_KERNEL_NO_CACHE); |
31 | } | |
32 | EXPORT_SYMBOL(ioremap); | |
33 | ||
34 | /* | |
35 | * ioremap with access flags | |
36 | * Cache semantics wise it is same as ioremap - "forced" uncached. | |
37 | * However unline vanilla ioremap which bypasses ARC MMU for addresses in | |
38 | * ARC hardware uncached region, this one still goes thru the MMU as caller | |
39 | * might need finer access control (R/W/X) | |
40 | */ | |
41 | void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size, | |
42 | unsigned long flags) | |
43 | { | |
44 | void __iomem *vaddr; | |
45 | struct vm_struct *area; | |
46 | unsigned long off, end; | |
47 | pgprot_t prot = __pgprot(flags); | |
48 | ||
49 | /* Don't allow wraparound, zero size */ | |
50 | end = paddr + size - 1; | |
51 | if ((!size) || (end < paddr)) | |
52 | return NULL; | |
53 | ||
1162b070 VG |
54 | /* An early platform driver might end up here */ |
55 | if (!slab_is_available()) | |
56 | return NULL; | |
57 | ||
4368902b GBY |
58 | /* force uncached */ |
59 | prot = pgprot_noncached(prot); | |
60 | ||
61 | /* Mappings have to be page-aligned */ | |
1162b070 VG |
62 | off = paddr & ~PAGE_MASK; |
63 | paddr &= PAGE_MASK; | |
64 | size = PAGE_ALIGN(end + 1) - paddr; | |
65 | ||
66 | /* | |
67 | * Ok, go for it.. | |
68 | */ | |
69 | area = get_vm_area(size, VM_IOREMAP); | |
70 | if (!area) | |
71 | return NULL; | |
1162b070 | 72 | area->phys_addr = paddr; |
4368902b GBY |
73 | vaddr = (void __iomem *)area->addr; |
74 | if (ioremap_page_range((unsigned long)vaddr, | |
75 | (unsigned long)vaddr + size, paddr, prot)) { | |
76 | vunmap((void __force *)vaddr); | |
1162b070 VG |
77 | return NULL; |
78 | } | |
1162b070 VG |
79 | return (void __iomem *)(off + (char __iomem *)vaddr); |
80 | } | |
4368902b GBY |
81 | EXPORT_SYMBOL(ioremap_prot); |
82 | ||
1162b070 VG |
83 | |
84 | void iounmap(const void __iomem *addr) | |
85 | { | |
86 | if (addr >= (void __force __iomem *)ARC_UNCACHED_ADDR_SPACE) | |
87 | return; | |
88 | ||
89 | vfree((void *)(PAGE_MASK & (unsigned long __force)addr)); | |
90 | } | |
91 | EXPORT_SYMBOL(iounmap); |