1 /*
2  * Cache control for MicroBlaze cache memories
3  *
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>
7  *
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.
11  */
12 
13 #include <asm/cacheflush.h>
14 #include <linux/cache.h>
15 #include <asm/cpuinfo.h>
16 #include <asm/pvr.h>
17 
__enable_icache_msr(void)18 static inline void __enable_icache_msr(void)
19 {
20 	__asm__ __volatile__ ("	msrset	r0, %0;		\
21 				nop; "			\
22 			: : "i" (MSR_ICE) : "memory");
23 }
24 
__disable_icache_msr(void)25 static inline void __disable_icache_msr(void)
26 {
27 	__asm__ __volatile__ ("	msrclr	r0, %0;		\
28 				nop; "			\
29 			: : "i" (MSR_ICE) : "memory");
30 }
31 
__enable_dcache_msr(void)32 static inline void __enable_dcache_msr(void)
33 {
34 	__asm__ __volatile__ ("	msrset	r0, %0;		\
35 				nop; "			\
36 				:			\
37 				: "i" (MSR_DCE)		\
38 				: "memory");
39 }
40 
__disable_dcache_msr(void)41 static inline void __disable_dcache_msr(void)
42 {
43 	__asm__ __volatile__ ("	msrclr	r0, %0;		\
44 				nop; "			\
45 				:			\
46 				: "i" (MSR_DCE)		\
47 				: "memory");
48 }
49 
__enable_icache_nomsr(void)50 static inline void __enable_icache_nomsr(void)
51 {
52 	__asm__ __volatile__ ("	mfs	r12, rmsr;	\
53 				nop;			\
54 				ori	r12, r12, %0;	\
55 				mts	rmsr, r12;	\
56 				nop; "			\
57 				:			\
58 				: "i" (MSR_ICE)		\
59 				: "memory", "r12");
60 }
61 
__disable_icache_nomsr(void)62 static inline void __disable_icache_nomsr(void)
63 {
64 	__asm__ __volatile__ ("	mfs	r12, rmsr;	\
65 				nop;			\
66 				andi	r12, r12, ~%0;	\
67 				mts	rmsr, r12;	\
68 				nop; "			\
69 				:			\
70 				: "i" (MSR_ICE)		\
71 				: "memory", "r12");
72 }
73 
__enable_dcache_nomsr(void)74 static inline void __enable_dcache_nomsr(void)
75 {
76 	__asm__ __volatile__ ("	mfs	r12, rmsr;	\
77 				nop;			\
78 				ori	r12, r12, %0;	\
79 				mts	rmsr, r12;	\
80 				nop; "			\
81 				:			\
82 				: "i" (MSR_DCE)		\
83 				: "memory", "r12");
84 }
85 
__disable_dcache_nomsr(void)86 static inline void __disable_dcache_nomsr(void)
87 {
88 	__asm__ __volatile__ ("	mfs	r12, rmsr;	\
89 				nop;			\
90 				andi	r12, r12, ~%0;	\
91 				mts	rmsr, r12;	\
92 				nop; "			\
93 				:			\
94 				: "i" (MSR_DCE)		\
95 				: "memory", "r12");
96 }
97 
98 
99 /* Helper macro for computing the limits of cache range loops
100  *
101  * End address can be unaligned which is OK for C implementation.
102  * ASM implementation align it in ASM macros
103  */
104 #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size)	\
105 do {									\
106 	int align = ~(cache_line_length - 1);				\
107 	end = min(start + cache_size, end);				\
108 	start &= align;							\
109 } while (0);
110 
111 /*
112  * Helper macro to loop over the specified cache_size/line_length and
113  * execute 'op' on that cacheline
114  */
115 #define CACHE_ALL_LOOP(cache_size, line_length, op)			\
116 do {									\
117 	unsigned int len = cache_size - line_length;			\
118 	int step = -line_length;					\
119 	WARN_ON(step >= 0);						\
120 									\
121 	__asm__ __volatile__ (" 1:      " #op " %0, r0;			\
122 					bgtid   %0, 1b;			\
123 					addk    %0, %0, %1;		\
124 					" : : "r" (len), "r" (step)	\
125 					: "memory");			\
126 } while (0);
127 
128 /* Used for wdc.flush/clear which can use rB for offset which is not possible
129  * to use for simple wdc or wic.
130  *
131  * start address is cache aligned
132  * end address is not aligned, if end is aligned then I have to subtract
133  * cacheline length because I can't flush/invalidate the next cacheline.
134  * If is not, I align it because I will flush/invalidate whole line.
135  */
136 #define CACHE_RANGE_LOOP_2(start, end, line_length, op)			\
137 do {									\
138 	int step = -line_length;					\
139 	int align = ~(line_length - 1);					\
140 	int count;							\
141 	end = ((end & align) == end) ? end - line_length : end & align;	\
142 	count = end - start;						\
143 	WARN_ON(count < 0);						\
144 									\
145 	__asm__ __volatile__ (" 1:	" #op "	%0, %1;			\
146 					bgtid	%1, 1b;			\
147 					addk	%1, %1, %2;		\
148 					" : : "r" (start), "r" (count),	\
149 					"r" (step) : "memory");		\
150 } while (0);
151 
152 /* It is used only first parameter for OP - for wic, wdc */
153 #define CACHE_RANGE_LOOP_1(start, end, line_length, op)			\
154 do {									\
155 	int volatile temp;						\
156 	int align = ~(line_length - 1);					\
157 	end = ((end & align) == end) ? end - line_length : end & align;	\
158 	WARN_ON(end - start < 0);					\
159 									\
160 	__asm__ __volatile__ (" 1:	" #op "	%1, r0;			\
161 					cmpu	%0, %1, %2;		\
162 					bgtid	%0, 1b;			\
163 					addk	%1, %1, %3;		\
164 				" : : "r" (temp), "r" (start), "r" (end),\
165 					"r" (line_length) : "memory");	\
166 } while (0);
167 
168 #define ASM_LOOP
169 
__flush_icache_range_msr_irq(unsigned long start,unsigned long end)170 static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
171 {
172 	unsigned long flags;
173 #ifndef ASM_LOOP
174 	int i;
175 #endif
176 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
177 				(unsigned int)start, (unsigned int) end);
178 
179 	CACHE_LOOP_LIMITS(start, end,
180 			cpuinfo.icache_line_length, cpuinfo.icache_size);
181 
182 	local_irq_save(flags);
183 	__disable_icache_msr();
184 
185 #ifdef ASM_LOOP
186 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
187 #else
188 	for (i = start; i < end; i += cpuinfo.icache_line_length)
189 		__asm__ __volatile__ ("wic	%0, r0;"	\
190 				: : "r" (i));
191 #endif
192 	__enable_icache_msr();
193 	local_irq_restore(flags);
194 }
195 
__flush_icache_range_nomsr_irq(unsigned long start,unsigned long end)196 static void __flush_icache_range_nomsr_irq(unsigned long start,
197 				unsigned long end)
198 {
199 	unsigned long flags;
200 #ifndef ASM_LOOP
201 	int i;
202 #endif
203 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
204 				(unsigned int)start, (unsigned int) end);
205 
206 	CACHE_LOOP_LIMITS(start, end,
207 			cpuinfo.icache_line_length, cpuinfo.icache_size);
208 
209 	local_irq_save(flags);
210 	__disable_icache_nomsr();
211 
212 #ifdef ASM_LOOP
213 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
214 #else
215 	for (i = start; i < end; i += cpuinfo.icache_line_length)
216 		__asm__ __volatile__ ("wic	%0, r0;"	\
217 				: : "r" (i));
218 #endif
219 
220 	__enable_icache_nomsr();
221 	local_irq_restore(flags);
222 }
223 
__flush_icache_range_noirq(unsigned long start,unsigned long end)224 static void __flush_icache_range_noirq(unsigned long start,
225 				unsigned long end)
226 {
227 #ifndef ASM_LOOP
228 	int i;
229 #endif
230 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
231 				(unsigned int)start, (unsigned int) end);
232 
233 	CACHE_LOOP_LIMITS(start, end,
234 			cpuinfo.icache_line_length, cpuinfo.icache_size);
235 #ifdef ASM_LOOP
236 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
237 #else
238 	for (i = start; i < end; i += cpuinfo.icache_line_length)
239 		__asm__ __volatile__ ("wic	%0, r0;"	\
240 				: : "r" (i));
241 #endif
242 }
243 
__flush_icache_all_msr_irq(void)244 static void __flush_icache_all_msr_irq(void)
245 {
246 	unsigned long flags;
247 #ifndef ASM_LOOP
248 	int i;
249 #endif
250 	pr_debug("%s\n", __func__);
251 
252 	local_irq_save(flags);
253 	__disable_icache_msr();
254 #ifdef ASM_LOOP
255 	CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
256 #else
257 	for (i = 0; i < cpuinfo.icache_size;
258 		 i += cpuinfo.icache_line_length)
259 			__asm__ __volatile__ ("wic	%0, r0;" \
260 					: : "r" (i));
261 #endif
262 	__enable_icache_msr();
263 	local_irq_restore(flags);
264 }
265 
__flush_icache_all_nomsr_irq(void)266 static void __flush_icache_all_nomsr_irq(void)
267 {
268 	unsigned long flags;
269 #ifndef ASM_LOOP
270 	int i;
271 #endif
272 	pr_debug("%s\n", __func__);
273 
274 	local_irq_save(flags);
275 	__disable_icache_nomsr();
276 #ifdef ASM_LOOP
277 	CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
278 #else
279 	for (i = 0; i < cpuinfo.icache_size;
280 		 i += cpuinfo.icache_line_length)
281 			__asm__ __volatile__ ("wic	%0, r0;" \
282 					: : "r" (i));
283 #endif
284 	__enable_icache_nomsr();
285 	local_irq_restore(flags);
286 }
287 
__flush_icache_all_noirq(void)288 static void __flush_icache_all_noirq(void)
289 {
290 #ifndef ASM_LOOP
291 	int i;
292 #endif
293 	pr_debug("%s\n", __func__);
294 #ifdef ASM_LOOP
295 	CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
296 #else
297 	for (i = 0; i < cpuinfo.icache_size;
298 		 i += cpuinfo.icache_line_length)
299 			__asm__ __volatile__ ("wic	%0, r0;" \
300 					: : "r" (i));
301 #endif
302 }
303 
__invalidate_dcache_all_msr_irq(void)304 static void __invalidate_dcache_all_msr_irq(void)
305 {
306 	unsigned long flags;
307 #ifndef ASM_LOOP
308 	int i;
309 #endif
310 	pr_debug("%s\n", __func__);
311 
312 	local_irq_save(flags);
313 	__disable_dcache_msr();
314 #ifdef ASM_LOOP
315 	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
316 #else
317 	for (i = 0; i < cpuinfo.dcache_size;
318 		 i += cpuinfo.dcache_line_length)
319 			__asm__ __volatile__ ("wdc	%0, r0;" \
320 					: : "r" (i));
321 #endif
322 	__enable_dcache_msr();
323 	local_irq_restore(flags);
324 }
325 
__invalidate_dcache_all_nomsr_irq(void)326 static void __invalidate_dcache_all_nomsr_irq(void)
327 {
328 	unsigned long flags;
329 #ifndef ASM_LOOP
330 	int i;
331 #endif
332 	pr_debug("%s\n", __func__);
333 
334 	local_irq_save(flags);
335 	__disable_dcache_nomsr();
336 #ifdef ASM_LOOP
337 	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
338 #else
339 	for (i = 0; i < cpuinfo.dcache_size;
340 		 i += cpuinfo.dcache_line_length)
341 			__asm__ __volatile__ ("wdc	%0, r0;" \
342 					: : "r" (i));
343 #endif
344 	__enable_dcache_nomsr();
345 	local_irq_restore(flags);
346 }
347 
__invalidate_dcache_all_noirq_wt(void)348 static void __invalidate_dcache_all_noirq_wt(void)
349 {
350 #ifndef ASM_LOOP
351 	int i;
352 #endif
353 	pr_debug("%s\n", __func__);
354 #ifdef ASM_LOOP
355 	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc)
356 #else
357 	for (i = 0; i < cpuinfo.dcache_size;
358 		 i += cpuinfo.dcache_line_length)
359 			__asm__ __volatile__ ("wdc	%0, r0;" \
360 					: : "r" (i));
361 #endif
362 }
363 
364 /* FIXME It is blindly invalidation as is expected
365  * but can't be called on noMMU in microblaze_cache_init below
366  *
367  * MS: noMMU kernel won't boot if simple wdc is used
368  * The reason should be that there are discared data which kernel needs
369  */
__invalidate_dcache_all_wb(void)370 static void __invalidate_dcache_all_wb(void)
371 {
372 #ifndef ASM_LOOP
373 	int i;
374 #endif
375 	pr_debug("%s\n", __func__);
376 #ifdef ASM_LOOP
377 	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
378 					wdc)
379 #else
380 	for (i = 0; i < cpuinfo.dcache_size;
381 		 i += cpuinfo.dcache_line_length)
382 			__asm__ __volatile__ ("wdc	%0, r0;" \
383 					: : "r" (i));
384 #endif
385 }
386 
__invalidate_dcache_range_wb(unsigned long start,unsigned long end)387 static void __invalidate_dcache_range_wb(unsigned long start,
388 						unsigned long end)
389 {
390 #ifndef ASM_LOOP
391 	int i;
392 #endif
393 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
394 				(unsigned int)start, (unsigned int) end);
395 
396 	CACHE_LOOP_LIMITS(start, end,
397 			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
398 #ifdef ASM_LOOP
399 	CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear);
400 #else
401 	for (i = start; i < end; i += cpuinfo.dcache_line_length)
402 		__asm__ __volatile__ ("wdc.clear	%0, r0;"	\
403 				: : "r" (i));
404 #endif
405 }
406 
__invalidate_dcache_range_nomsr_wt(unsigned long start,unsigned long end)407 static void __invalidate_dcache_range_nomsr_wt(unsigned long start,
408 							unsigned long end)
409 {
410 #ifndef ASM_LOOP
411 	int i;
412 #endif
413 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
414 				(unsigned int)start, (unsigned int) end);
415 	CACHE_LOOP_LIMITS(start, end,
416 			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
417 
418 #ifdef ASM_LOOP
419 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
420 #else
421 	for (i = start; i < end; i += cpuinfo.dcache_line_length)
422 		__asm__ __volatile__ ("wdc	%0, r0;"	\
423 				: : "r" (i));
424 #endif
425 }
426 
__invalidate_dcache_range_msr_irq_wt(unsigned long start,unsigned long end)427 static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
428 							unsigned long end)
429 {
430 	unsigned long flags;
431 #ifndef ASM_LOOP
432 	int i;
433 #endif
434 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
435 				(unsigned int)start, (unsigned int) end);
436 	CACHE_LOOP_LIMITS(start, end,
437 			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
438 
439 	local_irq_save(flags);
440 	__disable_dcache_msr();
441 
442 #ifdef ASM_LOOP
443 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
444 #else
445 	for (i = start; i < end; i += cpuinfo.dcache_line_length)
446 		__asm__ __volatile__ ("wdc	%0, r0;"	\
447 				: : "r" (i));
448 #endif
449 
450 	__enable_dcache_msr();
451 	local_irq_restore(flags);
452 }
453 
__invalidate_dcache_range_nomsr_irq(unsigned long start,unsigned long end)454 static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
455 							unsigned long end)
456 {
457 	unsigned long flags;
458 #ifndef ASM_LOOP
459 	int i;
460 #endif
461 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
462 				(unsigned int)start, (unsigned int) end);
463 
464 	CACHE_LOOP_LIMITS(start, end,
465 			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
466 
467 	local_irq_save(flags);
468 	__disable_dcache_nomsr();
469 
470 #ifdef ASM_LOOP
471 	CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
472 #else
473 	for (i = start; i < end; i += cpuinfo.dcache_line_length)
474 		__asm__ __volatile__ ("wdc	%0, r0;"	\
475 				: : "r" (i));
476 #endif
477 
478 	__enable_dcache_nomsr();
479 	local_irq_restore(flags);
480 }
481 
__flush_dcache_all_wb(void)482 static void __flush_dcache_all_wb(void)
483 {
484 #ifndef ASM_LOOP
485 	int i;
486 #endif
487 	pr_debug("%s\n", __func__);
488 #ifdef ASM_LOOP
489 	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
490 				wdc.flush);
491 #else
492 	for (i = 0; i < cpuinfo.dcache_size;
493 		 i += cpuinfo.dcache_line_length)
494 			__asm__ __volatile__ ("wdc.flush	%0, r0;" \
495 					: : "r" (i));
496 #endif
497 }
498 
__flush_dcache_range_wb(unsigned long start,unsigned long end)499 static void __flush_dcache_range_wb(unsigned long start, unsigned long end)
500 {
501 #ifndef ASM_LOOP
502 	int i;
503 #endif
504 	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
505 				(unsigned int)start, (unsigned int) end);
506 
507 	CACHE_LOOP_LIMITS(start, end,
508 			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
509 #ifdef ASM_LOOP
510 	CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush);
511 #else
512 	for (i = start; i < end; i += cpuinfo.dcache_line_length)
513 		__asm__ __volatile__ ("wdc.flush	%0, r0;"	\
514 				: : "r" (i));
515 #endif
516 }
517 
518 /* struct for wb caches and for wt caches */
519 struct scache *mbc;
520 
521 /* new wb cache model */
522 static const struct scache wb_msr = {
523 	.ie = __enable_icache_msr,
524 	.id = __disable_icache_msr,
525 	.ifl = __flush_icache_all_noirq,
526 	.iflr = __flush_icache_range_noirq,
527 	.iin = __flush_icache_all_noirq,
528 	.iinr = __flush_icache_range_noirq,
529 	.de = __enable_dcache_msr,
530 	.dd = __disable_dcache_msr,
531 	.dfl = __flush_dcache_all_wb,
532 	.dflr = __flush_dcache_range_wb,
533 	.din = __invalidate_dcache_all_wb,
534 	.dinr = __invalidate_dcache_range_wb,
535 };
536 
537 /* There is only difference in ie, id, de, dd functions */
538 static const struct scache wb_nomsr = {
539 	.ie = __enable_icache_nomsr,
540 	.id = __disable_icache_nomsr,
541 	.ifl = __flush_icache_all_noirq,
542 	.iflr = __flush_icache_range_noirq,
543 	.iin = __flush_icache_all_noirq,
544 	.iinr = __flush_icache_range_noirq,
545 	.de = __enable_dcache_nomsr,
546 	.dd = __disable_dcache_nomsr,
547 	.dfl = __flush_dcache_all_wb,
548 	.dflr = __flush_dcache_range_wb,
549 	.din = __invalidate_dcache_all_wb,
550 	.dinr = __invalidate_dcache_range_wb,
551 };
552 
553 /* Old wt cache model with disabling irq and turn off cache */
554 static const struct scache wt_msr = {
555 	.ie = __enable_icache_msr,
556 	.id = __disable_icache_msr,
557 	.ifl = __flush_icache_all_msr_irq,
558 	.iflr = __flush_icache_range_msr_irq,
559 	.iin = __flush_icache_all_msr_irq,
560 	.iinr = __flush_icache_range_msr_irq,
561 	.de = __enable_dcache_msr,
562 	.dd = __disable_dcache_msr,
563 	.dfl = __invalidate_dcache_all_msr_irq,
564 	.dflr = __invalidate_dcache_range_msr_irq_wt,
565 	.din = __invalidate_dcache_all_msr_irq,
566 	.dinr = __invalidate_dcache_range_msr_irq_wt,
567 };
568 
569 static const struct scache wt_nomsr = {
570 	.ie = __enable_icache_nomsr,
571 	.id = __disable_icache_nomsr,
572 	.ifl = __flush_icache_all_nomsr_irq,
573 	.iflr = __flush_icache_range_nomsr_irq,
574 	.iin = __flush_icache_all_nomsr_irq,
575 	.iinr = __flush_icache_range_nomsr_irq,
576 	.de = __enable_dcache_nomsr,
577 	.dd = __disable_dcache_nomsr,
578 	.dfl = __invalidate_dcache_all_nomsr_irq,
579 	.dflr = __invalidate_dcache_range_nomsr_irq,
580 	.din = __invalidate_dcache_all_nomsr_irq,
581 	.dinr = __invalidate_dcache_range_nomsr_irq,
582 };
583 
584 /* New wt cache model for newer Microblaze versions */
585 static const struct scache wt_msr_noirq = {
586 	.ie = __enable_icache_msr,
587 	.id = __disable_icache_msr,
588 	.ifl = __flush_icache_all_noirq,
589 	.iflr = __flush_icache_range_noirq,
590 	.iin = __flush_icache_all_noirq,
591 	.iinr = __flush_icache_range_noirq,
592 	.de = __enable_dcache_msr,
593 	.dd = __disable_dcache_msr,
594 	.dfl = __invalidate_dcache_all_noirq_wt,
595 	.dflr = __invalidate_dcache_range_nomsr_wt,
596 	.din = __invalidate_dcache_all_noirq_wt,
597 	.dinr = __invalidate_dcache_range_nomsr_wt,
598 };
599 
600 static const struct scache wt_nomsr_noirq = {
601 	.ie = __enable_icache_nomsr,
602 	.id = __disable_icache_nomsr,
603 	.ifl = __flush_icache_all_noirq,
604 	.iflr = __flush_icache_range_noirq,
605 	.iin = __flush_icache_all_noirq,
606 	.iinr = __flush_icache_range_noirq,
607 	.de = __enable_dcache_nomsr,
608 	.dd = __disable_dcache_nomsr,
609 	.dfl = __invalidate_dcache_all_noirq_wt,
610 	.dflr = __invalidate_dcache_range_nomsr_wt,
611 	.din = __invalidate_dcache_all_noirq_wt,
612 	.dinr = __invalidate_dcache_range_nomsr_wt,
613 };
614 
615 /* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */
616 #define CPUVER_7_20_A	0x0c
617 #define CPUVER_7_20_D	0x0f
618 
619 #define INFO(s)	printk(KERN_INFO "cache: " s "\n");
620 
microblaze_cache_init(void)621 void microblaze_cache_init(void)
622 {
623 	if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) {
624 		if (cpuinfo.dcache_wb) {
625 			INFO("wb_msr");
626 			mbc = (struct scache *)&wb_msr;
627 			if (cpuinfo.ver_code <= CPUVER_7_20_D) {
628 				/* MS: problem with signal handling - hw bug */
629 				INFO("WB won't work properly");
630 			}
631 		} else {
632 			if (cpuinfo.ver_code >= CPUVER_7_20_A) {
633 				INFO("wt_msr_noirq");
634 				mbc = (struct scache *)&wt_msr_noirq;
635 			} else {
636 				INFO("wt_msr");
637 				mbc = (struct scache *)&wt_msr;
638 			}
639 		}
640 	} else {
641 		if (cpuinfo.dcache_wb) {
642 			INFO("wb_nomsr");
643 			mbc = (struct scache *)&wb_nomsr;
644 			if (cpuinfo.ver_code <= CPUVER_7_20_D) {
645 				/* MS: problem with signal handling - hw bug */
646 				INFO("WB won't work properly");
647 			}
648 		} else {
649 			if (cpuinfo.ver_code >= CPUVER_7_20_A) {
650 				INFO("wt_nomsr_noirq");
651 				mbc = (struct scache *)&wt_nomsr_noirq;
652 			} else {
653 				INFO("wt_nomsr");
654 				mbc = (struct scache *)&wt_nomsr;
655 			}
656 		}
657 	}
658 /* FIXME Invalidation is done in U-BOOT
659  * WT cache: Data is already written to main memory
660  * WB cache: Discard data on noMMU which caused that kernel doesn't boot
661  */
662 	/* invalidate_dcache(); */
663 	enable_dcache();
664 
665 	invalidate_icache();
666 	enable_icache();
667 }
668