diff options
Diffstat (limited to 'arch/powerpc/mm/hash_native_64.c')
-rw-r--r-- | arch/powerpc/mm/hash_native_64.c | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index ae4962a06476..9c4880ddecd6 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c | |||
@@ -283,19 +283,17 @@ static long native_hpte_remove(unsigned long hpte_group) | |||
283 | 283 | ||
284 | static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, | 284 | static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, |
285 | unsigned long vpn, int bpsize, | 285 | unsigned long vpn, int bpsize, |
286 | int apsize, int ssize, int local) | 286 | int apsize, int ssize, unsigned long flags) |
287 | { | 287 | { |
288 | struct hash_pte *hptep = htab_address + slot; | 288 | struct hash_pte *hptep = htab_address + slot; |
289 | unsigned long hpte_v, want_v; | 289 | unsigned long hpte_v, want_v; |
290 | int ret = 0; | 290 | int ret = 0, local = 0; |
291 | 291 | ||
292 | want_v = hpte_encode_avpn(vpn, bpsize, ssize); | 292 | want_v = hpte_encode_avpn(vpn, bpsize, ssize); |
293 | 293 | ||
294 | DBG_LOW(" update(vpn=%016lx, avpnv=%016lx, group=%lx, newpp=%lx)", | 294 | DBG_LOW(" update(vpn=%016lx, avpnv=%016lx, group=%lx, newpp=%lx)", |
295 | vpn, want_v & HPTE_V_AVPN, slot, newpp); | 295 | vpn, want_v & HPTE_V_AVPN, slot, newpp); |
296 | 296 | ||
297 | native_lock_hpte(hptep); | ||
298 | |||
299 | hpte_v = be64_to_cpu(hptep->v); | 297 | hpte_v = be64_to_cpu(hptep->v); |
300 | /* | 298 | /* |
301 | * We need to invalidate the TLB always because hpte_remove doesn't do | 299 | * We need to invalidate the TLB always because hpte_remove doesn't do |
@@ -308,15 +306,30 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, | |||
308 | DBG_LOW(" -> miss\n"); | 306 | DBG_LOW(" -> miss\n"); |
309 | ret = -1; | 307 | ret = -1; |
310 | } else { | 308 | } else { |
311 | DBG_LOW(" -> hit\n"); | 309 | native_lock_hpte(hptep); |
312 | /* Update the HPTE */ | 310 | /* recheck with locks held */ |
313 | hptep->r = cpu_to_be64((be64_to_cpu(hptep->r) & ~(HPTE_R_PP | HPTE_R_N)) | | 311 | hpte_v = be64_to_cpu(hptep->v); |
314 | (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C))); | 312 | if (unlikely(!HPTE_V_COMPARE(hpte_v, want_v) || |
313 | !(hpte_v & HPTE_V_VALID))) { | ||
314 | ret = -1; | ||
315 | } else { | ||
316 | DBG_LOW(" -> hit\n"); | ||
317 | /* Update the HPTE */ | ||
318 | hptep->r = cpu_to_be64((be64_to_cpu(hptep->r) & | ||
319 | ~(HPTE_R_PP | HPTE_R_N)) | | ||
320 | (newpp & (HPTE_R_PP | HPTE_R_N | | ||
321 | HPTE_R_C))); | ||
322 | } | ||
323 | native_unlock_hpte(hptep); | ||
315 | } | 324 | } |
316 | native_unlock_hpte(hptep); | ||
317 | 325 | ||
318 | /* Ensure it is out of the tlb too. */ | 326 | if (flags & HPTE_LOCAL_UPDATE) |
319 | tlbie(vpn, bpsize, apsize, ssize, local); | 327 | local = 1; |
328 | /* | ||
329 | * Ensure it is out of the tlb too if it is not a nohpte fault | ||
330 | */ | ||
331 | if (!(flags & HPTE_NOHPTE_UPDATE)) | ||
332 | tlbie(vpn, bpsize, apsize, ssize, local); | ||
320 | 333 | ||
321 | return ret; | 334 | return ret; |
322 | } | 335 | } |
@@ -419,7 +432,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn, | |||
419 | static void native_hugepage_invalidate(unsigned long vsid, | 432 | static void native_hugepage_invalidate(unsigned long vsid, |
420 | unsigned long addr, | 433 | unsigned long addr, |
421 | unsigned char *hpte_slot_array, | 434 | unsigned char *hpte_slot_array, |
422 | int psize, int ssize) | 435 | int psize, int ssize, int local) |
423 | { | 436 | { |
424 | int i; | 437 | int i; |
425 | struct hash_pte *hptep; | 438 | struct hash_pte *hptep; |
@@ -465,7 +478,7 @@ static void native_hugepage_invalidate(unsigned long vsid, | |||
465 | * instruction compares entry_VA in tlb with the VA specified | 478 | * instruction compares entry_VA in tlb with the VA specified |
466 | * here | 479 | * here |
467 | */ | 480 | */ |
468 | tlbie(vpn, psize, actual_psize, ssize, 0); | 481 | tlbie(vpn, psize, actual_psize, ssize, local); |
469 | } | 482 | } |
470 | local_irq_restore(flags); | 483 | local_irq_restore(flags); |
471 | } | 484 | } |
@@ -629,7 +642,7 @@ static void native_flush_hash_range(unsigned long number, int local) | |||
629 | unsigned long want_v; | 642 | unsigned long want_v; |
630 | unsigned long flags; | 643 | unsigned long flags; |
631 | real_pte_t pte; | 644 | real_pte_t pte; |
632 | struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); | 645 | struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); |
633 | unsigned long psize = batch->psize; | 646 | unsigned long psize = batch->psize; |
634 | int ssize = batch->ssize; | 647 | int ssize = batch->ssize; |
635 | int i; | 648 | int i; |