aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2010-09-13 11:18:30 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-10-04 15:57:09 -0400
commit8925ec4c530094b878e7e28a1fd78e7122afd973 (patch)
tree2b7200f64892299c185d3a07d1f793ea9217b5d4 /arch
parentf8b63c184ad13cc8adc3dadb557d4fbc29f76e4d (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.h8
-rw-r--r--arch/arm/kernel/setup.c39
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
10extern unsigned int cacheid; 11extern 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
241static 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
241static void __init cacheid_init(void) 269static 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