Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9cba3ccc authored by Catalin Marinas's avatar Catalin Marinas Committed by Russell King
Browse files

[ARM] 5488/1: ARM errata: Invalidation of the Instruction Cache operation can fail



This patch implements the recommended workaround for erratum 411920
(ARM1136, ARM1156, ARM1176).

Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 10993374
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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"
+33 −0
Original line number Diff line number Diff line
@@ -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,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
+21 −2
Original line number Diff line number Diff line
@@ -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
	}
}