diff options
author | Michal Simek <monstr@monstr.eu> | 2010-04-26 02:54:13 -0400 |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2010-05-06 05:22:00 -0400 |
commit | 3274c5707c22221574b396d140d0db3480a2027a (patch) | |
tree | 914be5462b00a74db910795062f5616baa0a3ce6 /arch | |
parent | 385e1efafc73a5deeb20645ae8b227b4896852e2 (diff) |
microblaze: Optimize CACHE_LOOP_LIMITS and CACHE_RANGE_LOOP macros
1. Remove CACHE_ALL_LOOP2 macro because it is identical to CACHE_ALL_LOOP
2. Change BUG_ON to WARN_ON
3. Remove end aligned from CACHE_LOOP_LIMITS.
C implementation do not need aligned end address and ASM code do aligned
in their macros
4. ASM optimized CACHE_RANGE_LOOP_1/2 macros needs to get aligned end address.
Because end address is compound from start + size, end address is the first address
which is exclude.
Here is the corresponding code which describe it.
+ int align = ~(line_length - 1);
+ end = ((end & align) == end) ? end - line_length : end & align;
a) end is aligned:
it is necessary to subtruct line length because we don't want to work with
next cacheline
b) end address is not aligned:
Just align it to be ready for ASM code.
Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/microblaze/kernel/cpu/cache.c | 62 |
1 files changed, 35 insertions, 27 deletions
diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c index 19dae71dbaaf..21c3a92394de 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,21 @@ 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; \ |
139 | int align = ~(line_length - 1); \ | ||
140 | end = ((end & align) == end) ? end - line_length : end & align; \ | ||
143 | int count = end - start; \ | 141 | int count = end - start; \ |
144 | BUG_ON(count <= 0); \ | 142 | WARN_ON(count < 0); \ |
145 | \ | 143 | \ |
146 | __asm__ __volatile__ (" 1: " #op " %0, %1; \ | 144 | __asm__ __volatile__ (" 1: " #op " %0, %1; \ |
147 | bgtid %1, 1b; \ | 145 | bgtid %1, 1b; \ |
@@ -154,7 +152,9 @@ do { \ | |||
154 | #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \ | 152 | #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \ |
155 | do { \ | 153 | do { \ |
156 | int volatile temp; \ | 154 | int volatile temp; \ |
157 | BUG_ON(end - start <= 0); \ | 155 | int align = ~(line_length - 1); \ |
156 | end = ((end & align) == end) ? end - line_length : end & align; \ | ||
157 | WARN_ON(end - start < 0); \ | ||
158 | \ | 158 | \ |
159 | __asm__ __volatile__ (" 1: " #op " %1, r0; \ | 159 | __asm__ __volatile__ (" 1: " #op " %1, r0; \ |
160 | cmpu %0, %1, %2; \ | 160 | cmpu %0, %1, %2; \ |
@@ -360,8 +360,12 @@ static void __invalidate_dcache_all_noirq_wt(void) | |||
360 | #endif | 360 | #endif |
361 | } | 361 | } |
362 | 362 | ||
363 | /* FIXME this is weird - should be only wdc but not work | 363 | /* FIXME It is blindly invalidation as is expected |
364 | * MS: I am getting bus errors and other weird things */ | 364 | * but can't be called on noMMU in microblaze_cache_init below |
365 | * | ||
366 | * MS: noMMU kernel won't boot if simple wdc is used | ||
367 | * The reason should be that there are discared data which kernel needs | ||
368 | */ | ||
365 | static void __invalidate_dcache_all_wb(void) | 369 | static void __invalidate_dcache_all_wb(void) |
366 | { | 370 | { |
367 | #ifndef ASM_LOOP | 371 | #ifndef ASM_LOOP |
@@ -369,12 +373,12 @@ static void __invalidate_dcache_all_wb(void) | |||
369 | #endif | 373 | #endif |
370 | pr_debug("%s\n", __func__); | 374 | pr_debug("%s\n", __func__); |
371 | #ifdef ASM_LOOP | 375 | #ifdef ASM_LOOP |
372 | CACHE_ALL_LOOP2(cpuinfo.dcache_size, cpuinfo.dcache_line_length, | 376 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, |
373 | wdc.clear) | 377 | wdc) |
374 | #else | 378 | #else |
375 | for (i = 0; i < cpuinfo.dcache_size; | 379 | for (i = 0; i < cpuinfo.dcache_size; |
376 | i += cpuinfo.dcache_line_length) | 380 | i += cpuinfo.dcache_line_length) |
377 | __asm__ __volatile__ ("wdc.clear %0, r0;" \ | 381 | __asm__ __volatile__ ("wdc %0, r0;" \ |
378 | : : "r" (i)); | 382 | : : "r" (i)); |
379 | #endif | 383 | #endif |
380 | } | 384 | } |
@@ -650,7 +654,11 @@ void microblaze_cache_init(void) | |||
650 | } | 654 | } |
651 | } | 655 | } |
652 | } | 656 | } |
653 | invalidate_dcache(); | 657 | /* FIXME Invalidation is done in U-BOOT |
658 | * WT cache: Data is already written to main memory | ||
659 | * WB cache: Discard data on noMMU which caused that kernel doesn't boot | ||
660 | */ | ||
661 | /* invalidate_dcache(); */ | ||
654 | enable_dcache(); | 662 | enable_dcache(); |
655 | 663 | ||
656 | invalidate_icache(); | 664 | invalidate_icache(); |