1 /* $NetBSD: cache_octeon.c,v 1.2 2016/07/11 16:15:36 matt Exp $ */
2
3 #include <sys/cdefs.h>
4 __KERNEL_RCSID(0, "$NetBSD: cache_octeon.c,v 1.2 2016/07/11 16:15:36 matt Exp $");
5
6 #include <sys/param.h>
7 #include <sys/systm.h>
8
9 #include <mips/locore.h>
10 #include <mips/cache.h>
11 #include <mips/cache_octeon.h>
12
13 #define SYNC __asm volatile("sync")
14
15 #ifdef OCTEON_ICACHE_DEBUG
16 int octeon_cache_debug;
17 #endif
18
19 static inline void
mips_synci(vaddr_t va)20 mips_synci(vaddr_t va)
21 {
22 __asm __volatile("synci 0(%0)" :: "r"(va));
23 }
24
25 void
octeon_icache_sync_all(void)26 octeon_icache_sync_all(void)
27 {
28 #ifdef OCTEON_ICACHE_DEBUG
29 if (__predict_false(octeon_cache_debug != 0))
30 printf("%s\n", __func__);
31 #endif
32 mips_synci(MIPS_KSEG0_START);
33 // cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_I);
34 SYNC;
35 }
36 void
octeon_icache_sync_range(register_t va,vsize_t size)37 octeon_icache_sync_range(register_t va, vsize_t size)
38 {
39 #ifdef OCTEON_ICACHE_DEBUG
40 if (__predict_false(octeon_cache_debug != 0))
41 printf("%s: va=%#"PRIxREGISTER", size=%#"PRIxVSIZE"\n",
42 __func__, va, size);
43 #endif
44 mips_synci(MIPS_KSEG0_START);
45 // cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_I);
46 SYNC;
47 }
48
49 void
octeon_icache_sync_range_index(vaddr_t va,vsize_t size)50 octeon_icache_sync_range_index(vaddr_t va, vsize_t size)
51 {
52 #ifdef OCTEON_ICACHE_DEBUG
53 if (__predict_false(octeon_cache_debug != 0))
54 printf("%s: va=%#"PRIxVADDR", size=%#"PRIxVSIZE"\n",
55 __func__, va, size);
56 #endif
57 mips_synci(MIPS_KSEG0_START);
58 // cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_I);
59 SYNC;
60 }
61
62 void
octeon_pdcache_inv_all(void)63 octeon_pdcache_inv_all(void)
64 {
65 #ifdef OCTEON_ICACHE_DEBUG
66 if (__predict_false(octeon_cache_debug != 0))
67 printf("%s\n", __func__);
68 #endif
69 cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_D);
70 SYNC;
71 }
72
73 void
octeon_pdcache_inv_range(register_t va,vsize_t size)74 octeon_pdcache_inv_range(register_t va, vsize_t size)
75 {
76 #ifdef OCTEON_ICACHE_DEBUG
77 if (__predict_false(octeon_cache_debug != 0))
78 printf("%s: va=%#"PRIxREGISTER", size=%#"PRIxVSIZE"\n",
79 __func__, va, size);
80 #endif
81 cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_D);
82 SYNC;
83 }
84
85 void
octeon_pdcache_inv_range_index(vaddr_t va,vsize_t size)86 octeon_pdcache_inv_range_index(vaddr_t va, vsize_t size)
87 {
88 #ifdef OCTEON_ICACHE_DEBUG
89 if (__predict_false(octeon_cache_debug != 0))
90 printf("%s: va=%#"PRIxVADDR", size=%#"PRIxVSIZE"\n",
91 __func__, va, size);
92 #endif
93 cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_D);
94 SYNC;
95 }
96
97 /* ---- debug dump */
98
99 #ifdef OCTEON_ICACHE_DEBUG
100
101 #ifndef __BIT
102 /* __BIT(n): nth bit, where __BIT(0) == 0x1. */
103 #define __BIT(__n) \
104 (((__n) >= NBBY * sizeof(uintmax_t)) ? 0 : ((uintmax_t)1 << (__n)))
105
106 /* __BITS(m, n): bits m through n, m < n. */
107 #define __BITS(__m, __n) \
108 ((__BIT(MAX((__m), (__n)) + 1) - 1) ^ (__BIT(MIN((__m), (__n))) - 1))
109 #endif
110
111 /* icache: 16KB, 2ways */
112
113 #define OCTEON_ICACHE_VA_WAY(_va) (((_va) & __BITS(14, 13)) >> 13)
114 #define OCTEON_ICACHE_VA_INDEX(_va) (((_va) & __BITS(12, 7)) >> 7)
115 #define OCTEON_ICACHE_VA_WORD(_va) (((_va) & __BITS( 6, 3)) >> 3)
116
117 #define OCTEON_ICACHE_TAGLO_R(_taglo) (((_taglo) & __BITS(63, 62)) >> 62)
118 #define OCTEON_ICACHE_TAGLO_ASID(_taglo) (((_taglo) & __BITS(59, 52)) >> 52)
119 #define OCTEON_ICACHE_TAGLO_TAG(_taglo) (((_taglo) & __BITS(48, 13)) >> 13)
120 #define OCTEON_ICACHE_TAGLO_INDEX(_taglo) (((_taglo) & __BITS(12, 7)) >> 7)
121 #define OCTEON_ICACHE_TAGLO_G(_taglo) (((_taglo) & __BITS( 1, 1)) >> 1)
122 #define OCTEON_ICACHE_TAGLO_VALID(_taglo) (((_taglo) & __BITS( 0, 0)) >> 0)
123
124 /* dcache: 8KB, 64ways */
125
126 #define OCTEON_DCACHE_VA_WAY(_va) (((_va) & __BITS(12, 7)) >> 7)
127 #define OCTEON_DCACHE_VA_WORD(_va) (((_va) & __BITS( 6, 3)) >> 3)
128
129 #define OCTEON_DCACHE_TAGLO_R(_taglo) (((_taglo) & __BITS(63, 62)) >> 62)
130 #define OCTEON_DCACHE_TAGLO_ASID(_taglo) (((_taglo) & __BITS(59, 52)) >> 52)
131 #define OCTEON_DCACHE_TAGLO_TAG(_taglo) (((_taglo) & __BITS(48, 7)) >> 7)
132 #define OCTEON_DCACHE_TAGLO_G(_taglo) (((_taglo) & __BITS( 1, 1)) >> 1)
133 #define OCTEON_DCACHE_TAGLO_VALID(_taglo) (((_taglo) & __BITS( 0, 0)) >> 0)
134
135 #define OCTEON_DCACHE_TAGHI_PTAG(_taghi) (((_taghi) & __BITS(35, 7)) >> 7)
136 #define OCTEON_DCACHE_TAGHI_VALID(_taghi) (((_taghi) & __BITS( 0, 0)) >> 0)
137
138 void octeon_icache_dump_all(void);
139 void octeon_icache_dump_way(int);
140 void octeon_icache_dump_index(int, int);
141 void octeon_icache_dump_va(register_t);
142 void octeon_dcache_dump_all(void);
143 void octeon_dcache_dump_way(int);
144 void octeon_dcache_dump_index(int, int);
145 void octeon_dcache_dump_va(register_t);
146
147 void
octeon_icache_dump_all(void)148 octeon_icache_dump_all(void)
149 {
150 /* way = (0 .. 3) */
151 const int maxway = 2; /* XXX 2 << (14 - 13 + 1) == 4? */
152 int way;
153
154 for (way = 0; way < maxway; way++)
155 octeon_icache_dump_way(way);
156 }
157
158 void
octeon_icache_dump_way(int way)159 octeon_icache_dump_way(int way)
160 {
161 /* index = (0 .. 127) */
162 const int maxindex = 64; /* XXX 2 << (12 - 7 + 1) == 128? */;
163 int index;
164
165 for (index = 0; index < maxindex; index++)
166 octeon_icache_dump_index(way, index);
167 }
168
169 void
octeon_icache_dump_index(int way,int index)170 octeon_icache_dump_index(int way, int index)
171 {
172 const vaddr_t va = (way << 13) | (index << 7);
173
174 octeon_icache_dump_va(va);
175 }
176
177 void
octeon_icache_dump_va(register_t va)178 octeon_icache_dump_va(register_t va)
179 {
180 uint64_t taglo, datalo, datahi;
181
182 /* icache */
183 __asm __volatile (
184 " .set push \n"
185 " .set noreorder \n"
186 " .set arch=octeon \n"
187 " cache 4, 0(%[va]) \n"
188 " dmfc0 %[taglo], $28, 0 \n"
189 " dmfc0 %[datalo], $28, 1 \n"
190 " dmfc0 %[datahi], $29, 1 \n"
191 " .set pop \n"
192 : [taglo] "=r" (taglo),
193 [datalo] "=r" (datalo),
194 [datahi] "=r" (datahi)
195 : [va] "r" (va));
196
197 printf("%s: va=%08x "
198 "(way=%01x, index=%02x"/* ", word=%01d" */"), "
199 "taglo=%016"PRIx64" "
200 "(R=%01"PRIx64", asid=%02"PRIx64", tag=%09"PRIx64", index=%02"PRIx64", G=%01"PRIx64", valid=%01"PRIx64"), "
201 "datahi=%01"PRIx64", datalo=%016"PRIx64""
202 "\n",
203 __func__,
204 (int)((taglo) & __BITS(48, 7)), /* (int)va */
205 (int)OCTEON_ICACHE_VA_WAY(va),
206 (int)OCTEON_ICACHE_VA_INDEX(va),
207 /* (int)OCTEON_ICACHE_VA_WORD(va), */
208 taglo,
209 OCTEON_ICACHE_TAGLO_R(taglo),
210 OCTEON_ICACHE_TAGLO_ASID(taglo),
211 OCTEON_ICACHE_TAGLO_TAG(taglo),
212 OCTEON_ICACHE_TAGLO_INDEX(taglo),
213 OCTEON_ICACHE_TAGLO_G(taglo),
214 OCTEON_ICACHE_TAGLO_VALID(taglo),
215 datahi, datalo);
216 }
217
218 void
octeon_dcache_dump_all(void)219 octeon_dcache_dump_all(void)
220 {
221 /* way = (0 .. 63) */
222 const int maxway = 64;
223 int way;
224
225 for (way = 0; way < maxway; way++)
226 octeon_dcache_dump_way(way);
227 }
228
229 void
octeon_dcache_dump_way(int way)230 octeon_dcache_dump_way(int way)
231 {
232 /* index = (0 .. 0) */
233 const int maxindex = 1;
234 int index;
235
236 for (index = 0; index < maxindex; index++)
237 octeon_dcache_dump_index(way, index);
238 }
239
240 void
octeon_dcache_dump_index(int way,int index)241 octeon_dcache_dump_index(int way, int index)
242 {
243 const vaddr_t va = (way << 7); /* no index in dcache */
244
245 octeon_dcache_dump_va(va);
246 }
247
248 void
octeon_dcache_dump_va(register_t va)249 octeon_dcache_dump_va(register_t va)
250 {
251 uint64_t taglo, taghi, datalo, datahi;
252
253 /* dcache */
254 __asm __volatile (
255 " .set push \n"
256 " .set noreorder \n"
257 " .set arch=octeon \n"
258 " cache 5, 0(%[va]) \n"
259 " dmfc0 %[taglo], $28, 2 \n"
260 " dmfc0 %[taghi], $29, 2 \n"
261 " dmfc0 %[datalo], $28, 3 \n"
262 " dmfc0 %[datahi], $29, 3 \n"
263 " .set pop \n"
264 : [taglo] "=r" (taglo),
265 [taghi] "=r" (taghi),
266 [datalo] "=r" (datalo),
267 [datahi] "=r" (datahi)
268 : [va] "r" (va));
269
270 printf("%s: va=%08x "
271 "(way=%02x"/* ", word=%01d" */"), "
272 "taglo=%016"PRIx64" "
273 "(R=%01"PRIx64", asid=%02"PRIx64", tag=%09"PRIx64", G=%01"PRIx64", valid=%01"PRIx64"), "
274 "taghi=%016"PRIx64" "
275 "(ptag=%08"PRIx64", valid=%01"PRIx64"), "
276 "datahi=%02"PRIx64", datalo=%016"PRIx64""
277 "\n",
278 __func__,
279 (int)((taglo) & __BITS(48, 13)), /* (int)va */
280 (int)OCTEON_DCACHE_VA_WAY(va),
281 /* (int)OCTEON_DCACHE_VA_WORD(va), */
282 taglo,
283 OCTEON_DCACHE_TAGLO_R(taglo),
284 OCTEON_DCACHE_TAGLO_ASID(taglo),
285 OCTEON_DCACHE_TAGLO_TAG(taglo),
286 OCTEON_DCACHE_TAGLO_G(taglo),
287 OCTEON_DCACHE_TAGLO_VALID(taglo),
288 taghi,
289 OCTEON_DCACHE_TAGHI_PTAG(taghi),
290 OCTEON_DCACHE_TAGHI_VALID(taghi),
291 datahi, datalo);
292 }
293
294 #endif /* OCTEON_ICACHE_DEBUG */
295