1 /* $NetBSD: cache_r10k.c,v 1.8 2016/07/13 21:25:15 macallan Exp $ */
2
3 /*-
4 * Copyright (c) 2003 Takao Shinohara.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 /*
28 * Copyright 2001 Wasabi Systems, Inc.
29 * All rights reserved.
30 *
31 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed for the NetBSD Project by
44 * Wasabi Systems, Inc.
45 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
46 * or promote products derived from this software without specific prior
47 * written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
51 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
52 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
53 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
54 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
55 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
56 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
57 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
58 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
59 * POSSIBILITY OF SUCH DAMAGE.
60 */
61
62 #include <sys/param.h>
63
64 #include <mips/cpuregs.h>
65 #include <mips/cache.h>
66 #include <mips/cache_r4k.h>
67 #include <mips/cache_r10k.h>
68
69 /*
70 * Cache operations for R10000-style caches:
71 *
72 * 2-way, write-back
73 * primary cache: virtual index/physical tag
74 * secondary cache: physical index/physical tag
75 */
76
77 __asm(".set mips3");
78
79 #define round_line(x) (((x) + 64 - 1) & ~(64 - 1))
80 #define trunc_line(x) ((x) & ~(64 - 1))
81
82 void
r10k_icache_sync_all(void)83 r10k_icache_sync_all(void)
84 {
85 const struct mips_cache_info * const mci = &mips_cache_info;
86 vaddr_t va = MIPS_PHYS_TO_KSEG0(0);
87 vaddr_t eva = va + mci->mci_picache_way_size;
88
89 mips_dcache_wbinv_all();
90
91 __asm volatile("sync");
92
93 while (va < eva) {
94 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
95 va++;
96 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
97 va += 63;
98 }
99 }
100
101 void
r10k_icache_sync_range(register_t va,vsize_t size)102 r10k_icache_sync_range(register_t va, vsize_t size)
103 {
104 vaddr_t eva = round_line(va + size);
105
106 va = trunc_line(va);
107
108 mips_dcache_wb_range(va, (eva - va));
109
110 __asm volatile("sync");
111
112 while (va < eva) {
113 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV);
114 va += 64;
115 }
116 }
117
118 void
r10k_icache_sync_range_index(vaddr_t va,vsize_t size)119 r10k_icache_sync_range_index(vaddr_t va, vsize_t size)
120 {
121 const struct mips_cache_info * const mci = &mips_cache_info;
122 vaddr_t eva, orig_va;
123
124 orig_va = va;
125
126 eva = round_line(va + size);
127 va = trunc_line(va);
128
129 mips_dcache_wbinv_range_index(va, (eva - va));
130
131 __asm volatile("sync");
132
133 /*
134 * Since we're doing Index ops, we expect to not be able
135 * to access the address we've been given. So, get the
136 * bits that determine the cache index, and make a KSEG0
137 * address out of them.
138 */
139 va = MIPS_PHYS_TO_KSEG0(orig_va & mci->mci_picache_way_mask);
140
141 eva = round_line(va + size);
142 va = trunc_line(va);
143
144 while (va < eva) {
145 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
146 va++;
147 cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV);
148 va += 63;
149 }
150 }
151
152 #undef round_line
153 #undef trunc_line
154
155 #define round_line(x) (((x) + 32 - 1) & ~(32 - 1))
156 #define trunc_line(x) ((x) & ~(32 - 1))
157
158 void
r10k_pdcache_wbinv_all(void)159 r10k_pdcache_wbinv_all(void)
160 {
161 const struct mips_cache_info * const mci = &mips_cache_info;
162 vaddr_t va = MIPS_PHYS_TO_KSEG0(0);
163 vaddr_t eva = va + mci->mci_pdcache_way_size;
164
165 while (va < eva) {
166 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
167 va++;
168 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
169 va += 31;
170 }
171 }
172
173 void
r10k_pdcache_wbinv_range(register_t va,vsize_t size)174 r10k_pdcache_wbinv_range(register_t va, vsize_t size)
175 {
176 vaddr_t eva = round_line(va + size);
177
178 va = trunc_line(va);
179
180 while (va < eva) {
181 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
182 va += 32;
183 }
184 }
185
186 void
r10k_pdcache_wbinv_range_index(vaddr_t va,vsize_t size)187 r10k_pdcache_wbinv_range_index(vaddr_t va, vsize_t size)
188 {
189 const struct mips_cache_info * const mci = &mips_cache_info;
190 vaddr_t eva;
191
192 /*
193 * Since we're doing Index ops, we expect to not be able
194 * to access the address we've been given. So, get the
195 * bits that determine the cache index, and make a KSEG0
196 * address out of them.
197 */
198 va = MIPS_PHYS_TO_KSEG0(va & mci->mci_pdcache_way_mask);
199
200 eva = round_line(va + size);
201 va = trunc_line(va);
202
203 while (va < eva) {
204 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
205 va++;
206 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV);
207 va += 31;
208 }
209 }
210
211 void
r10k_pdcache_inv_range(register_t va,vsize_t size)212 r10k_pdcache_inv_range(register_t va, vsize_t size)
213 {
214 vaddr_t eva = round_line(va + size);
215
216 va = trunc_line(va);
217
218 while (va < eva) {
219 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
220 va += 32;
221 }
222 }
223
224 void
r10k_pdcache_wb_range(register_t va,vsize_t size)225 r10k_pdcache_wb_range(register_t va, vsize_t size)
226 {
227 vaddr_t eva = round_line(va + size);
228
229 va = trunc_line(va);
230
231 while (va < eva) {
232 /* R10000 does not support HitWriteBack operation */
233 cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
234 va += 32;
235 }
236 }
237
238 #undef round_line
239 #undef trunc_line
240
241 #define round_line(x) (((x) + mci->mci_sdcache_line_size - 1) & ~(mci->mci_sdcache_line_size - 1))
242 #define trunc_line(x) ((x) & ~(mci->mci_sdcache_line_size - 1))
243
244 void
r10k_sdcache_wbinv_all(void)245 r10k_sdcache_wbinv_all(void)
246 {
247 const struct mips_cache_info * const mci = &mips_cache_info;
248 vaddr_t va = MIPS_PHYS_TO_KSEG0(0);
249 vaddr_t eva = va + mci->mci_sdcache_way_size;
250 vsize_t line_size = mci->mci_sdcache_line_size;
251
252 while (va < eva) {
253 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV);
254 va++;
255 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV);
256 va += line_size - 1;
257 }
258 }
259
260 void
r10k_sdcache_wbinv_range(register_t va,vsize_t size)261 r10k_sdcache_wbinv_range(register_t va, vsize_t size)
262 {
263 const struct mips_cache_info * const mci = &mips_cache_info;
264 vaddr_t eva = round_line(va + size);
265 vsize_t line_size = mci->mci_sdcache_line_size;
266
267 va = trunc_line(va);
268
269 while (va < eva) {
270 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV);
271 va += line_size;
272 }
273 }
274
275 void
r10k_sdcache_wbinv_range_index(vaddr_t va,vsize_t size)276 r10k_sdcache_wbinv_range_index(vaddr_t va, vsize_t size)
277 {
278 const struct mips_cache_info * const mci = &mips_cache_info;
279 vaddr_t eva;
280 vsize_t line_size = mci->mci_sdcache_line_size;
281
282 /*
283 * Since we're doing Index ops, we expect to not be able
284 * to access the address we've been given. So, get the
285 * bits that determine the cache index, and make a KSEG0
286 * address out of them.
287 */
288 va = MIPS_PHYS_TO_KSEG0(va & mci->mci_sdcache_way_mask);
289
290 eva = round_line(va + size);
291 va = trunc_line(va);
292
293 while (va < eva) {
294 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV);
295 va++;
296 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV);
297 va += line_size - 1;
298 }
299 }
300
301 void
r10k_sdcache_inv_range(register_t va,vsize_t size)302 r10k_sdcache_inv_range(register_t va, vsize_t size)
303 {
304 const struct mips_cache_info * const mci = &mips_cache_info;
305 vaddr_t eva = round_line(va + size);
306 vsize_t line_size = mci->mci_sdcache_line_size;
307
308 va = trunc_line(va);
309
310 while (va < eva) {
311 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV);
312 va += line_size;
313 }
314 }
315
316 void
r10k_sdcache_wb_range(register_t va,vsize_t size)317 r10k_sdcache_wb_range(register_t va, vsize_t size)
318 {
319 const struct mips_cache_info * const mci = &mips_cache_info;
320 vaddr_t eva = round_line(va + size);
321 vsize_t line_size = mci->mci_sdcache_line_size;
322
323 va = trunc_line(va);
324
325 while (va < eva) {
326 /* R10000 does not support HitWriteBack operation */
327 cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV);
328 va += line_size;
329 }
330 }
331
332 #undef round_line
333 #undef trunc_line
334