diff options
author | Marek Szyprowski <m.szyprowski@samsung.com> | 2019-05-15 09:53:55 +0200 |
---|---|---|
committer | Marek Szyprowski <m.szyprowski@samsung.com> | 2019-05-15 12:55:38 +0200 |
commit | 493d0bdbcf660d92a31c4ca492beb6eabb5e47b1 (patch) | |
tree | 66810eff42ab0c025e2970ce0d35364d332abd5c | |
parent | 5612984b6ef7e17578e0cadb407f578a6139e70e (diff) | |
download | linux-exynos-493d0bdbcf660d92a31c4ca492beb6eabb5e47b1.tar.gz linux-exynos-493d0bdbcf660d92a31c4ca492beb6eabb5e47b1.tar.bz2 linux-exynos-493d0bdbcf660d92a31c4ca492beb6eabb5e47b1.zip |
ARM: Add workaround for I-Cache line size mismatch between CPU cores
Some big.LITTLE systems have mismatch of I-Cache line size between
LITTLE and big cores. This patch adds workaround for proper I-Cache
support on such systems. Without it, some code (typically self-modifying)
might suffer from random SIGILL failures.
Similar workaround exists for ARM64 architecture, added by commit
116c81f427ff ("arm64: Work around systems with mismatched cache line
sizes").
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Change-Id: I76e1cb24cde91dbfd5a16bd8d5dc97c7953767ff
-rw-r--r-- | arch/arm/include/asm/cacheflush.h | 7 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 1 | ||||
-rw-r--r-- | arch/arm/mm/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/mm/cache-v7.S | 13 | ||||
-rw-r--r-- | arch/arm/mm/init.c | 16 | ||||
-rw-r--r-- | arch/arm/mm/mm.h | 2 |
6 files changed, 47 insertions, 0 deletions
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 74504b154256..060edfc1c972 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -481,4 +481,11 @@ static inline void __sync_cache_range_r(volatile void *p, size_t size) void flush_uprobe_xol_access(struct page *page, unsigned long uaddr, void *kaddr, unsigned long len); + +#ifdef CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND +void check_cpu_icache_size(int cpuid); +#else +static inline void check_cpu_icache_size(int cpuid) { } +#endif + #endif diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 80811a4e46f6..1865625db2d6 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -347,6 +347,7 @@ static void smp_store_cpu_info(unsigned int cpuid) cpu_info->cpuid = read_cpuid_id(); store_cpu_topology(cpuid); + check_cpu_icache_size(cpuid); } /* diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 50e0b45a22db..54c533135ffa 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -786,6 +786,14 @@ config CPU_ICACHE_DISABLE Say Y here to disable the processor instruction cache. Unless you have a reason not to or are unsure, say N. +config CPU_ICACHE_MISMATCH_WORKAROUND + bool "Workaround for I-Cache line size mismatch between CPU cores" + depends on (SMP && CPU_V7) + help + Some big.LITTLE systems have mismatch of I-Cache line size between + LITTLE and big cores. Say Y here to enable workaround for proper + I-Cache support on such systems. If unsure, say N. + config CPU_DCACHE_DISABLE bool "Disable D-Cache (C-bit)" depends on (CPU_CP15 && !SMP) || CPU_V7M diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index 50a70edbc863..69cfee658794 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -18,6 +18,14 @@ #include "proc-macros.S" +#ifdef CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND +.globl icache_size + .data + .align 2 +icache_size: + .long 64 + .text +#endif /* * The secondary kernel init calls v7_flush_dcache_all before it enables * the L1; however, the L1 comes out of reset in an undefined state, so @@ -283,7 +291,12 @@ ENTRY(v7_coherent_user_range) cmp r12, r1 blo 1b dsb ishst +#ifdef CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND + ldr r3, =icache_size + ldr r2, [r3, #0] +#else icache_line_size r2, r3 +#endif sub r3, r2, #1 bic r12, r0, r3 2: diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index defb7fc26428..57d3643538ac 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -277,6 +277,22 @@ static void __init arm_initrd_init(void) #endif } +#ifdef CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND +void check_cpu_icache_size(int cpuid) +{ + u32 size, ctr; + + asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr)); + + size = 1 << ((ctr & 0xf) + 2); + if (cpuid != 0 && icache_size != size) + pr_info("CPU%u: detected I-Cache line size mismatch, workaround enabled\n", + cpuid); + if (icache_size > size) + icache_size = size; +} +#endif + void __init arm_memblock_init(const struct machine_desc *mdesc) { /* Register the kernel text, kernel data and initrd with memblock. */ diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index 6b045c6653ea..941356d95a67 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h @@ -8,6 +8,8 @@ /* the upper-most page table pointer */ extern pmd_t *top_pmd; +extern int icache_size; + /* * 0xffff8000 to 0xffffffff is reserved for any ARM architecture * specific hacks for copying pages efficiently, while 0xffff4000 |