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>
This commit is contained in:
committed by
Russell King
parent
f8b63c184a
commit
8925ec4c53
@@ -6,6 +6,7 @@
|
|||||||
#define CACHEID_VIPT_ALIASING (1 << 2)
|
#define CACHEID_VIPT_ALIASING (1 << 2)
|
||||||
#define CACHEID_VIPT (CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING)
|
#define CACHEID_VIPT (CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING)
|
||||||
#define CACHEID_ASID_TAGGED (1 << 3)
|
#define CACHEID_ASID_TAGGED (1 << 3)
|
||||||
|
#define CACHEID_VIPT_I_ALIASING (1 << 4)
|
||||||
|
|
||||||
extern unsigned int cacheid;
|
extern unsigned int cacheid;
|
||||||
|
|
||||||
@@ -14,15 +15,18 @@ extern unsigned int cacheid;
|
|||||||
#define cache_is_vipt_nonaliasing() cacheid_is(CACHEID_VIPT_NONALIASING)
|
#define cache_is_vipt_nonaliasing() cacheid_is(CACHEID_VIPT_NONALIASING)
|
||||||
#define cache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_ALIASING)
|
#define cache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_ALIASING)
|
||||||
#define icache_is_vivt_asid_tagged() cacheid_is(CACHEID_ASID_TAGGED)
|
#define icache_is_vivt_asid_tagged() cacheid_is(CACHEID_ASID_TAGGED)
|
||||||
|
#define icache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_I_ALIASING)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* __LINUX_ARM_ARCH__ is the minimum supported CPU architecture
|
* __LINUX_ARM_ARCH__ is the minimum supported CPU architecture
|
||||||
* Mask out support which will never be present on newer CPUs.
|
* Mask out support which will never be present on newer CPUs.
|
||||||
* - v6+ is never VIVT
|
* - v6+ is never VIVT
|
||||||
* - v7+ VIPT never aliases
|
* - v7+ VIPT never aliases on D-side
|
||||||
*/
|
*/
|
||||||
#if __LINUX_ARM_ARCH__ >= 7
|
#if __LINUX_ARM_ARCH__ >= 7
|
||||||
#define __CACHEID_ARCH_MIN (CACHEID_VIPT_NONALIASING | CACHEID_ASID_TAGGED)
|
#define __CACHEID_ARCH_MIN (CACHEID_VIPT_NONALIASING |\
|
||||||
|
CACHEID_ASID_TAGGED |\
|
||||||
|
CACHEID_VIPT_I_ALIASING)
|
||||||
#elif __LINUX_ARM_ARCH__ >= 6
|
#elif __LINUX_ARM_ARCH__ >= 6
|
||||||
#define __CACHEID_ARCH_MIN (~CACHEID_VIVT)
|
#define __CACHEID_ARCH_MIN (~CACHEID_VIVT)
|
||||||
#else
|
#else
|
||||||
|
@@ -238,6 +238,34 @@ int cpu_architecture(void)
|
|||||||
return cpu_arch;
|
return cpu_arch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cpu_has_aliasing_icache(unsigned int arch)
|
||||||
|
{
|
||||||
|
int aliasing_icache;
|
||||||
|
unsigned int id_reg, num_sets, line_size;
|
||||||
|
|
||||||
|
/* arch specifies the register format */
|
||||||
|
switch (arch) {
|
||||||
|
case CPU_ARCH_ARMv7:
|
||||||
|
asm("mcr p15, 2, %1, c0, c0, 0 @ set CSSELR\n"
|
||||||
|
"isb\n"
|
||||||
|
"mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR"
|
||||||
|
: "=r" (id_reg)
|
||||||
|
: "r" (1));
|
||||||
|
line_size = 4 << ((id_reg & 0x7) + 2);
|
||||||
|
num_sets = ((id_reg >> 13) & 0x7fff) + 1;
|
||||||
|
aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
|
||||||
|
break;
|
||||||
|
case CPU_ARCH_ARMv6:
|
||||||
|
aliasing_icache = read_cpuid_cachetype() & (1 << 11);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* I-cache aliases will be handled by D-cache aliasing code */
|
||||||
|
aliasing_icache = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return aliasing_icache;
|
||||||
|
}
|
||||||
|
|
||||||
static void __init cacheid_init(void)
|
static void __init cacheid_init(void)
|
||||||
{
|
{
|
||||||
unsigned int cachetype = read_cpuid_cachetype();
|
unsigned int cachetype = read_cpuid_cachetype();
|
||||||
@@ -249,10 +277,15 @@ static void __init cacheid_init(void)
|
|||||||
cacheid = CACHEID_VIPT_NONALIASING;
|
cacheid = CACHEID_VIPT_NONALIASING;
|
||||||
if ((cachetype & (3 << 14)) == 1 << 14)
|
if ((cachetype & (3 << 14)) == 1 << 14)
|
||||||
cacheid |= CACHEID_ASID_TAGGED;
|
cacheid |= CACHEID_ASID_TAGGED;
|
||||||
} else if (cachetype & (1 << 23))
|
else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
|
||||||
|
cacheid |= CACHEID_VIPT_I_ALIASING;
|
||||||
|
} else if (cachetype & (1 << 23)) {
|
||||||
cacheid = CACHEID_VIPT_ALIASING;
|
cacheid = CACHEID_VIPT_ALIASING;
|
||||||
else
|
} else {
|
||||||
cacheid = CACHEID_VIPT_NONALIASING;
|
cacheid = CACHEID_VIPT_NONALIASING;
|
||||||
|
if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6))
|
||||||
|
cacheid |= CACHEID_VIPT_I_ALIASING;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cacheid = CACHEID_VIVT;
|
cacheid = CACHEID_VIVT;
|
||||||
}
|
}
|
||||||
@@ -263,7 +296,7 @@ static void __init cacheid_init(void)
|
|||||||
cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown",
|
cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown",
|
||||||
cache_is_vivt() ? "VIVT" :
|
cache_is_vivt() ? "VIVT" :
|
||||||
icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
|
icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
|
||||||
cache_is_vipt_aliasing() ? "VIPT aliasing" :
|
icache_is_vipt_aliasing() ? "VIPT aliasing" :
|
||||||
cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
|
cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user