]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
LoongArch: KVM: Add AVEC basic support
authorSong Gao <gaosong@loongson.cn>
Thu, 27 Nov 2025 03:00:18 +0000 (11:00 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Thu, 27 Nov 2025 03:00:18 +0000 (11:00 +0800)
Check whether the host CPU supported AVEC, and save/restore CSR_MSGIS0-
CSR_MSGIS3 when necessary.

Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/include/asm/kvm_vcpu.h
arch/loongarch/include/uapi/asm/kvm.h
arch/loongarch/kvm/interrupt.c
arch/loongarch/kvm/vcpu.c
arch/loongarch/kvm/vm.c

index f1efd7cfbc20f5c07a8bd484443661aec3ba9790..3784ab4ccdb509bb1aa37ff3393ba3ebc80e269f 100644 (file)
@@ -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))
index 57ba1a563bb1a2563f77f1317b1d60b60866e52a..de6c3f18e40ab13f9f56daeeed9b6d3c7a9fe17b 100644 (file)
@@ -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
index 8462083f030174633966ac2f7950f4d6ea87ba90..a6d42d399a597dc9740db90b3ee395b1ff78697a 100644 (file)
@@ -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)
@@ -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:
@@ -58,6 +64,11 @@ static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
        if (priority < EXCCODE_INT_NUM)
                irq = priority_to_irq[priority];
 
+       if (cpu_has_msgint && (priority == INT_AVEC)) {
+               clear_gcsr_estat(irq);
+               return 1;
+       }
+
        switch (priority) {
        case INT_TI:
        case INT_IPI:
@@ -83,10 +94,10 @@ void kvm_deliver_intr(struct kvm_vcpu *vcpu)
        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)
+       for_each_set_bit(priority, pending_clr, EXCCODE_INT_NUM)
                kvm_irq_clear(vcpu, priority);
 
-       for_each_set_bit(priority, pending, INT_IPI + 1)
+       for_each_set_bit(priority, pending, EXCCODE_INT_NUM)
                kvm_irq_deliver(vcpu, priority);
 }
 
index 1245a6b358966f47025cf775a2925cb31ea32bbb..cd5f8d3c3c379dafd19a6292c9461a72c2845977 100644 (file)
@@ -659,8 +659,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 */
@@ -728,6 +727,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 */
@@ -1657,6 +1660,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]);
@@ -1746,6 +1755,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;
 
index e4f480342020533f087ab3e5ed60e3121013fe9b..194ccbcdc3b3830c794c25e252128a3244729ef2 100644 (file)
@@ -154,6 +154,10 @@ static int kvm_vm_feature_has_attr(struct kvm *kvm, struct kvm_device_attr *attr
                if (cpu_has_ptw)
                        return 0;
                return -ENXIO;
+       case KVM_LOONGARCH_VM_FEAT_MSGINT:
+               if (cpu_has_msgint)
+                       return 0;
+               return -ENXIO;
        case KVM_LOONGARCH_VM_FEAT_PMU:
        case KVM_LOONGARCH_VM_FEAT_PV_IPI:
        case KVM_LOONGARCH_VM_FEAT_PV_STEALTIME: