ARM: tlb: reduce scope of barrier domains for TLB invalidation
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / arm / include / asm / tlbflush.h
index f467e9b..3896026 100644 (file)
@@ -319,67 +319,110 @@ 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)
+static inline void __local_flush_tlb_all(void)
 {
        const int zero = 0;
        const unsigned int __tlb_flag = __cpu_tlb_flags;
 
-       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);
+}
+
+static inline void local_flush_tlb_all(void)
+{
+       const int zero = 0;
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       if (tlb_flag(TLB_WB))
+               dsb(nshst);
+
+       __local_flush_tlb_all();
+       tlb_op(TLB_V7_UIS_FULL, "c8, c7, 0", zero);
 
        if (tlb_flag(TLB_BARRIER)) {
-               dsb();
+               dsb(nsh);
                isb();
        }
 }
 
-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();
+               dsb(ishst);
+
+       __local_flush_tlb_all();
+       tlb_op(TLB_V7_UIS_FULL, "c8, c3, 0", zero);
+
+       if (tlb_flag(TLB_BARRIER)) {
+               dsb(ish);
+               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(nshst);
+
+       __local_flush_tlb_mm(mm);
+       tlb_op(TLB_V7_UIS_ASID, "c8, c7, 2", asid);
+
+       if (tlb_flag(TLB_BARRIER))
+               dsb(nsh);
+}
+
+static inline void __flush_tlb_mm(struct mm_struct *mm)
+{
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+
+       if (tlb_flag(TLB_WB))
+               dsb(ishst);
+
+       __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))
-               dsb();
+               dsb(ish);
 }
 
 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(nshst);
+
+       __local_flush_tlb_page(vma, uaddr);
+       tlb_op(TLB_V7_UIS_PAGE, "c8, c7, 1", uaddr);
+
+       if (tlb_flag(TLB_BARRIER))
+               dsb(nsh);
+}
+
+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(ishst);
+
+       __local_flush_tlb_page(vma, uaddr);
 #ifdef CONFIG_ARM_ERRATA_720789
        tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", uaddr & PAGE_MASK);
 #else
@@ -399,19 +472,14 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
 #endif
 
        if (tlb_flag(TLB_BARRIER))
-               dsb();
+               dsb(ish);
 }
 
-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,26 +489,75 @@ 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(nshst);
+
+       __local_flush_tlb_kernel_page(kaddr);
+       tlb_op(TLB_V7_UIS_PAGE, "c8, c7, 1", kaddr);
+
+       if (tlb_flag(TLB_BARRIER)) {
+               dsb(nsh);
+               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(ishst);
+
+       __local_flush_tlb_kernel_page(kaddr);
        tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", kaddr);
 
        if (tlb_flag(TLB_BARRIER)) {
-               dsb();
+               dsb(ish);
                isb();
        }
 }
 
+/*
+ * 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>
@@ -461,7 +578,7 @@ static inline void dummy_flush_tlb_a15_erratum(void)
         * Dummy TLBIMVAIS. Using the unmapped address 0 and ASID 0.
         */
        asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0));
-       dsb();
+       dsb(ish);
 }
 #else
 static inline int erratum_a15_798181(void)
@@ -495,7 +612,7 @@ static inline void flush_pmd_entry(void *pmd)
        tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1  @ L2 flush_pmd", pmd);
 
        if (tlb_flag(TLB_WB))
-               dsb();
+               dsb(ishst);
 }
 
 static inline void clean_pmd_entry(void *pmd)