[PATCH v2 3/5] LoongArch: KVM: Inject interrupt with batch method
From: Bibo Mao
Date: Thu May 14 2026 - 02:36:27 EST
With bitmask method, interrupt can be injected with batch mode, rather
than one by one. Also remove unused array priority_to_irqp[] here.
Signed-off-by: Bibo Mao <maobibo@xxxxxxxxxxx>
---
arch/loongarch/kvm/interrupt.c | 95 ++++++++++------------------------
1 file changed, 28 insertions(+), 67 deletions(-)
diff --git a/arch/loongarch/kvm/interrupt.c b/arch/loongarch/kvm/interrupt.c
index 48dd56aa4dc5..380aabb3d4d0 100644
--- a/arch/loongarch/kvm/interrupt.c
+++ b/arch/loongarch/kvm/interrupt.c
@@ -9,39 +9,16 @@
#include <asm/kvm_vcpu.h>
#include <asm/kvm_dmsintc.h>
-static unsigned int priority_to_irq[EXCCODE_INT_NUM] = {
- [INT_TI] = CPU_TIMER,
- [INT_IPI] = CPU_IPI,
- [INT_SWI0] = CPU_SIP0,
- [INT_SWI1] = CPU_SIP1,
- [INT_HWI0] = CPU_IP0,
- [INT_HWI1] = CPU_IP1,
- [INT_HWI2] = CPU_IP2,
- [INT_HWI3] = CPU_IP3,
- [INT_HWI4] = CPU_IP4,
- [INT_HWI5] = CPU_IP5,
- [INT_HWI6] = CPU_IP6,
- [INT_HWI7] = CPU_IP7,
- [INT_AVEC] = CPU_AVEC,
-};
-
-static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
+static void kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned long mask)
{
- unsigned int irq = 0;
+ unsigned long irq;
unsigned long old, new;
- clear_bit(priority, &vcpu->arch.irq_pending);
- if (priority < EXCCODE_INT_NUM)
- irq = priority_to_irq[priority];
-
- switch (priority) {
- case INT_AVEC:
- dmsintc_inject_irq(vcpu);
- fallthrough;
- case INT_TI:
- case INT_IPI:
- case INT_SWI0:
- case INT_SWI1:
+ irq = mask & KVM_ESTAT_IRQ_MASK;
+ if (irq) {
+ if (irq & CPU_AVEC)
+ dmsintc_inject_irq(vcpu);
+
old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
set_gcsr_estat(irq);
new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
@@ -49,34 +26,20 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
/* Inject TI if TVAL inverted */
if (new > old)
set_gcsr_estat(CPU_TIMER);
- break;
-
- case INT_HWI0 ... INT_HWI7:
- set_csr_gintc(irq);
- break;
-
- default:
- break;
}
- return 1;
+ irq = (mask >> 2) & KVM_GINTC_IRQ_MASK;
+ if (irq)
+ set_csr_gintc(irq);
}
-static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
+static void kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned long mask)
{
- unsigned int irq = 0;
+ unsigned long irq;
unsigned long old, new;
- clear_bit(priority, &vcpu->arch.irq_clear);
- if (priority < EXCCODE_INT_NUM)
- irq = priority_to_irq[priority];
-
- switch (priority) {
- case INT_AVEC:
- case INT_TI:
- case INT_IPI:
- case INT_SWI0:
- case INT_SWI1:
+ irq = mask & KVM_ESTAT_IRQ_MASK;
+ if (irq) {
old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
clear_gcsr_estat(irq);
new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
@@ -84,30 +47,28 @@ static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
/* Inject TI if TVAL inverted */
if (new > old)
set_gcsr_estat(CPU_TIMER);
- break;
-
- case INT_HWI0 ... INT_HWI7:
- clear_csr_gintc(irq);
- break;
-
- default:
- break;
}
- return 1;
+ irq = (mask >> 2) & KVM_GINTC_IRQ_MASK;
+ if (irq)
+ clear_csr_gintc(irq);
}
void kvm_deliver_intr(struct kvm_vcpu *vcpu)
{
- unsigned int priority;
- unsigned long *pending = &vcpu->arch.irq_pending;
- unsigned long *pending_clr = &vcpu->arch.irq_clear;
+ unsigned long mask;
- for_each_set_bit(priority, pending_clr, EXCCODE_INT_NUM)
- kvm_irq_clear(vcpu, priority);
+ mask = READ_ONCE(vcpu->arch.irq_clear);
+ if (mask) {
+ mask = xchg_relaxed(&vcpu->arch.irq_clear, 0);
+ kvm_irq_clear(vcpu, mask);
+ }
- for_each_set_bit(priority, pending, EXCCODE_INT_NUM)
- kvm_irq_deliver(vcpu, priority);
+ mask = READ_ONCE(vcpu->arch.irq_pending);
+ if (mask) {
+ mask = xchg_relaxed(&vcpu->arch.irq_pending, 0);
+ kvm_irq_deliver(vcpu, mask);
+ }
}
int kvm_pending_timer(struct kvm_vcpu *vcpu)
--
2.39.3