VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / sh / mm / cache-sh4.c
1 /* $Id: cache-sh4.c,v 1.26 2004/02/19 12:47:24 lethal Exp $
2  *
3  *  linux/arch/sh/mm/cache-sh4.c
4  *
5  * Copyright (C) 1999, 2000, 2002  Niibe Yutaka
6  * Copyright (C) 2001, 2002, 2003, 2004  Paul Mundt
7  * Copyright (C) 2003  Richard Curnow
8  */
9
10 #include <linux/config.h>
11 #include <linux/init.h>
12 #include <linux/mman.h>
13 #include <linux/mm.h>
14 #include <linux/threads.h>
15 #include <asm/addrspace.h>
16 #include <asm/page.h>
17 #include <asm/pgtable.h>
18 #include <asm/processor.h>
19 #include <asm/cache.h>
20 #include <asm/io.h>
21 #include <asm/uaccess.h>
22 #include <asm/pgalloc.h>
23 #include <asm/mmu_context.h>
24 #include <asm/cacheflush.h>
25
26 extern void __flush_cache_4096_all(unsigned long start);
27 static void __flush_cache_4096_all_ex(unsigned long start);
28 extern void __flush_dcache_all(void);
29 static void __flush_dcache_all_ex(void);
30
31 int __init detect_cpu_and_cache_system(void)
32 {
33         unsigned long pvr, prr, cvr;
34         unsigned long size;
35
36         static unsigned long sizes[16] = {
37                 [1] = (1 << 12),
38                 [2] = (1 << 13),
39                 [4] = (1 << 14),
40                 [8] = (1 << 15),
41                 [9] = (1 << 16)
42         };
43
44         pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffff;
45         prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff;
46         cvr = (ctrl_inl(CCN_CVR));
47
48         /*
49          * Setup some sane SH-4 defaults for the icache
50          */
51         cpu_data->icache.way_incr       = (1 << 13);
52         cpu_data->icache.entry_shift    = 5;
53         cpu_data->icache.entry_mask     = 0x1fe0;
54         cpu_data->icache.sets           = 256;
55         cpu_data->icache.ways           = 1;
56         cpu_data->icache.linesz         = L1_CACHE_BYTES;
57
58         /*
59          * And again for the dcache ..
60          */
61         cpu_data->dcache.way_incr       = (1 << 14);
62         cpu_data->dcache.entry_shift    = 5;
63         cpu_data->dcache.entry_mask     = 0x3fe0;
64         cpu_data->dcache.sets           = 512;
65         cpu_data->dcache.ways           = 1;
66         cpu_data->dcache.linesz         = L1_CACHE_BYTES;
67
68         /* Set the FPU flag, virtually all SH-4's have one */
69         cpu_data->flags |= CPU_HAS_FPU;
70
71         /*
72          * Probe the underlying processor version/revision and
73          * adjust cpu_data setup accordingly.
74          */
75         switch (pvr) {
76         case 0x205:
77                 cpu_data->type = CPU_SH7750;
78                 cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG;
79                 break;
80         case 0x206:
81                 cpu_data->type = CPU_SH7750S;
82
83                 /* 
84                  * FIXME: This is needed for 7750, but do we need it for the
85                  * 7750S too? For now, assume we do.. -- PFM
86                  */
87                 cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG;
88
89                 break;
90         case 0x1100:
91                 cpu_data->type = CPU_SH7751;
92                 break;
93         case 0x8000:
94                 cpu_data->type = CPU_ST40RA;
95                 break;
96         case 0x8100:
97                 cpu_data->type = CPU_ST40GX1;
98                 break;
99         case 0x700:
100                 cpu_data->type = CPU_SH4_501;
101                 cpu_data->icache.ways = 2;
102                 cpu_data->dcache.ways = 2;
103
104                 /* No FPU on the SH4-500 series.. */
105                 cpu_data->flags &= ~CPU_HAS_FPU;
106                 break;
107         case 0x600:
108                 cpu_data->type = CPU_SH4_202;
109                 cpu_data->icache.ways = 2;
110                 cpu_data->dcache.ways = 2;
111                 break;
112         case 0x500 ... 0x501:
113                 switch (prr) {
114                     case 0x10: cpu_data->type = CPU_SH7750R; break;
115                     case 0x11: cpu_data->type = CPU_SH7751R; break;
116                     case 0x50: cpu_data->type = CPU_SH7760;  break;
117                 }
118
119                 cpu_data->icache.ways = 2;
120                 cpu_data->dcache.ways = 2;
121
122                 break;
123         default:
124                 cpu_data->type = CPU_SH_NONE;
125                 break;
126         }
127
128         /*
129          * On anything that's not a direct-mapped cache, look to the CVR
130          * for I/D-cache specifics.
131          */
132         if (cpu_data->icache.ways > 1) {
133                 size = sizes[(cvr >> 20) & 0xf];
134                 cpu_data->icache.way_incr       = size / cpu_data->icache.ways;
135                 cpu_data->icache.sets           = (size >> 6);
136                 cpu_data->icache.entry_mask     =
137                         ((size / cpu_data->icache.ways) - (1 << 5));
138         }
139
140         if (cpu_data->dcache.ways > 1) {
141                 size = sizes[(cvr >> 16) & 0xf];
142                 cpu_data->dcache.way_incr       = size / cpu_data->dcache.ways;
143                 cpu_data->dcache.sets           = (size >> 6);
144                 cpu_data->dcache.entry_mask     =
145                         ((size / cpu_data->dcache.ways) - (1 << 5));
146         }
147
148         return 0;
149 }
150
151 /*
152  * SH-4 has virtually indexed and physically tagged cache.
153  */
154
155 struct semaphore p3map_sem[4];
156
157 void __init p3_cache_init(void)
158 {
159         if (remap_area_pages(P3SEG, 0, PAGE_SIZE*4, _PAGE_CACHABLE))
160                 panic("%s failed.", __FUNCTION__);
161
162         sema_init (&p3map_sem[0], 1);
163         sema_init (&p3map_sem[1], 1);
164         sema_init (&p3map_sem[2], 1);
165         sema_init (&p3map_sem[3], 1);
166 }
167
168 /*
169  * Write back the dirty D-caches, but not invalidate them.
170  *
171  * START: Virtual Address (U0, P1, or P3)
172  * SIZE: Size of the region.
173  */
174 void __flush_wback_region(void *start, int size)
175 {
176         unsigned long v;
177         unsigned long begin, end;
178
179         begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
180         end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
181                 & ~(L1_CACHE_BYTES-1);
182         for (v = begin; v < end; v+=L1_CACHE_BYTES) {
183                 asm volatile("ocbwb     %0"
184                              : /* no output */
185                              : "m" (__m(v)));
186         }
187 }
188
189 /*
190  * Write back the dirty D-caches and invalidate them.
191  *
192  * START: Virtual Address (U0, P1, or P3)
193  * SIZE: Size of the region.
194  */
195 void __flush_purge_region(void *start, int size)
196 {
197         unsigned long v;
198         unsigned long begin, end;
199
200         begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
201         end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
202                 & ~(L1_CACHE_BYTES-1);
203         for (v = begin; v < end; v+=L1_CACHE_BYTES) {
204                 asm volatile("ocbp      %0"
205                              : /* no output */
206                              : "m" (__m(v)));
207         }
208 }
209
210
211 /*
212  * No write back please
213  */
214 void __flush_invalidate_region(void *start, int size)
215 {
216         unsigned long v;
217         unsigned long begin, end;
218
219         begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
220         end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
221                 & ~(L1_CACHE_BYTES-1);
222         for (v = begin; v < end; v+=L1_CACHE_BYTES) {
223                 asm volatile("ocbi      %0"
224                              : /* no output */
225                              : "m" (__m(v)));
226         }
227 }
228
229 static void __flush_dcache_all_ex(void)
230 {
231         unsigned long addr, end_addr, entry_offset;
232
233         end_addr = CACHE_OC_ADDRESS_ARRAY + (cpu_data->dcache.sets << cpu_data->dcache.entry_shift) * cpu_data->dcache.ways;
234         entry_offset = 1 << cpu_data->dcache.entry_shift;
235         for (addr = CACHE_OC_ADDRESS_ARRAY; addr < end_addr; addr += entry_offset) {
236                 ctrl_outl(0, addr);
237         }
238 }
239
240 static void __flush_cache_4096_all_ex(unsigned long start)
241 {
242         unsigned long addr, entry_offset;
243         int i;
244
245         entry_offset = 1 << cpu_data->dcache.entry_shift;
246         for (i = 0; i < cpu_data->dcache.ways; i++, start += cpu_data->dcache.way_incr) {
247                 for (addr = CACHE_OC_ADDRESS_ARRAY + start;
248                      addr < CACHE_OC_ADDRESS_ARRAY + 4096 + start;
249                      addr += entry_offset) {
250                         ctrl_outl(0, addr);
251                 }
252         }
253 }
254
255 void flush_cache_4096_all(unsigned long start)
256 {
257         if (cpu_data->dcache.ways == 1)
258                 __flush_cache_4096_all(start);
259         else
260                 __flush_cache_4096_all_ex(start);
261 }
262
263 /*
264  * Write back the range of D-cache, and purge the I-cache.
265  *
266  * Called from kernel/module.c:sys_init_module and routine for a.out format.
267  */
268 void flush_icache_range(unsigned long start, unsigned long end)
269 {
270         flush_cache_all();
271 }
272
273 /*
274  * Write back the D-cache and purge the I-cache for signal trampoline. 
275  * .. which happens to be the same behavior as flush_icache_range().
276  * So, we simply flush out a line.
277  */
278 void flush_cache_sigtramp(unsigned long addr)
279 {
280         unsigned long v, index;
281         unsigned long flags; 
282         int i;
283
284         v = addr & ~(L1_CACHE_BYTES-1);
285         asm volatile("ocbwb     %0"
286                      : /* no output */
287                      : "m" (__m(v)));
288
289         index = CACHE_IC_ADDRESS_ARRAY | (v & cpu_data->icache.entry_mask);
290
291         local_irq_save(flags);
292         jump_to_P2();
293         for(i = 0; i < cpu_data->icache.ways; i++, index += cpu_data->icache.way_incr)
294                 ctrl_outl(0, index);    /* Clear out Valid-bit */
295         back_to_P1();
296         local_irq_restore(flags);
297 }
298
299 static inline void flush_cache_4096(unsigned long start,
300                                     unsigned long phys)
301 {
302         unsigned long flags; 
303         extern void __flush_cache_4096(unsigned long addr, unsigned long phys, unsigned long exec_offset);
304
305         /*
306          * SH7751, SH7751R, and ST40 have no restriction to handle cache.
307          * (While SH7750 must do that at P2 area.)
308          */
309         if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG)
310            || start < CACHE_OC_ADDRESS_ARRAY) {
311                 local_irq_save(flags);
312                 __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0x20000000);
313                 local_irq_restore(flags);
314         } else {
315                 __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0);
316         }
317 }
318
319 /*
320  * Write back & invalidate the D-cache of the page.
321  * (To avoid "alias" issues)
322  */
323 void flush_dcache_page(struct page *page)
324 {
325         if (test_bit(PG_mapped, &page->flags)) {
326                 unsigned long phys = PHYSADDR(page_address(page));
327
328                 /* Loop all the D-cache */
329                 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY,          phys);
330                 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x1000, phys);
331                 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x2000, phys);
332                 flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x3000, phys);
333         }
334 }
335
336 static inline void flush_icache_all(void)
337 {
338         unsigned long flags, ccr;
339
340         local_irq_save(flags);
341         jump_to_P2();
342
343         /* Flush I-cache */
344         ccr = ctrl_inl(CCR);
345         ccr |= CCR_CACHE_ICI;
346         ctrl_outl(ccr, CCR);
347
348         back_to_P1();
349         local_irq_restore(flags);
350 }
351
352 void flush_cache_all(void)
353 {
354         if (cpu_data->dcache.ways == 1)
355                 __flush_dcache_all();
356         else
357                 __flush_dcache_all_ex();
358         flush_icache_all();
359 }
360
361 void flush_cache_mm(struct mm_struct *mm)
362 {
363         /* Is there any good way? */
364         /* XXX: possibly call flush_cache_range for each vm area */
365         /* 
366          * FIXME: Really, the optimal solution here would be able to flush out
367          * individual lines created by the specified context, but this isn't
368          * feasible for a number of architectures (such as MIPS, and some
369          * SPARC) .. is this possible for SuperH?
370          *
371          * In the meantime, we'll just flush all of the caches.. this
372          * seems to be the simplest way to avoid at least a few wasted
373          * cache flushes. -Lethal
374          */
375         flush_cache_all();
376 }
377
378 static void __flush_cache_page(struct vm_area_struct *vma,
379                                unsigned long address,
380                                unsigned long phys)
381 {
382         /* We only need to flush D-cache when we have alias */
383         if ((address^phys) & CACHE_ALIAS) {
384                 /* Loop 4K of the D-cache */
385                 flush_cache_4096(
386                         CACHE_OC_ADDRESS_ARRAY | (address & CACHE_ALIAS),
387                         phys);
388                 /* Loop another 4K of the D-cache */
389                 flush_cache_4096(
390                         CACHE_OC_ADDRESS_ARRAY | (phys & CACHE_ALIAS),
391                         phys);
392         }
393
394         if (vma->vm_flags & VM_EXEC)
395                 /* Loop 4K (half) of the I-cache */
396                 flush_cache_4096(
397                         CACHE_IC_ADDRESS_ARRAY | (address & 0x1000),
398                         phys);
399 }
400
401 /*
402  * Write back and invalidate D-caches.
403  *
404  * START, END: Virtual Address (U0 address)
405  *
406  * NOTE: We need to flush the _physical_ page entry.
407  * Flushing the cache lines for U0 only isn't enough.
408  * We need to flush for P1 too, which may contain aliases.
409  */
410 void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
411                        unsigned long end)
412 {
413         unsigned long p = start & PAGE_MASK;
414         pgd_t *dir;
415         pmd_t *pmd;
416         pte_t *pte;
417         pte_t entry;
418         unsigned long phys;
419         unsigned long d = 0;
420
421         dir = pgd_offset(vma->vm_mm, p);
422         pmd = pmd_offset(dir, p);
423
424         do {
425                 if (pmd_none(*pmd) || pmd_bad(*pmd)) {
426                         p &= ~((1 << PMD_SHIFT) -1);
427                         p += (1 << PMD_SHIFT);
428                         pmd++;
429                         continue;
430                 }
431                 pte = pte_offset_kernel(pmd, p);
432                 do {
433                         entry = *pte;
434                         if ((pte_val(entry) & _PAGE_PRESENT)) {
435                                 phys = pte_val(entry)&PTE_PHYS_MASK;
436                                 if ((p^phys) & CACHE_ALIAS) {
437                                         d |= 1 << ((p & CACHE_ALIAS)>>12); 
438                                         d |= 1 << ((phys & CACHE_ALIAS)>>12);
439                                         if (d == 0x0f)
440                                                 goto loop_exit;
441                                 }
442                         }
443                         pte++;
444                         p += PAGE_SIZE;
445                 } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
446                 pmd++;
447         } while (p < end);
448  loop_exit:
449         if (d & 1)
450                 flush_cache_4096_all(0);
451         if (d & 2)
452                 flush_cache_4096_all(0x1000);
453         if (d & 4)
454                 flush_cache_4096_all(0x2000);
455         if (d & 8)
456                 flush_cache_4096_all(0x3000);
457         if (vma->vm_flags & VM_EXEC)
458                 flush_icache_all();
459 }
460
461 /*
462  * Write back and invalidate I/D-caches for the page.
463  *
464  * ADDR: Virtual Address (U0 address)
465  */
466 void flush_cache_page(struct vm_area_struct *vma, unsigned long address)
467 {
468         pgd_t *dir;
469         pmd_t *pmd;
470         pte_t *pte;
471         pte_t entry;
472         unsigned long phys;
473
474         dir = pgd_offset(vma->vm_mm, address);
475         pmd = pmd_offset(dir, address);
476         if (pmd_none(*pmd) || pmd_bad(*pmd))
477                 return;
478         pte = pte_offset_kernel(pmd, address);
479         entry = *pte;
480         if (!(pte_val(entry) & _PAGE_PRESENT))
481                 return;
482
483         phys = pte_val(entry)&PTE_PHYS_MASK;
484         __flush_cache_page(vma, address, phys);
485 }
486
487 /*
488  * flush_icache_user_range
489  * @vma: VMA of the process
490  * @page: page
491  * @addr: U0 address
492  * @len: length of the range (< page size)
493  */
494 void flush_icache_user_range(struct vm_area_struct *vma,
495                              struct page *page, unsigned long addr, int len)
496 {
497         __flush_cache_page(vma, addr, PHYSADDR(page_address(page)));
498 }
499