diff options
Diffstat (limited to 'arch/microblaze/kernel/cpu/cache.c')
-rw-r--r-- | arch/microblaze/kernel/cpu/cache.c | 75 |
1 files changed, 42 insertions, 33 deletions
diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c index f04d8a86dead..109876e8d643 100644 --- a/arch/microblaze/kernel/cpu/cache.c +++ b/arch/microblaze/kernel/cpu/cache.c | |||
@@ -96,13 +96,16 @@ static inline void __disable_dcache_nomsr(void) | |||
96 | } | 96 | } |
97 | 97 | ||
98 | 98 | ||
99 | /* Helper macro for computing the limits of cache range loops */ | 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 | */ | ||
100 | #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size) \ | 104 | #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size) \ |
101 | do { \ | 105 | do { \ |
102 | int align = ~(cache_line_length - 1); \ | 106 | int align = ~(cache_line_length - 1); \ |
103 | end = min(start + cache_size, end); \ | 107 | end = min(start + cache_size, end); \ |
104 | start &= align; \ | 108 | start &= align; \ |
105 | end = ((end & align) + cache_line_length); \ | ||
106 | } while (0); | 109 | } while (0); |
107 | 110 | ||
108 | /* | 111 | /* |
@@ -111,9 +114,9 @@ do { \ | |||
111 | */ | 114 | */ |
112 | #define CACHE_ALL_LOOP(cache_size, line_length, op) \ | 115 | #define CACHE_ALL_LOOP(cache_size, line_length, op) \ |
113 | do { \ | 116 | do { \ |
114 | unsigned int len = cache_size; \ | 117 | unsigned int len = cache_size - line_length; \ |
115 | int step = -line_length; \ | 118 | int step = -line_length; \ |
116 | BUG_ON(step >= 0); \ | 119 | WARN_ON(step >= 0); \ |
117 | \ | 120 | \ |
118 | __asm__ __volatile__ (" 1: " #op " %0, r0; \ | 121 | __asm__ __volatile__ (" 1: " #op " %0, r0; \ |
119 | bgtid %0, 1b; \ | 122 | bgtid %0, 1b; \ |
@@ -122,26 +125,22 @@ do { \ | |||
122 | : "memory"); \ | 125 | : "memory"); \ |
123 | } while (0); | 126 | } while (0); |
124 | 127 | ||
125 | 128 | /* Used for wdc.flush/clear which can use rB for offset which is not possible | |
126 | #define CACHE_ALL_LOOP2(cache_size, line_length, op) \ | 129 | * to use for simple wdc or wic. |
127 | do { \ | 130 | * |
128 | unsigned int len = cache_size; \ | 131 | * start address is cache aligned |
129 | int step = -line_length; \ | 132 | * end address is not aligned, if end is aligned then I have to substract |
130 | BUG_ON(step >= 0); \ | 133 | * cacheline length because I can't flush/invalidate the next cacheline. |
131 | \ | 134 | * If is not, I align it because I will flush/invalidate whole line. |
132 | __asm__ __volatile__ (" 1: " #op " r0, %0; \ | 135 | */ |
133 | bgtid %0, 1b; \ | ||
134 | addk %0, %0, %1; \ | ||
135 | " : : "r" (len), "r" (step) \ | ||
136 | : "memory"); \ | ||
137 | } while (0); | ||
138 | |||
139 | /* for wdc.flush/clear */ | ||
140 | #define CACHE_RANGE_LOOP_2(start, end, line_length, op) \ | 136 | #define CACHE_RANGE_LOOP_2(start, end, line_length, op) \ |
141 | do { \ | 137 | do { \ |
142 | int step = -line_length; \ | 138 | int step = -line_length; \ |
143 | int count = end - start; \ | 139 | int align = ~(line_length - 1); \ |
144 | BUG_ON(count <= 0); \ | 140 | int count; \ |
141 | end = ((end & align) == end) ? end - line_length : end & align; \ | ||
142 | count = end - start; \ | ||
143 | WARN_ON(count < 0); \ | ||
145 | \ | 144 | \ |
146 | __asm__ __volatile__ (" 1: " #op " %0, %1; \ | 145 | __asm__ __volatile__ (" 1: " #op " %0, %1; \ |
147 | bgtid %1, 1b; \ | 146 | bgtid %1, 1b; \ |
@@ -154,7 +153,9 @@ do { \ | |||
154 | #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \ | 153 | #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \ |
155 | do { \ | 154 | do { \ |
156 | int volatile temp; \ | 155 | int volatile temp; \ |
157 | BUG_ON(end - start <= 0); \ | 156 | int align = ~(line_length - 1); \ |
157 | end = ((end & align) == end) ? end - line_length : end & align; \ | ||
158 | WARN_ON(end - start < 0); \ | ||
158 | \ | 159 | \ |
159 | __asm__ __volatile__ (" 1: " #op " %1, r0; \ | 160 | __asm__ __volatile__ (" 1: " #op " %1, r0; \ |
160 | cmpu %0, %1, %2; \ | 161 | cmpu %0, %1, %2; \ |
@@ -360,8 +361,12 @@ static void __invalidate_dcache_all_noirq_wt(void) | |||
360 | #endif | 361 | #endif |
361 | } | 362 | } |
362 | 363 | ||
363 | /* FIXME this is weird - should be only wdc but not work | 364 | /* FIXME It is blindly invalidation as is expected |
364 | * MS: I am getting bus errors and other weird things */ | 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 | */ | ||
365 | static void __invalidate_dcache_all_wb(void) | 370 | static void __invalidate_dcache_all_wb(void) |
366 | { | 371 | { |
367 | #ifndef ASM_LOOP | 372 | #ifndef ASM_LOOP |
@@ -369,12 +374,12 @@ static void __invalidate_dcache_all_wb(void) | |||
369 | #endif | 374 | #endif |
370 | pr_debug("%s\n", __func__); | 375 | pr_debug("%s\n", __func__); |
371 | #ifdef ASM_LOOP | 376 | #ifdef ASM_LOOP |
372 | CACHE_ALL_LOOP2(cpuinfo.dcache_size, cpuinfo.dcache_line_length, | 377 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, |
373 | wdc.clear) | 378 | wdc) |
374 | #else | 379 | #else |
375 | for (i = 0; i < cpuinfo.dcache_size; | 380 | for (i = 0; i < cpuinfo.dcache_size; |
376 | i += cpuinfo.dcache_line_length) | 381 | i += cpuinfo.dcache_line_length) |
377 | __asm__ __volatile__ ("wdc.clear %0, r0;" \ | 382 | __asm__ __volatile__ ("wdc %0, r0;" \ |
378 | : : "r" (i)); | 383 | : : "r" (i)); |
379 | #endif | 384 | #endif |
380 | } | 385 | } |
@@ -393,7 +398,7 @@ static void __invalidate_dcache_range_wb(unsigned long start, | |||
393 | #ifdef ASM_LOOP | 398 | #ifdef ASM_LOOP |
394 | CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear); | 399 | CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear); |
395 | #else | 400 | #else |
396 | for (i = start; i < end; i += cpuinfo.icache_line_length) | 401 | for (i = start; i < end; i += cpuinfo.dcache_line_length) |
397 | __asm__ __volatile__ ("wdc.clear %0, r0;" \ | 402 | __asm__ __volatile__ ("wdc.clear %0, r0;" \ |
398 | : : "r" (i)); | 403 | : : "r" (i)); |
399 | #endif | 404 | #endif |
@@ -413,7 +418,7 @@ static void __invalidate_dcache_range_nomsr_wt(unsigned long start, | |||
413 | #ifdef ASM_LOOP | 418 | #ifdef ASM_LOOP |
414 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); | 419 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); |
415 | #else | 420 | #else |
416 | for (i = start; i < end; i += cpuinfo.icache_line_length) | 421 | for (i = start; i < end; i += cpuinfo.dcache_line_length) |
417 | __asm__ __volatile__ ("wdc %0, r0;" \ | 422 | __asm__ __volatile__ ("wdc %0, r0;" \ |
418 | : : "r" (i)); | 423 | : : "r" (i)); |
419 | #endif | 424 | #endif |
@@ -437,7 +442,7 @@ static void __invalidate_dcache_range_msr_irq_wt(unsigned long start, | |||
437 | #ifdef ASM_LOOP | 442 | #ifdef ASM_LOOP |
438 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); | 443 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); |
439 | #else | 444 | #else |
440 | for (i = start; i < end; i += cpuinfo.icache_line_length) | 445 | for (i = start; i < end; i += cpuinfo.dcache_line_length) |
441 | __asm__ __volatile__ ("wdc %0, r0;" \ | 446 | __asm__ __volatile__ ("wdc %0, r0;" \ |
442 | : : "r" (i)); | 447 | : : "r" (i)); |
443 | #endif | 448 | #endif |
@@ -465,7 +470,7 @@ static void __invalidate_dcache_range_nomsr_irq(unsigned long start, | |||
465 | #ifdef ASM_LOOP | 470 | #ifdef ASM_LOOP |
466 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); | 471 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); |
467 | #else | 472 | #else |
468 | for (i = start; i < end; i += cpuinfo.icache_line_length) | 473 | for (i = start; i < end; i += cpuinfo.dcache_line_length) |
469 | __asm__ __volatile__ ("wdc %0, r0;" \ | 474 | __asm__ __volatile__ ("wdc %0, r0;" \ |
470 | : : "r" (i)); | 475 | : : "r" (i)); |
471 | #endif | 476 | #endif |
@@ -504,7 +509,7 @@ static void __flush_dcache_range_wb(unsigned long start, unsigned long end) | |||
504 | #ifdef ASM_LOOP | 509 | #ifdef ASM_LOOP |
505 | CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush); | 510 | CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush); |
506 | #else | 511 | #else |
507 | for (i = start; i < end; i += cpuinfo.icache_line_length) | 512 | for (i = start; i < end; i += cpuinfo.dcache_line_length) |
508 | __asm__ __volatile__ ("wdc.flush %0, r0;" \ | 513 | __asm__ __volatile__ ("wdc.flush %0, r0;" \ |
509 | : : "r" (i)); | 514 | : : "r" (i)); |
510 | #endif | 515 | #endif |
@@ -650,7 +655,11 @@ void microblaze_cache_init(void) | |||
650 | } | 655 | } |
651 | } | 656 | } |
652 | } | 657 | } |
653 | invalidate_dcache(); | 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(); */ | ||
654 | enable_dcache(); | 663 | enable_dcache(); |
655 | 664 | ||
656 | invalidate_icache(); | 665 | invalidate_icache(); |