summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Szyprowski <m.szyprowski@samsung.com>2019-05-28 11:38:14 +0300
committerRussell King <rmk+kernel@armlinux.org.uk>2019-06-21 00:29:58 +0300
commit5f41f9198f296091c6a58bc2e86af1e9f019b2a3 (patch)
treef309f6b56520b0b974c46cff4de32b3d8decc1c1
parent304009a182b9fc6eff74060b415c8240380501cb (diff)
downloadlinux-5f41f9198f296091c6a58bc2e86af1e9f019b2a3.tar.xz
ARM: 8864/1: Add workaround for I-Cache line size mismatch between CPU cores
Some big.LITTLE systems have I-Cache line size mismatch between LITTLE and big cores. This patch adds a workaround for proper I-Cache support on such systems. Without it, some class of the userspace code (typically self-modifying) might suffer from random SIGILL failures. Similar workaround already exists for ARM64 architecture. I has been added by commit 116c81f427ff ("arm64: Work around systems with mismatched cache line sizes"). Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--arch/arm/configs/exynos_defconfig1
-rw-r--r--arch/arm/include/asm/cacheflush.h7
-rw-r--r--arch/arm/kernel/smp.c1
-rw-r--r--arch/arm/mm/Kconfig8
-rw-r--r--arch/arm/mm/cache-v7.S13
-rw-r--r--arch/arm/mm/init.c16
-rw-r--r--arch/arm/mm/mm.h2
7 files changed, 48 insertions, 0 deletions
diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig
index c95c54284da2..9b959afaaa12 100644
--- a/arch/arm/configs/exynos_defconfig
+++ b/arch/arm/configs/exynos_defconfig
@@ -9,6 +9,7 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_ARCH_EXYNOS=y
CONFIG_ARCH_EXYNOS3=y
+CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND=y
CONFIG_SMP=y
CONFIG_BIG_LITTLE=y
CONFIG_NR_CPUS=8
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index ec1a5fd0d294..ec4fd2e2dd60 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -479,4 +479,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 ebc53804d57b..12cf7c4324a9 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -375,6 +375,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 b169e580bf82..cc798115aa9b 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -780,6 +780,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 I-Cache line size mismatch between
+ LITTLE and big cores. Say Y here to enable a 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 2149b47a0c5a..db3986708c8a 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -19,6 +19,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
@@ -284,7 +292,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 be0b42937888..1a66af5bd259 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -242,6 +242,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