]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
LoongArch: KVM: Fix HW timer interrupt lost when inject interrupt by software
authorBibo Mao <maobibo@loongson.cn>
Mon, 4 May 2026 01:00:48 +0000 (09:00 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 14 May 2026 13:31:19 +0000 (15:31 +0200)
commit 2433f3f5724b3af569d9fb411ba728629524738b upstream.

With passthrough HW timer, timer interrupt is injected by HW. When
inject emulated CPU interrupt by software such SIP0/SIP1/IPI, HW timer
interrupt may be lost.

Here check whether there is timer tick value inversion before and after
injecting emulated CPU interrupt by software, timer enabling by reading
timer cfg register is skipped. If the timer tick value is detected with
changing, then timer should be enabled. And inject a timer interrupt by
software if there is.

Cc: <stable@vger.kernel.org>
Fixes: f45ad5b8aa93 ("LoongArch: KVM: Implement vcpu interrupt operations").
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/loongarch/kvm/interrupt.c

index fb704f4c8ac593f397b53840d064c48f95349f19..656092e19062a5205aa6219f9c0475e6c6be3856 100644 (file)
@@ -27,6 +27,7 @@ static unsigned int priority_to_irq[EXCCODE_INT_NUM] = {
 static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
 {
        unsigned int irq = 0;
+       unsigned long old, new;
 
        clear_bit(priority, &vcpu->arch.irq_pending);
        if (priority < EXCCODE_INT_NUM)
@@ -42,7 +43,13 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
        case INT_IPI:
        case INT_SWI0:
        case INT_SWI1:
+               old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
                set_gcsr_estat(irq);
+               new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
+
+               /* Inject TI if TVAL inverted */
+               if (new > old)
+                       set_gcsr_estat(CPU_TIMER);
                break;
 
        case INT_HWI0 ... INT_HWI7:
@@ -59,6 +66,7 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
 static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
 {
        unsigned int irq = 0;
+       unsigned long old, new;
 
        clear_bit(priority, &vcpu->arch.irq_clear);
        if (priority < EXCCODE_INT_NUM)
@@ -74,7 +82,13 @@ static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
        case INT_IPI:
        case INT_SWI0:
        case INT_SWI1:
+               old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
                clear_gcsr_estat(irq);
+               new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
+
+               /* Inject TI if TVAL inverted */
+               if (new > old)
+                       set_gcsr_estat(CPU_TIMER);
                break;
 
        case INT_HWI0 ... INT_HWI7: