ARM: 6299/1: errata: TLBIASIDIS and TLBIMVAIS operations can broadcast a faulty ASID
authorWill Deacon <will.deacon@arm.com>
Thu, 5 Aug 2010 10:20:51 +0000 (11:20 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 10 Aug 2010 21:10:54 +0000 (22:10 +0100)
On versions of the Cortex-A9 prior to r2p0, performing TLB invalidations by
ASID match can result in the incorrect ASID being broadcast to other CPUs.
As a consequence of this, the targetted TLB entries are not invalidated
across the system.

This workaround changes the TLB flushing routines to invalidate entries
regardless of the ASID.

Cc: <stable@kernel.org>
Tested-by: Rob Clark <rob@ti.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/Kconfig
arch/arm/include/asm/tlbflush.h

index 232f0c7..e395604 100644 (file)
@@ -1040,6 +1040,18 @@ config PL310_ERRATA_588369
           is not correctly implemented in PL310 as clean lines are not
           invalidated as a result of these operations. Note that this errata
           uses Texas Instrument's secure monitor api.
+
+config ARM_ERRATA_720789
+       bool "ARM errata: TLBIASIDIS and TLBIMVAIS operations can broadcast a faulty ASID"
+       depends on CPU_V7 && SMP
+       help
+         This option enables the workaround for the 720789 Cortex-A9 (prior to
+         r2p0) erratum. A faulty ASID can be sent to the other CPUs for the
+         broadcasted CP15 TLB maintenance operations TLBIASIDIS and TLBIMVAIS.
+         As a consequence of this erratum, some TLB entries which should be
+         invalidated are not, resulting in an incoherency in the system page
+         tables. The workaround changes the TLB flushing routines to invalidate
+         entries regardless of the ASID.
 endmenu
 
 source "arch/arm/common/Kconfig"
index bd863d8..33b546a 100644 (file)
@@ -378,7 +378,11 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
        if (tlb_flag(TLB_V6_I_ASID))
                asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
        if (tlb_flag(TLB_V7_UIS_ASID))
+#ifdef CONFIG_ARM_ERRATA_720789
+               asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc");
+#else
                asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc");
+#endif
 
        if (tlb_flag(TLB_BTB)) {
                /* flush the branch target cache */
@@ -424,7 +428,11 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
        if (tlb_flag(TLB_V6_I_PAGE))
                asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
        if (tlb_flag(TLB_V7_UIS_PAGE))
+#ifdef CONFIG_ARM_ERRATA_720789
+               asm("mcr p15, 0, %0, c8, c3, 3" : : "r" (uaddr & PAGE_MASK) : "cc");
+#else
                asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc");
+#endif
 
        if (tlb_flag(TLB_BTB)) {
                /* flush the branch target cache */