diff options
author | Will Deacon <will.deacon@arm.com> | 2010-09-13 11:18:30 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-10-04 15:57:09 -0400 |
commit | 8925ec4c530094b878e7e28a1fd78e7122afd973 (patch) | |
tree | 2b7200f64892299c185d3a07d1f793ea9217b5d4 /arch | |
parent | f8b63c184ad13cc8adc3dadb557d4fbc29f76e4d (diff) |
ARM: 6385/1: setup: detect aliasing I-cache when D-cache is non-aliasing
Currently, the Kernel assumes that if a CPU has a non-aliasing D-cache
then the I-cache is also non-aliasing. This may not be true on ARM cores
from v6 onwards, which may have aliasing I-caches but non-aliasing
D-caches.
This patch adds a cpu_has_aliasing_icache function, which is called from
cacheid_init and adds CACHEID_VIPT_I_ALIASING to the cacheid when
appropriate. A utility macro, icache_is_vipt_aliasing(), is also
provided.
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/cachetype.h | 8 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 39 |
2 files changed, 42 insertions, 5 deletions
diff --git a/arch/arm/include/asm/cachetype.h b/arch/arm/include/asm/cachetype.h index d3a4c2cb9f2f..c023db09fcc1 100644 --- a/arch/arm/include/asm/cachetype.h +++ b/arch/arm/include/asm/cachetype.h | |||
@@ -6,6 +6,7 @@ | |||
6 | #define CACHEID_VIPT_ALIASING (1 << 2) | 6 | #define CACHEID_VIPT_ALIASING (1 << 2) |
7 | #define CACHEID_VIPT (CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING) | 7 | #define CACHEID_VIPT (CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING) |
8 | #define CACHEID_ASID_TAGGED (1 << 3) | 8 | #define CACHEID_ASID_TAGGED (1 << 3) |
9 | #define CACHEID_VIPT_I_ALIASING (1 << 4) | ||
9 | 10 | ||
10 | extern unsigned int cacheid; | 11 | extern unsigned int cacheid; |
11 | 12 | ||
@@ -14,15 +15,18 @@ extern unsigned int cacheid; | |||
14 | #define cache_is_vipt_nonaliasing() cacheid_is(CACHEID_VIPT_NONALIASING) | 15 | #define cache_is_vipt_nonaliasing() cacheid_is(CACHEID_VIPT_NONALIASING) |
15 | #define cache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_ALIASING) | 16 | #define cache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_ALIASING) |
16 | #define icache_is_vivt_asid_tagged() cacheid_is(CACHEID_ASID_TAGGED) | 17 | #define icache_is_vivt_asid_tagged() cacheid_is(CACHEID_ASID_TAGGED) |
18 | #define icache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_I_ALIASING) | ||
17 | 19 | ||
18 | /* | 20 | /* |
19 | * __LINUX_ARM_ARCH__ is the minimum supported CPU architecture | 21 | * __LINUX_ARM_ARCH__ is the minimum supported CPU architecture |
20 | * Mask out support which will never be present on newer CPUs. | 22 | * Mask out support which will never be present on newer CPUs. |
21 | * - v6+ is never VIVT | 23 | * - v6+ is never VIVT |
22 | * - v7+ VIPT never aliases | 24 | * - v7+ VIPT never aliases on D-side |
23 | */ | 25 | */ |
24 | #if __LINUX_ARM_ARCH__ >= 7 | 26 | #if __LINUX_ARM_ARCH__ >= 7 |
25 | #define __CACHEID_ARCH_MIN (CACHEID_VIPT_NONALIASING | CACHEID_ASID_TAGGED) | 27 | #define __CACHEID_ARCH_MIN (CACHEID_VIPT_NONALIASING |\ |
28 | CACHEID_ASID_TAGGED |\ | ||
29 | CACHEID_VIPT_I_ALIASING) | ||
26 | #elif __LINUX_ARM_ARCH__ >= 6 | 30 | #elif __LINUX_ARM_ARCH__ >= 6 |
27 | #define __CACHEID_ARCH_MIN (~CACHEID_VIVT) | 31 | #define __CACHEID_ARCH_MIN (~CACHEID_VIVT) |
28 | #else | 32 | #else |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index d5231ae7355a..9fc483393bae 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -238,6 +238,34 @@ int cpu_architecture(void) | |||
238 | return cpu_arch; | 238 | return cpu_arch; |
239 | } | 239 | } |
240 | 240 | ||
241 | static int cpu_has_aliasing_icache(unsigned int arch) | ||
242 | { | ||
243 | int aliasing_icache; | ||
244 | unsigned int id_reg, num_sets, line_size; | ||
245 | |||
246 | /* arch specifies the register format */ | ||
247 | switch (arch) { | ||
248 | case CPU_ARCH_ARMv7: | ||
249 | asm("mcr p15, 2, %1, c0, c0, 0 @ set CSSELR\n" | ||
250 | "isb\n" | ||
251 | "mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR" | ||
252 | : "=r" (id_reg) | ||
253 | : "r" (1)); | ||
254 | line_size = 4 << ((id_reg & 0x7) + 2); | ||
255 | num_sets = ((id_reg >> 13) & 0x7fff) + 1; | ||
256 | aliasing_icache = (line_size * num_sets) > PAGE_SIZE; | ||
257 | break; | ||
258 | case CPU_ARCH_ARMv6: | ||
259 | aliasing_icache = read_cpuid_cachetype() & (1 << 11); | ||
260 | break; | ||
261 | default: | ||
262 | /* I-cache aliases will be handled by D-cache aliasing code */ | ||
263 | aliasing_icache = 0; | ||
264 | } | ||
265 | |||
266 | return aliasing_icache; | ||
267 | } | ||
268 | |||
241 | static void __init cacheid_init(void) | 269 | static void __init cacheid_init(void) |
242 | { | 270 | { |
243 | unsigned int cachetype = read_cpuid_cachetype(); | 271 | unsigned int cachetype = read_cpuid_cachetype(); |
@@ -249,10 +277,15 @@ static void __init cacheid_init(void) | |||
249 | cacheid = CACHEID_VIPT_NONALIASING; | 277 | cacheid = CACHEID_VIPT_NONALIASING; |
250 | if ((cachetype & (3 << 14)) == 1 << 14) | 278 | if ((cachetype & (3 << 14)) == 1 << 14) |
251 | cacheid |= CACHEID_ASID_TAGGED; | 279 | cacheid |= CACHEID_ASID_TAGGED; |
252 | } else if (cachetype & (1 << 23)) | 280 | else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7)) |
281 | cacheid |= CACHEID_VIPT_I_ALIASING; | ||
282 | } else if (cachetype & (1 << 23)) { | ||
253 | cacheid = CACHEID_VIPT_ALIASING; | 283 | cacheid = CACHEID_VIPT_ALIASING; |
254 | else | 284 | } else { |
255 | cacheid = CACHEID_VIPT_NONALIASING; | 285 | cacheid = CACHEID_VIPT_NONALIASING; |
286 | if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6)) | ||
287 | cacheid |= CACHEID_VIPT_I_ALIASING; | ||
288 | } | ||
256 | } else { | 289 | } else { |
257 | cacheid = CACHEID_VIVT; | 290 | cacheid = CACHEID_VIVT; |
258 | } | 291 | } |
@@ -263,7 +296,7 @@ static void __init cacheid_init(void) | |||
263 | cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown", | 296 | cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown", |
264 | cache_is_vivt() ? "VIVT" : | 297 | cache_is_vivt() ? "VIVT" : |
265 | icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : | 298 | icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : |
266 | cache_is_vipt_aliasing() ? "VIPT aliasing" : | 299 | icache_is_vipt_aliasing() ? "VIPT aliasing" : |
267 | cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); | 300 | cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); |
268 | } | 301 | } |
269 | 302 | ||