Skip to content

Commit

Permalink
powerpc/mm/hash: Reduce contention on hpte lock
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Aneesh Kumar K.V authored and Michael Ellerman committed Jul 24, 2018
1 parent a833280 commit 27d8959
Showing 1 changed file with 33 additions and 16 deletions.
49 changes: 33 additions & 16 deletions arch/powerpc/mm/hash_native_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,23 +568,26 @@ 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
* random entry from it. When we do that we don't invalidate the TLB
* (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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
}

Expand Down

0 comments on commit 27d8959

Please sign in to comment.