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: releng/8.0/sys/mips/mips/cache_mipsNN.c 178172 2008-04-13 07:27:37Z imp $");
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
Cache object: da56275bc2392e72379c2a134eb0f357
|