diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/lpar.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/lpar.c | 90 |
1 files changed, 49 insertions, 41 deletions
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 8cc6eeeaae2f..9a455d46379d 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <asm/tlbflush.h> | 35 | #include <asm/tlbflush.h> |
36 | #include <asm/tlb.h> | 36 | #include <asm/tlb.h> |
37 | #include <asm/prom.h> | 37 | #include <asm/prom.h> |
38 | #include <asm/abs_addr.h> | ||
39 | #include <asm/cputable.h> | 38 | #include <asm/cputable.h> |
40 | #include <asm/udbg.h> | 39 | #include <asm/udbg.h> |
41 | #include <asm/smp.h> | 40 | #include <asm/smp.h> |
@@ -285,7 +284,7 @@ void vpa_init(int cpu) | |||
285 | static long pSeries_lpar_hpte_insert(unsigned long hpte_group, | 284 | static long pSeries_lpar_hpte_insert(unsigned long hpte_group, |
286 | unsigned long va, unsigned long pa, | 285 | unsigned long va, unsigned long pa, |
287 | unsigned long rflags, unsigned long vflags, | 286 | unsigned long rflags, unsigned long vflags, |
288 | int psize) | 287 | int psize, int ssize) |
289 | { | 288 | { |
290 | unsigned long lpar_rc; | 289 | unsigned long lpar_rc; |
291 | unsigned long flags; | 290 | unsigned long flags; |
@@ -297,7 +296,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, | |||
297 | "rflags=%lx, vflags=%lx, psize=%d)\n", | 296 | "rflags=%lx, vflags=%lx, psize=%d)\n", |
298 | hpte_group, va, pa, rflags, vflags, psize); | 297 | hpte_group, va, pa, rflags, vflags, psize); |
299 | 298 | ||
300 | hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; | 299 | hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID; |
301 | hpte_r = hpte_encode_r(pa, psize) | rflags; | 300 | hpte_r = hpte_encode_r(pa, psize) | rflags; |
302 | 301 | ||
303 | if (!(vflags & HPTE_V_BOLTED)) | 302 | if (!(vflags & HPTE_V_BOLTED)) |
@@ -393,6 +392,22 @@ static void pSeries_lpar_hptab_clear(void) | |||
393 | } | 392 | } |
394 | 393 | ||
395 | /* | 394 | /* |
395 | * This computes the AVPN and B fields of the first dword of a HPTE, | ||
396 | * for use when we want to match an existing PTE. The bottom 7 bits | ||
397 | * of the returned value are zero. | ||
398 | */ | ||
399 | static inline unsigned long hpte_encode_avpn(unsigned long va, int psize, | ||
400 | int ssize) | ||
401 | { | ||
402 | unsigned long v; | ||
403 | |||
404 | v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm); | ||
405 | v <<= HPTE_V_AVPN_SHIFT; | ||
406 | v |= ((unsigned long) ssize) << HPTE_V_SSIZE_SHIFT; | ||
407 | return v; | ||
408 | } | ||
409 | |||
410 | /* | ||
396 | * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and | 411 | * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and |
397 | * the low 3 bits of flags happen to line up. So no transform is needed. | 412 | * the low 3 bits of flags happen to line up. So no transform is needed. |
398 | * We can probably optimize here and assume the high bits of newpp are | 413 | * We can probably optimize here and assume the high bits of newpp are |
@@ -401,18 +416,18 @@ static void pSeries_lpar_hptab_clear(void) | |||
401 | static long pSeries_lpar_hpte_updatepp(unsigned long slot, | 416 | static long pSeries_lpar_hpte_updatepp(unsigned long slot, |
402 | unsigned long newpp, | 417 | unsigned long newpp, |
403 | unsigned long va, | 418 | unsigned long va, |
404 | int psize, int local) | 419 | int psize, int ssize, int local) |
405 | { | 420 | { |
406 | unsigned long lpar_rc; | 421 | unsigned long lpar_rc; |
407 | unsigned long flags = (newpp & 7) | H_AVPN; | 422 | unsigned long flags = (newpp & 7) | H_AVPN; |
408 | unsigned long want_v; | 423 | unsigned long want_v; |
409 | 424 | ||
410 | want_v = hpte_encode_v(va, psize); | 425 | want_v = hpte_encode_avpn(va, psize, ssize); |
411 | 426 | ||
412 | DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ", | 427 | DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ", |
413 | want_v & HPTE_V_AVPN, slot, flags, psize); | 428 | want_v, slot, flags, psize); |
414 | 429 | ||
415 | lpar_rc = plpar_pte_protect(flags, slot, want_v & HPTE_V_AVPN); | 430 | lpar_rc = plpar_pte_protect(flags, slot, want_v); |
416 | 431 | ||
417 | if (lpar_rc == H_NOT_FOUND) { | 432 | if (lpar_rc == H_NOT_FOUND) { |
418 | DBG_LOW("not found !\n"); | 433 | DBG_LOW("not found !\n"); |
@@ -445,32 +460,25 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) | |||
445 | return dword0; | 460 | return dword0; |
446 | } | 461 | } |
447 | 462 | ||
448 | static long pSeries_lpar_hpte_find(unsigned long va, int psize) | 463 | static long pSeries_lpar_hpte_find(unsigned long va, int psize, int ssize) |
449 | { | 464 | { |
450 | unsigned long hash; | 465 | unsigned long hash; |
451 | unsigned long i, j; | 466 | unsigned long i; |
452 | long slot; | 467 | long slot; |
453 | unsigned long want_v, hpte_v; | 468 | unsigned long want_v, hpte_v; |
454 | 469 | ||
455 | hash = hpt_hash(va, mmu_psize_defs[psize].shift); | 470 | hash = hpt_hash(va, mmu_psize_defs[psize].shift, ssize); |
456 | want_v = hpte_encode_v(va, psize); | 471 | want_v = hpte_encode_avpn(va, psize, ssize); |
457 | 472 | ||
458 | for (j = 0; j < 2; j++) { | 473 | /* Bolted entries are always in the primary group */ |
459 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | 474 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; |
460 | for (i = 0; i < HPTES_PER_GROUP; i++) { | 475 | for (i = 0; i < HPTES_PER_GROUP; i++) { |
461 | hpte_v = pSeries_lpar_hpte_getword0(slot); | 476 | hpte_v = pSeries_lpar_hpte_getword0(slot); |
462 | 477 | ||
463 | if (HPTE_V_COMPARE(hpte_v, want_v) | 478 | if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID)) |
464 | && (hpte_v & HPTE_V_VALID) | 479 | /* HPTE matches */ |
465 | && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { | 480 | return slot; |
466 | /* HPTE matches */ | 481 | ++slot; |
467 | if (j) | ||
468 | slot = -slot; | ||
469 | return slot; | ||
470 | } | ||
471 | ++slot; | ||
472 | } | ||
473 | hash = ~hash; | ||
474 | } | 482 | } |
475 | 483 | ||
476 | return -1; | 484 | return -1; |
@@ -478,14 +486,14 @@ static long pSeries_lpar_hpte_find(unsigned long va, int psize) | |||
478 | 486 | ||
479 | static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, | 487 | static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, |
480 | unsigned long ea, | 488 | unsigned long ea, |
481 | int psize) | 489 | int psize, int ssize) |
482 | { | 490 | { |
483 | unsigned long lpar_rc, slot, vsid, va, flags; | 491 | unsigned long lpar_rc, slot, vsid, va, flags; |
484 | 492 | ||
485 | vsid = get_kernel_vsid(ea); | 493 | vsid = get_kernel_vsid(ea, ssize); |
486 | va = (vsid << 28) | (ea & 0x0fffffff); | 494 | va = hpt_va(ea, vsid, ssize); |
487 | 495 | ||
488 | slot = pSeries_lpar_hpte_find(va, psize); | 496 | slot = pSeries_lpar_hpte_find(va, psize, ssize); |
489 | BUG_ON(slot == -1); | 497 | BUG_ON(slot == -1); |
490 | 498 | ||
491 | flags = newpp & 7; | 499 | flags = newpp & 7; |
@@ -495,7 +503,7 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, | |||
495 | } | 503 | } |
496 | 504 | ||
497 | static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, | 505 | static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, |
498 | int psize, int local) | 506 | int psize, int ssize, int local) |
499 | { | 507 | { |
500 | unsigned long want_v; | 508 | unsigned long want_v; |
501 | unsigned long lpar_rc; | 509 | unsigned long lpar_rc; |
@@ -504,9 +512,8 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, | |||
504 | DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d", | 512 | DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d", |
505 | slot, va, psize, local); | 513 | slot, va, psize, local); |
506 | 514 | ||
507 | want_v = hpte_encode_v(va, psize); | 515 | want_v = hpte_encode_avpn(va, psize, ssize); |
508 | lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v & HPTE_V_AVPN, | 516 | lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v, &dummy1, &dummy2); |
509 | &dummy1, &dummy2); | ||
510 | if (lpar_rc == H_NOT_FOUND) | 517 | if (lpar_rc == H_NOT_FOUND) |
511 | return; | 518 | return; |
512 | 519 | ||
@@ -534,18 +541,19 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) | |||
534 | unsigned long va; | 541 | unsigned long va; |
535 | unsigned long hash, index, shift, hidx, slot; | 542 | unsigned long hash, index, shift, hidx, slot; |
536 | real_pte_t pte; | 543 | real_pte_t pte; |
537 | int psize; | 544 | int psize, ssize; |
538 | 545 | ||
539 | if (lock_tlbie) | 546 | if (lock_tlbie) |
540 | spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); | 547 | spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); |
541 | 548 | ||
542 | psize = batch->psize; | 549 | psize = batch->psize; |
550 | ssize = batch->ssize; | ||
543 | pix = 0; | 551 | pix = 0; |
544 | for (i = 0; i < number; i++) { | 552 | for (i = 0; i < number; i++) { |
545 | va = batch->vaddr[i]; | 553 | va = batch->vaddr[i]; |
546 | pte = batch->pte[i]; | 554 | pte = batch->pte[i]; |
547 | pte_iterate_hashed_subpages(pte, psize, va, index, shift) { | 555 | pte_iterate_hashed_subpages(pte, psize, va, index, shift) { |
548 | hash = hpt_hash(va, shift); | 556 | hash = hpt_hash(va, shift, ssize); |
549 | hidx = __rpte_to_hidx(pte, index); | 557 | hidx = __rpte_to_hidx(pte, index); |
550 | if (hidx & _PTEIDX_SECONDARY) | 558 | if (hidx & _PTEIDX_SECONDARY) |
551 | hash = ~hash; | 559 | hash = ~hash; |
@@ -553,11 +561,11 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) | |||
553 | slot += hidx & _PTEIDX_GROUP_IX; | 561 | slot += hidx & _PTEIDX_GROUP_IX; |
554 | if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { | 562 | if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { |
555 | pSeries_lpar_hpte_invalidate(slot, va, psize, | 563 | pSeries_lpar_hpte_invalidate(slot, va, psize, |
556 | local); | 564 | ssize, local); |
557 | } else { | 565 | } else { |
558 | param[pix] = HBR_REQUEST | HBR_AVPN | slot; | 566 | param[pix] = HBR_REQUEST | HBR_AVPN | slot; |
559 | param[pix+1] = hpte_encode_v(va, psize) & | 567 | param[pix+1] = hpte_encode_avpn(va, psize, |
560 | HPTE_V_AVPN; | 568 | ssize); |
561 | pix += 2; | 569 | pix += 2; |
562 | if (pix == 8) { | 570 | if (pix == 8) { |
563 | rc = plpar_hcall9(H_BULK_REMOVE, param, | 571 | rc = plpar_hcall9(H_BULK_REMOVE, param, |