Skip to content

Commit

Permalink
powerpc/mm: Always invalidate tlb on hpte invalidate and update
Browse files Browse the repository at this point in the history
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". This implies that when
we are invalidating or updating pte, even if HPTE entry is not valid
we should do a tlb invalidate.

This was a regression introduced by b1022fb

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
  • Loading branch information
Aneesh Kumar K.V authored and Benjamin Herrenschmidt committed May 31, 2013
1 parent 280a5ba commit 0608d69
Showing 1 changed file with 22 additions and 8 deletions.
30 changes: 22 additions & 8 deletions arch/powerpc/mm/hash_native_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,18 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,

hpte_v = hptep->v;
actual_psize = hpte_actual_psize(hptep, psize);
/*
* 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 (actual_psize < 0) {
native_unlock_hpte(hptep);
return -1;
actual_psize = psize;
ret = -1;
goto err_out;
}
/* Even if we miss, we need to invalidate the TLB */
if (!HPTE_V_COMPARE(hpte_v, want_v)) {
DBG_LOW(" -> miss\n");
ret = -1;
Expand All @@ -350,6 +357,7 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
(newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C));
}
err_out:
native_unlock_hpte(hptep);

/* Ensure it is out of the tlb too. */
Expand Down Expand Up @@ -409,7 +417,7 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
hptep = htab_address + slot;
actual_psize = hpte_actual_psize(hptep, psize);
if (actual_psize < 0)
return;
actual_psize = psize;

/* Update the HPTE */
hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
Expand Down Expand Up @@ -437,21 +445,27 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
hpte_v = hptep->v;

actual_psize = hpte_actual_psize(hptep, psize);
/*
* 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 (actual_psize < 0) {
actual_psize = psize;
native_unlock_hpte(hptep);
local_irq_restore(flags);
return;
goto err_out;
}
/* Even if we miss, we need to invalidate the TLB */
if (!HPTE_V_COMPARE(hpte_v, want_v))
native_unlock_hpte(hptep);
else
/* Invalidate the hpte. NOTE: this also unlocks it */
hptep->v = 0;

err_out:
/* Invalidate the TLB */
tlbie(vpn, psize, actual_psize, ssize, local);

local_irq_restore(flags);
}

Expand Down

0 comments on commit 0608d69

Please sign in to comment.