powerpc/mm: Update tlbiel loop on POWER10
authorAneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Wed, 7 Oct 2020 05:33:05 +0000 (11:03 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 19 Nov 2020 03:50:15 +0000 (14:50 +1100)
With POWER10, single tlbiel instruction invalidates all the congruence
class of the TLB and hence we need to issue only one tlbiel with SET=0.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20201007053305.232879-1-aneesh.kumar@linux.ibm.com
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_builtin.c
arch/powerpc/mm/book3s64/radix_tlb.c

index e3b1839..0faafe6 100644 (file)
@@ -4949,7 +4949,12 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
         * Work out how many sets the TLB has, for the use of
         * the TLB invalidation loop in book3s_hv_rmhandlers.S.
         */
-       if (radix_enabled())
+       if (cpu_has_feature(CPU_FTR_ARCH_31)) {
+               /*
+                * P10 will flush all the congruence class with a single tlbiel
+                */
+               kvm->arch.tlb_sets = 1;
+       } else if (radix_enabled())
                kvm->arch.tlb_sets = POWER9_TLB_SETS_RADIX;     /* 128 */
        else if (cpu_has_feature(CPU_FTR_ARCH_300))
                kvm->arch.tlb_sets = POWER9_TLB_SETS_HASH;      /* 256 */
index 8f58dd2..8053efd 100644 (file)
@@ -694,6 +694,7 @@ static void wait_for_sync(struct kvm_split_mode *sip, int phase)
 
 void kvmhv_p9_set_lpcr(struct kvm_split_mode *sip)
 {
+       int num_sets;
        unsigned long rb, set;
 
        /* wait for every other thread to get to real mode */
@@ -704,11 +705,19 @@ void kvmhv_p9_set_lpcr(struct kvm_split_mode *sip)
        mtspr(SPRN_LPID, sip->lpidr_req);
        isync();
 
+       /*
+        * P10 will flush all the congruence class with a single tlbiel
+        */
+       if (cpu_has_feature(CPU_FTR_ARCH_31))
+               num_sets =  1;
+       else
+               num_sets = POWER9_TLB_SETS_RADIX;
+
        /* Invalidate the TLB on thread 0 */
        if (local_paca->kvm_hstate.tid == 0) {
                sip->do_set = 0;
                asm volatile("ptesync" : : : "memory");
-               for (set = 0; set < POWER9_TLB_SETS_RADIX; ++set) {
+               for (set = 0; set < num_sets; ++set) {
                        rb = TLBIEL_INVAL_SET_LPID +
                                (set << TLBIEL_INVAL_SET_SHIFT);
                        asm volatile(PPC_TLBIEL(%0, %1, 0, 0, 0) : :
index b487b48..fb66d15 100644 (file)
@@ -56,14 +56,21 @@ static void tlbiel_all_isa300(unsigned int num_sets, unsigned int is)
        if (early_cpu_has_feature(CPU_FTR_HVMODE)) {
                /* MSR[HV] should flush partition scope translations first. */
                tlbiel_radix_set_isa300(0, is, 0, RIC_FLUSH_ALL, 0);
-               for (set = 1; set < num_sets; set++)
-                       tlbiel_radix_set_isa300(set, is, 0, RIC_FLUSH_TLB, 0);
+
+               if (!early_cpu_has_feature(CPU_FTR_ARCH_31)) {
+                       for (set = 1; set < num_sets; set++)
+                               tlbiel_radix_set_isa300(set, is, 0,
+                                                       RIC_FLUSH_TLB, 0);
+               }
        }
 
        /* Flush process scoped entries. */
        tlbiel_radix_set_isa300(0, is, 0, RIC_FLUSH_ALL, 1);
-       for (set = 1; set < num_sets; set++)
-               tlbiel_radix_set_isa300(set, is, 0, RIC_FLUSH_TLB, 1);
+
+       if (!early_cpu_has_feature(CPU_FTR_ARCH_31)) {
+               for (set = 1; set < num_sets; set++)
+                       tlbiel_radix_set_isa300(set, is, 0, RIC_FLUSH_TLB, 1);
+       }
 
        ppc_after_tlbiel_barrier();
 }
@@ -300,9 +307,11 @@ static __always_inline void _tlbiel_pid(unsigned long pid, unsigned long ric)
                return;
        }
 
-       /* For the remaining sets, just flush the TLB */
-       for (set = 1; set < POWER9_TLB_SETS_RADIX ; set++)
-               __tlbiel_pid(pid, set, RIC_FLUSH_TLB);
+       if (!cpu_has_feature(CPU_FTR_ARCH_31)) {
+               /* For the remaining sets, just flush the TLB */
+               for (set = 1; set < POWER9_TLB_SETS_RADIX ; set++)
+                       __tlbiel_pid(pid, set, RIC_FLUSH_TLB);
+       }
 
        ppc_after_tlbiel_barrier();
        asm volatile(PPC_RADIX_INVALIDATE_ERAT_USER "; isync" : : :"memory");