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