* [PATCH v2 0/5] LoongArch: KVM: Small enhancement about interrupt injection
@ 2026-05-14 6:28 Bibo Mao
2026-05-14 6:28 ` [PATCH v2 1/5] LoongArch: KVM: Check irq validility in kvm_vcpu_ioctl_interrupt() Bibo Mao
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Bibo Mao @ 2026-05-14 6:28 UTC (permalink / raw)
To: Huacai Chen; +Cc: kernel, kvm, loongarch, linux-kernel
Here make interrupt status acquire interface simpler, add new interface
kvm_vcpu_sync_intr() to sync pending interrupt to software ESTAT
register, and remove expensive vcpu_load() and vcpu_put() function call.
Also interrupt inject is handled with batch method, rather one by one.
---
v1 ... v2:
1. Add irq validility check in function kvm_vcpu_ioctl_interrupt().
2. Add valid bit check when set ESTAT CSR register.
3. Merge two patches about interrupt clear and set with batch method into
one.
---
Bibo Mao (5):
LoongArch: KVM: Check irq validility in kvm_vcpu_ioctl_interrupt()
LoongArch: KVM: Use existing macro about interrupt bit mask
LoongArch: KVM: Inject interrupt with batch method
LoongArch: KVM: Add valid bit check when set ESTAT CSR register
LoongArch: KVM: Simple interrupt status acquire interface
arch/loongarch/include/asm/kvm_vcpu.h | 44 +++++---
arch/loongarch/kvm/interrupt.c | 140 +++++++++++++-------------
arch/loongarch/kvm/vcpu.c | 57 +++++++----
3 files changed, 136 insertions(+), 105 deletions(-)
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
--
2.39.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/5] LoongArch: KVM: Check irq validility in kvm_vcpu_ioctl_interrupt()
2026-05-14 6:28 [PATCH v2 0/5] LoongArch: KVM: Small enhancement about interrupt injection Bibo Mao
@ 2026-05-14 6:28 ` Bibo Mao
2026-05-14 6:28 ` [PATCH v2 2/5] LoongArch: KVM: Use existing macro about interrupt bit mask Bibo Mao
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Bibo Mao @ 2026-05-14 6:28 UTC (permalink / raw)
To: Huacai Chen; +Cc: kernel, kvm, loongarch, linux-kernel
Function kvm_vcpu_ioctl_interrupt() can be called from userspace, here
add irq validility cheking in kvm_vcpu_ioctl_interrupt(). Also add
msgint feature checking if irq number is INT_AVEC.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/kvm/interrupt.c | 5 -----
arch/loongarch/kvm/vcpu.c | 22 +++++++++++++++-------
2 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/arch/loongarch/kvm/interrupt.c b/arch/loongarch/kvm/interrupt.c
index a18c60dffbba..48dd56aa4dc5 100644
--- a/arch/loongarch/kvm/interrupt.c
+++ b/arch/loongarch/kvm/interrupt.c
@@ -36,8 +36,6 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
switch (priority) {
case INT_AVEC:
- if (!kvm_guest_has_msgint(&vcpu->arch))
- break;
dmsintc_inject_irq(vcpu);
fallthrough;
case INT_TI:
@@ -75,9 +73,6 @@ static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
switch (priority) {
case INT_AVEC:
- if (!kvm_guest_has_msgint(&vcpu->arch))
- break;
- fallthrough;
case INT_TI:
case INT_IPI:
case INT_SWI0:
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index e28084c49e68..dc2a1f56650b 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -1487,15 +1487,23 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu)
int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
{
int intr = (int)irq->irq;
+ int vector;
- if (intr > 0)
- kvm_queue_irq(vcpu, intr);
- else if (intr < 0)
- kvm_dequeue_irq(vcpu, -intr);
- else {
- kvm_err("%s: invalid interrupt ioctl %d\n", __func__, irq->irq);
+ vector = intr;
+ if (intr < 0)
+ vector = -intr;
+
+ if (vector >= EXCCODE_INT_NUM)
return -EINVAL;
- }
+
+ if (!kvm_guest_has_msgint(&vcpu->arch) && (vector == INT_AVEC))
+ return -EINVAL;
+
+ /* Clear irq function with intr == 0 is missing... */
+ if (intr >= 0)
+ kvm_queue_irq(vcpu, vector);
+ else
+ kvm_dequeue_irq(vcpu, vector);
kvm_vcpu_kick(vcpu);
--
2.39.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 2/5] LoongArch: KVM: Use existing macro about interrupt bit mask
2026-05-14 6:28 [PATCH v2 0/5] LoongArch: KVM: Small enhancement about interrupt injection Bibo Mao
2026-05-14 6:28 ` [PATCH v2 1/5] LoongArch: KVM: Check irq validility in kvm_vcpu_ioctl_interrupt() Bibo Mao
@ 2026-05-14 6:28 ` Bibo Mao
2026-05-14 6:28 ` [PATCH v2 3/5] LoongArch: KVM: Inject interrupt with batch method Bibo Mao
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Bibo Mao @ 2026-05-14 6:28 UTC (permalink / raw)
To: Huacai Chen; +Cc: kernel, kvm, loongarch, linux-kernel
With interrupt post, register CSR_GINTC and CSR_GSTAT is used, and
CSR_GSTAT is used for percpu interrupt injection and CSR_GINTC is for
external hardware interrupt injection.
Here use existing macro about interrupt bit of register CSR_GINTC and
CSR_GSTAT, rather than hard coded constant value.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/include/asm/kvm_vcpu.h | 43 ++++++++++++++++++---------
1 file changed, 29 insertions(+), 14 deletions(-)
diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h
index 3784ab4ccdb5..efe26b04b35f 100644
--- a/arch/loongarch/include/asm/kvm_vcpu.h
+++ b/arch/loongarch/include/asm/kvm_vcpu.h
@@ -10,22 +10,37 @@
#include <asm/loongarch.h>
/* Controlled by 0x5 guest estat */
-#define CPU_SIP0 (_ULCAST_(1))
-#define CPU_SIP1 (_ULCAST_(1) << 1)
-#define CPU_PMU (_ULCAST_(1) << 10)
-#define CPU_TIMER (_ULCAST_(1) << 11)
-#define CPU_IPI (_ULCAST_(1) << 12)
-#define CPU_AVEC (_ULCAST_(1) << 14)
+#define CPU_SIP0 BIT(INT_SWI0)
+#define CPU_SIP1 BIT(INT_SWI1)
+#define CPU_HWI0 BIT(INT_HWI0)
+#define CPU_HWI1 BIT(INT_HWI1)
+#define CPU_HWI2 BIT(INT_HWI2)
+#define CPU_HWI3 BIT(INT_HWI3)
+#define CPU_HWI4 BIT(INT_HWI4)
+#define CPU_HWI5 BIT(INT_HWI5)
+#define CPU_HWI6 BIT(INT_HWI6)
+#define CPU_HWI7 BIT(INT_HWI7)
+#define CPU_PMU BIT(INT_PCOV)
+#define CPU_TIMER BIT(INT_TI)
+#define CPU_IPI BIT(INT_IPI)
+#define CPU_AVEC BIT(INT_AVEC)
+#define KVM_ESTAT_IRQ_MASK (CPU_SIP0 | CPU_SIP1 | CPU_PMU | CPU_TIMER \
+ | CPU_IPI | CPU_AVEC)
+#define KVM_ESTAT_HWI_MASK (CPU_HWI0 | CPU_HWI1 | CPU_HWI2 | CPU_HWI3 \
+ | CPU_HWI4 | CPU_HWI5 | CPU_HWI6 | CPU_HWI7)
/* Controlled by 0x52 guest exception VIP aligned to estat bit 5~12 */
-#define CPU_IP0 (_ULCAST_(1))
-#define CPU_IP1 (_ULCAST_(1) << 1)
-#define CPU_IP2 (_ULCAST_(1) << 2)
-#define CPU_IP3 (_ULCAST_(1) << 3)
-#define CPU_IP4 (_ULCAST_(1) << 4)
-#define CPU_IP5 (_ULCAST_(1) << 5)
-#define CPU_IP6 (_ULCAST_(1) << 6)
-#define CPU_IP7 (_ULCAST_(1) << 7)
+#define GINTC_VIP_DELTA (INT_HWI0 - CSR_GINTC_VIP_SHIFT)
+#define CPU_IP0 BIT(INT_HWI0 - GINTC_VIP_DELTA)
+#define CPU_IP1 BIT(INT_HWI1 - GINTC_VIP_DELTA)
+#define CPU_IP2 BIT(INT_HWI2 - GINTC_VIP_DELTA)
+#define CPU_IP3 BIT(INT_HWI3 - GINTC_VIP_DELTA)
+#define CPU_IP4 BIT(INT_HWI4 - GINTC_VIP_DELTA)
+#define CPU_IP5 BIT(INT_HWI5 - GINTC_VIP_DELTA)
+#define CPU_IP6 BIT(INT_HWI6 - GINTC_VIP_DELTA)
+#define CPU_IP7 BIT(INT_HWI7 - GINTC_VIP_DELTA)
+#define KVM_GINTC_IRQ_MASK (CPU_IP0 | CPU_IP1 | CPU_IP2 | CPU_IP3 \
+ | CPU_IP4 | CPU_IP5 | CPU_IP6 | CPU_IP7)
#define MNSEC_PER_SEC (NSEC_PER_SEC >> 20)
--
2.39.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 3/5] LoongArch: KVM: Inject interrupt with batch method
2026-05-14 6:28 [PATCH v2 0/5] LoongArch: KVM: Small enhancement about interrupt injection Bibo Mao
2026-05-14 6:28 ` [PATCH v2 1/5] LoongArch: KVM: Check irq validility in kvm_vcpu_ioctl_interrupt() Bibo Mao
2026-05-14 6:28 ` [PATCH v2 2/5] LoongArch: KVM: Use existing macro about interrupt bit mask Bibo Mao
@ 2026-05-14 6:28 ` Bibo Mao
2026-05-14 6:28 ` [PATCH v2 4/5] LoongArch: KVM: Add valid bit check when set ESTAT CSR register Bibo Mao
2026-05-14 6:28 ` [PATCH v2 5/5] LoongArch: KVM: Simple interrupt status acquire interface Bibo Mao
4 siblings, 0 replies; 6+ messages in thread
From: Bibo Mao @ 2026-05-14 6:28 UTC (permalink / raw)
To: Huacai Chen; +Cc: kernel, kvm, loongarch, linux-kernel
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@loongson.cn>
---
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
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 4/5] LoongArch: KVM: Add valid bit check when set ESTAT CSR register
2026-05-14 6:28 [PATCH v2 0/5] LoongArch: KVM: Small enhancement about interrupt injection Bibo Mao
` (2 preceding siblings ...)
2026-05-14 6:28 ` [PATCH v2 3/5] LoongArch: KVM: Inject interrupt with batch method Bibo Mao
@ 2026-05-14 6:28 ` Bibo Mao
2026-05-14 6:28 ` [PATCH v2 5/5] LoongArch: KVM: Simple interrupt status acquire interface Bibo Mao
4 siblings, 0 replies; 6+ messages in thread
From: Bibo Mao @ 2026-05-14 6:28 UTC (permalink / raw)
To: Huacai Chen; +Cc: kernel, kvm, loongarch, linux-kernel
When set ESTAT CSR register in function _kvm_setcsr(), valid bit check
is added here. Also interrupt CPU_AVEC is checked by msgint feature.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/kvm/vcpu.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index dc2a1f56650b..2f4fd6fa5b0e 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -602,7 +602,7 @@ struct kvm_vcpu *kvm_get_vcpu_by_cpuid(struct kvm *kvm, int cpuid)
static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
{
- unsigned long gintc;
+ unsigned long gintc, estat;
struct loongarch_csrs *csr = vcpu->arch.csr;
if (get_gcsr_flag(id) & INVALID_GCSR)
@@ -621,8 +621,9 @@ static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
preempt_enable();
/* ESTAT IP0~IP7 get from GINTC */
- gintc = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & 0xff;
- *val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT) | (gintc << 2);
+ gintc = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & KVM_GINTC_IRQ_MASK;
+ estat = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT) & ~KVM_ESTAT_HWI_MASK;
+ *val = estat | (gintc << 2);
return 0;
}
@@ -637,7 +638,8 @@ static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
{
- int ret = 0, gintc;
+ int ret = 0;
+ unsigned long gintc, estat;
struct loongarch_csrs *csr = vcpu->arch.csr;
if (get_gcsr_flag(id) & INVALID_GCSR)
@@ -648,11 +650,15 @@ static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
if (id == LOONGARCH_CSR_ESTAT) {
/* ESTAT IP0~IP7 inject through GINTC */
- gintc = (val >> 2) & 0xff;
+ gintc = (val >> 2) & KVM_GINTC_IRQ_MASK;
kvm_set_sw_gcsr(csr, LOONGARCH_CSR_GINTC, gintc);
- gintc = val & ~(0xffUL << 2);
- kvm_set_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, gintc);
+ /* only set valid ESTAT bits */
+ estat = val & ~KVM_ESTAT_HWI_MASK;
+ estat &= CSR_ESTAT_IS | CSR_ESTAT_EXC | CSR_ESTAT_ESUBCODE;
+ if (!kvm_guest_has_msgint(&vcpu->arch))
+ estat &= ~CPU_AVEC;
+ kvm_set_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, estat);
return ret;
}
--
2.39.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 5/5] LoongArch: KVM: Simple interrupt status acquire interface
2026-05-14 6:28 [PATCH v2 0/5] LoongArch: KVM: Small enhancement about interrupt injection Bibo Mao
` (3 preceding siblings ...)
2026-05-14 6:28 ` [PATCH v2 4/5] LoongArch: KVM: Add valid bit check when set ESTAT CSR register Bibo Mao
@ 2026-05-14 6:28 ` Bibo Mao
4 siblings, 0 replies; 6+ messages in thread
From: Bibo Mao @ 2026-05-14 6:28 UTC (permalink / raw)
To: Huacai Chen; +Cc: kernel, kvm, loongarch, linux-kernel
When VM is migrating, interrupts status are stored in software CSR estat
register, also new injected interrupts are cached in
vcpu::arch::irq_pending.
With interrupt status acquire interface, there is expensive vcpu_load()
and vcpu_put() function call to sync cached vcpu::arch::irq_pending.
Here new internal API kvm_vcpu_sync_intr() is added to sync cached
pending irq to software CSR estat register.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
arch/loongarch/include/asm/kvm_vcpu.h | 1 +
arch/loongarch/kvm/interrupt.c | 42 +++++++++++++++++++++++++++
arch/loongarch/kvm/vcpu.c | 15 ++++++----
3 files changed, 52 insertions(+), 6 deletions(-)
diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h
index efe26b04b35f..e78bb2527329 100644
--- a/arch/loongarch/include/asm/kvm_vcpu.h
+++ b/arch/loongarch/include/asm/kvm_vcpu.h
@@ -64,6 +64,7 @@ int kvm_emu_idle(struct kvm_vcpu *vcpu);
int kvm_pending_timer(struct kvm_vcpu *vcpu);
int kvm_handle_fault(struct kvm_vcpu *vcpu, int fault);
void kvm_deliver_intr(struct kvm_vcpu *vcpu);
+void kvm_vcpu_sync_intr(struct kvm_vcpu *vcpu);
void kvm_deliver_exception(struct kvm_vcpu *vcpu);
void kvm_own_fpu(struct kvm_vcpu *vcpu);
diff --git a/arch/loongarch/kvm/interrupt.c b/arch/loongarch/kvm/interrupt.c
index 380aabb3d4d0..24925c238a65 100644
--- a/arch/loongarch/kvm/interrupt.c
+++ b/arch/loongarch/kvm/interrupt.c
@@ -71,6 +71,48 @@ void kvm_deliver_intr(struct kvm_vcpu *vcpu)
}
}
+void kvm_vcpu_sync_intr(struct kvm_vcpu *vcpu)
+{
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+ unsigned long mask, val;
+
+ if (!csr)
+ return;
+
+ mask = READ_ONCE(vcpu->arch.irq_clear);
+ if (mask) {
+ mask = xchg_relaxed(&vcpu->arch.irq_clear, 0);
+
+ /*
+ * sync cached irq_clear to sw state
+ *
+ * When VM is migrated to other physical machines or
+ * snapshot is created, cached irq pending state should
+ * be synced
+ */
+ val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT);
+ val &= ~(mask & KVM_ESTAT_IRQ_MASK);
+ kvm_write_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, val);
+
+ val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC);
+ val &= ~((mask >> 2) & KVM_GINTC_IRQ_MASK);
+ kvm_write_sw_gcsr(csr, LOONGARCH_CSR_GINTC, val);
+ }
+
+ mask = READ_ONCE(vcpu->arch.irq_pending);
+ if (mask) {
+ mask = xchg_relaxed(&vcpu->arch.irq_pending, 0);
+ /* sync cached irq_pending to sw state */
+ val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT);
+ val |= (mask & KVM_ESTAT_IRQ_MASK);
+ kvm_write_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, val);
+
+ val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC);
+ val |= (mask >> 2) & KVM_GINTC_IRQ_MASK;
+ kvm_write_sw_gcsr(csr, LOONGARCH_CSR_GINTC, val);
+ }
+}
+
int kvm_pending_timer(struct kvm_vcpu *vcpu)
{
return test_bit(INT_TI, &vcpu->arch.irq_pending);
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 2f4fd6fa5b0e..5f94360e8a4b 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -610,14 +610,11 @@ static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
if (id == LOONGARCH_CSR_ESTAT) {
preempt_disable();
- vcpu_load(vcpu);
/*
* Sync pending interrupts into ESTAT so that interrupt
* remains during VM migration stage
*/
- kvm_deliver_intr(vcpu);
- vcpu->arch.aux_inuse &= ~KVM_LARCH_SWCSR_LATEST;
- vcpu_put(vcpu);
+ kvm_vcpu_sync_intr(vcpu);
preempt_enable();
/* ESTAT IP0~IP7 get from GINTC */
@@ -1649,6 +1646,14 @@ static int _kvm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
/* Restore timer state regardless */
kvm_restore_timer(vcpu);
+
+ /*
+ * Restore Root.GINTC from unused Guest.GINTC register
+ *
+ * SW state about LOONGARCH_CSR_GINTC is updated with get_csr()
+ * ioctl command only. Update HW state from changed SW state.
+ */
+ write_csr_gintc(csr->csrs[LOONGARCH_CSR_GINTC]);
kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
/* Don't bother restoring registers multiple times unless necessary */
@@ -1711,8 +1716,6 @@ static int _kvm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ISR3);
}
- /* Restore Root.GINTC from unused Guest.GINTC register */
- write_csr_gintc(csr->csrs[LOONGARCH_CSR_GINTC]);
write_csr_gstat(csr->csrs[LOONGARCH_CSR_GSTAT]);
/*
--
2.39.3
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-05-14 6:30 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-14 6:28 [PATCH v2 0/5] LoongArch: KVM: Small enhancement about interrupt injection Bibo Mao
2026-05-14 6:28 ` [PATCH v2 1/5] LoongArch: KVM: Check irq validility in kvm_vcpu_ioctl_interrupt() Bibo Mao
2026-05-14 6:28 ` [PATCH v2 2/5] LoongArch: KVM: Use existing macro about interrupt bit mask Bibo Mao
2026-05-14 6:28 ` [PATCH v2 3/5] LoongArch: KVM: Inject interrupt with batch method Bibo Mao
2026-05-14 6:28 ` [PATCH v2 4/5] LoongArch: KVM: Add valid bit check when set ESTAT CSR register Bibo Mao
2026-05-14 6:28 ` [PATCH v2 5/5] LoongArch: KVM: Simple interrupt status acquire interface Bibo Mao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®