]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/mips/mips/cache_mipsNN.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / mips / mips / cache_mipsNN.c
1 /*      $NetBSD: cache_mipsNN.c,v 1.10 2005/12/24 20:07:19 perry Exp $  */
2
3 /*
4  * Copyright 2001 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed for the NetBSD Project by
20  *      Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <sys/types.h>
42 #include <sys/systm.h>
43 #include <sys/param.h>
44
45 #include <machine/cache.h>
46 #include <machine/cache_r4k.h>
47 #include <machine/cpuinfo.h>
48
49 #define round_line16(x)         (((x) + 15) & ~15)
50 #define trunc_line16(x)         ((x) & ~15)
51
52 #define round_line32(x)         (((x) + 31) & ~31)
53 #define trunc_line32(x)         ((x) & ~31)
54
55 #if defined(CPU_NLM)
56 static __inline void
57 xlp_sync(void)
58 {
59         __asm __volatile (
60             ".set push              \n"
61             ".set noreorder         \n"
62             ".set mips64            \n"
63             "dla    $8, 1f          \n"
64             "/* jr.hb $8 */         \n"
65             ".word 0x1000408        \n"
66             "nop                    \n"
67          "1: nop                    \n"
68             ".set pop               \n"
69             : : : "$8");
70 }
71 #endif
72
73 #if defined(SB1250_PASS1)
74 #define SYNC    __asm volatile("sync; sync")
75 #elif defined(CPU_NLM)
76 #define SYNC    xlp_sync()
77 #else
78 #define SYNC    __asm volatile("sync")
79 #endif
80
81 #if defined(CPU_CNMIPS)
82 #define SYNCI  mips_sync_icache();
83 #elif defined(CPU_NLM)
84 #define SYNCI   xlp_sync()
85 #else
86 #define SYNCI
87 #endif
88
89 /*
90  * Exported variables for consumers like bus_dma code
91  */
92 int mips_picache_linesize;
93 int mips_pdcache_linesize;
94
95 static int picache_size;
96 static int picache_stride;
97 static int picache_loopcount;
98 static int picache_way_mask;
99 static int pdcache_size;
100 static int pdcache_stride;
101 static int pdcache_loopcount;
102 static int pdcache_way_mask;
103
104 void
105 mipsNN_cache_init(struct mips_cpuinfo * cpuinfo)
106 {
107         int flush_multiple_lines_per_way;
108
109         flush_multiple_lines_per_way = cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_linesize > PAGE_SIZE;
110         if (cpuinfo->icache_virtual) {
111                 /*
112                  * With a virtual Icache we don't need to flush
113                  * multiples of the page size with index ops; we just
114                  * need to flush one pages' worth.
115                  */
116                 flush_multiple_lines_per_way = 0;
117         }
118
119         if (flush_multiple_lines_per_way) {
120                 picache_stride = PAGE_SIZE;
121                 picache_loopcount = (cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize / PAGE_SIZE) *
122                     cpuinfo->l1.ic_nways;
123         } else {
124                 picache_stride = cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize;
125                 picache_loopcount = cpuinfo->l1.ic_nways;
126         }
127
128         if (cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize < PAGE_SIZE) {
129                 pdcache_stride = cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize;
130                 pdcache_loopcount = cpuinfo->l1.dc_nways;
131         } else {
132                 pdcache_stride = PAGE_SIZE;
133                 pdcache_loopcount = (cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize / PAGE_SIZE) *
134                     cpuinfo->l1.dc_nways;
135         }
136
137         mips_picache_linesize = cpuinfo->l1.ic_linesize;
138         mips_pdcache_linesize = cpuinfo->l1.dc_linesize;
139
140         picache_size = cpuinfo->l1.ic_size;
141         picache_way_mask = cpuinfo->l1.ic_nways - 1;
142         pdcache_size = cpuinfo->l1.dc_size;
143         pdcache_way_mask = cpuinfo->l1.dc_nways - 1;
144
145 #define CACHE_DEBUG
146 #ifdef CACHE_DEBUG
147         printf("Cache info:\n");
148         if (cpuinfo->icache_virtual)
149                 printf("  icache is virtual\n");
150         printf("  picache_stride    = %d\n", picache_stride);
151         printf("  picache_loopcount = %d\n", picache_loopcount);
152         printf("  pdcache_stride    = %d\n", pdcache_stride);
153         printf("  pdcache_loopcount = %d\n", pdcache_loopcount);
154 #endif
155 }
156
157 void
158 mipsNN_icache_sync_all_16(void)
159 {
160         vm_offset_t va, eva;
161
162         va = MIPS_PHYS_TO_KSEG0(0);
163         eva = va + picache_size;
164
165         /*
166          * Since we're hitting the whole thing, we don't have to
167          * worry about the N different "ways".
168          */
169
170         mips_intern_dcache_wbinv_all();
171
172         while (va < eva) {
173                 cache_r4k_op_32lines_16(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
174                 va += (32 * 16);
175         }
176
177         SYNC;
178 }
179
180 void
181 mipsNN_icache_sync_all_32(void)
182 {
183         vm_offset_t va, eva;
184
185         va = MIPS_PHYS_TO_KSEG0(0);
186         eva = va + picache_size;
187
188         /*
189          * Since we're hitting the whole thing, we don't have to
190          * worry about the N different "ways".
191          */
192
193         mips_intern_dcache_wbinv_all();
194
195         while (va < eva) {
196                 cache_r4k_op_32lines_32(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
197                 va += (32 * 32);
198         }
199
200         SYNC;
201 }
202
203 void
204 mipsNN_icache_sync_range_16(vm_offset_t va, vm_size_t size)
205 {
206         vm_offset_t eva;
207
208         eva = round_line16(va + size);
209         va = trunc_line16(va);
210
211         mips_intern_dcache_wb_range(va, (eva - va));
212
213         while ((eva - va) >= (32 * 16)) {
214                 cache_r4k_op_32lines_16(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV);
215                 va += (32 * 16);
216         }
217
218         while (va < eva) {
219                 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV);
220                 va += 16;
221         }
222
223         SYNC;
224 }
225
226 void
227 mipsNN_icache_sync_range_32(vm_offset_t va, vm_size_t size)
228 {
229         vm_offset_t eva;
230
231         eva = round_line32(va + size);
232         va = trunc_line32(va);
233
234         mips_intern_dcache_wb_range(va, (eva - va));
235
236         while ((eva - va) >= (32 * 32)) {
237                 cache_r4k_op_32lines_32(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV);
238                 va += (32 * 32);
239         }
240
241         while (va < eva) {
242                 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV);
243                 va += 32;
244         }
245
246         SYNC;
247 }
248
249 void
250 mipsNN_icache_sync_range_index_16(vm_offset_t va, vm_size_t size)
251 {
252         vm_offset_t eva, tmpva;
253         int i, stride, loopcount;
254
255         /*
256          * Since we're doing Index ops, we expect to not be able
257          * to access the address we've been given.  So, get the
258          * bits that determine the cache index, and make a KSEG0
259          * address out of them.
260          */
261         va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask);
262
263         eva = round_line16(va + size);
264         va = trunc_line16(va);
265
266         /*
267          * GCC generates better code in the loops if we reference local
268          * copies of these global variables.
269          */
270         stride = picache_stride;
271         loopcount = picache_loopcount;
272
273         mips_intern_dcache_wbinv_range_index(va, (eva - va));
274
275         while ((eva - va) >= (8 * 16)) {
276                 tmpva = va;
277                 for (i = 0; i < loopcount; i++, tmpva += stride)
278                         cache_r4k_op_8lines_16(tmpva,
279                             CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
280                 va += 8 * 16;
281         }
282
283         while (va < eva) {
284                 tmpva = va;
285                 for (i = 0; i < loopcount; i++, tmpva += stride)
286                         cache_op_r4k_line(tmpva,
287                             CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
288                 va += 16;
289         }
290 }
291
292 void
293 mipsNN_icache_sync_range_index_32(vm_offset_t va, vm_size_t size)
294 {
295         vm_offset_t eva, tmpva;
296         int i, stride, loopcount;
297
298         /*
299          * Since we're doing Index ops, we expect to not be able
300          * to access the address we've been given.  So, get the
301          * bits that determine the cache index, and make a KSEG0
302          * address out of them.
303          */
304         va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask);
305
306         eva = round_line32(va + size);
307         va = trunc_line32(va);
308
309         /*
310          * GCC generates better code in the loops if we reference local
311          * copies of these global variables.
312          */
313         stride = picache_stride;
314         loopcount = picache_loopcount;
315
316         mips_intern_dcache_wbinv_range_index(va, (eva - va));
317
318         while ((eva - va) >= (8 * 32)) {
319                 tmpva = va;
320                 for (i = 0; i < loopcount; i++, tmpva += stride)
321                         cache_r4k_op_8lines_32(tmpva,
322                             CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
323                 va += 8 * 32;
324         }
325
326         while (va < eva) {
327                 tmpva = va;
328                 for (i = 0; i < loopcount; i++, tmpva += stride)
329                         cache_op_r4k_line(tmpva,
330                             CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
331                 va += 32;
332         }
333 }
334
335 void
336 mipsNN_pdcache_wbinv_all_16(void)
337 {
338         vm_offset_t va, eva;
339
340         va = MIPS_PHYS_TO_KSEG0(0);
341         eva = va + pdcache_size;
342
343         /*
344          * Since we're hitting the whole thing, we don't have to
345          * worry about the N different "ways".
346          */
347
348         while (va < eva) {
349                 cache_r4k_op_32lines_16(va,
350                     CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
351                 va += (32 * 16);
352         }
353
354         SYNC;
355 }
356
357 void
358 mipsNN_pdcache_wbinv_all_32(void)
359 {
360         vm_offset_t va, eva;
361
362         va = MIPS_PHYS_TO_KSEG0(0);
363         eva = va + pdcache_size;
364
365         /*
366          * Since we're hitting the whole thing, we don't have to
367          * worry about the N different "ways".
368          */
369
370         while (va < eva) {
371                 cache_r4k_op_32lines_32(va,
372                     CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
373                 va += (32 * 32);
374         }
375
376         SYNC;
377 }
378
379 void
380 mipsNN_pdcache_wbinv_range_16(vm_offset_t va, vm_size_t size)
381 {
382         vm_offset_t eva;
383
384         eva = round_line16(va + size);
385         va = trunc_line16(va);
386
387         while ((eva - va) >= (32 * 16)) {
388                 cache_r4k_op_32lines_16(va,
389                     CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
390                 va += (32 * 16);
391         }
392
393         while (va < eva) {
394                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
395                 va += 16;
396         }
397
398         SYNC;
399 }
400
401 void
402 mipsNN_pdcache_wbinv_range_32(vm_offset_t va, vm_size_t size)
403 {
404         vm_offset_t eva;
405
406         eva = round_line32(va + size);
407         va = trunc_line32(va);
408
409         while ((eva - va) >= (32 * 32)) {
410                 cache_r4k_op_32lines_32(va,
411                     CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
412                 va += (32 * 32);
413         }
414
415         while (va < eva) {
416                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
417                 va += 32;
418         }
419
420         SYNC;
421 }
422
423 void
424 mipsNN_pdcache_wbinv_range_index_16(vm_offset_t va, vm_size_t size)
425 {
426         vm_offset_t eva, tmpva;
427         int i, stride, loopcount;
428
429         /*
430          * Since we're doing Index ops, we expect to not be able
431          * to access the address we've been given.  So, get the
432          * bits that determine the cache index, and make a KSEG0
433          * address out of them.
434          */
435         va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask);
436
437         eva = round_line16(va + size);
438         va = trunc_line16(va);
439
440         /*
441          * GCC generates better code in the loops if we reference local
442          * copies of these global variables.
443          */
444         stride = pdcache_stride;
445         loopcount = pdcache_loopcount;
446
447         while ((eva - va) >= (8 * 16)) {
448                 tmpva = va;
449                 for (i = 0; i < loopcount; i++, tmpva += stride)
450                         cache_r4k_op_8lines_16(tmpva,
451                             CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
452                 va += 8 * 16;
453         }
454
455         while (va < eva) {
456                 tmpva = va;
457                 for (i = 0; i < loopcount; i++, tmpva += stride)
458                         cache_op_r4k_line(tmpva,
459                             CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
460                 va += 16;
461         }
462 }
463
464 void
465 mipsNN_pdcache_wbinv_range_index_32(vm_offset_t va, vm_size_t size)
466 {
467         vm_offset_t eva, tmpva;
468         int i, stride, loopcount;
469
470         /*
471          * Since we're doing Index ops, we expect to not be able
472          * to access the address we've been given.  So, get the
473          * bits that determine the cache index, and make a KSEG0
474          * address out of them.
475          */
476         va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask);
477
478         eva = round_line32(va + size);
479         va = trunc_line32(va);
480
481         /*
482          * GCC generates better code in the loops if we reference local
483          * copies of these global variables.
484          */
485         stride = pdcache_stride;
486         loopcount = pdcache_loopcount;
487
488         while ((eva - va) >= (8 * 32)) {
489                 tmpva = va;
490                 for (i = 0; i < loopcount; i++, tmpva += stride)
491                         cache_r4k_op_8lines_32(tmpva,
492                             CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
493                 va += 8 * 32;
494         }
495
496         while (va < eva) {
497                 tmpva = va;
498                 for (i = 0; i < loopcount; i++, tmpva += stride)
499                         cache_op_r4k_line(tmpva,
500                             CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
501                 va += 32;
502         }
503 }
504  
505 void
506 mipsNN_pdcache_inv_range_16(vm_offset_t va, vm_size_t size)
507 {
508         vm_offset_t eva;
509
510         eva = round_line16(va + size);
511         va = trunc_line16(va);
512
513         while ((eva - va) >= (32 * 16)) {
514                 cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
515                 va += (32 * 16);
516         }
517
518         while (va < eva) {
519                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
520                 va += 16;
521         }
522
523         SYNC;
524 }
525
526 void
527 mipsNN_pdcache_inv_range_32(vm_offset_t va, vm_size_t size)
528 {
529         vm_offset_t eva;
530
531         eva = round_line32(va + size);
532         va = trunc_line32(va);
533
534         while ((eva - va) >= (32 * 32)) {
535                 cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
536                 va += (32 * 32);
537         }
538
539         while (va < eva) {
540                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
541                 va += 32;
542         }
543
544         SYNC;
545 }
546
547 void
548 mipsNN_pdcache_wb_range_16(vm_offset_t va, vm_size_t size)
549 {
550         vm_offset_t eva;
551
552         eva = round_line16(va + size);
553         va = trunc_line16(va);
554
555         while ((eva - va) >= (32 * 16)) {
556                 cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
557                 va += (32 * 16);
558         }
559
560         while (va < eva) {
561                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
562                 va += 16;
563         }
564
565         SYNC;
566 }
567
568 void
569 mipsNN_pdcache_wb_range_32(vm_offset_t va, vm_size_t size)
570 {
571         vm_offset_t eva;
572
573         eva = round_line32(va + size);
574         va = trunc_line32(va);
575
576         while ((eva - va) >= (32 * 32)) {
577                 cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
578                 va += (32 * 32);
579         }
580
581         while (va < eva) {
582                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
583                 va += 32;
584         }
585
586         SYNC;
587 }
588
589
590 #ifdef CPU_CNMIPS
591
592 void
593 mipsNN_icache_sync_all_128(void)
594 {
595         SYNCI
596 }
597
598 void
599 mipsNN_icache_sync_range_128(vm_offset_t va, vm_size_t size)
600 {
601         SYNC;
602 }
603
604 void
605 mipsNN_icache_sync_range_index_128(vm_offset_t va, vm_size_t size)
606 {
607 }
608
609
610 void
611 mipsNN_pdcache_wbinv_all_128(void)
612 {
613 }
614
615
616 void
617 mipsNN_pdcache_wbinv_range_128(vm_offset_t va, vm_size_t size)
618 {
619         SYNC;
620 }
621
622 void
623 mipsNN_pdcache_wbinv_range_index_128(vm_offset_t va, vm_size_t size)
624 {
625 }
626
627 void
628 mipsNN_pdcache_inv_range_128(vm_offset_t va, vm_size_t size)
629 {
630 }
631
632 void
633 mipsNN_pdcache_wb_range_128(vm_offset_t va, vm_size_t size)
634 {
635         SYNC;
636 }
637
638 #endif