aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries/lpar.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/pseries/lpar.c')
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c90
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)
285static long pSeries_lpar_hpte_insert(unsigned long hpte_group, 284static 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 */
399static 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)
401static long pSeries_lpar_hpte_updatepp(unsigned long slot, 416static 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
448static long pSeries_lpar_hpte_find(unsigned long va, int psize) 463static 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
479static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, 487static 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
497static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, 505static 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,