1
2
3
4
5
6
7
8
9
10#include <linux/init.h>
11#include <linux/kernel.h>
12#include <linux/sched.h>
13#include <linux/mm.h>
14#include <asm/page.h>
15#include <asm/pgtable.h>
16#include <asm/r10kcache.h>
17#include <asm/system.h>
18#include <asm/sgialib.h>
19#include <asm/mmu_context.h>
20
21static int scache_lsz64;
22
23
24
25
26
27static void andes_clear_page(void * page)
28{
29 __asm__ __volatile__(
30 ".set\tnoreorder\n\t"
31 ".set\tnoat\n\t"
32 "daddiu\t$1,%0,%2\n"
33 "1:\tpref 7,512(%0)\n\t"
34 "sd\t$0,(%0)\n\t"
35 "sd\t$0,8(%0)\n\t"
36 "sd\t$0,16(%0)\n\t"
37 "sd\t$0,24(%0)\n\t"
38 "daddiu\t%0,64\n\t"
39 "sd\t$0,-32(%0)\n\t"
40 "sd\t$0,-24(%0)\n\t"
41 "sd\t$0,-16(%0)\n\t"
42 "bne\t$1,%0,1b\n\t"
43 "sd\t$0,-8(%0)\n\t"
44 ".set\tat\n\t"
45 ".set\treorder"
46 :"=r" (page)
47 :"0" (page), "I" (PAGE_SIZE)
48 :"$1", "memory");
49}
50
51
52static void andes_copy_page(void * to, void * from)
53{
54 unsigned long dummy1, dummy2, reg1, reg2, reg3, reg4;
55
56 __asm__ __volatile__(
57 ".set\tnoreorder\n\t"
58 ".set\tnoat\n\t"
59 "daddiu\t$1,%0,%8\n"
60 "1:\tpref\t0,2*128(%1)\n\t"
61 "pref\t1,2*128(%0)\n\t"
62 "ld\t%2,(%1)\n\t"
63 "ld\t%3,8(%1)\n\t"
64 "ld\t%4,16(%1)\n\t"
65 "ld\t%5,24(%1)\n\t"
66 "sd\t%2,(%0)\n\t"
67 "sd\t%3,8(%0)\n\t"
68 "sd\t%4,16(%0)\n\t"
69 "sd\t%5,24(%0)\n\t"
70 "daddiu\t%0,64\n\t"
71 "daddiu\t%1,64\n\t"
72 "ld\t%2,-32(%1)\n\t"
73 "ld\t%3,-24(%1)\n\t"
74 "ld\t%4,-16(%1)\n\t"
75 "ld\t%5,-8(%1)\n\t"
76 "sd\t%2,-32(%0)\n\t"
77 "sd\t%3,-24(%0)\n\t"
78 "sd\t%4,-16(%0)\n\t"
79 "bne\t$1,%0,1b\n\t"
80 " sd\t%5,-8(%0)\n\t"
81 ".set\tat\n\t"
82 ".set\treorder"
83 :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2),
84 "=&r" (reg3), "=&r" (reg4)
85 :"0" (to), "1" (from), "I" (PAGE_SIZE));
86}
87
88
89
90static void
91andes_flush_cache_l1(void)
92{
93 blast_dcache32(); blast_icache64();
94}
95
96
97
98
99
100static void
101andes_flush_cache_l2(void)
102{
103 switch (sc_lsize()) {
104 case 64:
105 blast_scache64();
106 break;
107 case 128:
108 blast_scache128();
109 break;
110 default:
111 printk("Unknown L2 line size\n");
112 while(1);
113 }
114}
115
116void
117andes_flush_icache_page(unsigned long page)
118{
119 if (scache_lsz64)
120 blast_scache64_page(page);
121 else
122 blast_scache128_page(page);
123}
124
125static void
126andes_flush_cache_sigtramp(unsigned long addr)
127{
128 protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
129 protected_flush_icache_line(addr & ~(ic_lsize - 1));
130}
131
132#define NTLB_ENTRIES 64
133#define NTLB_ENTRIES_HALF 32
134
135static inline void
136andes_flush_tlb_all(void)
137{
138 unsigned long flags;
139 unsigned long old_ctx;
140 unsigned long entry;
141
142#ifdef DEBUG_TLB
143 printk("[tlball]");
144#endif
145
146 local_irq_save(flags);
147
148 old_ctx = get_entryhi() & 0xff;
149 set_entryhi(CKSEG0);
150 set_entrylo0(0);
151 set_entrylo1(0);
152
153 entry = get_wired();
154
155
156 while(entry < NTLB_ENTRIES) {
157 set_index(entry);
158 tlb_write_indexed();
159 entry++;
160 }
161 set_entryhi(old_ctx);
162 local_irq_restore(flags);
163}
164
165static void andes_flush_tlb_mm(struct mm_struct *mm)
166{
167 if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
168 unsigned long flags;
169
170#ifdef DEBUG_TLB
171 printk("[tlbmm<%d>]", mm->context);
172#endif
173 local_irq_save(flags);
174 get_new_cpu_mmu_context(mm, smp_processor_id());
175 if(mm == current->mm)
176 set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff);
177 local_irq_restore(flags);
178 }
179}
180
181static void
182andes_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
183 unsigned long end)
184{
185 struct mm_struct *mm = vma->vm_mm;
186
187 if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
188 unsigned long flags;
189 int size;
190
191#ifdef DEBUG_TLB
192 printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff),
193 start, end);
194#endif
195 local_irq_save(flags);
196 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
197 size = (size + 1) >> 1;
198 if(size <= NTLB_ENTRIES_HALF) {
199 int oldpid = (get_entryhi() & 0xff);
200 int newpid = (CPU_CONTEXT(smp_processor_id(), mm) & 0xff);
201
202 start &= (PAGE_MASK << 1);
203 end += ((PAGE_SIZE << 1) - 1);
204 end &= (PAGE_MASK << 1);
205 while(start < end) {
206 int idx;
207
208 set_entryhi(start | newpid);
209 start += (PAGE_SIZE << 1);
210 tlb_probe();
211 idx = get_index();
212 set_entrylo0(0);
213 set_entrylo1(0);
214 set_entryhi(KSEG0);
215 if(idx < 0)
216 continue;
217 tlb_write_indexed();
218 }
219 set_entryhi(oldpid);
220 } else {
221 get_new_cpu_mmu_context(mm, smp_processor_id());
222 if(mm == current->mm)
223 set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) &
224 0xff);
225 }
226 local_irq_restore(flags);
227 }
228}
229
230static void
231andes_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
232{
233 if (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) != 0) {
234 unsigned long flags;
235 int oldpid, newpid, idx;
236
237#ifdef DEBUG_TLB
238 printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
239#endif
240 newpid = (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff);
241 page &= (PAGE_MASK << 1);
242 local_irq_save(flags);
243 oldpid = (get_entryhi() & 0xff);
244 set_entryhi(page | newpid);
245 tlb_probe();
246 idx = get_index();
247 set_entrylo0(0);
248 set_entrylo1(0);
249 set_entryhi(KSEG0);
250 if(idx < 0)
251 goto finish;
252 tlb_write_indexed();
253
254 finish:
255 set_entryhi(oldpid);
256 local_irq_restore(flags);
257 }
258}
259
260
261
262
263static void andes_update_mmu_cache(struct vm_area_struct * vma,
264 unsigned long address, pte_t pte)
265{
266 unsigned long flags;
267 pgd_t *pgdp;
268 pmd_t *pmdp;
269 pte_t *ptep;
270 int idx, pid;
271
272
273
274
275 if (current->active_mm != vma->vm_mm)
276 return;
277
278 local_irq_save(flags);
279 pid = get_entryhi() & 0xff;
280
281 if((pid != (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff)) ||
282 (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) == 0)) {
283 printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d "
284 "tlbpid=%d\n", (int) (CPU_CONTEXT(smp_processor_id(),
285 vma->vm_mm) & 0xff), pid);
286 }
287
288 address &= (PAGE_MASK << 1);
289 set_entryhi(address | (pid));
290 pgdp = pgd_offset(vma->vm_mm, address);
291 tlb_probe();
292 pmdp = pmd_offset(pgdp, address);
293 idx = get_index();
294 ptep = pte_offset(pmdp, address);
295 set_entrylo0(pte_val(*ptep++) >> 6);
296 set_entrylo1(pte_val(*ptep) >> 6);
297 set_entryhi(address | (pid));
298 if(idx < 0) {
299 tlb_write_random();
300 } else {
301 tlb_write_indexed();
302 }
303 set_entryhi(pid);
304 local_irq_restore(flags);
305}
306
307static void andes_show_regs(struct pt_regs *regs)
308{
309 printk("Cpu %d\n", smp_processor_id());
310
311 printk("$0 : %016lx %016lx %016lx %016lx\n",
312 0UL, regs->regs[1], regs->regs[2], regs->regs[3]);
313 printk("$4 : %016lx %016lx %016lx %016lx\n",
314 regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]);
315 printk("$8 : %016lx %016lx %016lx %016lx\n",
316 regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]);
317 printk("$12 : %016lx %016lx %016lx %016lx\n",
318 regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]);
319 printk("$16 : %016lx %016lx %016lx %016lx\n",
320 regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]);
321 printk("$20 : %016lx %016lx %016lx %016lx\n",
322 regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]);
323 printk("$24 : %016lx %016lx\n",
324 regs->regs[24], regs->regs[25]);
325 printk("$28 : %016lx %016lx %016lx %016lx\n",
326 regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]);
327 printk("Hi : %016lx\n", regs->hi);
328 printk("Lo : %016lx\n", regs->lo);
329
330
331 printk("epc : %016lx %s\nbadvaddr: %016lx\n",
332 regs->cp0_epc, print_tainted(), regs->cp0_badvaddr);
333 printk("Status : %08x\nCause : %08x\n",
334 (unsigned int) regs->cp0_status, (unsigned int) regs->cp0_cause);
335}
336
337void __init ld_mmu_andes(void)
338{
339 printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
340
341 printk("Primary instruction cache %dkb, linesize %d bytes\n",
342 icache_size >> 10, ic_lsize);
343 printk("Primary data cache %dkb, linesize %d bytes\n",
344 dcache_size >> 10, dc_lsize);
345 printk("Secondary cache sized at %ldK, linesize %ld\n",
346 scache_size() >> 10, sc_lsize());
347
348 _clear_page = andes_clear_page;
349 _copy_page = andes_copy_page;
350
351 _flush_cache_l1 = andes_flush_cache_l1;
352 _flush_cache_l2 = andes_flush_cache_l2;
353 _flush_cache_sigtramp = andes_flush_cache_sigtramp;
354
355 _flush_tlb_all = andes_flush_tlb_all;
356 _flush_tlb_mm = andes_flush_tlb_mm;
357 _flush_tlb_range = andes_flush_tlb_range;
358 _flush_tlb_page = andes_flush_tlb_page;
359
360 switch (sc_lsize()) {
361 case 64:
362 scache_lsz64 = 1;
363 break;
364 case 128:
365 scache_lsz64 = 0;
366 break;
367 default:
368 printk("Unknown L2 line size\n");
369 while(1);
370 }
371
372 update_mmu_cache = andes_update_mmu_cache;
373
374 _show_regs = andes_show_regs;
375
376 flush_cache_l1();
377
378
379
380
381
382
383
384
385 write_32bit_cp0_register(CP0_PAGEMASK, PM_4K);
386
387
388 _flush_tlb_all();
389
390
391}
392