diff options
Diffstat (limited to 'arch/powerpc/mm')
| -rw-r--r-- | arch/powerpc/mm/hash_native_64.c | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 6a2aead5b0e5..4c122c3f1623 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c | |||
| @@ -336,11 +336,18 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, | |||
| 336 | 336 | ||
| 337 | hpte_v = hptep->v; | 337 | hpte_v = hptep->v; |
| 338 | actual_psize = hpte_actual_psize(hptep, psize); | 338 | actual_psize = hpte_actual_psize(hptep, psize); |
| 339 | /* | ||
| 340 | * We need to invalidate the TLB always because hpte_remove doesn't do | ||
| 341 | * a tlb invalidate. If a hash bucket gets full, we "evict" a more/less | ||
| 342 | * random entry from it. When we do that we don't invalidate the TLB | ||
| 343 | * (hpte_remove) because we assume the old translation is still | ||
| 344 | * technically "valid". | ||
| 345 | */ | ||
| 339 | if (actual_psize < 0) { | 346 | if (actual_psize < 0) { |
| 340 | native_unlock_hpte(hptep); | 347 | actual_psize = psize; |
| 341 | return -1; | 348 | ret = -1; |
| 349 | goto err_out; | ||
| 342 | } | 350 | } |
| 343 | /* Even if we miss, we need to invalidate the TLB */ | ||
| 344 | if (!HPTE_V_COMPARE(hpte_v, want_v)) { | 351 | if (!HPTE_V_COMPARE(hpte_v, want_v)) { |
| 345 | DBG_LOW(" -> miss\n"); | 352 | DBG_LOW(" -> miss\n"); |
| 346 | ret = -1; | 353 | ret = -1; |
| @@ -350,6 +357,7 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, | |||
| 350 | hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) | | 357 | hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) | |
| 351 | (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C)); | 358 | (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C)); |
| 352 | } | 359 | } |
| 360 | err_out: | ||
| 353 | native_unlock_hpte(hptep); | 361 | native_unlock_hpte(hptep); |
| 354 | 362 | ||
| 355 | /* Ensure it is out of the tlb too. */ | 363 | /* Ensure it is out of the tlb too. */ |
| @@ -409,7 +417,7 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, | |||
| 409 | hptep = htab_address + slot; | 417 | hptep = htab_address + slot; |
| 410 | actual_psize = hpte_actual_psize(hptep, psize); | 418 | actual_psize = hpte_actual_psize(hptep, psize); |
| 411 | if (actual_psize < 0) | 419 | if (actual_psize < 0) |
| 412 | return; | 420 | actual_psize = psize; |
| 413 | 421 | ||
| 414 | /* Update the HPTE */ | 422 | /* Update the HPTE */ |
| 415 | hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) | | 423 | 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, | |||
| 437 | hpte_v = hptep->v; | 445 | hpte_v = hptep->v; |
| 438 | 446 | ||
| 439 | actual_psize = hpte_actual_psize(hptep, psize); | 447 | actual_psize = hpte_actual_psize(hptep, psize); |
| 448 | /* | ||
| 449 | * We need to invalidate the TLB always because hpte_remove doesn't do | ||
| 450 | * a tlb invalidate. If a hash bucket gets full, we "evict" a more/less | ||
| 451 | * random entry from it. When we do that we don't invalidate the TLB | ||
| 452 | * (hpte_remove) because we assume the old translation is still | ||
| 453 | * technically "valid". | ||
| 454 | */ | ||
| 440 | if (actual_psize < 0) { | 455 | if (actual_psize < 0) { |
| 456 | actual_psize = psize; | ||
| 441 | native_unlock_hpte(hptep); | 457 | native_unlock_hpte(hptep); |
| 442 | local_irq_restore(flags); | 458 | goto err_out; |
| 443 | return; | ||
| 444 | } | 459 | } |
| 445 | /* Even if we miss, we need to invalidate the TLB */ | ||
| 446 | if (!HPTE_V_COMPARE(hpte_v, want_v)) | 460 | if (!HPTE_V_COMPARE(hpte_v, want_v)) |
| 447 | native_unlock_hpte(hptep); | 461 | native_unlock_hpte(hptep); |
| 448 | else | 462 | else |
| 449 | /* Invalidate the hpte. NOTE: this also unlocks it */ | 463 | /* Invalidate the hpte. NOTE: this also unlocks it */ |
| 450 | hptep->v = 0; | 464 | hptep->v = 0; |
| 451 | 465 | ||
| 466 | err_out: | ||
| 452 | /* Invalidate the TLB */ | 467 | /* Invalidate the TLB */ |
| 453 | tlbie(vpn, psize, actual_psize, ssize, local); | 468 | tlbie(vpn, psize, actual_psize, ssize, local); |
| 454 | |||
| 455 | local_irq_restore(flags); | 469 | local_irq_restore(flags); |
| 456 | } | 470 | } |
| 457 | 471 | ||
