Commit | Line | Data |
---|---|---|
8beb8503 MS |
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 | |
2ee2ff87 | 6 | * Copyright (C) 2007-2009 John Williams <john.williams@petalogix.com> |
8beb8503 MS |
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> | |
2ee2ff87 | 16 | #include <asm/pvr.h> |
8beb8503 | 17 | |
2ee2ff87 | 18 | static inline void __enable_icache_msr(void) |
8beb8503 | 19 | { |
6bd55f0b MS |
20 | __asm__ __volatile__ (" msrset r0, %0;" \ |
21 | "nop;" \ | |
2ee2ff87 MS |
22 | : : "i" (MSR_ICE) : "memory"); |
23 | } | |
24 | ||
25 | static inline void __disable_icache_msr(void) | |
26 | { | |
6bd55f0b MS |
27 | __asm__ __volatile__ (" msrclr r0, %0;" \ |
28 | "nop;" \ | |
2ee2ff87 MS |
29 | : : "i" (MSR_ICE) : "memory"); |
30 | } | |
31 | ||
32 | static inline void __enable_dcache_msr(void) | |
33 | { | |
6bd55f0b MS |
34 | __asm__ __volatile__ (" msrset r0, %0;" \ |
35 | "nop;" \ | |
36 | : : "i" (MSR_DCE) : "memory"); | |
8beb8503 MS |
37 | } |
38 | ||
2ee2ff87 | 39 | static inline void __disable_dcache_msr(void) |
8beb8503 | 40 | { |
6bd55f0b MS |
41 | __asm__ __volatile__ (" msrclr r0, %0;" \ |
42 | "nop; " \ | |
43 | : : "i" (MSR_DCE) : "memory"); | |
2ee2ff87 MS |
44 | } |
45 | ||
46 | static inline void __enable_icache_nomsr(void) | |
47 | { | |
6bd55f0b MS |
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"); | |
8beb8503 MS |
54 | } |
55 | ||
2ee2ff87 | 56 | static inline void __disable_icache_nomsr(void) |
8beb8503 | 57 | { |
6bd55f0b MS |
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"); | |
8beb8503 MS |
64 | } |
65 | ||
2ee2ff87 | 66 | static inline void __enable_dcache_nomsr(void) |
8beb8503 | 67 | { |
6bd55f0b MS |
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"); | |
8beb8503 MS |
74 | } |
75 | ||
2ee2ff87 | 76 | static inline void __disable_dcache_nomsr(void) |
8beb8503 | 77 | { |
6bd55f0b MS |
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"); | |
8beb8503 MS |
84 | } |
85 | ||
2ee2ff87 | 86 | |
3274c570 MS |
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 | */ | |
2ee2ff87 MS |
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; \ | |
6bd55f0b | 97 | } while (0) |
2ee2ff87 MS |
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 { \ | |
3274c570 | 105 | unsigned int len = cache_size - line_length; \ |
2ee2ff87 | 106 | int step = -line_length; \ |
3274c570 | 107 | WARN_ON(step >= 0); \ |
2ee2ff87 | 108 | \ |
6bd55f0b MS |
109 | __asm__ __volatile__ (" 1: " #op " %0, r0;" \ |
110 | "bgtid %0, 1b;" \ | |
111 | "addk %0, %0, %1;" \ | |
112 | : : "r" (len), "r" (step) \ | |
2ee2ff87 | 113 | : "memory"); \ |
6bd55f0b | 114 | } while (0) |
2ee2ff87 | 115 | |
3274c570 MS |
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 | |
25985edc | 120 | * end address is not aligned, if end is aligned then I have to subtract |
3274c570 MS |
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 | */ | |
2ee2ff87 MS |
124 | #define CACHE_RANGE_LOOP_2(start, end, line_length, op) \ |
125 | do { \ | |
126 | int step = -line_length; \ | |
3274c570 | 127 | int align = ~(line_length - 1); \ |
ddfbc935 | 128 | int count; \ |
3274c570 | 129 | end = ((end & align) == end) ? end - line_length : end & align; \ |
ddfbc935 | 130 | count = end - start; \ |
3274c570 | 131 | WARN_ON(count < 0); \ |
2ee2ff87 | 132 | \ |
6bd55f0b MS |
133 | __asm__ __volatile__ (" 1: " #op " %0, %1;" \ |
134 | "bgtid %1, 1b;" \ | |
135 | "addk %1, %1, %2;" \ | |
136 | : : "r" (start), "r" (count), \ | |
2ee2ff87 | 137 | "r" (step) : "memory"); \ |
6bd55f0b | 138 | } while (0) |
2ee2ff87 MS |
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 { \ | |
2558cd8c MS |
143 | unsigned int volatile temp = 0; \ |
144 | unsigned int align = ~(line_length - 1); \ | |
3274c570 | 145 | end = ((end & align) == end) ? end - line_length : end & align; \ |
2558cd8c | 146 | WARN_ON(end < start); \ |
2ee2ff87 | 147 | \ |
6bd55f0b MS |
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), \ | |
0d670b24 | 153 | "r" (line_length) : "memory"); \ |
6bd55f0b | 154 | } while (0) |
2ee2ff87 | 155 | |
22607a28 MS |
156 | #define ASM_LOOP |
157 | ||
2ee2ff87 | 158 | static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end) |
8beb8503 | 159 | { |
2ee2ff87 | 160 | unsigned long flags; |
22607a28 MS |
161 | #ifndef ASM_LOOP |
162 | int i; | |
163 | #endif | |
2ee2ff87 MS |
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 | ||
22607a28 | 173 | #ifdef ASM_LOOP |
2ee2ff87 | 174 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic); |
22607a28 MS |
175 | #else |
176 | for (i = start; i < end; i += cpuinfo.icache_line_length) | |
177 | __asm__ __volatile__ ("wic %0, r0;" \ | |
178 | : : "r" (i)); | |
179 | #endif | |
2ee2ff87 MS |
180 | __enable_icache_msr(); |
181 | local_irq_restore(flags); | |
8beb8503 MS |
182 | } |
183 | ||
2ee2ff87 MS |
184 | static void __flush_icache_range_nomsr_irq(unsigned long start, |
185 | unsigned long end) | |
8beb8503 | 186 | { |
2ee2ff87 | 187 | unsigned long flags; |
22607a28 MS |
188 | #ifndef ASM_LOOP |
189 | int i; | |
190 | #endif | |
2ee2ff87 MS |
191 | pr_debug("%s: start 0x%x, end 0x%x\n", __func__, |
192 | (unsigned int)start, (unsigned int) end); | |
8beb8503 | 193 | |
2ee2ff87 MS |
194 | CACHE_LOOP_LIMITS(start, end, |
195 | cpuinfo.icache_line_length, cpuinfo.icache_size); | |
8beb8503 | 196 | |
2ee2ff87 MS |
197 | local_irq_save(flags); |
198 | __disable_icache_nomsr(); | |
199 | ||
22607a28 | 200 | #ifdef ASM_LOOP |
2ee2ff87 | 201 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic); |
22607a28 MS |
202 | #else |
203 | for (i = start; i < end; i += cpuinfo.icache_line_length) | |
204 | __asm__ __volatile__ ("wic %0, r0;" \ | |
205 | : : "r" (i)); | |
206 | #endif | |
2ee2ff87 MS |
207 | |
208 | __enable_icache_nomsr(); | |
209 | local_irq_restore(flags); | |
8beb8503 MS |
210 | } |
211 | ||
2ee2ff87 MS |
212 | static void __flush_icache_range_noirq(unsigned long start, |
213 | unsigned long end) | |
8beb8503 | 214 | { |
22607a28 MS |
215 | #ifndef ASM_LOOP |
216 | int i; | |
217 | #endif | |
2ee2ff87 MS |
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); | |
22607a28 | 223 | #ifdef ASM_LOOP |
2ee2ff87 | 224 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic); |
22607a28 MS |
225 | #else |
226 | for (i = start; i < end; i += cpuinfo.icache_line_length) | |
227 | __asm__ __volatile__ ("wic %0, r0;" \ | |
228 | : : "r" (i)); | |
229 | #endif | |
2ee2ff87 MS |
230 | } |
231 | ||
232 | static void __flush_icache_all_msr_irq(void) | |
233 | { | |
234 | unsigned long flags; | |
22607a28 MS |
235 | #ifndef ASM_LOOP |
236 | int i; | |
237 | #endif | |
2ee2ff87 MS |
238 | pr_debug("%s\n", __func__); |
239 | ||
240 | local_irq_save(flags); | |
241 | __disable_icache_msr(); | |
22607a28 | 242 | #ifdef ASM_LOOP |
2ee2ff87 | 243 | CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic); |
22607a28 MS |
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 | |
2ee2ff87 MS |
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; | |
22607a28 MS |
257 | #ifndef ASM_LOOP |
258 | int i; | |
259 | #endif | |
2ee2ff87 MS |
260 | pr_debug("%s\n", __func__); |
261 | ||
262 | local_irq_save(flags); | |
263 | __disable_icache_nomsr(); | |
22607a28 | 264 | #ifdef ASM_LOOP |
2ee2ff87 | 265 | CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic); |
22607a28 MS |
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 | |
2ee2ff87 MS |
272 | __enable_icache_nomsr(); |
273 | local_irq_restore(flags); | |
8beb8503 MS |
274 | } |
275 | ||
2ee2ff87 | 276 | static void __flush_icache_all_noirq(void) |
8beb8503 | 277 | { |
22607a28 MS |
278 | #ifndef ASM_LOOP |
279 | int i; | |
280 | #endif | |
2ee2ff87 | 281 | pr_debug("%s\n", __func__); |
22607a28 | 282 | #ifdef ASM_LOOP |
2ee2ff87 | 283 | CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic); |
22607a28 MS |
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 | |
8beb8503 MS |
290 | } |
291 | ||
2ee2ff87 | 292 | static void __invalidate_dcache_all_msr_irq(void) |
8beb8503 | 293 | { |
2ee2ff87 | 294 | unsigned long flags; |
22607a28 MS |
295 | #ifndef ASM_LOOP |
296 | int i; | |
297 | #endif | |
2ee2ff87 MS |
298 | pr_debug("%s\n", __func__); |
299 | ||
300 | local_irq_save(flags); | |
301 | __disable_dcache_msr(); | |
22607a28 | 302 | #ifdef ASM_LOOP |
2ee2ff87 | 303 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc); |
22607a28 MS |
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 | |
2ee2ff87 MS |
310 | __enable_dcache_msr(); |
311 | local_irq_restore(flags); | |
8beb8503 MS |
312 | } |
313 | ||
2ee2ff87 | 314 | static void __invalidate_dcache_all_nomsr_irq(void) |
8beb8503 | 315 | { |
2ee2ff87 | 316 | unsigned long flags; |
22607a28 MS |
317 | #ifndef ASM_LOOP |
318 | int i; | |
319 | #endif | |
2ee2ff87 MS |
320 | pr_debug("%s\n", __func__); |
321 | ||
322 | local_irq_save(flags); | |
323 | __disable_dcache_nomsr(); | |
22607a28 | 324 | #ifdef ASM_LOOP |
2ee2ff87 | 325 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc); |
22607a28 MS |
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 | |
2ee2ff87 MS |
332 | __enable_dcache_nomsr(); |
333 | local_irq_restore(flags); | |
8beb8503 MS |
334 | } |
335 | ||
2ee2ff87 | 336 | static void __invalidate_dcache_all_noirq_wt(void) |
8beb8503 | 337 | { |
22607a28 MS |
338 | #ifndef ASM_LOOP |
339 | int i; | |
340 | #endif | |
2ee2ff87 | 341 | pr_debug("%s\n", __func__); |
22607a28 | 342 | #ifdef ASM_LOOP |
6bd55f0b | 343 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc); |
22607a28 MS |
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 | |
8beb8503 MS |
350 | } |
351 | ||
6bd55f0b MS |
352 | /* |
353 | * FIXME It is blindly invalidation as is expected | |
3274c570 MS |
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 | */ | |
2ee2ff87 | 359 | static void __invalidate_dcache_all_wb(void) |
8beb8503 | 360 | { |
22607a28 MS |
361 | #ifndef ASM_LOOP |
362 | int i; | |
363 | #endif | |
2ee2ff87 | 364 | pr_debug("%s\n", __func__); |
22607a28 | 365 | #ifdef ASM_LOOP |
3274c570 | 366 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, |
6bd55f0b | 367 | wdc); |
22607a28 MS |
368 | #else |
369 | for (i = 0; i < cpuinfo.dcache_size; | |
370 | i += cpuinfo.dcache_line_length) | |
3274c570 | 371 | __asm__ __volatile__ ("wdc %0, r0;" \ |
22607a28 MS |
372 | : : "r" (i)); |
373 | #endif | |
2ee2ff87 MS |
374 | } |
375 | ||
376 | static void __invalidate_dcache_range_wb(unsigned long start, | |
377 | unsigned long end) | |
378 | { | |
22607a28 MS |
379 | #ifndef ASM_LOOP |
380 | int i; | |
381 | #endif | |
2ee2ff87 MS |
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); | |
22607a28 | 387 | #ifdef ASM_LOOP |
2ee2ff87 | 388 | CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear); |
22607a28 | 389 | #else |
c17e1a1c | 390 | for (i = start; i < end; i += cpuinfo.dcache_line_length) |
22607a28 MS |
391 | __asm__ __volatile__ ("wdc.clear %0, r0;" \ |
392 | : : "r" (i)); | |
393 | #endif | |
2ee2ff87 MS |
394 | } |
395 | ||
396 | static void __invalidate_dcache_range_nomsr_wt(unsigned long start, | |
397 | unsigned long end) | |
398 | { | |
22607a28 MS |
399 | #ifndef ASM_LOOP |
400 | int i; | |
401 | #endif | |
2ee2ff87 MS |
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 | ||
22607a28 | 407 | #ifdef ASM_LOOP |
2ee2ff87 | 408 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); |
22607a28 | 409 | #else |
c17e1a1c | 410 | for (i = start; i < end; i += cpuinfo.dcache_line_length) |
22607a28 MS |
411 | __asm__ __volatile__ ("wdc %0, r0;" \ |
412 | : : "r" (i)); | |
413 | #endif | |
8beb8503 MS |
414 | } |
415 | ||
2ee2ff87 MS |
416 | static void __invalidate_dcache_range_msr_irq_wt(unsigned long start, |
417 | unsigned long end) | |
8beb8503 | 418 | { |
2ee2ff87 | 419 | unsigned long flags; |
22607a28 MS |
420 | #ifndef ASM_LOOP |
421 | int i; | |
422 | #endif | |
2ee2ff87 MS |
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 | ||
22607a28 | 431 | #ifdef ASM_LOOP |
2ee2ff87 | 432 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); |
22607a28 | 433 | #else |
c17e1a1c | 434 | for (i = start; i < end; i += cpuinfo.dcache_line_length) |
22607a28 MS |
435 | __asm__ __volatile__ ("wdc %0, r0;" \ |
436 | : : "r" (i)); | |
437 | #endif | |
2ee2ff87 MS |
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; | |
22607a28 MS |
447 | #ifndef ASM_LOOP |
448 | int i; | |
449 | #endif | |
2ee2ff87 MS |
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 | ||
22607a28 | 459 | #ifdef ASM_LOOP |
2ee2ff87 | 460 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); |
22607a28 | 461 | #else |
c17e1a1c | 462 | for (i = start; i < end; i += cpuinfo.dcache_line_length) |
22607a28 MS |
463 | __asm__ __volatile__ ("wdc %0, r0;" \ |
464 | : : "r" (i)); | |
465 | #endif | |
2ee2ff87 MS |
466 | |
467 | __enable_dcache_nomsr(); | |
468 | local_irq_restore(flags); | |
469 | } | |
470 | ||
471 | static void __flush_dcache_all_wb(void) | |
472 | { | |
22607a28 MS |
473 | #ifndef ASM_LOOP |
474 | int i; | |
475 | #endif | |
2ee2ff87 | 476 | pr_debug("%s\n", __func__); |
22607a28 | 477 | #ifdef ASM_LOOP |
2ee2ff87 MS |
478 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, |
479 | wdc.flush); | |
22607a28 MS |
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 | |
8beb8503 MS |
486 | } |
487 | ||
2ee2ff87 | 488 | static void __flush_dcache_range_wb(unsigned long start, unsigned long end) |
8beb8503 | 489 | { |
22607a28 MS |
490 | #ifndef ASM_LOOP |
491 | int i; | |
492 | #endif | |
2ee2ff87 MS |
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); | |
22607a28 | 498 | #ifdef ASM_LOOP |
2ee2ff87 | 499 | CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush); |
22607a28 | 500 | #else |
c17e1a1c | 501 | for (i = start; i < end; i += cpuinfo.dcache_line_length) |
22607a28 MS |
502 | __asm__ __volatile__ ("wdc.flush %0, r0;" \ |
503 | : : "r" (i)); | |
504 | #endif | |
2ee2ff87 MS |
505 | } |
506 | ||
507 | /* struct for wb caches and for wt caches */ | |
508 | struct scache *mbc; | |
509 | ||
510 | /* new wb cache model */ | |
954e8b95 | 511 | static const struct scache wb_msr = { |
2ee2ff87 MS |
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 */ | |
954e8b95 | 527 | static const struct scache wb_nomsr = { |
2ee2ff87 MS |
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 */ | |
954e8b95 | 543 | static const struct scache wt_msr = { |
2ee2ff87 MS |
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 | ||
954e8b95 | 558 | static const struct scache wt_nomsr = { |
2ee2ff87 MS |
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 */ | |
954e8b95 | 574 | static const struct scache wt_msr_noirq = { |
2ee2ff87 MS |
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 | ||
954e8b95 | 589 | static const struct scache wt_nomsr_noirq = { |
2ee2ff87 MS |
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 | ||
2ee2ff87 MS |
608 | void microblaze_cache_init(void) |
609 | { | |
610 | if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) { | |
611 | if (cpuinfo.dcache_wb) { | |
6bd55f0b | 612 | pr_info("wb_msr\n"); |
2ee2ff87 | 613 | mbc = (struct scache *)&wb_msr; |
b9dc9e77 | 614 | if (cpuinfo.ver_code <= CPUVER_7_20_D) { |
2ee2ff87 | 615 | /* MS: problem with signal handling - hw bug */ |
6bd55f0b | 616 | pr_info("WB won't work properly\n"); |
2ee2ff87 MS |
617 | } |
618 | } else { | |
619 | if (cpuinfo.ver_code >= CPUVER_7_20_A) { | |
6bd55f0b | 620 | pr_info("wt_msr_noirq\n"); |
2ee2ff87 MS |
621 | mbc = (struct scache *)&wt_msr_noirq; |
622 | } else { | |
6bd55f0b | 623 | pr_info("wt_msr\n"); |
2ee2ff87 MS |
624 | mbc = (struct scache *)&wt_msr; |
625 | } | |
626 | } | |
627 | } else { | |
628 | if (cpuinfo.dcache_wb) { | |
6bd55f0b | 629 | pr_info("wb_nomsr\n"); |
2ee2ff87 | 630 | mbc = (struct scache *)&wb_nomsr; |
b9dc9e77 | 631 | if (cpuinfo.ver_code <= CPUVER_7_20_D) { |
2ee2ff87 | 632 | /* MS: problem with signal handling - hw bug */ |
6bd55f0b | 633 | pr_info("WB won't work properly\n"); |
2ee2ff87 MS |
634 | } |
635 | } else { | |
636 | if (cpuinfo.ver_code >= CPUVER_7_20_A) { | |
6bd55f0b | 637 | pr_info("wt_nomsr_noirq\n"); |
2ee2ff87 MS |
638 | mbc = (struct scache *)&wt_nomsr_noirq; |
639 | } else { | |
6bd55f0b | 640 | pr_info("wt_nomsr\n"); |
2ee2ff87 MS |
641 | mbc = (struct scache *)&wt_nomsr; |
642 | } | |
643 | } | |
644 | } | |
6bd55f0b MS |
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 | */ | |
3274c570 | 650 | /* invalidate_dcache(); */ |
407c1da0 MS |
651 | enable_dcache(); |
652 | ||
653 | invalidate_icache(); | |
654 | enable_icache(); | |
8beb8503 | 655 | } |