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.c265
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
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 = { 30static 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
109static void shmedia_mapioaddr(unsigned long pa, unsigned long va); 36static void shmedia_mapioaddr(unsigned long pa, unsigned long va,
37 unsigned long flags);
110static void shmedia_unmapioaddr(unsigned long vaddr); 38static void shmedia_unmapioaddr(unsigned long vaddr);
111static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz); 39static 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
131static struct xresource *xres_alloc(void) 60static 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
147static void xres_free(struct xresource *xrp) 76static 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
164static unsigned long shmedia_alloc_io(unsigned long phys, unsigned long size, 93static 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
200static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz) 131static 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
236static void shmedia_free_io(struct resource *res) 160static void shmedia_free_io(struct resource *res)
@@ -249,14 +173,12 @@ static void shmedia_free_io(struct resource *res)
249 173
250static __init_refok void *sh64_get_page(void) 174static __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
267static void shmedia_mapioaddr(unsigned long pa, unsigned long va) 189static 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
339unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name) 264void __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}
346EXPORT_SYMBOL(onchip_remap); 272EXPORT_SYMBOL(__ioremap);
347 273
348void onchip_unmap(unsigned long vaddr) 274void __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}
374EXPORT_SYMBOL(onchip_unmap); 298EXPORT_SYMBOL(__iounmap);
375 299
376#ifdef CONFIG_PROC_FS
377static int 300static int
378ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, 301ioremap_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
398static int __init register_proc_onchip(void) 323static 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 329late_initcall(register_proc_onchip);
406__initcall(register_proc_onchip);