xref: /openbmc/linux/arch/mips/include/asm/r4kcache.h (revision 31b90347)
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Inline assembly cache operations.
7  *
8  * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
9  * Copyright (C) 1997 - 2002 Ralf Baechle (ralf@gnu.org)
10  * Copyright (C) 2004 Ralf Baechle (ralf@linux-mips.org)
11  */
12 #ifndef _ASM_R4KCACHE_H
13 #define _ASM_R4KCACHE_H
14 
15 #include <asm/asm.h>
16 #include <asm/cacheops.h>
17 #include <asm/cpu-features.h>
18 #include <asm/cpu-type.h>
19 #include <asm/mipsmtregs.h>
20 
21 /*
22  * This macro return a properly sign-extended address suitable as base address
23  * for indexed cache operations.  Two issues here:
24  *
25  *  - The MIPS32 and MIPS64 specs permit an implementation to directly derive
26  *    the index bits from the virtual address.	This breaks with tradition
27  *    set by the R4000.	 To keep unpleasant surprises from happening we pick
28  *    an address in KSEG0 / CKSEG0.
29  *  - We need a properly sign extended address for 64-bit code.	 To get away
30  *    without ifdefs we let the compiler do it by a type cast.
31  */
32 #define INDEX_BASE	CKSEG0
33 
34 #define cache_op(op,addr)						\
35 	__asm__ __volatile__(						\
36 	"	.set	push					\n"	\
37 	"	.set	noreorder				\n"	\
38 	"	.set	mips3\n\t				\n"	\
39 	"	cache	%0, %1					\n"	\
40 	"	.set	pop					\n"	\
41 	:								\
42 	: "i" (op), "R" (*(unsigned char *)(addr)))
43 
44 #ifdef CONFIG_MIPS_MT
45 /*
46  * Temporary hacks for SMTC debug. Optionally force single-threaded
47  * execution during I-cache flushes.
48  */
49 
50 #define PROTECT_CACHE_FLUSHES 1
51 
52 #ifdef PROTECT_CACHE_FLUSHES
53 
54 extern int mt_protiflush;
55 extern int mt_protdflush;
56 extern void mt_cflush_lockdown(void);
57 extern void mt_cflush_release(void);
58 
59 #define BEGIN_MT_IPROT \
60 	unsigned long flags = 0;			\
61 	unsigned long mtflags = 0;			\
62 	if(mt_protiflush) {				\
63 		local_irq_save(flags);			\
64 		ehb();					\
65 		mtflags = dvpe();			\
66 		mt_cflush_lockdown();			\
67 	}
68 
69 #define END_MT_IPROT \
70 	if(mt_protiflush) {				\
71 		mt_cflush_release();			\
72 		evpe(mtflags);				\
73 		local_irq_restore(flags);		\
74 	}
75 
76 #define BEGIN_MT_DPROT \
77 	unsigned long flags = 0;			\
78 	unsigned long mtflags = 0;			\
79 	if(mt_protdflush) {				\
80 		local_irq_save(flags);			\
81 		ehb();					\
82 		mtflags = dvpe();			\
83 		mt_cflush_lockdown();			\
84 	}
85 
86 #define END_MT_DPROT \
87 	if(mt_protdflush) {				\
88 		mt_cflush_release();			\
89 		evpe(mtflags);				\
90 		local_irq_restore(flags);		\
91 	}
92 
93 #else
94 
95 #define BEGIN_MT_IPROT
96 #define BEGIN_MT_DPROT
97 #define END_MT_IPROT
98 #define END_MT_DPROT
99 
100 #endif /* PROTECT_CACHE_FLUSHES */
101 
102 #define __iflush_prologue						\
103 	unsigned long redundance;					\
104 	extern int mt_n_iflushes;					\
105 	BEGIN_MT_IPROT							\
106 	for (redundance = 0; redundance < mt_n_iflushes; redundance++) {
107 
108 #define __iflush_epilogue						\
109 	END_MT_IPROT							\
110 	}
111 
112 #define __dflush_prologue						\
113 	unsigned long redundance;					\
114 	extern int mt_n_dflushes;					\
115 	BEGIN_MT_DPROT							\
116 	for (redundance = 0; redundance < mt_n_dflushes; redundance++) {
117 
118 #define __dflush_epilogue \
119 	END_MT_DPROT	 \
120 	}
121 
122 #define __inv_dflush_prologue __dflush_prologue
123 #define __inv_dflush_epilogue __dflush_epilogue
124 #define __sflush_prologue {
125 #define __sflush_epilogue }
126 #define __inv_sflush_prologue __sflush_prologue
127 #define __inv_sflush_epilogue __sflush_epilogue
128 
129 #else /* CONFIG_MIPS_MT */
130 
131 #define __iflush_prologue {
132 #define __iflush_epilogue }
133 #define __dflush_prologue {
134 #define __dflush_epilogue }
135 #define __inv_dflush_prologue {
136 #define __inv_dflush_epilogue }
137 #define __sflush_prologue {
138 #define __sflush_epilogue }
139 #define __inv_sflush_prologue {
140 #define __inv_sflush_epilogue }
141 
142 #endif /* CONFIG_MIPS_MT */
143 
144 static inline void flush_icache_line_indexed(unsigned long addr)
145 {
146 	__iflush_prologue
147 	cache_op(Index_Invalidate_I, addr);
148 	__iflush_epilogue
149 }
150 
151 static inline void flush_dcache_line_indexed(unsigned long addr)
152 {
153 	__dflush_prologue
154 	cache_op(Index_Writeback_Inv_D, addr);
155 	__dflush_epilogue
156 }
157 
158 static inline void flush_scache_line_indexed(unsigned long addr)
159 {
160 	cache_op(Index_Writeback_Inv_SD, addr);
161 }
162 
163 static inline void flush_icache_line(unsigned long addr)
164 {
165 	__iflush_prologue
166 	switch (boot_cpu_type()) {
167 	case CPU_LOONGSON2:
168 		cache_op(Hit_Invalidate_I_Loongson23, addr);
169 		break;
170 
171 	default:
172 		cache_op(Hit_Invalidate_I, addr);
173 		break;
174 	}
175 	__iflush_epilogue
176 }
177 
178 static inline void flush_dcache_line(unsigned long addr)
179 {
180 	__dflush_prologue
181 	cache_op(Hit_Writeback_Inv_D, addr);
182 	__dflush_epilogue
183 }
184 
185 static inline void invalidate_dcache_line(unsigned long addr)
186 {
187 	__dflush_prologue
188 	cache_op(Hit_Invalidate_D, addr);
189 	__dflush_epilogue
190 }
191 
192 static inline void invalidate_scache_line(unsigned long addr)
193 {
194 	cache_op(Hit_Invalidate_SD, addr);
195 }
196 
197 static inline void flush_scache_line(unsigned long addr)
198 {
199 	cache_op(Hit_Writeback_Inv_SD, addr);
200 }
201 
202 #define protected_cache_op(op,addr)				\
203 	__asm__ __volatile__(					\
204 	"	.set	push			\n"		\
205 	"	.set	noreorder		\n"		\
206 	"	.set	mips3			\n"		\
207 	"1:	cache	%0, (%1)		\n"		\
208 	"2:	.set	pop			\n"		\
209 	"	.section __ex_table,\"a\"	\n"		\
210 	"	"STR(PTR)" 1b, 2b		\n"		\
211 	"	.previous"					\
212 	:							\
213 	: "i" (op), "r" (addr))
214 
215 /*
216  * The next two are for badland addresses like signal trampolines.
217  */
218 static inline void protected_flush_icache_line(unsigned long addr)
219 {
220 	switch (boot_cpu_type()) {
221 	case CPU_LOONGSON2:
222 		protected_cache_op(Hit_Invalidate_I_Loongson23, addr);
223 		break;
224 
225 	default:
226 		protected_cache_op(Hit_Invalidate_I, addr);
227 		break;
228 	}
229 }
230 
231 /*
232  * R10000 / R12000 hazard - these processors don't support the Hit_Writeback_D
233  * cacheop so we use Hit_Writeback_Inv_D which is supported by all R4000-style
234  * caches.  We're talking about one cacheline unnecessarily getting invalidated
235  * here so the penalty isn't overly hard.
236  */
237 static inline void protected_writeback_dcache_line(unsigned long addr)
238 {
239 	protected_cache_op(Hit_Writeback_Inv_D, addr);
240 }
241 
242 static inline void protected_writeback_scache_line(unsigned long addr)
243 {
244 	protected_cache_op(Hit_Writeback_Inv_SD, addr);
245 }
246 
247 /*
248  * This one is RM7000-specific
249  */
250 static inline void invalidate_tcache_page(unsigned long addr)
251 {
252 	cache_op(Page_Invalidate_T, addr);
253 }
254 
255 #define cache16_unroll32(base,op)					\
256 	__asm__ __volatile__(						\
257 	"	.set push					\n"	\
258 	"	.set noreorder					\n"	\
259 	"	.set mips3					\n"	\
260 	"	cache %1, 0x000(%0); cache %1, 0x010(%0)	\n"	\
261 	"	cache %1, 0x020(%0); cache %1, 0x030(%0)	\n"	\
262 	"	cache %1, 0x040(%0); cache %1, 0x050(%0)	\n"	\
263 	"	cache %1, 0x060(%0); cache %1, 0x070(%0)	\n"	\
264 	"	cache %1, 0x080(%0); cache %1, 0x090(%0)	\n"	\
265 	"	cache %1, 0x0a0(%0); cache %1, 0x0b0(%0)	\n"	\
266 	"	cache %1, 0x0c0(%0); cache %1, 0x0d0(%0)	\n"	\
267 	"	cache %1, 0x0e0(%0); cache %1, 0x0f0(%0)	\n"	\
268 	"	cache %1, 0x100(%0); cache %1, 0x110(%0)	\n"	\
269 	"	cache %1, 0x120(%0); cache %1, 0x130(%0)	\n"	\
270 	"	cache %1, 0x140(%0); cache %1, 0x150(%0)	\n"	\
271 	"	cache %1, 0x160(%0); cache %1, 0x170(%0)	\n"	\
272 	"	cache %1, 0x180(%0); cache %1, 0x190(%0)	\n"	\
273 	"	cache %1, 0x1a0(%0); cache %1, 0x1b0(%0)	\n"	\
274 	"	cache %1, 0x1c0(%0); cache %1, 0x1d0(%0)	\n"	\
275 	"	cache %1, 0x1e0(%0); cache %1, 0x1f0(%0)	\n"	\
276 	"	.set pop					\n"	\
277 		:							\
278 		: "r" (base),						\
279 		  "i" (op));
280 
281 #define cache32_unroll32(base,op)					\
282 	__asm__ __volatile__(						\
283 	"	.set push					\n"	\
284 	"	.set noreorder					\n"	\
285 	"	.set mips3					\n"	\
286 	"	cache %1, 0x000(%0); cache %1, 0x020(%0)	\n"	\
287 	"	cache %1, 0x040(%0); cache %1, 0x060(%0)	\n"	\
288 	"	cache %1, 0x080(%0); cache %1, 0x0a0(%0)	\n"	\
289 	"	cache %1, 0x0c0(%0); cache %1, 0x0e0(%0)	\n"	\
290 	"	cache %1, 0x100(%0); cache %1, 0x120(%0)	\n"	\
291 	"	cache %1, 0x140(%0); cache %1, 0x160(%0)	\n"	\
292 	"	cache %1, 0x180(%0); cache %1, 0x1a0(%0)	\n"	\
293 	"	cache %1, 0x1c0(%0); cache %1, 0x1e0(%0)	\n"	\
294 	"	cache %1, 0x200(%0); cache %1, 0x220(%0)	\n"	\
295 	"	cache %1, 0x240(%0); cache %1, 0x260(%0)	\n"	\
296 	"	cache %1, 0x280(%0); cache %1, 0x2a0(%0)	\n"	\
297 	"	cache %1, 0x2c0(%0); cache %1, 0x2e0(%0)	\n"	\
298 	"	cache %1, 0x300(%0); cache %1, 0x320(%0)	\n"	\
299 	"	cache %1, 0x340(%0); cache %1, 0x360(%0)	\n"	\
300 	"	cache %1, 0x380(%0); cache %1, 0x3a0(%0)	\n"	\
301 	"	cache %1, 0x3c0(%0); cache %1, 0x3e0(%0)	\n"	\
302 	"	.set pop					\n"	\
303 		:							\
304 		: "r" (base),						\
305 		  "i" (op));
306 
307 #define cache64_unroll32(base,op)					\
308 	__asm__ __volatile__(						\
309 	"	.set push					\n"	\
310 	"	.set noreorder					\n"	\
311 	"	.set mips3					\n"	\
312 	"	cache %1, 0x000(%0); cache %1, 0x040(%0)	\n"	\
313 	"	cache %1, 0x080(%0); cache %1, 0x0c0(%0)	\n"	\
314 	"	cache %1, 0x100(%0); cache %1, 0x140(%0)	\n"	\
315 	"	cache %1, 0x180(%0); cache %1, 0x1c0(%0)	\n"	\
316 	"	cache %1, 0x200(%0); cache %1, 0x240(%0)	\n"	\
317 	"	cache %1, 0x280(%0); cache %1, 0x2c0(%0)	\n"	\
318 	"	cache %1, 0x300(%0); cache %1, 0x340(%0)	\n"	\
319 	"	cache %1, 0x380(%0); cache %1, 0x3c0(%0)	\n"	\
320 	"	cache %1, 0x400(%0); cache %1, 0x440(%0)	\n"	\
321 	"	cache %1, 0x480(%0); cache %1, 0x4c0(%0)	\n"	\
322 	"	cache %1, 0x500(%0); cache %1, 0x540(%0)	\n"	\
323 	"	cache %1, 0x580(%0); cache %1, 0x5c0(%0)	\n"	\
324 	"	cache %1, 0x600(%0); cache %1, 0x640(%0)	\n"	\
325 	"	cache %1, 0x680(%0); cache %1, 0x6c0(%0)	\n"	\
326 	"	cache %1, 0x700(%0); cache %1, 0x740(%0)	\n"	\
327 	"	cache %1, 0x780(%0); cache %1, 0x7c0(%0)	\n"	\
328 	"	.set pop					\n"	\
329 		:							\
330 		: "r" (base),						\
331 		  "i" (op));
332 
333 #define cache128_unroll32(base,op)					\
334 	__asm__ __volatile__(						\
335 	"	.set push					\n"	\
336 	"	.set noreorder					\n"	\
337 	"	.set mips3					\n"	\
338 	"	cache %1, 0x000(%0); cache %1, 0x080(%0)	\n"	\
339 	"	cache %1, 0x100(%0); cache %1, 0x180(%0)	\n"	\
340 	"	cache %1, 0x200(%0); cache %1, 0x280(%0)	\n"	\
341 	"	cache %1, 0x300(%0); cache %1, 0x380(%0)	\n"	\
342 	"	cache %1, 0x400(%0); cache %1, 0x480(%0)	\n"	\
343 	"	cache %1, 0x500(%0); cache %1, 0x580(%0)	\n"	\
344 	"	cache %1, 0x600(%0); cache %1, 0x680(%0)	\n"	\
345 	"	cache %1, 0x700(%0); cache %1, 0x780(%0)	\n"	\
346 	"	cache %1, 0x800(%0); cache %1, 0x880(%0)	\n"	\
347 	"	cache %1, 0x900(%0); cache %1, 0x980(%0)	\n"	\
348 	"	cache %1, 0xa00(%0); cache %1, 0xa80(%0)	\n"	\
349 	"	cache %1, 0xb00(%0); cache %1, 0xb80(%0)	\n"	\
350 	"	cache %1, 0xc00(%0); cache %1, 0xc80(%0)	\n"	\
351 	"	cache %1, 0xd00(%0); cache %1, 0xd80(%0)	\n"	\
352 	"	cache %1, 0xe00(%0); cache %1, 0xe80(%0)	\n"	\
353 	"	cache %1, 0xf00(%0); cache %1, 0xf80(%0)	\n"	\
354 	"	.set pop					\n"	\
355 		:							\
356 		: "r" (base),						\
357 		  "i" (op));
358 
359 /* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */
360 #define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize) \
361 static inline void blast_##pfx##cache##lsize(void)			\
362 {									\
363 	unsigned long start = INDEX_BASE;				\
364 	unsigned long end = start + current_cpu_data.desc.waysize;	\
365 	unsigned long ws_inc = 1UL << current_cpu_data.desc.waybit;	\
366 	unsigned long ws_end = current_cpu_data.desc.ways <<		\
367 			       current_cpu_data.desc.waybit;		\
368 	unsigned long ws, addr;						\
369 									\
370 	__##pfx##flush_prologue						\
371 									\
372 	for (ws = 0; ws < ws_end; ws += ws_inc)				\
373 		for (addr = start; addr < end; addr += lsize * 32)	\
374 			cache##lsize##_unroll32(addr|ws, indexop);	\
375 									\
376 	__##pfx##flush_epilogue						\
377 }									\
378 									\
379 static inline void blast_##pfx##cache##lsize##_page(unsigned long page) \
380 {									\
381 	unsigned long start = page;					\
382 	unsigned long end = page + PAGE_SIZE;				\
383 									\
384 	__##pfx##flush_prologue						\
385 									\
386 	do {								\
387 		cache##lsize##_unroll32(start, hitop);			\
388 		start += lsize * 32;					\
389 	} while (start < end);						\
390 									\
391 	__##pfx##flush_epilogue						\
392 }									\
393 									\
394 static inline void blast_##pfx##cache##lsize##_page_indexed(unsigned long page) \
395 {									\
396 	unsigned long indexmask = current_cpu_data.desc.waysize - 1;	\
397 	unsigned long start = INDEX_BASE + (page & indexmask);		\
398 	unsigned long end = start + PAGE_SIZE;				\
399 	unsigned long ws_inc = 1UL << current_cpu_data.desc.waybit;	\
400 	unsigned long ws_end = current_cpu_data.desc.ways <<		\
401 			       current_cpu_data.desc.waybit;		\
402 	unsigned long ws, addr;						\
403 									\
404 	__##pfx##flush_prologue						\
405 									\
406 	for (ws = 0; ws < ws_end; ws += ws_inc)				\
407 		for (addr = start; addr < end; addr += lsize * 32)	\
408 			cache##lsize##_unroll32(addr|ws, indexop);	\
409 									\
410 	__##pfx##flush_epilogue						\
411 }
412 
413 __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16)
414 __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
415 __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16)
416 __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32)
417 __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
418 __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32)
419 __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 64)
420 __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
421 __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
422 __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
423 
424 __BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16)
425 __BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32)
426 __BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16)
427 __BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32)
428 __BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64)
429 __BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128)
430 
431 /* build blast_xxx_range, protected_blast_xxx_range */
432 #define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, extra)	\
433 static inline void prot##extra##blast_##pfx##cache##_range(unsigned long start, \
434 						    unsigned long end)	\
435 {									\
436 	unsigned long lsize = cpu_##desc##_line_size();			\
437 	unsigned long addr = start & ~(lsize - 1);			\
438 	unsigned long aend = (end - 1) & ~(lsize - 1);			\
439 									\
440 	__##pfx##flush_prologue						\
441 									\
442 	while (1) {							\
443 		prot##cache_op(hitop, addr);				\
444 		if (addr == aend)					\
445 			break;						\
446 		addr += lsize;						\
447 	}								\
448 									\
449 	__##pfx##flush_epilogue						\
450 }
451 
452 __BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, )
453 __BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_, )
454 __BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_, )
455 __BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I_Loongson23, \
456 	protected_, loongson23_)
457 __BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, , )
458 __BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, , )
459 /* blast_inv_dcache_range */
460 __BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, , )
461 __BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, , )
462 
463 #endif /* _ASM_R4KCACHE_H */
464