ARM: 8864/1: Add workaround for I-Cache line size mismatch between CPU cores
authorMarek Szyprowski <m.szyprowski@samsung.com>
Tue, 28 May 2019 08:38:14 +0000 (09:38 +0100)
committerRussell King <rmk+kernel@armlinux.org.uk>
Thu, 20 Jun 2019 21:29:58 +0000 (22:29 +0100)
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>
arch/arm/configs/exynos_defconfig
arch/arm/include/asm/cacheflush.h
arch/arm/kernel/smp.c
arch/arm/mm/Kconfig
arch/arm/mm/cache-v7.S
arch/arm/mm/init.c
arch/arm/mm/mm.h

index c95c542..9b959af 100644 (file)
@@ -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
index ec1a5fd..ec4fd2e 100644 (file)
@@ -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
index ebc5380..12cf7c4 100644 (file)
@@ -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);
 }
 
 /*
index b169e58..cc79811 100644 (file)
@@ -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
index 2149b47..db39867 100644 (file)
 
 #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:
index be0b429..1a66af5 100644 (file)
@@ -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. */
index 6b045c6..941356d 100644 (file)
@@ -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