1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/init.h>
18#include <linux/kernel.h>
19#include <linux/sched.h>
20#include <linux/mm.h>
21
22#include <asm/io.h>
23#include <asm/page.h>
24#include <asm/pgtable.h>
25#include <asm/system.h>
26#include <asm/bootinfo.h>
27#include <asm/mmu_context.h>
28
29
30#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
31 "nop; nop; nop; nop; nop; nop;\n\t" \
32 ".set reorder\n\t")
33
34
35static int icache_size, dcache_size;
36
37#define ic_lsize 32
38#define dc_lsize 32
39#define sc_lsize 32
40#define tc_pagesize (32*128)
41
42
43#define scache_size (256*1024)
44
45#include <asm/cacheops.h>
46#include <asm/r4kcache.h>
47
48int rm7k_tcache_enabled = 0;
49
50
51
52
53#define Page_Invalidate_T 0x16
54
55static inline void invalidate_tcache_page(unsigned long addr)
56{
57 __asm__ __volatile__(
58 ".set\tnoreorder\t\t\t# invalidate_tcache_page\n\t"
59 ".set\tmips3\n\t"
60 "cache\t%1, (%0)\n\t"
61 ".set\tmips0\n\t"
62 ".set\treorder"
63 :
64 : "r" (addr),
65 "i" (Page_Invalidate_T));
66}
67
68
69
70
71
72static void rm7k_clear_page(void * page)
73{
74 __asm__ __volatile__(
75 ".set\tnoreorder\n\t"
76 ".set\tnoat\n\t"
77 ".set\tmips3\n\t"
78 "daddiu\t$1,%0,%2\n"
79 "1:\tcache\t%3,(%0)\n\t"
80 "sd\t$0,(%0)\n\t"
81 "sd\t$0,8(%0)\n\t"
82 "sd\t$0,16(%0)\n\t"
83 "sd\t$0,24(%0)\n\t"
84 "daddiu\t%0,64\n\t"
85 "cache\t%3,-32(%0)\n\t"
86 "sd\t$0,-32(%0)\n\t"
87 "sd\t$0,-24(%0)\n\t"
88 "sd\t$0,-16(%0)\n\t"
89 "bne\t$1,%0,1b\n\t"
90 "sd\t$0,-8(%0)\n\t"
91 ".set\tmips0\n\t"
92 ".set\tat\n\t"
93 ".set\treorder"
94 :"=r" (page)
95 :"0" (page),
96 "I" (PAGE_SIZE),
97 "i" (Create_Dirty_Excl_D)
98 :"$1","memory");
99}
100
101
102
103
104
105
106static void rm7k_copy_page(void * to, void * from)
107{
108 unsigned long dummy1, dummy2;
109 unsigned long reg1, reg2, reg3, reg4;
110
111 __asm__ __volatile__(
112 ".set\tnoreorder\n\t"
113 ".set\tnoat\n\t"
114 ".set\tmips3\n\t"
115 "daddiu\t$1,%0,%8\n"
116 "1:\tcache\t%9,(%0)\n\t"
117 "lw\t%2,(%1)\n\t"
118 "lw\t%3,4(%1)\n\t"
119 "lw\t%4,8(%1)\n\t"
120 "lw\t%5,12(%1)\n\t"
121 "sw\t%2,(%0)\n\t"
122 "sw\t%3,4(%0)\n\t"
123 "sw\t%4,8(%0)\n\t"
124 "sw\t%5,12(%0)\n\t"
125 "lw\t%2,16(%1)\n\t"
126 "lw\t%3,20(%1)\n\t"
127 "lw\t%4,24(%1)\n\t"
128 "lw\t%5,28(%1)\n\t"
129 "sw\t%2,16(%0)\n\t"
130 "sw\t%3,20(%0)\n\t"
131 "sw\t%4,24(%0)\n\t"
132 "sw\t%5,28(%0)\n\t"
133 "cache\t%9,32(%0)\n\t"
134 "daddiu\t%0,64\n\t"
135 "daddiu\t%1,64\n\t"
136 "lw\t%2,-32(%1)\n\t"
137 "lw\t%3,-28(%1)\n\t"
138 "lw\t%4,-24(%1)\n\t"
139 "lw\t%5,-20(%1)\n\t"
140 "sw\t%2,-32(%0)\n\t"
141 "sw\t%3,-28(%0)\n\t"
142 "sw\t%4,-24(%0)\n\t"
143 "sw\t%5,-20(%0)\n\t"
144 "lw\t%2,-16(%1)\n\t"
145 "lw\t%3,-12(%1)\n\t"
146 "lw\t%4,-8(%1)\n\t"
147 "lw\t%5,-4(%1)\n\t"
148 "sw\t%2,-16(%0)\n\t"
149 "sw\t%3,-12(%0)\n\t"
150 "sw\t%4,-8(%0)\n\t"
151 "bne\t$1,%0,1b\n\t"
152 "sw\t%5,-4(%0)\n\t"
153 ".set\tmips0\n\t"
154 ".set\tat\n\t"
155 ".set\treorder"
156 :"=r" (dummy1), "=r" (dummy2),
157 "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4)
158 :"0" (to), "1" (from),
159 "I" (PAGE_SIZE),
160 "i" (Create_Dirty_Excl_D));
161}
162
163static void __flush_cache_all_d32i32(void)
164{
165 blast_dcache32();
166 blast_icache32();
167}
168
169static inline void rm7k_flush_cache_all_d32i32(void)
170{
171
172}
173
174static void rm7k_flush_cache_range_d32i32(struct vm_area_struct *vma,
175 unsigned long start,
176 unsigned long end)
177{
178
179}
180
181static void rm7k_flush_cache_mm_d32i32(struct mm_struct *mm)
182{
183
184}
185
186static void rm7k_flush_cache_page_d32i32(struct vm_area_struct *vma,
187 unsigned long page)
188{
189
190}
191
192static void rm7k_flush_page_to_ram_d32i32(struct page * page)
193{
194
195}
196
197static void rm7k_flush_icache_range(unsigned long start, unsigned long end)
198{
199
200
201
202 __flush_cache_all_d32i32();
203}
204
205static void rm7k_flush_icache_page(struct vm_area_struct *vma,
206 struct page *page)
207{
208
209
210
211
212
213 __flush_cache_all_d32i32();
214}
215
216
217
218
219
220
221static void
222rm7k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
223{
224 unsigned long end, a;
225
226 a = addr & ~(sc_lsize - 1);
227 end = (addr + size) & ~(sc_lsize - 1);
228 while (1) {
229 flush_dcache_line(a);
230 flush_icache_line(a);
231 flush_scache_line(a);
232 if (a == end) break;
233 a += sc_lsize;
234 }
235
236 if (!rm7k_tcache_enabled)
237 return;
238
239 a = addr & ~(tc_pagesize - 1);
240 end = (addr + size) & ~(tc_pagesize - 1);
241 while(1) {
242 invalidate_tcache_page(a);
243 if (a == end) break;
244 a += tc_pagesize;
245 }
246}
247
248static void
249rm7k_dma_cache_inv(unsigned long addr, unsigned long size)
250{
251 unsigned long end, a;
252
253 a = addr & ~(sc_lsize - 1);
254 end = (addr + size) & ~(sc_lsize - 1);
255 while (1) {
256 invalidate_dcache_line(a);
257 flush_icache_line(a);
258 invalidate_scache_line(a);
259 if (a == end) break;
260 a += sc_lsize;
261 }
262
263 if (!rm7k_tcache_enabled)
264 return;
265
266 a = addr & ~(tc_pagesize - 1);
267 end = (addr + size) & ~(tc_pagesize - 1);
268 while(1) {
269 invalidate_tcache_page(a);
270 if (a == end) break;
271 a += tc_pagesize;
272 }
273}
274
275static void
276rm7k_dma_cache_wback(unsigned long addr, unsigned long size)
277{
278 panic("rm7k_dma_cache_wback called - should not happen.\n");
279}
280
281
282
283
284
285
286static void rm7k_flush_cache_sigtramp(unsigned long addr)
287{
288 protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
289 protected_flush_icache_line(addr & ~(ic_lsize - 1));
290}
291
292
293
294
295
296
297
298
299static inline int __attribute__((const)) ntlb_entries(void)
300{
301 if (get_info() & (1 << 29))
302 return 64;
303
304 return 48;
305}
306
307void flush_tlb_all(void)
308{
309 unsigned long flags;
310 unsigned long old_ctx;
311 int entry;
312
313 local_irq_save(flags);
314
315 old_ctx = get_entryhi() & 0xff;
316 set_entryhi(KSEG0);
317 set_entrylo0(0);
318 set_entrylo1(0);
319 BARRIER;
320
321 entry = get_wired();
322
323
324 while (entry < ntlb_entries()) {
325 set_index(entry);
326 BARRIER;
327 tlb_write_indexed();
328 BARRIER;
329 entry++;
330 }
331 BARRIER;
332 set_entryhi(old_ctx);
333 local_irq_restore(flags);
334}
335
336void flush_tlb_mm(struct mm_struct *mm)
337{
338 if(mm->context != 0) {
339 unsigned long flags;
340
341 local_irq_save(flags);
342 get_new_mmu_context(mm, asid_cache);
343 if (mm == current->mm)
344 set_entryhi(mm->context & 0xff);
345 local_irq_restore(flags);
346 }
347}
348
349void flush_tlb_range(struct mm_struct *mm, unsigned long start,
350 unsigned long end)
351{
352 if(mm->context != 0) {
353 unsigned long flags;
354 int size;
355
356 local_irq_save(flags);
357 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
358 size = (size + 1) >> 1;
359 if (size <= (ntlb_entries() / 2)) {
360 int oldpid = (get_entryhi() & 0xff);
361 int newpid = (mm->context & 0xff);
362
363 start &= (PAGE_MASK << 1);
364 end += ((PAGE_SIZE << 1) - 1);
365 end &= (PAGE_MASK << 1);
366 while(start < end) {
367 int idx;
368
369 set_entryhi(start | newpid);
370 start += (PAGE_SIZE << 1);
371 BARRIER;
372 tlb_probe();
373 BARRIER;
374 idx = get_index();
375 set_entrylo0(0);
376 set_entrylo1(0);
377 set_entryhi(KSEG0);
378 BARRIER;
379 if(idx < 0)
380 continue;
381 tlb_write_indexed();
382 BARRIER;
383 }
384 set_entryhi(oldpid);
385 } else {
386 get_new_mmu_context(mm, asid_cache);
387 if(mm == current->mm)
388 set_entryhi(mm->context & 0xff);
389 }
390 local_irq_restore(flags);
391 }
392}
393
394void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
395{
396 if(vma->vm_mm->context != 0) {
397 unsigned long flags;
398 int oldpid, newpid, idx;
399
400 newpid = (vma->vm_mm->context & 0xff);
401 page &= (PAGE_MASK << 1);
402 local_irq_save(flags);
403 oldpid = (get_entryhi() & 0xff);
404 set_entryhi(page | newpid);
405 BARRIER;
406 tlb_probe();
407 BARRIER;
408 idx = get_index();
409 set_entrylo0(0);
410 set_entrylo1(0);
411 set_entryhi(KSEG0);
412 if(idx < 0)
413 goto finish;
414 BARRIER;
415 tlb_write_indexed();
416
417 finish:
418 BARRIER;
419 set_entryhi(oldpid);
420 local_irq_restore(flags);
421 }
422}
423
424void pgd_init(unsigned long page)
425{
426 unsigned long *p = (unsigned long *) page;
427 int i;
428
429 for (i = 0; i < USER_PTRS_PER_PGD; i+=8) {
430 p[i + 0] = (unsigned long) invalid_pte_table;
431 p[i + 1] = (unsigned long) invalid_pte_table;
432 p[i + 2] = (unsigned long) invalid_pte_table;
433 p[i + 3] = (unsigned long) invalid_pte_table;
434 p[i + 4] = (unsigned long) invalid_pte_table;
435 p[i + 5] = (unsigned long) invalid_pte_table;
436 p[i + 6] = (unsigned long) invalid_pte_table;
437 p[i + 7] = (unsigned long) invalid_pte_table;
438 }
439}
440
441
442
443
444
445
446void update_mmu_cache(struct vm_area_struct * vma,
447 unsigned long address, pte_t pte)
448{
449 unsigned long flags;
450 pgd_t *pgdp;
451 pmd_t *pmdp;
452 pte_t *ptep;
453 int idx, pid;
454
455
456
457
458 if (current->active_mm != vma->vm_mm)
459 return;
460
461 pid = get_entryhi() & 0xff;
462
463 local_irq_save(flags);
464 address &= (PAGE_MASK << 1);
465 set_entryhi(address | (pid));
466 pgdp = pgd_offset(vma->vm_mm, address);
467 BARRIER;
468 tlb_probe();
469 BARRIER;
470 pmdp = pmd_offset(pgdp, address);
471 idx = get_index();
472 ptep = pte_offset(pmdp, address);
473 BARRIER;
474 set_entrylo0(pte_val(*ptep++) >> 6);
475 set_entrylo1(pte_val(*ptep) >> 6);
476 set_entryhi(address | (pid));
477 BARRIER;
478 if (idx < 0) {
479 tlb_write_random();
480 } else {
481 tlb_write_indexed();
482 }
483 BARRIER;
484 set_entryhi(pid);
485 BARRIER;
486 local_irq_restore(flags);
487}
488
489void show_regs(struct pt_regs * regs)
490{
491
492 printk(KERN_INFO "$0 : %08lx %08lx %08lx %08lx\n",
493 0UL, regs->regs[1], regs->regs[2], regs->regs[3]);
494 printk(KERN_INFO "$4 : %08lx %08lx %08lx %08lx\n",
495 regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]);
496 printk(KERN_INFO "$8 : %08lx %08lx %08lx %08lx\n",
497 regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]);
498 printk(KERN_INFO "$12: %08lx %08lx %08lx %08lx\n",
499 regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]);
500 printk(KERN_INFO "$16: %08lx %08lx %08lx %08lx\n",
501 regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]);
502 printk(KERN_INFO "$20: %08lx %08lx %08lx %08lx\n",
503 regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]);
504 printk(KERN_INFO "$24: %08lx %08lx\n",
505 regs->regs[24], regs->regs[25]);
506 printk(KERN_INFO "$28: %08lx %08lx %08lx %08lx\n",
507 regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]);
508
509
510 printk(KERN_INFO "epc : %08lx %s\nStatus: %08lx\nCause : %08lx\n",
511 regs->cp0_epc, print_tainted(), regs->cp0_status, regs->cp0_cause);
512}
513
514void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
515 unsigned long entryhi, unsigned long pagemask)
516{
517 unsigned long flags;
518 unsigned long wired;
519 unsigned long old_pagemask;
520 unsigned long old_ctx;
521
522 local_irq_save(flags);
523
524 old_ctx = (get_entryhi() & 0xff);
525 old_pagemask = get_pagemask();
526 wired = get_wired();
527 set_wired (wired + 1);
528 set_index (wired);
529 BARRIER;
530 set_pagemask (pagemask);
531 set_entryhi(entryhi);
532 set_entrylo0(entrylo0);
533 set_entrylo1(entrylo1);
534 BARRIER;
535 tlb_write_indexed();
536 BARRIER;
537
538 set_entryhi(old_ctx);
539 BARRIER;
540 set_pagemask (old_pagemask);
541 flush_tlb_all();
542 local_irq_restore(flags);
543}
544
545
546
547
548
549static int temp_tlb_entry __initdata;
550
551__init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
552 unsigned long entryhi, unsigned long pagemask)
553{
554 int ret = 0;
555 unsigned long flags;
556 unsigned long wired;
557 unsigned long old_pagemask;
558 unsigned long old_ctx;
559
560 local_irq_save(flags);
561
562 old_ctx = (get_entryhi() & 0xff);
563 old_pagemask = get_pagemask();
564 wired = get_wired();
565 if (--temp_tlb_entry < wired) {
566 printk(KERN_WARNING "No TLB space left for add_temporary_entry\n");
567 ret = -ENOSPC;
568 goto out;
569 }
570
571 set_index (temp_tlb_entry);
572 BARRIER;
573 set_pagemask (pagemask);
574 set_entryhi(entryhi);
575 set_entrylo0(entrylo0);
576 set_entrylo1(entrylo1);
577 BARRIER;
578 tlb_write_indexed();
579 BARRIER;
580
581 set_entryhi(old_ctx);
582 BARRIER;
583 set_pagemask (old_pagemask);
584 out:
585 local_irq_restore(flags);
586 return ret;
587}
588
589
590
591
592static inline void probe_icache(unsigned long config)
593{
594 icache_size = 1 << (12 + ((config >> 9) & 7));
595
596 printk(KERN_INFO "Primary instruction cache %dKiB.\n", icache_size >> 10);
597}
598
599static inline void probe_dcache(unsigned long config)
600{
601 dcache_size = 1 << (12 + ((config >> 6) & 7));
602
603 printk(KERN_INFO "Primary data cache %dKiB.\n", dcache_size >> 10);
604}
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622static __init void setup_scache(void)
623{
624 int register i;
625
626 set_cp0_config(1<<3 );
627
628 set_taglo(0);
629 set_taghi(0);
630
631 for (i=0; i<scache_size; i+=sc_lsize) {
632 __asm__ __volatile__ (
633 ".set noreorder\n\t"
634 ".set mips3\n\t"
635 "cache %1, (%0)\n\t"
636 ".set mips0\n\t"
637 ".set reorder"
638 :
639 : "r" (KSEG0ADDR(i)),
640 "i" (Index_Store_Tag_SD));
641 }
642
643}
644
645static inline void probe_scache(unsigned long config)
646{
647 void (*func)(void) = KSEG1ADDR(&setup_scache);
648
649 if ((config >> 31) & 1)
650 return;
651
652 printk(KERN_INFO "Secondary cache %dKiB, linesize %d bytes.\n",
653 (scache_size >> 10), sc_lsize);
654
655 if ((config >> 3) & 1)
656 return;
657
658 printk(KERN_INFO "Enabling secondary cache...");
659 func();
660 printk("Done\n");
661}
662
663static inline void probe_tcache(unsigned long config)
664{
665 if ((config >> 17) & 1)
666 return;
667
668
669
670
671
672
673
674
675
676
677 printk(KERN_INFO "Tertiary cache present, %s enabled\n",
678 config&(1<<12) ? "already" : "not (yet)");
679
680 if ((config >> 12) & 1)
681 rm7k_tcache_enabled = 1;
682}
683
684void __init ld_mmu_rm7k(void)
685{
686 unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
687 unsigned long addr;
688
689 printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
690
691 change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
692
693
694 set_taglo(0);
695 set_taghi(0);
696 for (addr = KSEG0; addr <= KSEG0 + 4096; addr += ic_lsize) {
697 __asm__ __volatile__ (
698 ".set noreorder\n\t"
699 ".set mips3\n\t"
700 "cache\t%1, 0(%0)\n\t"
701 "cache\t%1, 0x1000(%0)\n\t"
702 "cache\t%1, 0x2000(%0)\n\t"
703 "cache\t%1, 0x3000(%0)\n\t"
704 "cache\t%2, 0(%0)\n\t"
705 "cache\t%2, 0x1000(%0)\n\t"
706 "cache\t%2, 0x2000(%0)\n\t"
707 "cache\t%2, 0x3000(%0)\n\t"
708 "cache\t%1, 0(%0)\n\t"
709 "cache\t%1, 0x1000(%0)\n\t"
710 "cache\t%1, 0x2000(%0)\n\t"
711 "cache\t%1, 0x3000(%0)\n\t"
712 ".set\tmips0\n\t"
713 ".set\treorder\n\t"
714 :
715 : "r" (addr), "i" (Index_Store_Tag_I), "i" (Fill));
716 }
717
718#ifndef CONFIG_MIPS_UNCACHED
719 change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT);
720#endif
721
722 probe_icache(config);
723 probe_dcache(config);
724 probe_scache(config);
725 probe_tcache(config);
726
727 printk("TLB has %d entries.\n", ntlb_entries());
728
729 _clear_page = rm7k_clear_page;
730 _copy_page = rm7k_copy_page;
731
732 _flush_cache_all = rm7k_flush_cache_all_d32i32;
733 ___flush_cache_all = __flush_cache_all_d32i32;
734 _flush_cache_mm = rm7k_flush_cache_mm_d32i32;
735 _flush_cache_range = rm7k_flush_cache_range_d32i32;
736 _flush_cache_page = rm7k_flush_cache_page_d32i32;
737 _flush_page_to_ram = rm7k_flush_page_to_ram_d32i32;
738 _flush_cache_sigtramp = rm7k_flush_cache_sigtramp;
739 _flush_icache_range = rm7k_flush_icache_range;
740 _flush_icache_page = rm7k_flush_icache_page;
741
742 _dma_cache_wback_inv = rm7k_dma_cache_wback_inv;
743 _dma_cache_wback = rm7k_dma_cache_wback;
744 _dma_cache_inv = rm7k_dma_cache_inv;
745
746 __flush_cache_all_d32i32();
747 write_32bit_cp0_register(CP0_WIRED, 0);
748 temp_tlb_entry = ntlb_entries() - 1;
749 write_32bit_cp0_register(CP0_PAGEMASK, PM_4K);
750 flush_tlb_all();
751}
752