aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/setup.c
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/arm/kernel/setup.c
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/arm/kernel/setup.c')
-rw-r--r--arch/arm/kernel/setup.c39
1 files changed, 36 insertions, 3 deletions
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