LoongArch: KVM: Remove SW timer switch when vcpu is halt polling
authorBibo Mao <maobibo@loongson.cn>
Tue, 19 Dec 2023 02:48:27 +0000 (10:48 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Tue, 19 Dec 2023 02:48:27 +0000 (10:48 +0800)
With halt-polling supported, there is checking for pending events or
interrupts when vcpu executes idle instruction. Pending interrupts
include injected SW interrupts and passthrough HW interrupts, such as
HW timer interrupts, since HW timer works still even if vcpu exists from
VM mode.

Since HW timer pending interrupt can be set directly with CSR status
register, and pending HW timer interrupt checking is used in vcpu block
checking function, it is not necessary to switch to SW timer during
halt-polling. This patch adds preemption disabling in function
kvm_cpu_has_pending_timer(), and removes SW timer switching in idle
instruction emulation function.

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/kvm/exit.c
arch/loongarch/kvm/timer.c
arch/loongarch/kvm/vcpu.c

index ce8de3fa472cc64c14c80099ec55e06d24bf79be..e708a1786d6bdc9f8affa4ab690eb5dc24de9e12 100644 (file)
@@ -200,17 +200,8 @@ int kvm_emu_idle(struct kvm_vcpu *vcpu)
        ++vcpu->stat.idle_exits;
        trace_kvm_exit_idle(vcpu, KVM_TRACE_EXIT_IDLE);
 
-       if (!kvm_arch_vcpu_runnable(vcpu)) {
-               /*
-                * Switch to the software timer before halt-polling/blocking as
-                * the guest's timer may be a break event for the vCPU, and the
-                * hypervisor timer runs only when the CPU is in guest mode.
-                * Switch before halt-polling so that KVM recognizes an expired
-                * timer before blocking.
-                */
-               kvm_save_timer(vcpu);
-               kvm_vcpu_block(vcpu);
-       }
+       if (!kvm_arch_vcpu_runnable(vcpu))
+               kvm_vcpu_halt(vcpu);
 
        return EMULATE_DONE;
 }
index 284bf553fefef5ef3940a3adca572bfbc4d0462c..12d58040122dd13fbc04c9899b210b28af0bda8d 100644 (file)
@@ -155,11 +155,17 @@ static void _kvm_save_timer(struct kvm_vcpu *vcpu)
                 */
                hrtimer_cancel(&vcpu->arch.swtimer);
                hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
-       } else
+       } else if (vcpu->stat.generic.blocking) {
                /*
-                * Inject timer interrupt so that hall polling can dectect and exit
+                * Inject timer interrupt so that halt polling can dectect and exit.
+                * VCPU is scheduled out already and sleeps in rcuwait queue and
+                * will not poll pending events again. kvm_queue_irq() is not enough,
+                * hrtimer swtimer should be used here.
                 */
-               kvm_queue_irq(vcpu, INT_TI);
+               expire = ktime_add_ns(ktime_get(), 10);
+               vcpu->arch.expire = expire;
+               hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
+       }
 }
 
 /*
index 73d0c2b9c1a5769215a68bfd572f2785679ef01e..54f544b30f32ac8d38ab15e2b3d679df01ce939f 100644 (file)
@@ -187,8 +187,15 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
 
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 {
-       return kvm_pending_timer(vcpu) ||
+       int ret;
+
+       /* Protect from TOD sync and vcpu_load/put() */
+       preempt_disable();
+       ret = kvm_pending_timer(vcpu) ||
                kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT) & (1 << INT_TI);
+       preempt_enable();
+
+       return ret;
 }
 
 int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu)