powerpc/mm: Always invalidate tlb on hpte invalidate and update

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 b1022fbd29

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
Aneesh Kumar K.V 2013-05-31 01:03:24 +00:00 коммит произвёл Benjamin Herrenschmidt
Родитель 280a5ba22c
Коммит 0608d69246
1 изменённых файлов: 22 добавлений и 8 удалений

Просмотреть файл

@ -336,11 +336,18 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
hpte_v = hptep->v; hpte_v = hptep->v;
actual_psize = hpte_actual_psize(hptep, psize); 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) { if (actual_psize < 0) {
native_unlock_hpte(hptep); actual_psize = psize;
return -1; ret = -1;
goto err_out;
} }
/* Even if we miss, we need to invalidate the TLB */
if (!HPTE_V_COMPARE(hpte_v, want_v)) { if (!HPTE_V_COMPARE(hpte_v, want_v)) {
DBG_LOW(" -> miss\n"); DBG_LOW(" -> miss\n");
ret = -1; ret = -1;
@ -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)) | hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
(newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C)); (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C));
} }
err_out:
native_unlock_hpte(hptep); native_unlock_hpte(hptep);
/* Ensure it is out of the tlb too. */ /* Ensure it is out of the tlb too. */
@ -409,7 +417,7 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
hptep = htab_address + slot; hptep = htab_address + slot;
actual_psize = hpte_actual_psize(hptep, psize); actual_psize = hpte_actual_psize(hptep, psize);
if (actual_psize < 0) if (actual_psize < 0)
return; actual_psize = psize;
/* Update the HPTE */ /* Update the HPTE */
hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) | hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
@ -437,21 +445,27 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
hpte_v = hptep->v; hpte_v = hptep->v;
actual_psize = hpte_actual_psize(hptep, psize); 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) { if (actual_psize < 0) {
actual_psize = psize;
native_unlock_hpte(hptep); native_unlock_hpte(hptep);
local_irq_restore(flags); goto err_out;
return;
} }
/* Even if we miss, we need to invalidate the TLB */
if (!HPTE_V_COMPARE(hpte_v, want_v)) if (!HPTE_V_COMPARE(hpte_v, want_v))
native_unlock_hpte(hptep); native_unlock_hpte(hptep);
else else
/* Invalidate the hpte. NOTE: this also unlocks it */ /* Invalidate the hpte. NOTE: this also unlocks it */
hptep->v = 0; hptep->v = 0;
err_out:
/* Invalidate the TLB */ /* Invalidate the TLB */
tlbie(vpn, psize, actual_psize, ssize, local); tlbie(vpn, psize, actual_psize, ssize, local);
local_irq_restore(flags); local_irq_restore(flags);
} }