diff options
author | Paul Mundt <lethal@linux-sh.org> | 2009-05-07 05:10:27 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-05-07 05:10:27 -0400 |
commit | 0fb849b9d743a20056f2418cd955e5c650658663 (patch) | |
tree | dd2d44103536ae83f8db483a8657bdcc36ad5c14 /arch/sh/mm | |
parent | ae318a148e4d255dfbc87d963fdd6031c2af9c46 (diff) |
sh: Integrate the SH-5 onchip_remap() more coherently.
Presently this is special-cased for early initialization. While there are
situations where these static early initializations are still necessary,
with minor changes it is possible to use this for the regular ioremap
implementation as well. This allows us to kill off the special-casing for
the remap completely and to start tidying up all of the SH-5
special-casing in drivers.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/mm')
-rw-r--r-- | arch/sh/mm/ioremap_64.c | 265 |
1 files changed, 94 insertions, 171 deletions
diff --git a/arch/sh/mm/ioremap_64.c b/arch/sh/mm/ioremap_64.c index 31e1bb5effbe..2331229f8126 100644 --- a/arch/sh/mm/ioremap_64.c +++ b/arch/sh/mm/ioremap_64.c | |||
@@ -27,88 +27,17 @@ | |||
27 | #include <asm/tlbflush.h> | 27 | #include <asm/tlbflush.h> |
28 | #include <asm/mmu.h> | 28 | #include <asm/mmu.h> |
29 | 29 | ||
30 | static void shmedia_mapioaddr(unsigned long, unsigned long); | ||
31 | static 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 | */ | ||
46 | void *__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 | } | ||
86 | EXPORT_SYMBOL(__ioremap); | ||
87 | |||
88 | void __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 | } | ||
101 | EXPORT_SYMBOL(__iounmap); | ||
102 | |||
103 | static struct resource shmedia_iomap = { | 30 | static struct resource shmedia_iomap = { |
104 | .name = "shmedia_iomap", | 31 | .name = "shmedia_iomap", |
105 | .start = IOBASE_VADDR + PAGE_SIZE, | 32 | .start = IOBASE_VADDR + PAGE_SIZE, |
106 | .end = IOBASE_END - 1, | 33 | .end = IOBASE_END - 1, |
107 | }; | 34 | }; |
108 | 35 | ||
109 | static void shmedia_mapioaddr(unsigned long pa, unsigned long va); | 36 | static void shmedia_mapioaddr(unsigned long pa, unsigned long va, |
37 | unsigned long flags); | ||
110 | static void shmedia_unmapioaddr(unsigned long vaddr); | 38 | static void shmedia_unmapioaddr(unsigned long vaddr); |
111 | static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz); | 39 | static void __iomem *shmedia_ioremap(struct resource *res, u32 pa, |
40 | int sz, unsigned long flags); | ||
112 | 41 | ||
113 | /* | 42 | /* |
114 | * We have the same problem as the SPARC, so lets have the same comment: | 43 | * We have the same problem as the SPARC, so lets have the same comment: |
@@ -130,18 +59,18 @@ static struct xresource xresv[XNRES]; | |||
130 | 59 | ||
131 | static struct xresource *xres_alloc(void) | 60 | static struct xresource *xres_alloc(void) |
132 | { | 61 | { |
133 | struct xresource *xrp; | 62 | struct xresource *xrp; |
134 | int n; | 63 | int n; |
135 | 64 | ||
136 | xrp = xresv; | 65 | xrp = xresv; |
137 | for (n = 0; n < XNRES; n++) { | 66 | for (n = 0; n < XNRES; n++) { |
138 | if (xrp->xflag == 0) { | 67 | if (xrp->xflag == 0) { |
139 | xrp->xflag = 1; | 68 | xrp->xflag = 1; |
140 | return xrp; | 69 | return xrp; |
141 | } | 70 | } |
142 | xrp++; | 71 | xrp++; |
143 | } | 72 | } |
144 | return NULL; | 73 | return NULL; |
145 | } | 74 | } |
146 | 75 | ||
147 | static void xres_free(struct xresource *xrp) | 76 | static void xres_free(struct xresource *xrp) |
@@ -161,76 +90,71 @@ static struct resource *shmedia_find_resource(struct resource *root, | |||
161 | return NULL; | 90 | return NULL; |
162 | } | 91 | } |
163 | 92 | ||
164 | static unsigned long shmedia_alloc_io(unsigned long phys, unsigned long size, | 93 | static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size, |
165 | const char *name) | 94 | const char *name, unsigned long flags) |
166 | { | 95 | { |
167 | static int printed_full = 0; | 96 | static int printed_full; |
168 | struct xresource *xres; | 97 | struct xresource *xres; |
169 | struct resource *res; | 98 | struct resource *res; |
170 | char *tack; | 99 | char *tack; |
171 | int tlen; | 100 | int tlen; |
172 | 101 | ||
173 | if (name == NULL) name = "???"; | 102 | if (name == NULL) |
174 | 103 | name = "???"; | |
175 | if ((xres = xres_alloc()) != 0) { | 104 | |
176 | tack = xres->xname; | 105 | xres = xres_alloc(); |
177 | res = &xres->xres; | 106 | if (xres != 0) { |
178 | } else { | 107 | tack = xres->xname; |
179 | if (!printed_full) { | 108 | res = &xres->xres; |
180 | printk("%s: done with statics, switching to kmalloc\n", | 109 | } else { |
181 | __func__); | 110 | if (!printed_full) { |
182 | printed_full = 1; | 111 | printk(KERN_NOTICE "%s: done with statics, " |
183 | } | 112 | "switching to kmalloc\n", __func__); |
184 | tlen = strlen(name); | 113 | printed_full = 1; |
185 | tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL); | 114 | } |
186 | if (!tack) | 115 | tlen = strlen(name); |
187 | return -ENOMEM; | 116 | tack = kmalloc(sizeof(struct resource) + tlen + 1, GFP_KERNEL); |
188 | memset(tack, 0, sizeof(struct resource)); | 117 | if (!tack) |
189 | res = (struct resource *) tack; | 118 | return NULL; |
190 | tack += sizeof (struct resource); | 119 | memset(tack, 0, sizeof(struct resource)); |
191 | } | 120 | res = (struct resource *) tack; |
192 | 121 | tack += sizeof(struct resource); | |
193 | strncpy(tack, name, XNMLN); | 122 | } |
194 | tack[XNMLN] = 0; | 123 | |
195 | res->name = tack; | 124 | strncpy(tack, name, XNMLN); |
196 | 125 | tack[XNMLN] = 0; | |
197 | return shmedia_ioremap(res, phys, size); | 126 | res->name = tack; |
127 | |||
128 | return shmedia_ioremap(res, phys, size, flags); | ||
198 | } | 129 | } |
199 | 130 | ||
200 | static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz) | 131 | static void __iomem *shmedia_ioremap(struct resource *res, u32 pa, int sz, |
132 | unsigned long flags) | ||
201 | { | 133 | { |
202 | unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK); | 134 | unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK); |
203 | unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK; | 135 | unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK; |
204 | unsigned long va; | 136 | unsigned long va; |
205 | unsigned int psz; | 137 | unsigned int psz; |
206 | 138 | ||
207 | if (allocate_resource(&shmedia_iomap, res, round_sz, | 139 | if (allocate_resource(&shmedia_iomap, res, round_sz, |
208 | shmedia_iomap.start, shmedia_iomap.end, | 140 | shmedia_iomap.start, shmedia_iomap.end, |
209 | PAGE_SIZE, NULL, NULL) != 0) { | 141 | PAGE_SIZE, NULL, NULL) != 0) { |
210 | panic("alloc_io_res(%s): cannot occupy\n", | 142 | panic("alloc_io_res(%s): cannot occupy\n", |
211 | (res->name != NULL)? res->name: "???"); | 143 | (res->name != NULL) ? res->name : "???"); |
212 | } | 144 | } |
213 | 145 | ||
214 | va = res->start; | 146 | va = res->start; |
215 | pa &= PAGE_MASK; | 147 | pa &= PAGE_MASK; |
216 | 148 | ||
217 | psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; | 149 | psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; |
218 | 150 | ||
219 | /* log at boot time ... */ | 151 | 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", | 152 | shmedia_mapioaddr(pa, va, flags); |
221 | ((res->name != NULL) ? res->name : "???"), | 153 | va += PAGE_SIZE; |
222 | psz, psz == 1 ? " " : "s", va, pa); | 154 | pa += PAGE_SIZE; |
223 | 155 | } | |
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 | 156 | ||
233 | return res->start; | 157 | return (void __iomem *)(unsigned long)(res->start + offset); |
234 | } | 158 | } |
235 | 159 | ||
236 | static void shmedia_free_io(struct resource *res) | 160 | static void shmedia_free_io(struct resource *res) |
@@ -249,14 +173,12 @@ static void shmedia_free_io(struct resource *res) | |||
249 | 173 | ||
250 | static __init_refok void *sh64_get_page(void) | 174 | static __init_refok void *sh64_get_page(void) |
251 | { | 175 | { |
252 | extern int after_bootmem; | ||
253 | void *page; | 176 | void *page; |
254 | 177 | ||
255 | if (after_bootmem) { | 178 | if (after_bootmem) |
256 | page = (void *)get_zeroed_page(GFP_ATOMIC); | 179 | page = (void *)get_zeroed_page(GFP_KERNEL); |
257 | } else { | 180 | else |
258 | page = alloc_bootmem_pages(PAGE_SIZE); | 181 | page = alloc_bootmem_pages(PAGE_SIZE); |
259 | } | ||
260 | 182 | ||
261 | if (!page || ((unsigned long)page & ~PAGE_MASK)) | 183 | if (!page || ((unsigned long)page & ~PAGE_MASK)) |
262 | panic("sh64_get_page: Out of memory already?\n"); | 184 | panic("sh64_get_page: Out of memory already?\n"); |
@@ -264,17 +186,20 @@ static __init_refok void *sh64_get_page(void) | |||
264 | return page; | 186 | return page; |
265 | } | 187 | } |
266 | 188 | ||
267 | static void shmedia_mapioaddr(unsigned long pa, unsigned long va) | 189 | static void shmedia_mapioaddr(unsigned long pa, unsigned long va, |
190 | unsigned long flags) | ||
268 | { | 191 | { |
269 | pgd_t *pgdp; | 192 | pgd_t *pgdp; |
270 | pud_t *pudp; | 193 | pud_t *pudp; |
271 | pmd_t *pmdp; | 194 | pmd_t *pmdp; |
272 | pte_t *ptep, pte; | 195 | pte_t *ptep, pte; |
273 | pgprot_t prot; | 196 | pgprot_t prot; |
274 | unsigned long flags = 1; /* 1 = CB0-1 device */ | ||
275 | 197 | ||
276 | pr_debug("shmedia_mapiopage pa %08lx va %08lx\n", pa, va); | 198 | pr_debug("shmedia_mapiopage pa %08lx va %08lx\n", pa, va); |
277 | 199 | ||
200 | if (!flags) | ||
201 | flags = 1; /* 1 = CB0-1 device */ | ||
202 | |||
278 | pgdp = pgd_offset_k(va); | 203 | pgdp = pgd_offset_k(va); |
279 | if (pgd_none(*pgdp) || !pgd_present(*pgdp)) { | 204 | if (pgd_none(*pgdp) || !pgd_present(*pgdp)) { |
280 | pudp = (pud_t *)sh64_get_page(); | 205 | pudp = (pud_t *)sh64_get_page(); |
@@ -288,7 +213,7 @@ static void shmedia_mapioaddr(unsigned long pa, unsigned long va) | |||
288 | } | 213 | } |
289 | 214 | ||
290 | pmdp = pmd_offset(pudp, va); | 215 | pmdp = pmd_offset(pudp, va); |
291 | if (pmd_none(*pmdp) || !pmd_present(*pmdp) ) { | 216 | if (pmd_none(*pmdp) || !pmd_present(*pmdp)) { |
292 | ptep = (pte_t *)sh64_get_page(); | 217 | ptep = (pte_t *)sh64_get_page(); |
293 | set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE)); | 218 | set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE)); |
294 | } | 219 | } |
@@ -336,17 +261,19 @@ static void shmedia_unmapioaddr(unsigned long vaddr) | |||
336 | pte_clear(&init_mm, vaddr, ptep); | 261 | pte_clear(&init_mm, vaddr, ptep); |
337 | } | 262 | } |
338 | 263 | ||
339 | unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name) | 264 | void __iomem *__ioremap(unsigned long offset, unsigned long size, |
265 | unsigned long flags) | ||
340 | { | 266 | { |
341 | if (size < PAGE_SIZE) | 267 | char name[14]; |
342 | size = PAGE_SIZE; | ||
343 | 268 | ||
344 | return shmedia_alloc_io(phys, size, name); | 269 | sprintf(name, "phys_%08x", (u32)offset); |
270 | return shmedia_alloc_io(offset, size, name, flags); | ||
345 | } | 271 | } |
346 | EXPORT_SYMBOL(onchip_remap); | 272 | EXPORT_SYMBOL(__ioremap); |
347 | 273 | ||
348 | void onchip_unmap(unsigned long vaddr) | 274 | void __iounmap(void __iomem *virtual) |
349 | { | 275 | { |
276 | unsigned long vaddr = (unsigned long)virtual & PAGE_MASK; | ||
350 | struct resource *res; | 277 | struct resource *res; |
351 | unsigned int psz; | 278 | unsigned int psz; |
352 | 279 | ||
@@ -357,10 +284,7 @@ void onchip_unmap(unsigned long vaddr) | |||
357 | return; | 284 | return; |
358 | } | 285 | } |
359 | 286 | ||
360 | psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; | 287 | 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 | 288 | ||
365 | shmedia_free_io(res); | 289 | shmedia_free_io(res); |
366 | 290 | ||
@@ -371,9 +295,8 @@ void onchip_unmap(unsigned long vaddr) | |||
371 | kfree(res); | 295 | kfree(res); |
372 | } | 296 | } |
373 | } | 297 | } |
374 | EXPORT_SYMBOL(onchip_unmap); | 298 | EXPORT_SYMBOL(__iounmap); |
375 | 299 | ||
376 | #ifdef CONFIG_PROC_FS | ||
377 | static int | 300 | static int |
378 | ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, | 301 | ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, |
379 | void *data) | 302 | void *data) |
@@ -385,7 +308,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) { | 308 | for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) { |
386 | if (p + 32 >= e) /* Better than nothing */ | 309 | if (p + 32 >= e) /* Better than nothing */ |
387 | break; | 310 | break; |
388 | if ((nm = r->name) == 0) nm = "???"; | 311 | nm = r->name; |
312 | if (nm == NULL) | ||
313 | nm = "???"; | ||
314 | |||
389 | p += sprintf(p, "%08lx-%08lx: %s\n", | 315 | p += sprintf(p, "%08lx-%08lx: %s\n", |
390 | (unsigned long)r->start, | 316 | (unsigned long)r->start, |
391 | (unsigned long)r->end, nm); | 317 | (unsigned long)r->end, nm); |
@@ -393,14 +319,11 @@ ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, | |||
393 | 319 | ||
394 | return p-buf; | 320 | return p-buf; |
395 | } | 321 | } |
396 | #endif /* CONFIG_PROC_FS */ | ||
397 | 322 | ||
398 | static int __init register_proc_onchip(void) | 323 | static int __init register_proc_onchip(void) |
399 | { | 324 | { |
400 | #ifdef CONFIG_PROC_FS | 325 | 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); | 326 | &shmedia_iomap); |
402 | #endif | ||
403 | return 0; | 327 | return 0; |
404 | } | 328 | } |
405 | 329 | late_initcall(register_proc_onchip); | |
406 | __initcall(register_proc_onchip); | ||