aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/mm/ioremap_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/mm/ioremap_64.c')
-rw-r--r--arch/sh/mm/ioremap_64.c266
1 files changed, 95 insertions, 171 deletions
diff --git a/arch/sh/mm/ioremap_64.c b/arch/sh/mm/ioremap_64.c
index 31e1bb5effbe..828c8597219d 100644
--- a/arch/sh/mm/ioremap_64.c
+++ b/arch/sh/mm/ioremap_64.c
@@ -20,6 +20,7 @@
20#include <linux/io.h> 20#include <linux/io.h>
21#include <linux/bootmem.h> 21#include <linux/bootmem.h>
22#include <linux/proc_fs.h> 22#include <linux/proc_fs.h>
23#include <linux/slab.h>
23#include <asm/page.h> 24#include <asm/page.h>
24#include <asm/pgalloc.h> 25#include <asm/pgalloc.h>
25#include <asm/addrspace.h> 26#include <asm/addrspace.h>
@@ -27,88 +28,17 @@
27#include <asm/tlbflush.h> 28#include <asm/tlbflush.h>
28#include <asm/mmu.h> 29#include <asm/mmu.h>
29 30
30static void shmedia_mapioaddr(unsigned long, unsigned long);
31static unsigned long shmedia_ioremap(struct resource *, u32, int);
32
33/*
34 * Generic mapping function (not visible outside):
35 */
36
37/*
38 * Remap an arbitrary physical address space into the kernel virtual
39 * address space. Needed when the kernel wants to access high addresses
40 * directly.
41 *
42 * NOTE! We need to allow non-page-aligned mappings too: we will obviously
43 * have to convert them into an offset in a page-aligned mapping, but the
44 * caller shouldn't need to know that small detail.
45 */
46void *__ioremap(unsigned long phys_addr, unsigned long size,
47 unsigned long flags)
48{
49 void * addr;
50 struct vm_struct * area;
51 unsigned long offset, last_addr;
52 pgprot_t pgprot;
53
54 /* Don't allow wraparound or zero size */
55 last_addr = phys_addr + size - 1;
56 if (!size || last_addr < phys_addr)
57 return NULL;
58
59 pgprot = __pgprot(_PAGE_PRESENT | _PAGE_READ |
60 _PAGE_WRITE | _PAGE_DIRTY |
61 _PAGE_ACCESSED | _PAGE_SHARED | flags);
62
63 /*
64 * Mappings have to be page-aligned
65 */
66 offset = phys_addr & ~PAGE_MASK;
67 phys_addr &= PAGE_MASK;
68 size = PAGE_ALIGN(last_addr + 1) - phys_addr;
69
70 /*
71 * Ok, go for it..
72 */
73 area = get_vm_area(size, VM_IOREMAP);
74 if (!area)
75 return NULL;
76 pr_debug("Get vm_area returns %p addr %p\n", area, area->addr);
77 area->phys_addr = phys_addr;
78 addr = area->addr;
79 if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
80 phys_addr, pgprot)) {
81 vunmap(addr);
82 return NULL;
83 }
84 return (void *) (offset + (char *)addr);
85}
86EXPORT_SYMBOL(__ioremap);
87
88void __iounmap(void *addr)
89{
90 struct vm_struct *area;
91
92 vfree((void *) (PAGE_MASK & (unsigned long) addr));
93 area = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr));
94 if (!area) {
95 printk(KERN_ERR "iounmap: bad address %p\n", addr);
96 return;
97 }
98
99 kfree(area);
100}
101EXPORT_SYMBOL(__iounmap);
102
103static struct resource shmedia_iomap = { 31static struct resource shmedia_iomap = {
104 .name = "shmedia_iomap", 32 .name = "shmedia_iomap",
105 .start = IOBASE_VADDR + PAGE_SIZE, 33 .start = IOBASE_VADDR + PAGE_SIZE,
106 .end = IOBASE_END - 1, 34 .end = IOBASE_END - 1,
107}; 35};
108 36
109static void shmedia_mapioaddr(unsigned long pa, unsigned long va); 37static void shmedia_mapioaddr(unsigned long pa, unsigned long va,
38 unsigned long flags);
110static void shmedia_unmapioaddr(unsigned long vaddr); 39static void shmedia_unmapioaddr(unsigned long vaddr);
111static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz); 40static void __iomem *shmedia_ioremap(struct resource *res, u32 pa,
41 int sz, unsigned long flags);
112 42
113/* 43/*
114 * We have the same problem as the SPARC, so lets have the same comment: 44 * We have the same problem as the SPARC, so lets have the same comment:
@@ -130,18 +60,18 @@ static struct xresource xresv[XNRES];
130 60
131static struct xresource *xres_alloc(void) 61static struct xresource *xres_alloc(void)
132{ 62{
133 struct xresource *xrp; 63 struct xresource *xrp;
134 int n; 64 int n;
135 65
136 xrp = xresv; 66 xrp = xresv;
137 for (n = 0; n < XNRES; n++) { 67 for (n = 0; n < XNRES; n++) {
138 if (xrp->xflag == 0) { 68 if (xrp->xflag == 0) {
139 xrp->xflag = 1; 69 xrp->xflag = 1;
140 return xrp; 70 return xrp;
141 } 71 }
142 xrp++; 72 xrp++;
143 } 73 }
144 return NULL; 74 return NULL;
145} 75}
146 76
147static void xres_free(struct xresource *xrp) 77static void xres_free(struct xresource *xrp)
@@ -161,76 +91,71 @@ static struct resource *shmedia_find_resource(struct resource *root,
161 return NULL; 91 return NULL;
162} 92}
163 93
164static unsigned long shmedia_alloc_io(unsigned long phys, unsigned long size, 94static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size,
165 const char *name) 95 const char *name, unsigned long flags)
166{ 96{
167 static int printed_full = 0; 97 static int printed_full;
168 struct xresource *xres; 98 struct xresource *xres;
169 struct resource *res; 99 struct resource *res;
170 char *tack; 100 char *tack;
171 int tlen; 101 int tlen;
172 102
173 if (name == NULL) name = "???"; 103 if (name == NULL)
174 104 name = "???";
175 if ((xres = xres_alloc()) != 0) { 105
176 tack = xres->xname; 106 xres = xres_alloc();
177 res = &xres->xres; 107 if (xres != 0) {
178 } else { 108 tack = xres->xname;
179 if (!printed_full) { 109 res = &xres->xres;
180 printk("%s: done with statics, switching to kmalloc\n", 110 } else {
181 __func__); 111 if (!printed_full) {
182 printed_full = 1; 112 printk(KERN_NOTICE "%s: done with statics, "
183 } 113 "switching to kmalloc\n", __func__);
184 tlen = strlen(name); 114 printed_full = 1;
185 tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL); 115 }
186 if (!tack) 116 tlen = strlen(name);
187 return -ENOMEM; 117 tack = kmalloc(sizeof(struct resource) + tlen + 1, GFP_KERNEL);
188 memset(tack, 0, sizeof(struct resource)); 118 if (!tack)
189 res = (struct resource *) tack; 119 return NULL;
190 tack += sizeof (struct resource); 120 memset(tack, 0, sizeof(struct resource));
191 } 121 res = (struct resource *) tack;
192 122 tack += sizeof(struct resource);
193 strncpy(tack, name, XNMLN); 123 }
194 tack[XNMLN] = 0; 124
195 res->name = tack; 125 strncpy(tack, name, XNMLN);
196 126 tack[XNMLN] = 0;
197 return shmedia_ioremap(res, phys, size); 127 res->name = tack;
128
129 return shmedia_ioremap(res, phys, size, flags);
198} 130}
199 131
200static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz) 132static void __iomem *shmedia_ioremap(struct resource *res, u32 pa, int sz,
133 unsigned long flags)
201{ 134{
202 unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK); 135 unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);
203 unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK; 136 unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK;
204 unsigned long va; 137 unsigned long va;
205 unsigned int psz; 138 unsigned int psz;
206 139
207 if (allocate_resource(&shmedia_iomap, res, round_sz, 140 if (allocate_resource(&shmedia_iomap, res, round_sz,
208 shmedia_iomap.start, shmedia_iomap.end, 141 shmedia_iomap.start, shmedia_iomap.end,
209 PAGE_SIZE, NULL, NULL) != 0) { 142 PAGE_SIZE, NULL, NULL) != 0) {
210 panic("alloc_io_res(%s): cannot occupy\n", 143 panic("alloc_io_res(%s): cannot occupy\n",
211 (res->name != NULL)? res->name: "???"); 144 (res->name != NULL) ? res->name : "???");
212 } 145 }
213 146
214 va = res->start; 147 va = res->start;
215 pa &= PAGE_MASK; 148 pa &= PAGE_MASK;
216 149
217 psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; 150 psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
218 151
219 /* log at boot time ... */ 152 for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) {
220 printk("mapioaddr: %6s [%2d page%s] va 0x%08lx pa 0x%08x\n", 153 shmedia_mapioaddr(pa, va, flags);
221 ((res->name != NULL) ? res->name : "???"), 154 va += PAGE_SIZE;
222 psz, psz == 1 ? " " : "s", va, pa); 155 pa += PAGE_SIZE;
223 156 }
224 for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) {
225 shmedia_mapioaddr(pa, va);
226 va += PAGE_SIZE;
227 pa += PAGE_SIZE;
228 }
229
230 res->start += offset;
231 res->end = res->start + sz - 1; /* not strictly necessary.. */
232 157
233 return res->start; 158 return (void __iomem *)(unsigned long)(res->start + offset);
234} 159}
235 160
236static void shmedia_free_io(struct resource *res) 161static void shmedia_free_io(struct resource *res)
@@ -249,14 +174,12 @@ static void shmedia_free_io(struct resource *res)
249 174
250static __init_refok void *sh64_get_page(void) 175static __init_refok void *sh64_get_page(void)
251{ 176{
252 extern int after_bootmem;
253 void *page; 177 void *page;
254 178
255 if (after_bootmem) { 179 if (slab_is_available())
256 page = (void *)get_zeroed_page(GFP_ATOMIC); 180 page = (void *)get_zeroed_page(GFP_KERNEL);
257 } else { 181 else
258 page = alloc_bootmem_pages(PAGE_SIZE); 182 page = alloc_bootmem_pages(PAGE_SIZE);
259 }
260 183
261 if (!page || ((unsigned long)page & ~PAGE_MASK)) 184 if (!page || ((unsigned long)page & ~PAGE_MASK))
262 panic("sh64_get_page: Out of memory already?\n"); 185 panic("sh64_get_page: Out of memory already?\n");
@@ -264,17 +187,20 @@ static __init_refok void *sh64_get_page(void)
264 return page; 187 return page;
265} 188}
266 189
267static void shmedia_mapioaddr(unsigned long pa, unsigned long va) 190static void shmedia_mapioaddr(unsigned long pa, unsigned long va,
191 unsigned long flags)
268{ 192{
269 pgd_t *pgdp; 193 pgd_t *pgdp;
270 pud_t *pudp; 194 pud_t *pudp;
271 pmd_t *pmdp; 195 pmd_t *pmdp;
272 pte_t *ptep, pte; 196 pte_t *ptep, pte;
273 pgprot_t prot; 197 pgprot_t prot;
274 unsigned long flags = 1; /* 1 = CB0-1 device */
275 198
276 pr_debug("shmedia_mapiopage pa %08lx va %08lx\n", pa, va); 199 pr_debug("shmedia_mapiopage pa %08lx va %08lx\n", pa, va);
277 200
201 if (!flags)
202 flags = 1; /* 1 = CB0-1 device */
203
278 pgdp = pgd_offset_k(va); 204 pgdp = pgd_offset_k(va);
279 if (pgd_none(*pgdp) || !pgd_present(*pgdp)) { 205 if (pgd_none(*pgdp) || !pgd_present(*pgdp)) {
280 pudp = (pud_t *)sh64_get_page(); 206 pudp = (pud_t *)sh64_get_page();
@@ -288,7 +214,7 @@ static void shmedia_mapioaddr(unsigned long pa, unsigned long va)
288 } 214 }
289 215
290 pmdp = pmd_offset(pudp, va); 216 pmdp = pmd_offset(pudp, va);
291 if (pmd_none(*pmdp) || !pmd_present(*pmdp) ) { 217 if (pmd_none(*pmdp) || !pmd_present(*pmdp)) {
292 ptep = (pte_t *)sh64_get_page(); 218 ptep = (pte_t *)sh64_get_page();
293 set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE)); 219 set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE));
294 } 220 }
@@ -336,17 +262,19 @@ static void shmedia_unmapioaddr(unsigned long vaddr)
336 pte_clear(&init_mm, vaddr, ptep); 262 pte_clear(&init_mm, vaddr, ptep);
337} 263}
338 264
339unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name) 265void __iomem *__ioremap(unsigned long offset, unsigned long size,
266 unsigned long flags)
340{ 267{
341 if (size < PAGE_SIZE) 268 char name[14];
342 size = PAGE_SIZE;
343 269
344 return shmedia_alloc_io(phys, size, name); 270 sprintf(name, "phys_%08x", (u32)offset);
271 return shmedia_alloc_io(offset, size, name, flags);
345} 272}
346EXPORT_SYMBOL(onchip_remap); 273EXPORT_SYMBOL(__ioremap);
347 274
348void onchip_unmap(unsigned long vaddr) 275void __iounmap(void __iomem *virtual)
349{ 276{
277 unsigned long vaddr = (unsigned long)virtual & PAGE_MASK;
350 struct resource *res; 278 struct resource *res;
351 unsigned int psz; 279 unsigned int psz;
352 280
@@ -357,10 +285,7 @@ void onchip_unmap(unsigned long vaddr)
357 return; 285 return;
358 } 286 }
359 287
360 psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; 288 psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
361
362 printk(KERN_DEBUG "unmapioaddr: %6s [%2d page%s] freed\n",
363 res->name, psz, psz == 1 ? " " : "s");
364 289
365 shmedia_free_io(res); 290 shmedia_free_io(res);
366 291
@@ -371,9 +296,8 @@ void onchip_unmap(unsigned long vaddr)
371 kfree(res); 296 kfree(res);
372 } 297 }
373} 298}
374EXPORT_SYMBOL(onchip_unmap); 299EXPORT_SYMBOL(__iounmap);
375 300
376#ifdef CONFIG_PROC_FS
377static int 301static int
378ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, 302ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
379 void *data) 303 void *data)
@@ -385,7 +309,10 @@ ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
385 for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) { 309 for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) {
386 if (p + 32 >= e) /* Better than nothing */ 310 if (p + 32 >= e) /* Better than nothing */
387 break; 311 break;
388 if ((nm = r->name) == 0) nm = "???"; 312 nm = r->name;
313 if (nm == NULL)
314 nm = "???";
315
389 p += sprintf(p, "%08lx-%08lx: %s\n", 316 p += sprintf(p, "%08lx-%08lx: %s\n",
390 (unsigned long)r->start, 317 (unsigned long)r->start,
391 (unsigned long)r->end, nm); 318 (unsigned long)r->end, nm);
@@ -393,14 +320,11 @@ ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
393 320
394 return p-buf; 321 return p-buf;
395} 322}
396#endif /* CONFIG_PROC_FS */
397 323
398static int __init register_proc_onchip(void) 324static int __init register_proc_onchip(void)
399{ 325{
400#ifdef CONFIG_PROC_FS 326 create_proc_read_entry("io_map", 0, 0, ioremap_proc_info,
401 create_proc_read_entry("io_map",0,0, ioremap_proc_info, &shmedia_iomap); 327 &shmedia_iomap);
402#endif
403 return 0; 328 return 0;
404} 329}
405 330late_initcall(register_proc_onchip);
406__initcall(register_proc_onchip);