powerpc/mm/hash: Reduce contention on hpte lock
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Fri, 29 Jun 2018 08:36:31 +0000 (14:06 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 24 Jul 2018 12:03:18 +0000 (22:03 +1000)
We do this in some part. This patch make sure we always try to search
for hpte without holding lock and redo the compare with lock held once
match found.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/mm/hash_native_64.c

index 68e6eaf41bb927e9cbc16a013d4eaa175f03af14..ffbd5ed4e8de94886c33b7661e76341d8a213d46 100644 (file)
@@ -568,9 +568,19 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
        DBG_LOW("    invalidate(vpn=%016lx, hash: %lx)\n", vpn, slot);
 
        want_v = hpte_encode_avpn(vpn, bpsize, ssize);
-       native_lock_hpte(hptep);
        hpte_v = hpte_get_old_v(hptep);
 
+       if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID)) {
+               native_lock_hpte(hptep);
+               /* recheck with locks held */
+               hpte_v = hpte_get_old_v(hptep);
+
+               if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID))
+                       /* Invalidate the hpte. NOTE: this also unlocks it */
+                       hptep->v = 0;
+               else
+                       native_unlock_hpte(hptep);
+       }
        /*
         * We need to invalidate the TLB always because hpte_remove doesn't do
         * a tlb invalidate. If a hash bucket gets full, we "evict" a more/less
@@ -578,13 +588,6 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
         * (hpte_remove) because we assume the old translation is still
         * technically "valid".
         */
-       if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID))
-               native_unlock_hpte(hptep);
-       else
-               /* Invalidate the hpte. NOTE: this also unlocks it */
-               hptep->v = 0;
-
-       /* Invalidate the TLB */
        tlbie(vpn, bpsize, apsize, ssize, local);
 
        local_irq_restore(flags);
@@ -626,15 +629,23 @@ static void native_hugepage_invalidate(unsigned long vsid,
 
                hptep = htab_address + slot;
                want_v = hpte_encode_avpn(vpn, psize, ssize);
-               native_lock_hpte(hptep);
                hpte_v = hpte_get_old_v(hptep);
 
                /* Even if we miss, we need to invalidate the TLB */
-               if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID))
-                       native_unlock_hpte(hptep);
-               else
-                       /* Invalidate the hpte. NOTE: this also unlocks it */
-                       hptep->v = 0;
+               if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID)) {
+                       /* recheck with locks held */
+                       native_lock_hpte(hptep);
+                       hpte_v = hpte_get_old_v(hptep);
+
+                       if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID)) {
+                               /*
+                                * Invalidate the hpte. NOTE: this also unlocks it
+                                */
+
+                               hptep->v = 0;
+                       } else
+                               native_unlock_hpte(hptep);
+               }
                /*
                 * We need to do tlb invalidate for all the address, tlbie
                 * instruction compares entry_VA in tlb with the VA specified
@@ -802,13 +813,19 @@ static void native_flush_hash_range(unsigned long number, int local)
                        slot += hidx & _PTEIDX_GROUP_IX;
                        hptep = htab_address + slot;
                        want_v = hpte_encode_avpn(vpn, psize, ssize);
+                       hpte_v = hpte_get_old_v(hptep);
+
+                       if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID))
+                               continue;
+                       /* lock and try again */
                        native_lock_hpte(hptep);
                        hpte_v = hpte_get_old_v(hptep);
-                       if (!HPTE_V_COMPARE(hpte_v, want_v) ||
-                           !(hpte_v & HPTE_V_VALID))
+
+                       if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID))
                                native_unlock_hpte(hptep);
                        else
                                hptep->v = 0;
+
                } pte_iterate_hashed_end();
        }