aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries/lpar.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-10-11 06:37:10 -0400
committerPaul Mackerras <paulus@samba.org>2007-10-12 00:05:17 -0400
commit1189be6508d45183013ddb82b18f4934193de274 (patch)
tree58924481b4de56699e4a884dce8dc601e71cf7d1 /arch/powerpc/platforms/pseries/lpar.c
parent287e5d6fcccfa38b953cebe307e1ddfd32363355 (diff)
[POWERPC] Use 1TB segments
This makes the kernel use 1TB segments for all kernel mappings and for user addresses of 1TB and above, on machines which support them (currently POWER5+, POWER6 and PA6T). We detect that the machine supports 1TB segments by looking at the ibm,processor-segment-sizes property in the device tree. We don't currently use 1TB segments for user addresses < 1T, since that would effectively prevent 32-bit processes from using huge pages unless we also had a way to revert to using 256MB segments. That would be possible but would involve extra complications (such as keeping track of which segment size was used when HPTEs were inserted) and is not addressed here. Parts of this patch were originally written by Ben Herrenschmidt. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/pseries/lpar.c')
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c89
1 files changed, 49 insertions, 40 deletions
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index ea327ca345c..9a455d46379 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -284,7 +284,7 @@ void vpa_init(int cpu)
284static long pSeries_lpar_hpte_insert(unsigned long hpte_group, 284static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
285 unsigned long va, unsigned long pa, 285 unsigned long va, unsigned long pa,
286 unsigned long rflags, unsigned long vflags, 286 unsigned long rflags, unsigned long vflags,
287 int psize) 287 int psize, int ssize)
288{ 288{
289 unsigned long lpar_rc; 289 unsigned long lpar_rc;
290 unsigned long flags; 290 unsigned long flags;
@@ -296,7 +296,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
296 "rflags=%lx, vflags=%lx, psize=%d)\n", 296 "rflags=%lx, vflags=%lx, psize=%d)\n",
297 hpte_group, va, pa, rflags, vflags, psize); 297 hpte_group, va, pa, rflags, vflags, psize);
298 298
299 hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; 299 hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID;
300 hpte_r = hpte_encode_r(pa, psize) | rflags; 300 hpte_r = hpte_encode_r(pa, psize) | rflags;
301 301
302 if (!(vflags & HPTE_V_BOLTED)) 302 if (!(vflags & HPTE_V_BOLTED))
@@ -392,6 +392,22 @@ static void pSeries_lpar_hptab_clear(void)
392} 392}
393 393
394/* 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/*
395 * 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
396 * 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.
397 * 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
@@ -400,18 +416,18 @@ static void pSeries_lpar_hptab_clear(void)
400static long pSeries_lpar_hpte_updatepp(unsigned long slot, 416static long pSeries_lpar_hpte_updatepp(unsigned long slot,
401 unsigned long newpp, 417 unsigned long newpp,
402 unsigned long va, 418 unsigned long va,
403 int psize, int local) 419 int psize, int ssize, int local)
404{ 420{
405 unsigned long lpar_rc; 421 unsigned long lpar_rc;
406 unsigned long flags = (newpp & 7) | H_AVPN; 422 unsigned long flags = (newpp & 7) | H_AVPN;
407 unsigned long want_v; 423 unsigned long want_v;
408 424
409 want_v = hpte_encode_v(va, psize); 425 want_v = hpte_encode_avpn(va, psize, ssize);
410 426
411 DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ", 427 DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ",
412 want_v & HPTE_V_AVPN, slot, flags, psize); 428 want_v, slot, flags, psize);
413 429
414 lpar_rc = plpar_pte_protect(flags, slot, want_v & HPTE_V_AVPN); 430 lpar_rc = plpar_pte_protect(flags, slot, want_v);
415 431
416 if (lpar_rc == H_NOT_FOUND) { 432 if (lpar_rc == H_NOT_FOUND) {
417 DBG_LOW("not found !\n"); 433 DBG_LOW("not found !\n");
@@ -444,32 +460,25 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot)
444 return dword0; 460 return dword0;
445} 461}
446 462
447static long pSeries_lpar_hpte_find(unsigned long va, int psize) 463static long pSeries_lpar_hpte_find(unsigned long va, int psize, int ssize)
448{ 464{
449 unsigned long hash; 465 unsigned long hash;
450 unsigned long i, j; 466 unsigned long i;
451 long slot; 467 long slot;
452 unsigned long want_v, hpte_v; 468 unsigned long want_v, hpte_v;
453 469
454 hash = hpt_hash(va, mmu_psize_defs[psize].shift); 470 hash = hpt_hash(va, mmu_psize_defs[psize].shift, ssize);
455 want_v = hpte_encode_v(va, psize); 471 want_v = hpte_encode_avpn(va, psize, ssize);
456 472
457 for (j = 0; j < 2; j++) { 473 /* Bolted entries are always in the primary group */
458 slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; 474 slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
459 for (i = 0; i < HPTES_PER_GROUP; i++) { 475 for (i = 0; i < HPTES_PER_GROUP; i++) {
460 hpte_v = pSeries_lpar_hpte_getword0(slot); 476 hpte_v = pSeries_lpar_hpte_getword0(slot);
461 477
462 if (HPTE_V_COMPARE(hpte_v, want_v) 478 if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID))
463 && (hpte_v & HPTE_V_VALID) 479 /* HPTE matches */
464 && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { 480 return slot;
465 /* HPTE matches */ 481 ++slot;
466 if (j)
467 slot = -slot;
468 return slot;
469 }
470 ++slot;
471 }
472 hash = ~hash;
473 } 482 }
474 483
475 return -1; 484 return -1;
@@ -477,14 +486,14 @@ static long pSeries_lpar_hpte_find(unsigned long va, int psize)
477 486
478static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, 487static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
479 unsigned long ea, 488 unsigned long ea,
480 int psize) 489 int psize, int ssize)
481{ 490{
482 unsigned long lpar_rc, slot, vsid, va, flags; 491 unsigned long lpar_rc, slot, vsid, va, flags;
483 492
484 vsid = get_kernel_vsid(ea); 493 vsid = get_kernel_vsid(ea, ssize);
485 va = (vsid << 28) | (ea & 0x0fffffff); 494 va = hpt_va(ea, vsid, ssize);
486 495
487 slot = pSeries_lpar_hpte_find(va, psize); 496 slot = pSeries_lpar_hpte_find(va, psize, ssize);
488 BUG_ON(slot == -1); 497 BUG_ON(slot == -1);
489 498
490 flags = newpp & 7; 499 flags = newpp & 7;
@@ -494,7 +503,7 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
494} 503}
495 504
496static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, 505static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
497 int psize, int local) 506 int psize, int ssize, int local)
498{ 507{
499 unsigned long want_v; 508 unsigned long want_v;
500 unsigned long lpar_rc; 509 unsigned long lpar_rc;
@@ -503,9 +512,8 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
503 DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d", 512 DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d",
504 slot, va, psize, local); 513 slot, va, psize, local);
505 514
506 want_v = hpte_encode_v(va, psize); 515 want_v = hpte_encode_avpn(va, psize, ssize);
507 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);
508 &dummy1, &dummy2);
509 if (lpar_rc == H_NOT_FOUND) 517 if (lpar_rc == H_NOT_FOUND)
510 return; 518 return;
511 519
@@ -533,18 +541,19 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local)
533 unsigned long va; 541 unsigned long va;
534 unsigned long hash, index, shift, hidx, slot; 542 unsigned long hash, index, shift, hidx, slot;
535 real_pte_t pte; 543 real_pte_t pte;
536 int psize; 544 int psize, ssize;
537 545
538 if (lock_tlbie) 546 if (lock_tlbie)
539 spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); 547 spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
540 548
541 psize = batch->psize; 549 psize = batch->psize;
550 ssize = batch->ssize;
542 pix = 0; 551 pix = 0;
543 for (i = 0; i < number; i++) { 552 for (i = 0; i < number; i++) {
544 va = batch->vaddr[i]; 553 va = batch->vaddr[i];
545 pte = batch->pte[i]; 554 pte = batch->pte[i];
546 pte_iterate_hashed_subpages(pte, psize, va, index, shift) { 555 pte_iterate_hashed_subpages(pte, psize, va, index, shift) {
547 hash = hpt_hash(va, shift); 556 hash = hpt_hash(va, shift, ssize);
548 hidx = __rpte_to_hidx(pte, index); 557 hidx = __rpte_to_hidx(pte, index);
549 if (hidx & _PTEIDX_SECONDARY) 558 if (hidx & _PTEIDX_SECONDARY)
550 hash = ~hash; 559 hash = ~hash;
@@ -552,11 +561,11 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local)
552 slot += hidx & _PTEIDX_GROUP_IX; 561 slot += hidx & _PTEIDX_GROUP_IX;
553 if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { 562 if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) {
554 pSeries_lpar_hpte_invalidate(slot, va, psize, 563 pSeries_lpar_hpte_invalidate(slot, va, psize,
555 local); 564 ssize, local);
556 } else { 565 } else {
557 param[pix] = HBR_REQUEST | HBR_AVPN | slot; 566 param[pix] = HBR_REQUEST | HBR_AVPN | slot;
558 param[pix+1] = hpte_encode_v(va, psize) & 567 param[pix+1] = hpte_encode_avpn(va, psize,
559 HPTE_V_AVPN; 568 ssize);
560 pix += 2; 569 pix += 2;
561 if (pix == 8) { 570 if (pix == 8) {
562 rc = plpar_hcall9(H_BULK_REMOVE, param, 571 rc = plpar_hcall9(H_BULK_REMOVE, param,