HV interrupts may be taken with the MMU enabled when radix guests are
running. Enable LPCR[HAIL] on ISA v3.1 processors for radix guests.
Make this depend on the host LPCR[HAIL] being enabled. Currently that is
always enabled, but having this test means any issue that might require
LPCR[HAIL] to be disabled in the host will not have to be duplicated in
KVM.

-1380 cycles on P10 NULL hcall entry+exit

Reviewed-by: Fabiano Rosas <faro...@linux.ibm.com>
Signed-off-by: Nicholas Piggin <npig...@gmail.com>
---
 arch/powerpc/kvm/book3s_hv.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 0cef578930f9..e7f8cc04944b 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -5004,6 +5004,8 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
  */
 int kvmppc_switch_mmu_to_hpt(struct kvm *kvm)
 {
+       unsigned long lpcr, lpcr_mask;
+
        if (nesting_enabled(kvm))
                kvmhv_release_all_nested(kvm);
        kvmppc_rmap_reset(kvm);
@@ -5013,8 +5015,13 @@ int kvmppc_switch_mmu_to_hpt(struct kvm *kvm)
        kvm->arch.radix = 0;
        spin_unlock(&kvm->mmu_lock);
        kvmppc_free_radix(kvm);
-       kvmppc_update_lpcr(kvm, LPCR_VPM1,
-                          LPCR_VPM1 | LPCR_UPRT | LPCR_GTSE | LPCR_HR);
+
+       lpcr = LPCR_VPM1;
+       lpcr_mask = LPCR_VPM1 | LPCR_UPRT | LPCR_GTSE | LPCR_HR;
+       if (cpu_has_feature(CPU_FTR_ARCH_31))
+               lpcr_mask |= LPCR_HAIL;
+       kvmppc_update_lpcr(kvm, lpcr, lpcr_mask);
+
        return 0;
 }
 
@@ -5024,6 +5031,7 @@ int kvmppc_switch_mmu_to_hpt(struct kvm *kvm)
  */
 int kvmppc_switch_mmu_to_radix(struct kvm *kvm)
 {
+       unsigned long lpcr, lpcr_mask;
        int err;
 
        err = kvmppc_init_vm_radix(kvm);
@@ -5035,8 +5043,17 @@ int kvmppc_switch_mmu_to_radix(struct kvm *kvm)
        kvm->arch.radix = 1;
        spin_unlock(&kvm->mmu_lock);
        kvmppc_free_hpt(&kvm->arch.hpt);
-       kvmppc_update_lpcr(kvm, LPCR_UPRT | LPCR_GTSE | LPCR_HR,
-                          LPCR_VPM1 | LPCR_UPRT | LPCR_GTSE | LPCR_HR);
+
+       lpcr = LPCR_UPRT | LPCR_GTSE | LPCR_HR;
+       lpcr_mask = LPCR_VPM1 | LPCR_UPRT | LPCR_GTSE | LPCR_HR;
+       if (cpu_has_feature(CPU_FTR_ARCH_31)) {
+               lpcr_mask |= LPCR_HAIL;
+               if (cpu_has_feature(CPU_FTR_HVMODE) &&
+                               (kvm->arch.host_lpcr & LPCR_HAIL))
+                       lpcr |= LPCR_HAIL;
+       }
+       kvmppc_update_lpcr(kvm, lpcr, lpcr_mask);
+
        return 0;
 }
 
@@ -5200,6 +5217,10 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
                kvm->arch.mmu_ready = 1;
                lpcr &= ~LPCR_VPM1;
                lpcr |= LPCR_UPRT | LPCR_GTSE | LPCR_HR;
+               if (cpu_has_feature(CPU_FTR_HVMODE) &&
+                   cpu_has_feature(CPU_FTR_ARCH_31) &&
+                   (kvm->arch.host_lpcr & LPCR_HAIL))
+                       lpcr |= LPCR_HAIL;
                ret = kvmppc_init_vm_radix(kvm);
                if (ret) {
                        kvmppc_free_lpid(kvm->arch.lpid);
-- 
2.23.0

Reply via email to