]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/mips/mips/cache_mipsNN.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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
56 #ifdef SB1250_PASS1
57 #define SYNC    __asm volatile("sync; sync")
58 #else
59 #define SYNC    __asm volatile("sync")
60 #endif
61
62 #ifdef TARGET_OCTEON
63 #define SYNCI  mips_sync_icache();
64 #else
65 #define SYNCI
66 #endif
67
68
69 __asm(".set mips32");
70
71 static int picache_size;
72 static int picache_stride;
73 static int picache_loopcount;
74 static int picache_way_mask;
75 static int pdcache_size;
76 static int pdcache_stride;
77 static int pdcache_loopcount;
78 static int pdcache_way_mask;
79
80 void
81 mipsNN_cache_init(struct mips_cpuinfo * cpuinfo)
82 {
83         int flush_multiple_lines_per_way;
84
85         flush_multiple_lines_per_way = cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_linesize > PAGE_SIZE;
86         if (cpuinfo->icache_virtual) {
87                 /*
88                  * With a virtual Icache we don't need to flush
89                  * multiples of the page size with index ops; we just
90                  * need to flush one pages' worth.
91                  */
92                 flush_multiple_lines_per_way = 0;
93         }
94
95         if (flush_multiple_lines_per_way) {
96                 picache_stride = PAGE_SIZE;
97                 picache_loopcount = (cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize / PAGE_SIZE) *
98                     cpuinfo->l1.ic_nways;
99         } else {
100                 picache_stride = cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize;
101                 picache_loopcount = cpuinfo->l1.ic_nways;
102         }
103
104         if (cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize < PAGE_SIZE) {
105                 pdcache_stride = cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize;
106                 pdcache_loopcount = cpuinfo->l1.dc_nways;
107         } else {
108                 pdcache_stride = PAGE_SIZE;
109                 pdcache_loopcount = (cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize / PAGE_SIZE) *
110                     cpuinfo->l1.dc_nways;
111         }
112         picache_size = cpuinfo->l1.ic_size;
113         picache_way_mask = cpuinfo->l1.ic_nways - 1;
114         pdcache_size = cpuinfo->l1.dc_size;
115         pdcache_way_mask = cpuinfo->l1.dc_nways - 1;
116 #define CACHE_DEBUG
117 #ifdef CACHE_DEBUG
118         if (cpuinfo->icache_virtual)
119                 printf("  icache is virtual\n");
120         printf("  picache_stride    = %d\n", picache_stride);
121         printf("  picache_loopcount = %d\n", picache_loopcount);
122         printf("  pdcache_stride    = %d\n", pdcache_stride);
123         printf("  pdcache_loopcount = %d\n", pdcache_loopcount);
124 #endif
125 }
126
127 void
128 mipsNN_icache_sync_all_16(void)
129 {
130         vm_offset_t va, eva;
131
132         va = MIPS_PHYS_TO_KSEG0(0);
133         eva = va + picache_size;
134
135         /*
136          * Since we're hitting the whole thing, we don't have to
137          * worry about the N different "ways".
138          */
139
140         mips_intern_dcache_wbinv_all();
141
142         while (va < eva) {
143                 cache_r4k_op_32lines_16(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
144                 va += (32 * 16);
145         }
146
147         SYNC;
148 }
149
150 void
151 mipsNN_icache_sync_all_32(void)
152 {
153         vm_offset_t va, eva;
154
155         va = MIPS_PHYS_TO_KSEG0(0);
156         eva = va + picache_size;
157
158         /*
159          * Since we're hitting the whole thing, we don't have to
160          * worry about the N different "ways".
161          */
162
163         mips_intern_dcache_wbinv_all();
164
165         while (va < eva) {
166                 cache_r4k_op_32lines_32(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
167                 va += (32 * 32);
168         }
169
170         SYNC;
171 }
172
173 void
174 mipsNN_icache_sync_range_16(vm_offset_t va, vm_size_t size)
175 {
176         vm_offset_t eva;
177
178         eva = round_line16(va + size);
179         va = trunc_line16(va);
180
181         mips_intern_dcache_wb_range(va, (eva - va));
182
183         while ((eva - va) >= (32 * 16)) {
184                 cache_r4k_op_32lines_16(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV);
185                 va += (32 * 16);
186         }
187
188         while (va < eva) {
189                 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV);
190                 va += 16;
191         }
192
193         SYNC;
194 }
195
196 void
197 mipsNN_icache_sync_range_32(vm_offset_t va, vm_size_t size)
198 {
199         vm_offset_t eva;
200
201         eva = round_line32(va + size);
202         va = trunc_line32(va);
203
204         mips_intern_dcache_wb_range(va, (eva - va));
205
206         while ((eva - va) >= (32 * 32)) {
207                 cache_r4k_op_32lines_32(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV);
208                 va += (32 * 32);
209         }
210
211         while (va < eva) {
212                 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV);
213                 va += 32;
214         }
215
216         SYNC;
217 }
218
219 void
220 mipsNN_icache_sync_range_index_16(vm_offset_t va, vm_size_t size)
221 {
222         unsigned int eva, tmpva;
223         int i, stride, loopcount;
224
225         /*
226          * Since we're doing Index ops, we expect to not be able
227          * to access the address we've been given.  So, get the
228          * bits that determine the cache index, and make a KSEG0
229          * address out of them.
230          */
231         va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask);
232
233         eva = round_line16(va + size);
234         va = trunc_line16(va);
235
236         /*
237          * GCC generates better code in the loops if we reference local
238          * copies of these global variables.
239          */
240         stride = picache_stride;
241         loopcount = picache_loopcount;
242
243         mips_intern_dcache_wbinv_range_index(va, (eva - va));
244
245         while ((eva - va) >= (8 * 16)) {
246                 tmpva = va;
247                 for (i = 0; i < loopcount; i++, tmpva += stride)
248                         cache_r4k_op_8lines_16(tmpva,
249                             CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
250                 va += 8 * 16;
251         }
252
253         while (va < eva) {
254                 tmpva = va;
255                 for (i = 0; i < loopcount; i++, tmpva += stride)
256                         cache_op_r4k_line(tmpva,
257                             CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
258                 va += 16;
259         }
260 }
261
262 void
263 mipsNN_icache_sync_range_index_32(vm_offset_t va, vm_size_t size)
264 {
265         unsigned int eva, tmpva;
266         int i, stride, loopcount;
267
268         /*
269          * Since we're doing Index ops, we expect to not be able
270          * to access the address we've been given.  So, get the
271          * bits that determine the cache index, and make a KSEG0
272          * address out of them.
273          */
274         va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask);
275
276         eva = round_line32(va + size);
277         va = trunc_line32(va);
278
279         /*
280          * GCC generates better code in the loops if we reference local
281          * copies of these global variables.
282          */
283         stride = picache_stride;
284         loopcount = picache_loopcount;
285
286         mips_intern_dcache_wbinv_range_index(va, (eva - va));
287
288         while ((eva - va) >= (8 * 32)) {
289                 tmpva = va;
290                 for (i = 0; i < loopcount; i++, tmpva += stride)
291                         cache_r4k_op_8lines_32(tmpva,
292                             CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
293                 va += 8 * 32;
294         }
295
296         while (va < eva) {
297                 tmpva = va;
298                 for (i = 0; i < loopcount; i++, tmpva += stride)
299                         cache_op_r4k_line(tmpva,
300                             CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
301                 va += 32;
302         }
303 }
304
305 void
306 mipsNN_pdcache_wbinv_all_16(void)
307 {
308         vm_offset_t va, eva;
309
310         va = MIPS_PHYS_TO_KSEG0(0);
311         eva = va + pdcache_size;
312
313         /*
314          * Since we're hitting the whole thing, we don't have to
315          * worry about the N different "ways".
316          */
317
318         while (va < eva) {
319                 cache_r4k_op_32lines_16(va,
320                     CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
321                 va += (32 * 16);
322         }
323
324         SYNC;
325 }
326
327 void
328 mipsNN_pdcache_wbinv_all_32(void)
329 {
330         vm_offset_t va, eva;
331
332         va = MIPS_PHYS_TO_KSEG0(0);
333         eva = va + pdcache_size;
334
335         /*
336          * Since we're hitting the whole thing, we don't have to
337          * worry about the N different "ways".
338          */
339
340         while (va < eva) {
341                 cache_r4k_op_32lines_32(va,
342                     CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
343                 va += (32 * 32);
344         }
345
346         SYNC;
347 }
348
349 void
350 mipsNN_pdcache_wbinv_range_16(vm_offset_t va, vm_size_t size)
351 {
352         vm_offset_t eva;
353
354         eva = round_line16(va + size);
355         va = trunc_line16(va);
356
357         while ((eva - va) >= (32 * 16)) {
358                 cache_r4k_op_32lines_16(va,
359                     CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
360                 va += (32 * 16);
361         }
362
363         while (va < eva) {
364                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
365                 va += 16;
366         }
367
368         SYNC;
369 }
370
371 void
372 mipsNN_pdcache_wbinv_range_32(vm_offset_t va, vm_size_t size)
373 {
374         vm_offset_t eva;
375
376         eva = round_line32(va + size);
377         va = trunc_line32(va);
378
379         while ((eva - va) >= (32 * 32)) {
380                 cache_r4k_op_32lines_32(va,
381                     CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
382                 va += (32 * 32);
383         }
384
385         while (va < eva) {
386                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
387                 va += 32;
388         }
389
390         SYNC;
391 }
392
393 void
394 mipsNN_pdcache_wbinv_range_index_16(vm_offset_t va, vm_size_t size)
395 {
396         unsigned int eva, tmpva;
397         int i, stride, loopcount;
398
399         /*
400          * Since we're doing Index ops, we expect to not be able
401          * to access the address we've been given.  So, get the
402          * bits that determine the cache index, and make a KSEG0
403          * address out of them.
404          */
405         va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask);
406
407         eva = round_line16(va + size);
408         va = trunc_line16(va);
409
410         /*
411          * GCC generates better code in the loops if we reference local
412          * copies of these global variables.
413          */
414         stride = pdcache_stride;
415         loopcount = pdcache_loopcount;
416
417         while ((eva - va) >= (8 * 16)) {
418                 tmpva = va;
419                 for (i = 0; i < loopcount; i++, tmpva += stride)
420                         cache_r4k_op_8lines_16(tmpva,
421                             CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
422                 va += 8 * 16;
423         }
424
425         while (va < eva) {
426                 tmpva = va;
427                 for (i = 0; i < loopcount; i++, tmpva += stride)
428                         cache_op_r4k_line(tmpva,
429                             CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
430                 va += 16;
431         }
432 }
433
434 void
435 mipsNN_pdcache_wbinv_range_index_32(vm_offset_t va, vm_size_t size)
436 {
437         unsigned int eva, tmpva;
438         int i, stride, loopcount;
439
440         /*
441          * Since we're doing Index ops, we expect to not be able
442          * to access the address we've been given.  So, get the
443          * bits that determine the cache index, and make a KSEG0
444          * address out of them.
445          */
446         va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask);
447
448         eva = round_line32(va + size);
449         va = trunc_line32(va);
450
451         /*
452          * GCC generates better code in the loops if we reference local
453          * copies of these global variables.
454          */
455         stride = pdcache_stride;
456         loopcount = pdcache_loopcount;
457
458         while ((eva - va) >= (8 * 32)) {
459                 tmpva = va;
460                 for (i = 0; i < loopcount; i++, tmpva += stride)
461                         cache_r4k_op_8lines_32(tmpva,
462                             CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
463                 va += 8 * 32;
464         }
465
466         while (va < eva) {
467                 tmpva = va;
468                 for (i = 0; i < loopcount; i++, tmpva += stride)
469                         cache_op_r4k_line(tmpva,
470                             CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
471                 va += 32;
472         }
473 }
474  
475 void
476 mipsNN_pdcache_inv_range_16(vm_offset_t va, vm_size_t size)
477 {
478         vm_offset_t eva;
479
480         eva = round_line16(va + size);
481         va = trunc_line16(va);
482
483         while ((eva - va) >= (32 * 16)) {
484                 cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
485                 va += (32 * 16);
486         }
487
488         while (va < eva) {
489                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
490                 va += 16;
491         }
492
493         SYNC;
494 }
495
496 void
497 mipsNN_pdcache_inv_range_32(vm_offset_t va, vm_size_t size)
498 {
499         vm_offset_t eva;
500
501         eva = round_line32(va + size);
502         va = trunc_line32(va);
503
504         while ((eva - va) >= (32 * 32)) {
505                 cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
506                 va += (32 * 32);
507         }
508
509         while (va < eva) {
510                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
511                 va += 32;
512         }
513
514         SYNC;
515 }
516
517 void
518 mipsNN_pdcache_wb_range_16(vm_offset_t va, vm_size_t size)
519 {
520         vm_offset_t eva;
521
522         eva = round_line16(va + size);
523         va = trunc_line16(va);
524
525         while ((eva - va) >= (32 * 16)) {
526                 cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
527                 va += (32 * 16);
528         }
529
530         while (va < eva) {
531                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
532                 va += 16;
533         }
534
535         SYNC;
536 }
537
538 void
539 mipsNN_pdcache_wb_range_32(vm_offset_t va, vm_size_t size)
540 {
541         vm_offset_t eva;
542
543         eva = round_line32(va + size);
544         va = trunc_line32(va);
545
546         while ((eva - va) >= (32 * 32)) {
547                 cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
548                 va += (32 * 32);
549         }
550
551         while (va < eva) {
552                 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
553                 va += 32;
554         }
555
556         SYNC;
557 }
558
559
560 #ifdef TARGET_OCTEON
561
562 void
563 mipsNN_icache_sync_all_128(void)
564 {
565         SYNCI
566 }
567
568 void
569 mipsNN_icache_sync_range_128(vm_offset_t va, vm_size_t size)
570 {
571         SYNC;
572 }
573
574 void
575 mipsNN_icache_sync_range_index_128(vm_offset_t va, vm_size_t size)
576 {
577 }
578
579
580 void
581 mipsNN_pdcache_wbinv_all_128(void)
582 {
583 }
584
585
586 void
587 mipsNN_pdcache_wbinv_range_128(vm_offset_t va, vm_size_t size)
588 {
589         SYNC;
590 }
591
592 void
593 mipsNN_pdcache_wbinv_range_index_128(vm_offset_t va, vm_size_t size)
594 {
595 }
596
597 void
598 mipsNN_pdcache_inv_range_128(vm_offset_t va, vm_size_t size)
599 {
600 }
601
602 void
603 mipsNN_pdcache_wb_range_128(vm_offset_t va, vm_size_t size)
604 {
605         SYNC;
606 }
607
608 #endif