aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-07-08 06:08:25 -0400
committerAlexander Graf <agraf@suse.de>2013-07-10 07:14:09 -0400
commit5448050124d9d289bc2f5177318c68c0484ca413 (patch)
tree17312ecb5e3a072edde8068b9c202ba6b3f01acb
parent990978e99359e1f3a843563b9f96f9dc7bb7c05a (diff)
KVM: PPC: Book3S HV: Correct tlbie usage
This corrects the usage of the tlbie (TLB invalidate entry) instruction in HV KVM. The tlbie instruction changed between PPC970 and POWER7. On the PPC970, the bit to select large vs. small page is in the instruction, not in the RB register value. This changes the code to use the correct form on PPC970. On POWER7 we were calculating the AVAL (Abbreviated Virtual Address, Lower) field of the RB value incorrectly for 64k pages. This fixes it. Since we now have several cases to handle for the tlbie instruction, this factors out the code to do a sequence of tlbies into a new function, do_tlbies(), and calls that from the various places where the code was doing tlbie instructions inline. It also makes kvmppc_h_bulk_remove() use the same global_invalidates() function for determining whether to do local or global TLB invalidations as is used in other places, for consistency, and also to make sure that kvm->arch.need_tlb_flush gets updated properly. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
-rw-r--r--arch/powerpc/include/asm/kvm_book3s_64.h2
-rw-r--r--arch/powerpc/kvm/book3s_hv_rm_mmu.c139
2 files changed, 82 insertions, 59 deletions
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index 76ff0b5c9996..154ba3f6b7a9 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -100,7 +100,7 @@ static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
100 /* (masks depend on page size) */ 100 /* (masks depend on page size) */
101 rb |= 0x1000; /* page encoding in LP field */ 101 rb |= 0x1000; /* page encoding in LP field */
102 rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */ 102 rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
103 rb |= (va_low & 0xfe); /* AVAL field (P7 doesn't seem to care) */ 103 rb |= ((va_low << 4) & 0xf0); /* AVAL field (P7 doesn't seem to care) */
104 } 104 }
105 } else { 105 } else {
106 /* 4kB page */ 106 /* 4kB page */
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 6dcbb49105a4..105b00f24f27 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -385,6 +385,80 @@ static inline int try_lock_tlbie(unsigned int *lock)
385 return old == 0; 385 return old == 0;
386} 386}
387 387
388/*
389 * tlbie/tlbiel is a bit different on the PPC970 compared to later
390 * processors such as POWER7; the large page bit is in the instruction
391 * not RB, and the top 16 bits and the bottom 12 bits of the VA
392 * in RB must be 0.
393 */
394static void do_tlbies_970(struct kvm *kvm, unsigned long *rbvalues,
395 long npages, int global, bool need_sync)
396{
397 long i;
398
399 if (global) {
400 while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
401 cpu_relax();
402 if (need_sync)
403 asm volatile("ptesync" : : : "memory");
404 for (i = 0; i < npages; ++i) {
405 unsigned long rb = rbvalues[i];
406
407 if (rb & 1) /* large page */
408 asm volatile("tlbie %0,1" : :
409 "r" (rb & 0x0000fffffffff000ul));
410 else
411 asm volatile("tlbie %0,0" : :
412 "r" (rb & 0x0000fffffffff000ul));
413 }
414 asm volatile("eieio; tlbsync; ptesync" : : : "memory");
415 kvm->arch.tlbie_lock = 0;
416 } else {
417 if (need_sync)
418 asm volatile("ptesync" : : : "memory");
419 for (i = 0; i < npages; ++i) {
420 unsigned long rb = rbvalues[i];
421
422 if (rb & 1) /* large page */
423 asm volatile("tlbiel %0,1" : :
424 "r" (rb & 0x0000fffffffff000ul));
425 else
426 asm volatile("tlbiel %0,0" : :
427 "r" (rb & 0x0000fffffffff000ul));
428 }
429 asm volatile("ptesync" : : : "memory");
430 }
431}
432
433static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
434 long npages, int global, bool need_sync)
435{
436 long i;
437
438 if (cpu_has_feature(CPU_FTR_ARCH_201)) {
439 /* PPC970 tlbie instruction is a bit different */
440 do_tlbies_970(kvm, rbvalues, npages, global, need_sync);
441 return;
442 }
443 if (global) {
444 while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
445 cpu_relax();
446 if (need_sync)
447 asm volatile("ptesync" : : : "memory");
448 for (i = 0; i < npages; ++i)
449 asm volatile(PPC_TLBIE(%1,%0) : :
450 "r" (rbvalues[i]), "r" (kvm->arch.lpid));
451 asm volatile("eieio; tlbsync; ptesync" : : : "memory");
452 kvm->arch.tlbie_lock = 0;
453 } else {
454 if (need_sync)
455 asm volatile("ptesync" : : : "memory");
456 for (i = 0; i < npages; ++i)
457 asm volatile("tlbiel %0" : : "r" (rbvalues[i]));
458 asm volatile("ptesync" : : : "memory");
459 }
460}
461
388long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags, 462long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags,
389 unsigned long pte_index, unsigned long avpn, 463 unsigned long pte_index, unsigned long avpn,
390 unsigned long *hpret) 464 unsigned long *hpret)
@@ -410,19 +484,7 @@ long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags,
410 if (v & HPTE_V_VALID) { 484 if (v & HPTE_V_VALID) {
411 hpte[0] &= ~HPTE_V_VALID; 485 hpte[0] &= ~HPTE_V_VALID;
412 rb = compute_tlbie_rb(v, hpte[1], pte_index); 486 rb = compute_tlbie_rb(v, hpte[1], pte_index);
413 if (global_invalidates(kvm, flags)) { 487 do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags), true);
414 while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
415 cpu_relax();
416 asm volatile("ptesync" : : : "memory");
417 asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
418 : : "r" (rb), "r" (kvm->arch.lpid));
419 asm volatile("ptesync" : : : "memory");
420 kvm->arch.tlbie_lock = 0;
421 } else {
422 asm volatile("ptesync" : : : "memory");
423 asm volatile("tlbiel %0" : : "r" (rb));
424 asm volatile("ptesync" : : : "memory");
425 }
426 /* Read PTE low word after tlbie to get final R/C values */ 488 /* Read PTE low word after tlbie to get final R/C values */
427 remove_revmap_chain(kvm, pte_index, rev, v, hpte[1]); 489 remove_revmap_chain(kvm, pte_index, rev, v, hpte[1]);
428 } 490 }
@@ -450,12 +512,11 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
450 unsigned long *hp, *hptes[4], tlbrb[4]; 512 unsigned long *hp, *hptes[4], tlbrb[4];
451 long int i, j, k, n, found, indexes[4]; 513 long int i, j, k, n, found, indexes[4];
452 unsigned long flags, req, pte_index, rcbits; 514 unsigned long flags, req, pte_index, rcbits;
453 long int local = 0; 515 int global;
454 long int ret = H_SUCCESS; 516 long int ret = H_SUCCESS;
455 struct revmap_entry *rev, *revs[4]; 517 struct revmap_entry *rev, *revs[4];
456 518
457 if (atomic_read(&kvm->online_vcpus) == 1) 519 global = global_invalidates(kvm, 0);
458 local = 1;
459 for (i = 0; i < 4 && ret == H_SUCCESS; ) { 520 for (i = 0; i < 4 && ret == H_SUCCESS; ) {
460 n = 0; 521 n = 0;
461 for (; i < 4; ++i) { 522 for (; i < 4; ++i) {
@@ -531,22 +592,7 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
531 break; 592 break;
532 593
533 /* Now that we've collected a batch, do the tlbies */ 594 /* Now that we've collected a batch, do the tlbies */
534 if (!local) { 595 do_tlbies(kvm, tlbrb, n, global, true);
535 while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
536 cpu_relax();
537 asm volatile("ptesync" : : : "memory");
538 for (k = 0; k < n; ++k)
539 asm volatile(PPC_TLBIE(%1,%0) : :
540 "r" (tlbrb[k]),
541 "r" (kvm->arch.lpid));
542 asm volatile("eieio; tlbsync; ptesync" : : : "memory");
543 kvm->arch.tlbie_lock = 0;
544 } else {
545 asm volatile("ptesync" : : : "memory");
546 for (k = 0; k < n; ++k)
547 asm volatile("tlbiel %0" : : "r" (tlbrb[k]));
548 asm volatile("ptesync" : : : "memory");
549 }
550 596
551 /* Read PTE low words after tlbie to get final R/C values */ 597 /* Read PTE low words after tlbie to get final R/C values */
552 for (k = 0; k < n; ++k) { 598 for (k = 0; k < n; ++k) {
@@ -605,19 +651,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
605 if (v & HPTE_V_VALID) { 651 if (v & HPTE_V_VALID) {
606 rb = compute_tlbie_rb(v, r, pte_index); 652 rb = compute_tlbie_rb(v, r, pte_index);
607 hpte[0] = v & ~HPTE_V_VALID; 653 hpte[0] = v & ~HPTE_V_VALID;
608 if (global_invalidates(kvm, flags)) { 654 do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags), true);
609 while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
610 cpu_relax();
611 asm volatile("ptesync" : : : "memory");
612 asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
613 : : "r" (rb), "r" (kvm->arch.lpid));
614 asm volatile("ptesync" : : : "memory");
615 kvm->arch.tlbie_lock = 0;
616 } else {
617 asm volatile("ptesync" : : : "memory");
618 asm volatile("tlbiel %0" : : "r" (rb));
619 asm volatile("ptesync" : : : "memory");
620 }
621 /* 655 /*
622 * If the host has this page as readonly but the guest 656 * If the host has this page as readonly but the guest
623 * wants to make it read/write, reduce the permissions. 657 * wants to make it read/write, reduce the permissions.
@@ -688,13 +722,7 @@ void kvmppc_invalidate_hpte(struct kvm *kvm, unsigned long *hptep,
688 722
689 hptep[0] &= ~HPTE_V_VALID; 723 hptep[0] &= ~HPTE_V_VALID;
690 rb = compute_tlbie_rb(hptep[0], hptep[1], pte_index); 724 rb = compute_tlbie_rb(hptep[0], hptep[1], pte_index);
691 while (!try_lock_tlbie(&kvm->arch.tlbie_lock)) 725 do_tlbies(kvm, &rb, 1, 1, true);
692 cpu_relax();
693 asm volatile("ptesync" : : : "memory");
694 asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
695 : : "r" (rb), "r" (kvm->arch.lpid));
696 asm volatile("ptesync" : : : "memory");
697 kvm->arch.tlbie_lock = 0;
698} 726}
699EXPORT_SYMBOL_GPL(kvmppc_invalidate_hpte); 727EXPORT_SYMBOL_GPL(kvmppc_invalidate_hpte);
700 728
@@ -708,12 +736,7 @@ void kvmppc_clear_ref_hpte(struct kvm *kvm, unsigned long *hptep,
708 rbyte = (hptep[1] & ~HPTE_R_R) >> 8; 736 rbyte = (hptep[1] & ~HPTE_R_R) >> 8;
709 /* modify only the second-last byte, which contains the ref bit */ 737 /* modify only the second-last byte, which contains the ref bit */
710 *((char *)hptep + 14) = rbyte; 738 *((char *)hptep + 14) = rbyte;
711 while (!try_lock_tlbie(&kvm->arch.tlbie_lock)) 739 do_tlbies(kvm, &rb, 1, 1, false);
712 cpu_relax();
713 asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
714 : : "r" (rb), "r" (kvm->arch.lpid));
715 asm volatile("ptesync" : : : "memory");
716 kvm->arch.tlbie_lock = 0;
717} 740}
718EXPORT_SYMBOL_GPL(kvmppc_clear_ref_hpte); 741EXPORT_SYMBOL_GPL(kvmppc_clear_ref_hpte);
719 742