]> Pileus Git - ~andy/linux/blobdiff - arch/arm/include/asm/tlbflush.h
ARM: tlb: don't perform inner-shareable invalidation for local BP ops
[~andy/linux] / arch / arm / include / asm / tlbflush.h
index fdbb9e369745c4b09d776a4568caa52702b7e9a7..84718240340c3ecee7999bf4bfa58868bb8029b4 100644 (file)
@@ -319,6 +319,16 @@ extern struct cpu_tlb_fns cpu_tlb;
 #define tlb_op(f, regs, arg)   __tlb_op(f, "p15, 0, %0, " regs, arg)
 #define tlb_l2_op(f, regs, arg)        __tlb_op(f, "p15, 1, %0, " regs, arg)
 
+static inline void __local_flush_tlb_all(void)
+{
+       const int zero = 0;
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       tlb_op(TLB_V4_U_FULL | TLB_V6_U_FULL, "c8, c7, 0", zero);
+       tlb_op(TLB_V4_D_FULL | TLB_V6_D_FULL, "c8, c6, 0", zero);
+       tlb_op(TLB_V4_I_FULL | TLB_V6_I_FULL, "c8, c5, 0", zero);
+}
+
 static inline void local_flush_tlb_all(void)
 {
        const int zero = 0;
@@ -327,10 +337,8 @@ static inline void local_flush_tlb_all(void)
        if (tlb_flag(TLB_WB))
                dsb();
 
-       tlb_op(TLB_V4_U_FULL | TLB_V6_U_FULL, "c8, c7, 0", zero);
-       tlb_op(TLB_V4_D_FULL | TLB_V6_D_FULL, "c8, c6, 0", zero);
-       tlb_op(TLB_V4_I_FULL | TLB_V6_I_FULL, "c8, c5, 0", zero);
-       tlb_op(TLB_V7_UIS_FULL, "c8, c3, 0", zero);
+       __local_flush_tlb_all();
+       tlb_op(TLB_V7_UIS_FULL, "c8, c7, 0", zero);
 
        if (tlb_flag(TLB_BARRIER)) {
                dsb();
@@ -338,31 +346,69 @@ static inline void local_flush_tlb_all(void)
        }
 }
 
-static inline void local_flush_tlb_mm(struct mm_struct *mm)
+static inline void __flush_tlb_all(void)
 {
        const int zero = 0;
-       const int asid = ASID(mm);
        const unsigned int __tlb_flag = __cpu_tlb_flags;
 
        if (tlb_flag(TLB_WB))
                dsb();
 
+       __local_flush_tlb_all();
+       tlb_op(TLB_V7_UIS_FULL, "c8, c3, 0", zero);
+
+       if (tlb_flag(TLB_BARRIER)) {
+               dsb();
+               isb();
+       }
+}
+
+static inline void __local_flush_tlb_mm(struct mm_struct *mm)
+{
+       const int zero = 0;
+       const int asid = ASID(mm);
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
        if (possible_tlb_flags & (TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) {
-               if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) {
+               if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) {
                        tlb_op(TLB_V4_U_FULL, "c8, c7, 0", zero);
                        tlb_op(TLB_V4_D_FULL, "c8, c6, 0", zero);
                        tlb_op(TLB_V4_I_FULL, "c8, c5, 0", zero);
                }
-               put_cpu();
        }
 
        tlb_op(TLB_V6_U_ASID, "c8, c7, 2", asid);
        tlb_op(TLB_V6_D_ASID, "c8, c6, 2", asid);
        tlb_op(TLB_V6_I_ASID, "c8, c5, 2", asid);
+}
+
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
+{
+       const int asid = ASID(mm);
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       if (tlb_flag(TLB_WB))
+               dsb();
+
+       __local_flush_tlb_mm(mm);
+       tlb_op(TLB_V7_UIS_ASID, "c8, c7, 2", asid);
+
+       if (tlb_flag(TLB_BARRIER))
+               dsb();
+}
+
+static inline void __flush_tlb_mm(struct mm_struct *mm)
+{
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       if (tlb_flag(TLB_WB))
+               dsb();
+
+       __local_flush_tlb_mm(mm);
 #ifdef CONFIG_ARM_ERRATA_720789
-       tlb_op(TLB_V7_UIS_ASID, "c8, c3, 0", zero);
+       tlb_op(TLB_V7_UIS_ASID, "c8, c3, 0", 0);
 #else
-       tlb_op(TLB_V7_UIS_ASID, "c8, c3, 2", asid);
+       tlb_op(TLB_V7_UIS_ASID, "c8, c3, 2", ASID(mm));
 #endif
 
        if (tlb_flag(TLB_BARRIER))
@@ -370,16 +416,13 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
 }
 
 static inline void
-local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+__local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
 {
        const int zero = 0;
        const unsigned int __tlb_flag = __cpu_tlb_flags;
 
        uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
 
-       if (tlb_flag(TLB_WB))
-               dsb();
-
        if (possible_tlb_flags & (TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) &&
            cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
                tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", uaddr);
@@ -392,6 +435,36 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
        tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", uaddr);
        tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", uaddr);
        tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", uaddr);
+}
+
+static inline void
+local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+{
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
+
+       if (tlb_flag(TLB_WB))
+               dsb();
+
+       __local_flush_tlb_page(vma, uaddr);
+       tlb_op(TLB_V7_UIS_PAGE, "c8, c7, 1", uaddr);
+
+       if (tlb_flag(TLB_BARRIER))
+               dsb();
+}
+
+static inline void
+__flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+{
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
+
+       if (tlb_flag(TLB_WB))
+               dsb();
+
+       __local_flush_tlb_page(vma, uaddr);
 #ifdef CONFIG_ARM_ERRATA_720789
        tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", uaddr & PAGE_MASK);
 #else
@@ -402,16 +475,11 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
                dsb();
 }
 
-static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
+static inline void __local_flush_tlb_kernel_page(unsigned long kaddr)
 {
        const int zero = 0;
        const unsigned int __tlb_flag = __cpu_tlb_flags;
 
-       kaddr &= PAGE_MASK;
-
-       if (tlb_flag(TLB_WB))
-               dsb();
-
        tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", kaddr);
        tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", kaddr);
        tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", kaddr);
@@ -421,6 +489,36 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
        tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", kaddr);
        tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", kaddr);
        tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", kaddr);
+}
+
+static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
+{
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       kaddr &= PAGE_MASK;
+
+       if (tlb_flag(TLB_WB))
+               dsb();
+
+       __local_flush_tlb_kernel_page(kaddr);
+       tlb_op(TLB_V7_UIS_PAGE, "c8, c7, 1", kaddr);
+
+       if (tlb_flag(TLB_BARRIER)) {
+               dsb();
+               isb();
+       }
+}
+
+static inline void __flush_tlb_kernel_page(unsigned long kaddr)
+{
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       kaddr &= PAGE_MASK;
+
+       if (tlb_flag(TLB_WB))
+               dsb();
+
+       __local_flush_tlb_kernel_page(kaddr);
        tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", kaddr);
 
        if (tlb_flag(TLB_BARRIER)) {
@@ -429,21 +527,51 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
        }
 }
 
+/*
+ * Branch predictor maintenance is paired with full TLB invalidation, so
+ * there is no need for any barriers here.
+ */
+static inline void __local_flush_bp_all(void)
+{
+       const int zero = 0;
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       if (tlb_flag(TLB_V6_BP))
+               asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero));
+}
+
 static inline void local_flush_bp_all(void)
 {
        const int zero = 0;
        const unsigned int __tlb_flag = __cpu_tlb_flags;
 
+       __local_flush_bp_all();
        if (tlb_flag(TLB_V7_UIS_BP))
-               asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero));
-       else if (tlb_flag(TLB_V6_BP))
                asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero));
+}
 
-       if (tlb_flag(TLB_BARRIER))
-               isb();
+static inline void __flush_bp_all(void)
+{
+       const int zero = 0;
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       __local_flush_bp_all();
+       if (tlb_flag(TLB_V7_UIS_BP))
+               asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero));
 }
 
+#include <asm/cputype.h>
 #ifdef CONFIG_ARM_ERRATA_798181
+static inline int erratum_a15_798181(void)
+{
+       unsigned int midr = read_cpuid_id();
+
+       /* Cortex-A15 r0p0..r3p2 affected */
+       if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2)
+               return 0;
+       return 1;
+}
+
 static inline void dummy_flush_tlb_a15_erratum(void)
 {
        /*
@@ -453,6 +581,11 @@ static inline void dummy_flush_tlb_a15_erratum(void)
        dsb();
 }
 #else
+static inline int erratum_a15_798181(void)
+{
+       return 0;
+}
+
 static inline void dummy_flush_tlb_a15_erratum(void)
 {
 }