[ARM] 5488/1: ARM errata: Invalidation of the Instruction Cache operation can fail
authorCatalin Marinas <catalin.marinas@arm.com>
Thu, 30 Apr 2009 16:06:03 +0000 (17:06 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 30 Apr 2009 19:12:47 +0000 (20:12 +0100)
This patch implements the recommended workaround for erratum 411920
(ARM1136, ARM1156, ARM1176).

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/Kconfig
arch/arm/mm/cache-v6.S
arch/arm/mm/flush.c

index 99875dd06f507bec97ceab05783320af5a17bf61..e28a76bd17936022fde2828680b1c14de9b46e31 100644 (file)
@@ -740,6 +740,15 @@ if !MMU
 source "arch/arm/Kconfig-nommu"
 endif
 
+config ARM_ERRATA_411920
+       bool "ARM errata: Invalidation of the Instruction Cache operation can fail"
+       depends on CPU_V6 && !SMP
+       help
+         Invalidation of the Instruction Cache operation can
+         fail. This erratum is present in 1136 (before r1p4), 1156 and 1176.
+         It does not affect the MPCore. This option enables the ARM Ltd.
+         recommended workaround.
+
 endmenu
 
 source "arch/arm/common/Kconfig"
index 2c6c2a7c05a0e0df74a77bd4cf68ecd17eb6f8cc..8f5c13f4c93614abbcc37315b8c7a3fbb987d38b 100644 (file)
 #define D_CACHE_LINE_SIZE      32
 #define BTB_FLUSH_SIZE         8
 
+#ifdef CONFIG_ARM_ERRATA_411920
+/*
+ * Invalidate the entire I cache (this code is a workaround for the ARM1136
+ * erratum 411920 - Invalidate Instruction Cache operation can fail. This
+ * erratum is present in 1136, 1156 and 1176. It does not affect the MPCore.
+ *
+ * Registers:
+ *   r0 - set to 0
+ *   r1 - corrupted
+ */
+ENTRY(v6_icache_inval_all)
+       mov     r0, #0
+       mrs     r1, cpsr
+       cpsid   ifa                             @ disable interrupts
+       mcr     p15, 0, r0, c7, c5, 0           @ invalidate entire I-cache
+       mcr     p15, 0, r0, c7, c5, 0           @ invalidate entire I-cache
+       mcr     p15, 0, r0, c7, c5, 0           @ invalidate entire I-cache
+       mcr     p15, 0, r0, c7, c5, 0           @ invalidate entire I-cache
+       msr     cpsr_cx, r1                     @ restore interrupts
+       .rept   11                              @ ARM Ltd recommends at least
+       nop                                     @ 11 NOPs
+       .endr
+       mov     pc, lr
+#endif
+
 /*
  *     v6_flush_cache_all()
  *
@@ -31,7 +56,11 @@ ENTRY(v6_flush_kern_cache_all)
        mov     r0, #0
 #ifdef HARVARD_CACHE
        mcr     p15, 0, r0, c7, c14, 0          @ D cache clean+invalidate
+#ifndef CONFIG_ARM_ERRATA_411920
        mcr     p15, 0, r0, c7, c5, 0           @ I+BTB cache invalidate
+#else
+       b       v6_icache_inval_all
+#endif
 #else
        mcr     p15, 0, r0, c7, c15, 0          @ Cache clean+invalidate
 #endif
@@ -103,7 +132,11 @@ ENTRY(v6_coherent_user_range)
        mov     r0, #0
 #ifdef HARVARD_CACHE
        mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
+#ifndef CONFIG_ARM_ERRATA_411920
        mcr     p15, 0, r0, c7, c5, 0           @ I+BTB cache invalidate
+#else
+       b       v6_icache_inval_all
+#endif
 #else
        mcr     p15, 0, r0, c7, c5, 6           @ invalidate BTB
 #endif
index 4e283481cee126e9697c7320203441a8db27cd78..c07222eb5ce012b141189beb61c191e79ef8d59f 100644 (file)
 
 #include "mm.h"
 
+#ifdef CONFIG_ARM_ERRATA_411920
+extern void v6_icache_inval_all(void);
+#endif
+
 #ifdef CONFIG_CPU_CACHE_VIPT
 
 #define ALIAS_FLUSH_START      0xffff4000
@@ -32,10 +36,15 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
 
        asm(    "mcrr   p15, 0, %1, %0, c14\n"
        "       mcr     p15, 0, %2, c7, c10, 4\n"
+#ifndef CONFIG_ARM_ERRATA_411920
        "       mcr     p15, 0, %2, c7, c5, 0\n"
+#endif
            :
            : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES), "r" (zero)
            : "cc");
+#ifdef CONFIG_ARM_ERRATA_411920
+       v6_icache_inval_all();
+#endif
 }
 
 void flush_cache_mm(struct mm_struct *mm)
@@ -48,11 +57,16 @@ void flush_cache_mm(struct mm_struct *mm)
 
        if (cache_is_vipt_aliasing()) {
                asm(    "mcr    p15, 0, %0, c7, c14, 0\n"
+               "       mcr     p15, 0, %0, c7, c10, 4\n"
+#ifndef CONFIG_ARM_ERRATA_411920
                "       mcr     p15, 0, %0, c7, c5, 0\n"
-               "       mcr     p15, 0, %0, c7, c10, 4"
+#endif
                    :
                    : "r" (0)
                    : "cc");
+#ifdef CONFIG_ARM_ERRATA_411920
+               v6_icache_inval_all();
+#endif
        }
 }
 
@@ -67,11 +81,16 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned
 
        if (cache_is_vipt_aliasing()) {
                asm(    "mcr    p15, 0, %0, c7, c14, 0\n"
+               "       mcr     p15, 0, %0, c7, c10, 4\n"
+#ifndef CONFIG_ARM_ERRATA_411920
                "       mcr     p15, 0, %0, c7, c5, 0\n"
-               "       mcr     p15, 0, %0, c7, c10, 4"
+#endif
                    :
                    : "r" (0)
                    : "cc");
+#ifdef CONFIG_ARM_ERRATA_411920
+               v6_icache_inval_all();
+#endif
        }
 }