Re: [PATCH v6 2/2] LongArch: KVM: Add dmsintc inject msi to the dest vcpu
From: gaosong
Date: Mon Mar 09 2026 - 04:23:25 EST
在 2026/3/5 下午3:33, Huacai Chen 写道:
Hi, Song,I'll move it to patch1.
On Fri, Feb 6, 2026 at 9:45 AM Song Gao <gaosong@xxxxxxxxxxx> wrote:
Implement irqfd deliver msi to vcpu and vcpu dmsintc inject irq.I'm not sure but maybe this part should go to the first patch?
Add irqfd choice dmsintc to set msi irq by the msg_addr and
implement dmsintc set msi irq.
Signed-off-by: Song Gao <gaosong@xxxxxxxxxxx>
---
arch/loongarch/include/asm/kvm_dmsintc.h | 1 +
arch/loongarch/include/asm/kvm_host.h | 5 ++
arch/loongarch/kvm/intc/dmsintc.c | 6 +++
arch/loongarch/kvm/interrupt.c | 1 +
arch/loongarch/kvm/irqfd.c | 42 +++++++++++++++--
arch/loongarch/kvm/vcpu.c | 58 ++++++++++++++++++++++++
6 files changed, 109 insertions(+), 4 deletions(-)
diff --git a/arch/loongarch/include/asm/kvm_dmsintc.h b/arch/loongarch/include/asm/kvm_dmsintc.h
index 1d4f66996f3c..9b5436a2fcbe 100644
--- a/arch/loongarch/include/asm/kvm_dmsintc.h
+++ b/arch/loongarch/include/asm/kvm_dmsintc.h
@@ -11,6 +11,7 @@ struct loongarch_dmsintc {
struct kvm *kvm;
uint64_t msg_addr_base;
uint64_t msg_addr_size;
+ uint32_t cpu_mask;
};
struct dmsintc_state {
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 5e9e2af7312f..91e0190aeaec 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -258,6 +258,11 @@ struct kvm_vcpu_arch {
} st;
};
+void loongarch_dmsintc_inject_irq(struct kvm_vcpu *vcpu);
+int kvm_loongarch_deliver_msi_to_vcpu(struct kvm *kvm,
+ struct kvm_vcpu *vcpu,
+ u32 vector, int level);
+
static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
{
return csr->csrs[reg];
diff --git a/arch/loongarch/kvm/intc/dmsintc.c b/arch/loongarch/kvm/intc/dmsintc.c
index 00e401de0464..1bb61e55d061 100644
--- a/arch/loongarch/kvm/intc/dmsintc.c
+++ b/arch/loongarch/kvm/intc/dmsintc.c
@@ -15,6 +15,7 @@ static int kvm_dmsintc_ctrl_access(struct kvm_device *dev,
void __user *data;
struct loongarch_dmsintc *s = dev->kvm->arch.dmsintc;
u64 tmp;
+ u32 cpu_bit;
data = (void __user *)attr->addr;
switch (addr) {
@@ -30,6 +31,11 @@ static int kvm_dmsintc_ctrl_access(struct kvm_device *dev,
s->msg_addr_base = tmp;
else
return -EFAULT;
+ s->msg_addr_base = tmp;
+ cpu_bit = find_first_bit((unsigned long *)&(s->msg_addr_base), 64)
+ - AVEC_CPU_SHIFT;
+ cpu_bit = min(cpu_bit, AVEC_CPU_BIT);
+ s->cpu_mask = GENMASK(cpu_bit - 1, 0) & AVEC_CPU_MASK;
}
break;
case KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_SIZE:
Got it .diff --git a/arch/loongarch/kvm/interrupt.c b/arch/loongarch/kvm/interrupt.cRename loongarch_set_msi() to loongarch_msi_set_irq(), rename
index a6d42d399a59..893a81ca1079 100644
--- a/arch/loongarch/kvm/interrupt.c
+++ b/arch/loongarch/kvm/interrupt.c
@@ -33,6 +33,7 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
irq = priority_to_irq[priority];
if (cpu_has_msgint && (priority == INT_AVEC)) {
+ loongarch_dmsintc_inject_irq(vcpu);
set_gcsr_estat(irq);
return 1;
}
diff --git a/arch/loongarch/kvm/irqfd.c b/arch/loongarch/kvm/irqfd.c
index 9a39627aecf0..3bbb26f4e2b7 100644
--- a/arch/loongarch/kvm/irqfd.c
+++ b/arch/loongarch/kvm/irqfd.c
@@ -6,6 +6,7 @@
#include <linux/kvm_host.h>
#include <trace/events/kvm.h>
#include <asm/kvm_pch_pic.h>
+#include <asm/kvm_vcpu.h>
static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level, bool line_status)
@@ -16,6 +17,38 @@ static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
return 0;
}
+static int kvm_dmsintc_set_msi_irq(struct kvm *kvm, u32 addr, int data, int level)
+{
+ unsigned int virq, dest;
+ struct kvm_vcpu *vcpu;
+
+ virq = (addr >> AVEC_IRQ_SHIFT) & AVEC_IRQ_MASK;
+ dest = (addr >> AVEC_CPU_SHIFT) & kvm->arch.dmsintc->cpu_mask;
+ if (dest > KVM_MAX_VCPUS)
+ return -EINVAL;
+ vcpu = kvm_get_vcpu_by_cpuid(kvm, dest);
+ if (!vcpu)
+ return -EINVAL;
+ return kvm_loongarch_deliver_msi_to_vcpu(kvm, vcpu, virq, level);
+}
+
+static int loongarch_set_msi(struct kvm_kernel_irq_routing_entry *e,
+ struct kvm *kvm, int level)
+{
+ u64 msg_addr;
+
+ msg_addr = (((u64)e->msi.address_hi) << 32) | e->msi.address_lo;
+ if (cpu_has_msgint && kvm->arch.dmsintc &&
+ msg_addr >= kvm->arch.dmsintc->msg_addr_base &&
+ msg_addr < (kvm->arch.dmsintc->msg_addr_base + kvm->arch.dmsintc->msg_addr_size)) {
+ return kvm_dmsintc_set_msi_irq(kvm, msg_addr, e->msi.data, level);
+ } else {
+ pch_msi_set_irq(kvm, e->msi.data, level);
+ }
+
+ return 0;
+}
kvm_dmsintc_set_msi_irq() to dmsintc_msi_set_irq(), this makes the
naming more consistent.
Got it.+The only caller is in interrupt.c, so rename
/*
* kvm_set_msi: inject the MSI corresponding to the
* MSI routing entry
@@ -29,9 +62,7 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
if (!level)
return -1;
- pch_msi_set_irq(kvm, e->msi.data, level);
-
- return 0;
+ return loongarch_set_msi(e, kvm, level);
}
/*
@@ -71,12 +102,15 @@ int kvm_set_routing_entry(struct kvm *kvm,
int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level, bool line_status)
{
+ if (!level)
+ return -EWOULDBLOCK;
+
switch (e->type) {
case KVM_IRQ_ROUTING_IRQCHIP:
pch_pic_set_irq(kvm->arch.pch_pic, e->irqchip.pin, level);
return 0;
case KVM_IRQ_ROUTING_MSI:
- pch_msi_set_irq(kvm, e->msi.data, level);
+ loongarch_set_msi(e, kvm, level);
return 0;
default:
return -EWOULDBLOCK;
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 656b954c1134..325bb084d704 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -14,6 +14,64 @@
#define CREATE_TRACE_POINTS
#include "trace.h"
+void loongarch_dmsintc_inject_irq(struct kvm_vcpu *vcpu)
+{
+ struct dmsintc_state *ds = &vcpu->arch.dmsintc_state;
+ unsigned int i;
+ unsigned long temp[4], old;
+
+ if (!ds)
+ return;
+
+ for (i = 0; i < 4; i++) {
+ old = atomic64_read(&(ds->vector_map[i]));
+ if (old)
+ temp[i] = atomic64_xchg(&(ds->vector_map[i]), 0);
+ }
+
+ if (temp[0]) {
+ old = kvm_read_hw_gcsr(LOONGARCH_CSR_ISR0);
+ kvm_write_hw_gcsr(LOONGARCH_CSR_ISR0, temp[0]|old);
+ }
+
+ if (temp[1]) {
+ old = kvm_read_hw_gcsr(LOONGARCH_CSR_ISR1);
+ kvm_write_hw_gcsr(LOONGARCH_CSR_ISR1, temp[1]|old);
+ }
+
+ if (temp[2]) {
+ old = kvm_read_hw_gcsr(LOONGARCH_CSR_ISR2);
+ kvm_write_hw_gcsr(LOONGARCH_CSR_ISR2, temp[2]|old);
+ }
+
+ if (temp[3]) {
+ old = kvm_read_hw_gcsr(LOONGARCH_CSR_ISR3);
+ kvm_write_hw_gcsr(LOONGARCH_CSR_ISR3, temp[3]|old);
+ }
+}
loongarch_dmsintc_inject_irq() to msgint_inject_irq() (or
dmsintc_inject_irq() if you prefer), and move it to interrupt.c, then
we don't need to declare it as a extern function.
Got it .+The only caller is in irqfd.c, so rename
+int kvm_loongarch_deliver_msi_to_vcpu(struct kvm *kvm,
+ struct kvm_vcpu *vcpu,
+ u32 vector, int level)
+{
+ struct kvm_interrupt vcpu_irq;
+ struct dmsintc_state *ds;
+
+ if (!level)
+ return 0;
+ if (!vcpu || vector >= 256)
+ return -EINVAL;
+ ds = &vcpu->arch.dmsintc_state;
+ if (!ds)
+ return -ENODEV;
+ set_bit(vector, (unsigned long *)&ds->vector_map);
+ vcpu_irq.irq = INT_AVEC;
+ kvm_vcpu_ioctl_interrupt(vcpu, &vcpu_irq);
+ kvm_vcpu_kick(vcpu);
+ return 0;
+}
kvm_loongarch_deliver_msi_to_vcpu() to dmsintc_deliver_msi_to_vcpu(),
and move it to irqfd.c, then we don't need to declare it as a extern
function.
And in addition, from Documentation/arch/loongarch/irq-chip-model.rst,
all msi irq are triggered from "pch_msi_irq", which means it is not
reasonable to dispatch the dmsintc/pch_msi paths in
loongarch_set_msi(). Instead, we should dispatch the dmsintc/eiointc
paths in pch_msi_set_irq(), this needs a rework...
longarch_set_msi() is equivalent to what you mentioned as pch_msi_set_irq(). I will correct it in the next version.
Thanks.
Song Gao
Huacai
+
+
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
KVM_GENERIC_VCPU_STATS(),
STATS_DESC_COUNTER(VCPU, int_exits),
--
2.39.3