KVM: PPC: Book3S HV Nested: Avoid extra mftb() in nested entry
authorNicholas Piggin <npiggin@gmail.com>
Tue, 23 Nov 2021 09:52:22 +0000 (19:52 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 24 Nov 2021 10:09:02 +0000 (21:09 +1100)
mftb() is expensive and one can be avoided on nested guest dispatch.

If the time checking code distinguishes between the L0 timer and the
nested HV timer, then both can be tested in the same place with the
same mftb() value.

This also nicely illustrates the relationship between the L0 and nested
HV timers.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20211123095231.1036501-45-npiggin@gmail.com
arch/powerpc/include/asm/kvm_asm.h
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_nested.c

index fbbf3cec92e90710f667bcefc2cb67ba270f26c5..d68d71987d5cf35174ab4031d87984d488c91d5a 100644 (file)
@@ -79,6 +79,7 @@
 #define BOOK3S_INTERRUPT_FP_UNAVAIL    0x800
 #define BOOK3S_INTERRUPT_DECREMENTER   0x900
 #define BOOK3S_INTERRUPT_HV_DECREMENTER        0x980
+#define BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER 0x1980
 #define BOOK3S_INTERRUPT_DOORBELL      0xa00
 #define BOOK3S_INTERRUPT_SYSCALL       0xc00
 #define BOOK3S_INTERRUPT_TRACE         0xd00
index df4e3f88398dc12f16ed7c999a88a812b68ea9b2..65c9157579a3a476b8eb2101e750dd78a50831ca 100644 (file)
@@ -1486,6 +1486,10 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu,
        run->ready_for_interrupt_injection = 1;
        switch (vcpu->arch.trap) {
        /* We're good on these - the host merely wanted to get our attention */
+       case BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER:
+               WARN_ON_ONCE(1); /* Should never happen */
+               vcpu->arch.trap = BOOK3S_INTERRUPT_HV_DECREMENTER;
+               fallthrough;
        case BOOK3S_INTERRUPT_HV_DECREMENTER:
                vcpu->stat.dec_exits++;
                r = RESUME_GUEST;
@@ -1814,6 +1818,12 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu)
                vcpu->stat.ext_intr_exits++;
                r = RESUME_GUEST;
                break;
+       /* These need to go to the nested HV */
+       case BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER:
+               vcpu->arch.trap = BOOK3S_INTERRUPT_HV_DECREMENTER;
+               vcpu->stat.dec_exits++;
+               r = RESUME_HOST;
+               break;
        /* SR/HMI/PMI are HV interrupts that host has handled. Resume guest.*/
        case BOOK3S_INTERRUPT_HMI:
        case BOOK3S_INTERRUPT_PERFMON:
@@ -3993,6 +4003,8 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
                return BOOK3S_INTERRUPT_HV_DECREMENTER;
        if (next_timer < time_limit)
                time_limit = next_timer;
+       else if (*tb >= time_limit) /* nested time limit */
+               return BOOK3S_INTERRUPT_NESTED_HV_DECREMENTER;
 
        vcpu->arch.ceded = 0;
 
index 7bed0b91245ee08b5c81d2547ba0b9ea75f2844c..e57c08b968c0adeacbd1ec223cad371b001f023b 100644 (file)
@@ -375,11 +375,6 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)
        vcpu->arch.ret = RESUME_GUEST;
        vcpu->arch.trap = 0;
        do {
-               if (mftb() >= hdec_exp) {
-                       vcpu->arch.trap = BOOK3S_INTERRUPT_HV_DECREMENTER;
-                       r = RESUME_HOST;
-                       break;
-               }
                r = kvmhv_run_single_vcpu(vcpu, hdec_exp, lpcr);
        } while (is_kvmppc_resume_guest(r));