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