From 0741f1a58a1255531b0dcb1bea598b08112616e3 Mon Sep 17 00:00:00 2001
From: Catalin Marinas <catalin.marinas@arm.com>
Date: Tue, 13 Feb 2007 13:17:29 +0000
Subject: [PATCH] Workaround for the global I cache invalidation ARM1136 Errata

Errata 411920 - Invalidation of the Instruction Cache operation can
fail. This Errata is present in 1136, 1156 and 1176. It does not
affect the MPCore. This patch implements the ARM Ltd recommended
workaround.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm/mm/cache-v6.S | 41 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mm/flush.c    | 22 +++++++++++++++++-----
 2 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
index 2c6c2a7c05a..c9c4d7baad0 100644
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -20,6 +20,39 @@
 #define D_CACHE_LINE_SIZE	32
 #define BTB_FLUSH_SIZE		8
 
+#ifndef CONFIG_SMP
+/*
+ * Invalidate the entire I cache (this code is a workaround for the ARM1136
+ * Errata 411920 - Invalidate Instruction Cache operation can fail. This
+ * Errata 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
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	mov	pc, lr
+#endif
+
 /*
  *	v6_flush_cache_all()
  *
@@ -31,7 +64,11 @@ ENTRY(v6_flush_kern_cache_all)
 	mov	r0, #0
 #ifdef HARVARD_CACHE
 	mcr	p15, 0, r0, c7, c14, 0		@ D cache clean+invalidate
+#ifdef CONFIG_SMP
 	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 +140,11 @@ ENTRY(v6_coherent_user_range)
 	mov	r0, #0
 #ifdef HARVARD_CACHE
 	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer
+#ifdef CONFIG_SMP
 	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
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 454205b789d..1b33376e04b 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -31,10 +31,14 @@ 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"
+#if __LINUX_ARM_ARCH__ != 6 || defined(CONFIG_SMP)
 	"	mcr	p15, 0, %2, c7, c5, 0\n"
+#else
+	"	bl	v6_icache_inval_all\n"
+#endif
 	    :
 	    : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES), "r" (zero)
-	    : "cc");
+	    : "r0", "r1", "lr");
 }
 
 void flush_cache_mm(struct mm_struct *mm)
@@ -47,11 +51,15 @@ 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"
+#if __LINUX_ARM_ARCH__ != 6 || defined(CONFIG_SMP)
 		"	mcr	p15, 0, %0, c7, c5, 0\n"
-		"	mcr	p15, 0, %0, c7, c10, 4"
+#else
+		"	bl	v6_icache_inval_all\n"
+#endif
 		    :
 		    : "r" (0)
-		    : "cc");
+		    : "r0", "r1", "lr", "cc");
 	}
 }
 
@@ -66,11 +74,15 @@ 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"
+#if __LINUX_ARM_ARCH__ != 6 || defined(CONFIG_SMP)
 		"	mcr	p15, 0, %0, c7, c5, 0\n"
-		"	mcr	p15, 0, %0, c7, c10, 4"
+#else
+		"	bl	v6_icache_inval_all\n"
+#endif
 		    :
 		    : "r" (0)
-		    : "cc");
+		    : "r0", "r1", "lr", "cc");
 	}
 }
 
-- 
2.25.4