1 /*        $NetBSD: cache_ls2.c,v 1.5 2016/07/11 16:15:36 matt Exp $   */
2 
3 /*-
4  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Matt Thomas <matt@3am-software.com>.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: cache_ls2.c,v 1.5 2016/07/11 16:15:36 matt Exp $");
34 
35 #include <sys/param.h>
36 
37 #include <mips/cache.h>
38 #include <mips/cache_ls2.h>
39 #include <mips/locore.h>
40 
41 /*
42  * Cache operations for Loongson2-style caches:
43  *
44  *        - 4-way set-associative 32b/l
45  *        - Write-back
46  *        - Primary is virtually indexed, physically tagged
47  *        - Seconadry is physically indexed, physically tagged
48  */
49 
50 #define   round_line(x)                 (((x) + 31) & ~31)
51 #define   trunc_line(x)                 ((x) & ~31)
52 
53 __asm(".set mips3");
54 
55 void
ls2_icache_sync_range(register_t va,vsize_t size)56 ls2_icache_sync_range(register_t va, vsize_t size)
57 {
58           struct mips_cache_info * const mci = &mips_cache_info;
59           const vaddr_t eva = round_line(va + size);
60 
61           va = trunc_line(va);
62 
63           if (va + mci->mci_picache_size <= eva) {
64                     ls2_icache_sync_all();
65                     return;
66           }
67 
68           for (; va + 8 * 32 <= eva; va += 8 * 32) {
69                     cache_op_ls2_8line(va, CACHEOP_LS2_D_HIT_WB_INV);
70                     cache_op_ls2_8line(va, CACHEOP_LS2_I_INDEX_INV);
71           }
72 
73           for (; va < eva; va += 32) {
74                     cache_op_ls2_line(va, CACHEOP_LS2_D_HIT_WB_INV);
75                     cache_op_ls2_line(va, CACHEOP_LS2_I_INDEX_INV);
76           }
77 
78           __asm volatile("sync");
79 }
80 
81 void
ls2_icache_sync_range_index(vaddr_t va,vsize_t size)82 ls2_icache_sync_range_index(vaddr_t va, vsize_t size)
83 {
84           vaddr_t eva;
85           struct mips_cache_info * const mci = &mips_cache_info;
86 
87           /*
88            * Since we're doing Index ops, we expect to not be able
89            * to access the address we've been given.  So, get the
90            * bits that determine the cache index, and make a KSEG0
91            * address out of them.
92            */
93 
94           va = MIPS_PHYS_TO_KSEG0(va & mci->mci_picache_way_mask);
95           eva = round_line(va + size);
96           va = trunc_line(va);
97 
98           if (va + mci->mci_picache_way_size < eva) {
99                     va = MIPS_PHYS_TO_KSEG0(0);
100                     eva = mci->mci_picache_way_size;
101           }
102 
103           for (; va + 8 * 32 <= eva; va += 8 * 32) {
104                     cache_op_ls2_8line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV);
105                     cache_op_ls2_8line(va, CACHEOP_LS2_I_INDEX_INV);
106           }
107 
108           for (; va < eva; va += 32) {
109                     cache_op_ls2_line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV);
110                     cache_op_ls2_line(va, CACHEOP_LS2_I_INDEX_INV);
111           }
112 
113           __asm volatile("sync");
114 }
115 
116 void
ls2_icache_sync_all(void)117 ls2_icache_sync_all(void)
118 {
119           struct mips_cache_info * const mci = &mips_cache_info;
120           ls2_icache_sync_range_index(0, mci->mci_picache_way_size);
121 }
122 
123 void
ls2_pdcache_inv_range(register_t va,vsize_t size)124 ls2_pdcache_inv_range(register_t va, vsize_t size)
125 {
126           const vaddr_t eva = round_line(va + size);
127 
128           va = trunc_line(va);
129 
130           for (; va + 8 * 32 <= eva; va += 8 * 32) {
131                     cache_op_ls2_8line(va, CACHEOP_LS2_D_HIT_INV);
132           }
133 
134           for (; va < eva; va += 32) {
135                     cache_op_ls2_line(va, CACHEOP_LS2_D_HIT_INV);
136           }
137 
138           __asm volatile("sync");
139 }
140 
141 void
ls2_pdcache_wbinv_range(register_t va,vsize_t size)142 ls2_pdcache_wbinv_range(register_t va, vsize_t size)
143 {
144           const vaddr_t eva = round_line(va + size);
145 
146           va = trunc_line(va);
147 
148           for (; va + 8 * 32 <= eva; va += 8 * 32) {
149                     cache_op_ls2_8line(va, CACHEOP_LS2_D_HIT_WB_INV);
150           }
151 
152           for (; va < eva; va += 32) {
153                     cache_op_ls2_line(va, CACHEOP_LS2_D_HIT_WB_INV);
154           }
155 
156           __asm volatile("sync");
157 }
158 
159 void
ls2_pdcache_wb_range(register_t va,vsize_t size)160 ls2_pdcache_wb_range(register_t va, vsize_t size)
161 {
162           /*
163            * Alas, can't writeback without invalidating...
164            */
165           ls2_pdcache_wbinv_range(va, size);
166 }
167 
168 void
ls2_pdcache_wbinv_range_index(vaddr_t va,vsize_t size)169 ls2_pdcache_wbinv_range_index(vaddr_t va, vsize_t size)
170 {
171           vaddr_t eva;
172           struct mips_cache_info * const mci = &mips_cache_info;
173 
174           /*
175            * Since we're doing Index ops, we expect to not be able
176            * to access the address we've been given.  So, get the
177            * bits that determine the cache index, and make a KSEG0
178            * address out of them.
179            */
180           va = MIPS_PHYS_TO_KSEG0(va & mci->mci_pdcache_way_mask);
181 
182           eva = round_line(va + size);
183           va = trunc_line(va);
184 
185           if (va + mci->mci_pdcache_way_size > eva) {
186                     va = MIPS_PHYS_TO_KSEG0(0);
187                     eva = mci->mci_pdcache_way_size;
188           }
189 
190           for (; va + 8 * 32 <= eva; va += 8 * 32) {
191                     cache_op_ls2_8line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV);
192           }
193 
194           for (; va < eva; va += 32) {
195                     cache_op_ls2_line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV);
196           }
197 
198           __asm volatile("sync");
199 }
200 
201 void
ls2_pdcache_wbinv_all(void)202 ls2_pdcache_wbinv_all(void)
203 {
204           struct mips_cache_info * const mci = &mips_cache_info;
205           ls2_pdcache_wbinv_range_index(0, mci->mci_pdcache_way_size);
206 }
207 
208 /*
209  * Cache operations for secondary caches:
210  *
211  *        - Direct-mapped
212  *        - Write-back
213  *        - Physically indexed, physically tagged
214  *
215  */
216 
217 void
ls2_sdcache_inv_range(register_t va,vsize_t size)218 ls2_sdcache_inv_range(register_t va, vsize_t size)
219 {
220           const vaddr_t eva = round_line(va + size);
221 
222           va = trunc_line(va);
223 
224           for (; va + 8 * 32 <= eva; va += 8 * 32) {
225                     cache_op_ls2_8line(va, CACHEOP_LS2_D_HIT_INV);
226                     cache_op_ls2_8line(va, CACHEOP_LS2_S_HIT_INV);
227           }
228 
229           for (; va < eva; va += 32) {
230                     cache_op_ls2_line(va, CACHEOP_LS2_D_HIT_INV);
231                     cache_op_ls2_line(va, CACHEOP_LS2_S_HIT_INV);
232           }
233 
234           __asm volatile("sync");
235 }
236 
237 void
ls2_sdcache_wbinv_range(register_t va,vsize_t size)238 ls2_sdcache_wbinv_range(register_t va, vsize_t size)
239 {
240           const vaddr_t eva = round_line(va + size);
241 
242           va = trunc_line(va);
243 
244           for (; va + 8 * 32 <= eva; va += 8 * 32) {
245                     cache_op_ls2_8line(va, CACHEOP_LS2_D_HIT_WB_INV);
246                     cache_op_ls2_8line(va, CACHEOP_LS2_S_HIT_WB_INV);
247           }
248 
249           for (; va < eva; va += 32) {
250                     cache_op_ls2_line(va, CACHEOP_LS2_D_HIT_WB_INV);
251                     cache_op_ls2_line(va, CACHEOP_LS2_S_HIT_WB_INV);
252           }
253 
254           __asm volatile("sync");
255 }
256 
257 void
ls2_sdcache_wb_range(register_t va,vsize_t size)258 ls2_sdcache_wb_range(register_t va, vsize_t size)
259 {
260           /*
261            * Alas, can't writeback without invalidating...
262            */
263           ls2_sdcache_wbinv_range(va, size);
264 }
265 
266 void
ls2_sdcache_wbinv_range_index(vaddr_t va,vsize_t size)267 ls2_sdcache_wbinv_range_index(vaddr_t va, vsize_t size)
268 {
269           vaddr_t eva;
270           struct mips_cache_info * const mci = &mips_cache_info;
271 
272           /*
273            * Since we're doing Index ops, we expect to not be able
274            * to access the address we've been given.  So, get the
275            * bits that determine the cache index, and make a KSEG0
276            * address out of them.
277            */
278           va = MIPS_PHYS_TO_KSEG0(va & mci->mci_sdcache_way_mask);
279 
280           eva = round_line(va + size);
281           va = trunc_line(va);
282 
283           if (va + mci->mci_sdcache_way_size > eva) {
284                     va = MIPS_PHYS_TO_KSEG0(0);
285                     eva = va + mci->mci_sdcache_way_size;
286           }
287 
288           for (; va + 8 * 32 <= eva; va += 8 * 32) {
289                     cache_op_ls2_8line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV);
290                     cache_op_ls2_8line_4way(va, CACHEOP_LS2_S_INDEX_WB_INV);
291           }
292 
293           for (; va < eva; va += 32) {
294                     cache_op_ls2_line_4way(va, CACHEOP_LS2_D_INDEX_WB_INV);
295                     cache_op_ls2_line_4way(va, CACHEOP_LS2_S_INDEX_WB_INV);
296           }
297 
298           __asm volatile("sync");
299 }
300 
301 void
ls2_sdcache_wbinv_all(void)302 ls2_sdcache_wbinv_all(void)
303 {
304           struct mips_cache_info * const mci = &mips_cache_info;
305           ls2_sdcache_wbinv_range_index(0, mci->mci_sdcache_way_size);
306 }
307