diff options
-rw-r--r-- | arch/arm/Kconfig | 9 | ||||
-rw-r--r-- | arch/arm/mm/cache-v6.S | 33 | ||||
-rw-r--r-- | arch/arm/mm/flush.c | 23 |
3 files changed, 63 insertions, 2 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 99875dd06f50..e28a76bd1793 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -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" diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index 2c6c2a7c05a0..8f5c13f4c936 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S @@ -20,6 +20,31 @@ #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,8 +56,12 @@ 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 mov pc, lr @@ -103,8 +132,12 @@ 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 mov pc, lr diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 4e283481cee1..c07222eb5ce0 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -18,6 +18,10 @@ #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 } } |