diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/lpar.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/lpar.c | 55 |
1 files changed, 51 insertions, 4 deletions
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 721436db3ef0..7496005566ef 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c | |||
@@ -502,23 +502,70 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, | |||
502 | BUG_ON(lpar_rc != H_SUCCESS); | 502 | BUG_ON(lpar_rc != H_SUCCESS); |
503 | } | 503 | } |
504 | 504 | ||
505 | /* Flag bits for H_BULK_REMOVE */ | ||
506 | #define HBR_REQUEST 0x4000000000000000UL | ||
507 | #define HBR_RESPONSE 0x8000000000000000UL | ||
508 | #define HBR_END 0xc000000000000000UL | ||
509 | #define HBR_AVPN 0x0200000000000000UL | ||
510 | #define HBR_ANDCOND 0x0100000000000000UL | ||
511 | |||
505 | /* | 512 | /* |
506 | * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie | 513 | * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie |
507 | * lock. | 514 | * lock. |
508 | */ | 515 | */ |
509 | static void pSeries_lpar_flush_hash_range(unsigned long number, int local) | 516 | static void pSeries_lpar_flush_hash_range(unsigned long number, int local) |
510 | { | 517 | { |
511 | int i; | 518 | unsigned long i, pix, rc; |
512 | unsigned long flags = 0; | 519 | unsigned long flags = 0; |
513 | struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); | 520 | struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); |
514 | int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); | 521 | int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); |
522 | unsigned long param[9]; | ||
523 | unsigned long va; | ||
524 | unsigned long hash, index, shift, hidx, slot; | ||
525 | real_pte_t pte; | ||
526 | int psize; | ||
515 | 527 | ||
516 | if (lock_tlbie) | 528 | if (lock_tlbie) |
517 | spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); | 529 | spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); |
518 | 530 | ||
519 | for (i = 0; i < number; i++) | 531 | psize = batch->psize; |
520 | flush_hash_page(batch->vaddr[i], batch->pte[i], | 532 | pix = 0; |
521 | batch->psize, local); | 533 | for (i = 0; i < number; i++) { |
534 | va = batch->vaddr[i]; | ||
535 | pte = batch->pte[i]; | ||
536 | pte_iterate_hashed_subpages(pte, psize, va, index, shift) { | ||
537 | hash = hpt_hash(va, shift); | ||
538 | hidx = __rpte_to_hidx(pte, index); | ||
539 | if (hidx & _PTEIDX_SECONDARY) | ||
540 | hash = ~hash; | ||
541 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | ||
542 | slot += hidx & _PTEIDX_GROUP_IX; | ||
543 | if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { | ||
544 | pSeries_lpar_hpte_invalidate(slot, va, psize, | ||
545 | local); | ||
546 | } else { | ||
547 | param[pix] = HBR_REQUEST | HBR_AVPN | slot; | ||
548 | param[pix+1] = hpte_encode_v(va, psize) & | ||
549 | HPTE_V_AVPN; | ||
550 | pix += 2; | ||
551 | if (pix == 8) { | ||
552 | rc = plpar_hcall9(H_BULK_REMOVE, param, | ||
553 | param[0], param[1], param[2], | ||
554 | param[3], param[4], param[5], | ||
555 | param[6], param[7]); | ||
556 | BUG_ON(rc != H_SUCCESS); | ||
557 | pix = 0; | ||
558 | } | ||
559 | } | ||
560 | } pte_iterate_hashed_end(); | ||
561 | } | ||
562 | if (pix) { | ||
563 | param[pix] = HBR_END; | ||
564 | rc = plpar_hcall9(H_BULK_REMOVE, param, param[0], param[1], | ||
565 | param[2], param[3], param[4], param[5], | ||
566 | param[6], param[7]); | ||
567 | BUG_ON(rc != H_SUCCESS); | ||
568 | } | ||
522 | 569 | ||
523 | if (lock_tlbie) | 570 | if (lock_tlbie) |
524 | spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); | 571 | spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); |