Re: [PATCH v2] LoongArch: KVM: Add AVEC support

From: Bibo Mao

Date: Mon Oct 13 2025 - 00:10:21 EST




On 2025/10/13 上午11:18, gaosong wrote:
在 2025/10/11 上午9:29, Bibo Mao 写道:


On 2025/10/10 下午2:48, Song Gao wrote:
Add cpu_has_msgint() to check whether the host cpu supported avec,
and restore/save CSR_MSGIS0-CSR_MSGIS3.

Signed-off-by: Song Gao <gaosong@xxxxxxxxxxx>
---
Based-on: https://patchew.org/linux/20250930093741.2734974-1-maobibo@xxxxxxxxxxx/
v2: fix build error.
It is not necessary based on this patch, you can base it on master branch. The later merged patch need based on previous version in general.

Got it.

  arch/loongarch/include/asm/kvm_host.h |  4 ++++
  arch/loongarch/include/asm/kvm_vcpu.h |  1 +
  arch/loongarch/include/uapi/asm/kvm.h |  1 +
  arch/loongarch/kvm/interrupt.c        |  3 +++
  arch/loongarch/kvm/vcpu.c             | 19 +++++++++++++++++--
  arch/loongarch/kvm/vm.c               |  4 ++++
  6 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 392480c9b958..446f1104d59d 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -285,6 +285,10 @@ static inline bool kvm_guest_has_lbt(struct kvm_vcpu_arch *arch)
      return arch->cpucfg[2] & (CPUCFG2_X86BT | CPUCFG2_ARMBT | CPUCFG2_MIPSBT);
  }
  +static inline bool cpu_has_msgint(void)
+{
+    return read_cpucfg(LOONGARCH_CPUCFG1) & CPUCFG1_MSGINT;
+}
  static inline bool kvm_guest_has_pmu(struct kvm_vcpu_arch *arch)
  {
      return arch->cpucfg[6] & CPUCFG6_PMP;
diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h
index f1efd7cfbc20..3784ab4ccdb5 100644
--- a/arch/loongarch/include/asm/kvm_vcpu.h
+++ b/arch/loongarch/include/asm/kvm_vcpu.h
@@ -15,6 +15,7 @@
  #define CPU_PMU                (_ULCAST_(1) << 10)
  #define CPU_TIMER            (_ULCAST_(1) << 11)
  #define CPU_IPI                (_ULCAST_(1) << 12)
+#define CPU_AVEC                        (_ULCAST_(1) << 14)
    /* Controlled by 0x52 guest exception VIP aligned to estat bit 5~12 */
  #define CPU_IP0                (_ULCAST_(1))
diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
index 57ba1a563bb1..de6c3f18e40a 100644
--- a/arch/loongarch/include/uapi/asm/kvm.h
+++ b/arch/loongarch/include/uapi/asm/kvm.h
@@ -104,6 +104,7 @@ struct kvm_fpu {
  #define  KVM_LOONGARCH_VM_FEAT_PV_IPI        6
  #define  KVM_LOONGARCH_VM_FEAT_PV_STEALTIME    7
  #define  KVM_LOONGARCH_VM_FEAT_PTW        8
+#define  KVM_LOONGARCH_VM_FEAT_MSGINT        9
    /* Device Control API on vcpu fd */
  #define KVM_LOONGARCH_VCPU_CPUCFG    0
diff --git a/arch/loongarch/kvm/interrupt.c b/arch/loongarch/kvm/interrupt.c
index 8462083f0301..adc278fb3cb9 100644
--- a/arch/loongarch/kvm/interrupt.c
+++ b/arch/loongarch/kvm/interrupt.c
@@ -21,6 +21,7 @@ static unsigned int priority_to_irq[EXCCODE_INT_NUM] = {
      [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)
@@ -36,6 +37,7 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
      case INT_IPI:
      case INT_SWI0:
      case INT_SWI1:
+    case INT_AVEC:
          set_gcsr_estat(irq);
Do we need cpu_has_msgint() here ? It is impossible that VMM inject INT_AVEC interrrupt on non-msgint machine such as 3C5000.

yes we need , how about this?

@@ -31,6 +32,11 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
        if (priority < EXCCODE_INT_NUM)
                irq = priority_to_irq[priority];

+        if (cpu_has_msgint() && (priority == INT_AVEC)) {
+                set_gcsr_estat(irq);
+                return 1;
+        }
+
        switch (priority) {
        case INT_TI:
        case INT_IPI:
This is workable. Another way is to add checking in irq inject root source function kvm_vcpu_ioctl_interrupt(). Both works for me.

BTW, I think that there should be modification with function kvm_deliver_intr() also. max irq bit is *INT_IPI + 1* where there will be problem with INT_AVEC. Should it be modified as *EXCCODE_INT_NUM*?

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;

for_each_set_bit(priority, pending_clr, INT_IPI + 1)
kvm_irq_clear(vcpu, priority);

for_each_set_bit(priority, pending, INT_IPI + 1)
kvm_irq_deliver(vcpu, priority);
}

Regards
Bibo Mao

Thanks.
Song Gao


          break;
  @@ -63,6 +65,7 @@ static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
      case INT_IPI:
      case INT_SWI0:
      case INT_SWI1:
+    case INT_AVEC:
          clear_gcsr_estat(irq);
Ditto.

The others look good to me.

Regards
Bibo Mao
          break;
  diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 30e3b089a596..226c735155be 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -657,8 +657,7 @@ static int _kvm_get_cpucfg_mask(int id, u64 *v)
          *v = GENMASK(31, 0);
          return 0;
      case LOONGARCH_CPUCFG1:
-        /* CPUCFG1_MSGINT is not supported by KVM */
-        *v = GENMASK(25, 0);
+        *v = GENMASK(26, 0);
          return 0;
      case LOONGARCH_CPUCFG2:
          /* CPUCFG2 features unconditionally supported by KVM */
@@ -726,6 +725,10 @@ static int kvm_check_cpucfg(int id, u64 val)
          return -EINVAL;
        switch (id) {
+    case LOONGARCH_CPUCFG1:
+        if ((val & CPUCFG1_MSGINT) && (!cpu_has_msgint()))
+            return -EINVAL;
+        return 0;
      case LOONGARCH_CPUCFG2:
          if (!(val & CPUCFG2_LLFTP))
              /* Guests must have a constant timer */
@@ -1658,6 +1661,12 @@ static int _kvm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
      kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN2);
      kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN3);
      kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_LLBCTL);
+    if (cpu_has_msgint()) {
+        kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ISR0);
+        kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ISR1);
+        kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ISR2);
+        kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ISR3);
+    }
        /* Restore Root.GINTC from unused Guest.GINTC register */
      write_csr_gintc(csr->csrs[LOONGARCH_CSR_GINTC]);
@@ -1747,6 +1756,12 @@ static int _kvm_vcpu_put(struct kvm_vcpu *vcpu, int cpu)
      kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN1);
      kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN2);
      kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN3);
+    if (cpu_has_msgint()) {
+        kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ISR0);
+        kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ISR1);
+        kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ISR2);
+        kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ISR3);
+    }
        vcpu->arch.aux_inuse |= KVM_LARCH_SWCSR_LATEST;
  diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c
index d8c813e2d72e..438885b6f2b1 100644
--- a/arch/loongarch/kvm/vm.c
+++ b/arch/loongarch/kvm/vm.c
@@ -37,6 +37,9 @@ static void kvm_vm_init_features(struct kvm *kvm)
          kvm->arch.support_features |= BIT(KVM_LOONGARCH_VM_FEAT_PV_STEALTIME);
      }
  +    if (cpu_has_msgint())
+        kvm->arch.support_features |= BIT(KVM_LOONGARCH_VM_FEAT_MSGINT);
+
      val = read_csr_gcfg();
      if (val & CSR_GCFG_GPMP)
          kvm->arch.support_features |= BIT(KVM_LOONGARCH_VM_FEAT_PMU);
@@ -153,6 +156,7 @@ static int kvm_vm_feature_has_attr(struct kvm *kvm, struct kvm_device_attr *attr
      case KVM_LOONGARCH_VM_FEAT_PMU:
      case KVM_LOONGARCH_VM_FEAT_PV_IPI:
      case KVM_LOONGARCH_VM_FEAT_PV_STEALTIME:
+        case KVM_LOONGARCH_VM_FEAT_MSGINT:
          if (kvm_vm_support(&kvm->arch, attr->attr))
              return 0;
          return -ENXIO;