2 * Cache control for MicroBlaze cache memories
4 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2007-2009 John Williams <john.williams@petalogix.com>
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of this
10 * archive for more details.
13 #include <asm/cacheflush.h>
14 #include <linux/cache.h>
15 #include <asm/cpuinfo.h>
18 static inline void __invalidate_flush_icache(unsigned int addr)
20 __asm__ __volatile__ ("wic %0, r0;" \
24 static inline void __flush_dcache(unsigned int addr)
26 __asm__ __volatile__ ("wdc.flush %0, r0;" \
30 static inline void __invalidate_dcache(unsigned int baseaddr,
33 __asm__ __volatile__ ("wdc.clear %0, %1;" \
34 : : "r" (baseaddr), "r" (offset));
37 static inline void __enable_icache_msr(void)
39 __asm__ __volatile__ (" msrset r0, %0; \
41 : : "i" (MSR_ICE) : "memory");
44 static inline void __disable_icache_msr(void)
46 __asm__ __volatile__ (" msrclr r0, %0; \
48 : : "i" (MSR_ICE) : "memory");
51 static inline void __enable_dcache_msr(void)
53 __asm__ __volatile__ (" msrset r0, %0; \
60 static inline void __disable_dcache_msr(void)
62 __asm__ __volatile__ (" msrclr r0, %0; \
69 static inline void __enable_icache_nomsr(void)
71 __asm__ __volatile__ (" mfs r12, rmsr; \
81 static inline void __disable_icache_nomsr(void)
83 __asm__ __volatile__ (" mfs r12, rmsr; \
93 static inline void __enable_dcache_nomsr(void)
95 __asm__ __volatile__ (" mfs r12, rmsr; \
105 static inline void __disable_dcache_nomsr(void)
107 __asm__ __volatile__ (" mfs r12, rmsr; \
109 andi r12, r12, ~%0; \
118 /* Helper macro for computing the limits of cache range loops */
119 #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size) \
121 int align = ~(cache_line_length - 1); \
122 end = min(start + cache_size, end); \
124 end = ((end & align) + cache_line_length); \
128 * Helper macro to loop over the specified cache_size/line_length and
129 * execute 'op' on that cacheline
131 #define CACHE_ALL_LOOP(cache_size, line_length, op) \
133 unsigned int len = cache_size; \
134 int step = -line_length; \
137 __asm__ __volatile__ (" 1: " #op " %0, r0; \
140 " : : "r" (len), "r" (step) \
145 #define CACHE_ALL_LOOP2(cache_size, line_length, op) \
147 unsigned int len = cache_size; \
148 int step = -line_length; \
151 __asm__ __volatile__ (" 1: " #op " r0, %0; \
154 " : : "r" (len), "r" (step) \
158 /* for wdc.flush/clear */
159 #define CACHE_RANGE_LOOP_2(start, end, line_length, op) \
161 int step = -line_length; \
162 int count = end - start; \
163 BUG_ON(count <= 0); \
165 __asm__ __volatile__ (" 1: " #op " %0, %1; \
168 " : : "r" (start), "r" (count), \
169 "r" (step) : "memory"); \
172 /* It is used only first parameter for OP - for wic, wdc */
173 #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \
176 BUG_ON(end - start <= 0); \
178 __asm__ __volatile__ (" 1: " #op " %1, r0; \
182 " : : "r" (temp), "r" (start), "r" (end),\
183 "r" (line_length) : "memory"); \
186 static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
190 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
191 (unsigned int)start, (unsigned int) end);
193 CACHE_LOOP_LIMITS(start, end,
194 cpuinfo.icache_line_length, cpuinfo.icache_size);
196 local_irq_save(flags);
197 __disable_icache_msr();
199 CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
201 __enable_icache_msr();
202 local_irq_restore(flags);
205 static void __flush_icache_range_nomsr_irq(unsigned long start,
210 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
211 (unsigned int)start, (unsigned int) end);
213 CACHE_LOOP_LIMITS(start, end,
214 cpuinfo.icache_line_length, cpuinfo.icache_size);
216 local_irq_save(flags);
217 __disable_icache_nomsr();
219 CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
221 __enable_icache_nomsr();
222 local_irq_restore(flags);
225 static void __flush_icache_range_noirq(unsigned long start,
228 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
229 (unsigned int)start, (unsigned int) end);
231 CACHE_LOOP_LIMITS(start, end,
232 cpuinfo.icache_line_length, cpuinfo.icache_size);
233 CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
236 static void __flush_icache_all_msr_irq(void)
240 pr_debug("%s\n", __func__);
242 local_irq_save(flags);
243 __disable_icache_msr();
245 CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
247 __enable_icache_msr();
248 local_irq_restore(flags);
251 static void __flush_icache_all_nomsr_irq(void)
255 pr_debug("%s\n", __func__);
257 local_irq_save(flags);
258 __disable_icache_nomsr();
260 CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
262 __enable_icache_nomsr();
263 local_irq_restore(flags);
266 static void __flush_icache_all_noirq(void)
268 pr_debug("%s\n", __func__);
269 CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
272 static void __invalidate_dcache_all_msr_irq(void)
276 pr_debug("%s\n", __func__);
278 local_irq_save(flags);
279 __disable_dcache_msr();
281 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
283 __enable_dcache_msr();
284 local_irq_restore(flags);
287 static void __invalidate_dcache_all_nomsr_irq(void)
291 pr_debug("%s\n", __func__);
293 local_irq_save(flags);
294 __disable_dcache_nomsr();
296 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
298 __enable_dcache_nomsr();
299 local_irq_restore(flags);
302 static void __invalidate_dcache_all_noirq_wt(void)
304 pr_debug("%s\n", __func__);
305 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc)
308 /* FIXME this is weird - should be only wdc but not work
309 * MS: I am getting bus errors and other weird things */
310 static void __invalidate_dcache_all_wb(void)
312 pr_debug("%s\n", __func__);
313 CACHE_ALL_LOOP2(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
317 static void __invalidate_dcache_range_wb(unsigned long start,
320 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
321 (unsigned int)start, (unsigned int) end);
323 CACHE_LOOP_LIMITS(start, end,
324 cpuinfo.dcache_line_length, cpuinfo.dcache_size);
325 CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear);
328 static void __invalidate_dcache_range_nomsr_wt(unsigned long start,
331 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
332 (unsigned int)start, (unsigned int) end);
333 CACHE_LOOP_LIMITS(start, end,
334 cpuinfo.dcache_line_length, cpuinfo.dcache_size);
336 CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
339 static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
344 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
345 (unsigned int)start, (unsigned int) end);
346 CACHE_LOOP_LIMITS(start, end,
347 cpuinfo.dcache_line_length, cpuinfo.dcache_size);
349 local_irq_save(flags);
350 __disable_dcache_msr();
352 CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
354 __enable_dcache_msr();
355 local_irq_restore(flags);
358 static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
363 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
364 (unsigned int)start, (unsigned int) end);
366 CACHE_LOOP_LIMITS(start, end,
367 cpuinfo.dcache_line_length, cpuinfo.dcache_size);
369 local_irq_save(flags);
370 __disable_dcache_nomsr();
372 CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
374 __enable_dcache_nomsr();
375 local_irq_restore(flags);
378 static void __flush_dcache_all_wb(void)
380 pr_debug("%s\n", __func__);
381 CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
385 static void __flush_dcache_range_wb(unsigned long start, unsigned long end)
387 pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
388 (unsigned int)start, (unsigned int) end);
390 CACHE_LOOP_LIMITS(start, end,
391 cpuinfo.dcache_line_length, cpuinfo.dcache_size);
392 CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush);
395 /* struct for wb caches and for wt caches */
398 /* new wb cache model */
399 const struct scache wb_msr = {
400 .ie = __enable_icache_msr,
401 .id = __disable_icache_msr,
402 .ifl = __flush_icache_all_noirq,
403 .iflr = __flush_icache_range_noirq,
404 .iin = __flush_icache_all_noirq,
405 .iinr = __flush_icache_range_noirq,
406 .de = __enable_dcache_msr,
407 .dd = __disable_dcache_msr,
408 .dfl = __flush_dcache_all_wb,
409 .dflr = __flush_dcache_range_wb,
410 .din = __invalidate_dcache_all_wb,
411 .dinr = __invalidate_dcache_range_wb,
414 /* There is only difference in ie, id, de, dd functions */
415 const struct scache wb_nomsr = {
416 .ie = __enable_icache_nomsr,
417 .id = __disable_icache_nomsr,
418 .ifl = __flush_icache_all_noirq,
419 .iflr = __flush_icache_range_noirq,
420 .iin = __flush_icache_all_noirq,
421 .iinr = __flush_icache_range_noirq,
422 .de = __enable_dcache_nomsr,
423 .dd = __disable_dcache_nomsr,
424 .dfl = __flush_dcache_all_wb,
425 .dflr = __flush_dcache_range_wb,
426 .din = __invalidate_dcache_all_wb,
427 .dinr = __invalidate_dcache_range_wb,
430 /* Old wt cache model with disabling irq and turn off cache */
431 const struct scache wt_msr = {
432 .ie = __enable_icache_msr,
433 .id = __disable_icache_msr,
434 .ifl = __flush_icache_all_msr_irq,
435 .iflr = __flush_icache_range_msr_irq,
436 .iin = __flush_icache_all_msr_irq,
437 .iinr = __flush_icache_range_msr_irq,
438 .de = __enable_dcache_msr,
439 .dd = __disable_dcache_msr,
440 .dfl = __invalidate_dcache_all_msr_irq,
441 .dflr = __invalidate_dcache_range_msr_irq_wt,
442 .din = __invalidate_dcache_all_msr_irq,
443 .dinr = __invalidate_dcache_range_msr_irq_wt,
446 const struct scache wt_nomsr = {
447 .ie = __enable_icache_nomsr,
448 .id = __disable_icache_nomsr,
449 .ifl = __flush_icache_all_nomsr_irq,
450 .iflr = __flush_icache_range_nomsr_irq,
451 .iin = __flush_icache_all_nomsr_irq,
452 .iinr = __flush_icache_range_nomsr_irq,
453 .de = __enable_dcache_nomsr,
454 .dd = __disable_dcache_nomsr,
455 .dfl = __invalidate_dcache_all_nomsr_irq,
456 .dflr = __invalidate_dcache_range_nomsr_irq,
457 .din = __invalidate_dcache_all_nomsr_irq,
458 .dinr = __invalidate_dcache_range_nomsr_irq,
461 /* New wt cache model for newer Microblaze versions */
462 const struct scache wt_msr_noirq = {
463 .ie = __enable_icache_msr,
464 .id = __disable_icache_msr,
465 .ifl = __flush_icache_all_noirq,
466 .iflr = __flush_icache_range_noirq,
467 .iin = __flush_icache_all_noirq,
468 .iinr = __flush_icache_range_noirq,
469 .de = __enable_dcache_msr,
470 .dd = __disable_dcache_msr,
471 .dfl = __invalidate_dcache_all_noirq_wt,
472 .dflr = __invalidate_dcache_range_nomsr_wt,
473 .din = __invalidate_dcache_all_noirq_wt,
474 .dinr = __invalidate_dcache_range_nomsr_wt,
477 const struct scache wt_nomsr_noirq = {
478 .ie = __enable_icache_nomsr,
479 .id = __disable_icache_nomsr,
480 .ifl = __flush_icache_all_noirq,
481 .iflr = __flush_icache_range_noirq,
482 .iin = __flush_icache_all_noirq,
483 .iinr = __flush_icache_range_noirq,
484 .de = __enable_dcache_nomsr,
485 .dd = __disable_dcache_nomsr,
486 .dfl = __invalidate_dcache_all_noirq_wt,
487 .dflr = __invalidate_dcache_range_nomsr_wt,
488 .din = __invalidate_dcache_all_noirq_wt,
489 .dinr = __invalidate_dcache_range_nomsr_wt,
492 /* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */
493 #define CPUVER_7_20_A 0x0c
494 #define CPUVER_7_20_D 0x0f
496 #define INFO(s) printk(KERN_INFO "cache: " s " \n");
498 void microblaze_cache_init(void)
500 if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) {
501 if (cpuinfo.dcache_wb) {
503 mbc = (struct scache *)&wb_msr;
504 if (cpuinfo.ver_code < CPUVER_7_20_D) {
505 /* MS: problem with signal handling - hw bug */
506 INFO("WB won't work properly");
509 if (cpuinfo.ver_code >= CPUVER_7_20_A) {
510 INFO("wt_msr_noirq");
511 mbc = (struct scache *)&wt_msr_noirq;
514 mbc = (struct scache *)&wt_msr;
518 if (cpuinfo.dcache_wb) {
520 mbc = (struct scache *)&wb_nomsr;
521 if (cpuinfo.ver_code < CPUVER_7_20_D) {
522 /* MS: problem with signal handling - hw bug */
523 INFO("WB won't work properly");
526 if (cpuinfo.ver_code >= CPUVER_7_20_A) {
527 INFO("wt_nomsr_noirq");
528 mbc = (struct scache *)&wt_nomsr_noirq;
531 mbc = (struct scache *)&wt_nomsr;