* [PATCH v3 1/2] KVM: LoongArch: selftests: Enable LASX feature by auto detect method
2026-06-16 2:26 [PATCH v3 0/2] KVM: LoongArch: selftests: Add FPU test case Bibo Mao
@ 2026-06-16 2:26 ` Bibo Mao
2026-06-16 2:39 ` sashiko-bot
2026-06-16 2:26 ` [PATCH v3 2/2] KVM: LoongArch: selftests: Add FPU test case Bibo Mao
1 sibling, 1 reply; 5+ messages in thread
From: Bibo Mao @ 2026-06-16 2:26 UTC (permalink / raw)
To: Huacai Chen; +Cc: kvm, loongarch, linux-kernel, linux-kselftest
Add LSX and LASX features when VM is created. These features are detected
firstly, enable it if it is available on host machine.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
.../selftests/kvm/include/loongarch/processor.h | 10 ++++++++++
.../testing/selftests/kvm/lib/loongarch/processor.c | 12 +++++++++++-
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/kvm/include/loongarch/processor.h b/tools/testing/selftests/kvm/include/loongarch/processor.h
index 93dc1fbd2e79..2324e311180f 100644
--- a/tools/testing/selftests/kvm/include/loongarch/processor.h
+++ b/tools/testing/selftests/kvm/include/loongarch/processor.h
@@ -131,6 +131,16 @@
#define CSR_TLBREHI_PS_SHIFT 0
#define CSR_TLBREHI_PS (0x3fUL << CSR_TLBREHI_PS_SHIFT)
+#define LOONGARCH_CPUCFG2 0x2
+#define CPUCFG2_FP BIT(0)
+#define CPUCFG2_FPSP BIT(1)
+#define CPUCFG2_FPDP BIT(2)
+#define CPUCFG2_FPVERS GENMASK(5, 3)
+#define CPUCFG2_LSX BIT(6)
+#define CPUCFG2_LASX BIT(7)
+#define CPUCFG2_LLFTP BIT(14)
+#define CPUCFG2_LLFTPREV GENMASK(17, 15)
+
#define read_cpucfg(reg) \
({ \
register unsigned long __v; \
diff --git a/tools/testing/selftests/kvm/lib/loongarch/processor.c b/tools/testing/selftests/kvm/lib/loongarch/processor.c
index 64d91fb76522..e7fb54d746f4 100644
--- a/tools/testing/selftests/kvm/lib/loongarch/processor.c
+++ b/tools/testing/selftests/kvm/lib/loongarch/processor.c
@@ -278,7 +278,7 @@ static void loongarch_set_csr(struct kvm_vcpu *vcpu, u64 id, u64 val)
void loongarch_vcpu_setup(struct kvm_vcpu *vcpu)
{
- int width;
+ int width, ret;
unsigned int cfg;
unsigned long val;
struct kvm_vm *vm = vcpu->vm;
@@ -292,6 +292,16 @@ void loongarch_vcpu_setup(struct kvm_vcpu *vcpu)
TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode);
}
+ /* Enable LSX/LASX feature by detecting host capability */
+ cfg = CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP | CPUCFG2_LLFTP;
+ ret = __kvm_has_device_attr(vm->fd, KVM_LOONGARCH_VM_FEAT_CTRL, KVM_LOONGARCH_VM_FEAT_LSX);
+ if (!ret)
+ cfg |= CPUCFG2_LSX;
+
+ ret = __kvm_has_device_attr(vm->fd, KVM_LOONGARCH_VM_FEAT_CTRL, KVM_LOONGARCH_VM_FEAT_LASX);
+ if (!ret)
+ cfg |= CPUCFG2_LASX;
+ loongarch_set_cpucfg(vcpu, LOONGARCH_CPUCFG2, cfg);
cfg = read_cpucfg(LOONGARCH_CPUCFG6);
loongarch_set_cpucfg(vcpu, LOONGARCH_CPUCFG6, cfg);
--
2.39.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v3 2/2] KVM: LoongArch: selftests: Add FPU test case
2026-06-16 2:26 [PATCH v3 0/2] KVM: LoongArch: selftests: Add FPU test case Bibo Mao
2026-06-16 2:26 ` [PATCH v3 1/2] KVM: LoongArch: selftests: Enable LASX feature by auto detect method Bibo Mao
@ 2026-06-16 2:26 ` Bibo Mao
2026-06-16 2:34 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Bibo Mao @ 2026-06-16 2:26 UTC (permalink / raw)
To: Huacai Chen; +Cc: kvm, loongarch, linux-kernel, linux-kselftest
Add FPU test case and verify FPU register get and set APIs, the
FPU width supports 64/128/256 bits.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../kvm/include/loongarch/processor.h | 8 +
.../selftests/kvm/loongarch/fpu_test.c | 138 ++++++++++++++++++
3 files changed, 147 insertions(+)
create mode 100644 tools/testing/selftests/kvm/loongarch/fpu_test.c
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 9118a5a51b89..7d11592b3759 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -224,6 +224,7 @@ TEST_GEN_PROGS_riscv += rseq_test
TEST_GEN_PROGS_riscv += steal_time
TEST_GEN_PROGS_loongarch = loongarch/pmu_test
+TEST_GEN_PROGS_loongarch += loongarch/fpu_test
TEST_GEN_PROGS_loongarch += arch_timer
TEST_GEN_PROGS_loongarch += coalesced_io_test
TEST_GEN_PROGS_loongarch += demand_paging_test
diff --git a/tools/testing/selftests/kvm/include/loongarch/processor.h b/tools/testing/selftests/kvm/include/loongarch/processor.h
index 2324e311180f..981ae7078354 100644
--- a/tools/testing/selftests/kvm/include/loongarch/processor.h
+++ b/tools/testing/selftests/kvm/include/loongarch/processor.h
@@ -82,6 +82,14 @@
#define PLV_MASK 0x3
#define LOONGARCH_CSR_PRMD 0x1
#define LOONGARCH_CSR_EUEN 0x2
+#define CSR_EUEN_LBTEN_SHIFT 3
+#define CSR_EUEN_LBTEN BIT_ULL(CSR_EUEN_LBTEN_SHIFT)
+#define CSR_EUEN_LASXEN_SHIFT 2
+#define CSR_EUEN_LASXEN BIT_ULL(CSR_EUEN_LASXEN_SHIFT)
+#define CSR_EUEN_LSXEN_SHIFT 1
+#define CSR_EUEN_LSXEN BIT_ULL(CSR_EUEN_LSXEN_SHIFT)
+#define CSR_EUEN_FPEN_SHIFT 0
+#define CSR_EUEN_FPEN BIT_ULL(CSR_EUEN_FPEN_SHIFT)
#define LOONGARCH_CSR_ECFG 0x4
#define ECFGB_PMU 10
#define ECFGF_PMU (BIT_ULL(ECFGB_PMU))
diff --git a/tools/testing/selftests/kvm/loongarch/fpu_test.c b/tools/testing/selftests/kvm/loongarch/fpu_test.c
new file mode 100644
index 000000000000..fe58ed4f93c0
--- /dev/null
+++ b/tools/testing/selftests/kvm/loongarch/fpu_test.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdio.h>
+#include <string.h>
+#include "kvm_util.h"
+#include "processor.h"
+#include "loongarch/processor.h"
+
+struct kvm_fpureg __aligned(64) vector = {{1, 2, 3, 4 }};
+
+static void guest_code(void)
+{
+ unsigned long val;
+ struct kvm_fpureg *fp = &vector;
+
+ val = csr_read(LOONGARCH_CSR_EUEN);
+ val |= CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN;
+ csr_write(val, LOONGARCH_CSR_EUEN);
+
+ __asm__ __volatile__("fld.d $f0, %0, 0\n" : : "r"(fp) : "$f0");
+ GUEST_SYNC(0);
+
+ __asm__ __volatile__("vld $vr0, %0, 0\n" : : "r"(fp) : "$vr0");
+ GUEST_SYNC(1);
+
+ __asm__ __volatile__("xvld $xr0, %0, 0\n" : : "r"(fp) : "$xr0");
+ GUEST_SYNC(2);
+
+ __asm__ __volatile__("fst.d $f0, %0, 0\n" : : "r"(fp) : "memory");
+ GUEST_SYNC(3);
+
+ __asm__ __volatile__("vst $vr0, %0, 0\n" : : "r"(fp) : "memory");
+ GUEST_SYNC(4);
+
+ __asm__ __volatile__("xvst $xr0, %0, 0\n" : : "r"(fp) : "memory");
+ GUEST_SYNC(5);
+
+ GUEST_DONE();
+}
+
+static void run_vcpu(struct kvm_vcpu *vcpu)
+{
+ struct ucall uc;
+ int cont;
+
+ cont = 1;
+ while (cont) {
+ vcpu_run(vcpu);
+
+ switch (get_ucall(vcpu, &uc)) {
+ case UCALL_PRINTF:
+ printf("%s", (const char *)uc.buffer);
+ break;
+ case UCALL_DONE:
+ printf("FPU test PASSED\n");
+ fallthrough;
+ case UCALL_SYNC:
+ cont = 0;
+ break;
+ case UCALL_ABORT:
+ REPORT_GUEST_ASSERT(uc);
+ default:
+ TEST_ASSERT(false, "Unexpected exit: %s",
+ exit_reason_str(vcpu->run->exit_reason));
+ }
+ }
+}
+
+int main(void)
+{
+ struct kvm_vcpu *vcpu;
+ struct kvm_vm *vm;
+ struct kvm_fpu fpu;
+ struct kvm_fpureg *fp = &vector;
+ int ret;
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+ ret = __kvm_has_device_attr(vm->fd, KVM_LOONGARCH_VM_FEAT_CTRL, KVM_LOONGARCH_VM_FEAT_LSX);
+ __TEST_REQUIRE(!ret, "LSX not available, skipping test\n");
+
+ ret = __kvm_has_device_attr(vm->fd, KVM_LOONGARCH_VM_FEAT_CTRL, KVM_LOONGARCH_VM_FEAT_LASX);
+ __TEST_REQUIRE(!ret, "LASX not available, skipping test\n");
+
+ run_vcpu(vcpu);
+ vcpu_fpu_get(vcpu, &fpu);
+ TEST_ASSERT(!memcmp(fpu.fpr, fp, 8), "Wanted 0x%llx from f0, got 0x%llx",
+ fp->val64[0], fpu.fpr[0].val64[0]);
+
+ run_vcpu(vcpu);
+ vcpu_fpu_get(vcpu, &fpu);
+ TEST_ASSERT(!memcmp(fpu.fpr, fp, 16), "Wanted 0x%llx %llx from vr0, got 0x%llx %llx",
+ fp->val64[0], fp->val64[1],
+ fpu.fpr[0].val64[0], fpu.fpr[0].val64[1]);
+
+ run_vcpu(vcpu);
+ vcpu_fpu_get(vcpu, &fpu);
+ TEST_ASSERT(!memcmp(fpu.fpr, fp, 32),
+ "Wanted 0x%llx %llx %llx %llx from xr0, got 0x%llx %llx %llx %llx",
+ fp->val64[0], fp->val64[1], fp->val64[2], fp->val64[3],
+ fpu.fpr[0].val64[0], fpu.fpr[0].val64[1],
+ fpu.fpr[0].val64[2], fpu.fpr[0].val64[3]);
+
+ fpu.fpr[0].val64[0] += random();
+ vcpu_fpu_set(vcpu, &fpu);
+ run_vcpu(vcpu);
+ vcpu_fpu_get(vcpu, &fpu);
+ sync_global_from_guest(vm, *fp);
+ TEST_ASSERT(!memcmp(fpu.fpr, fp, 8), "Wanted 0x%llx from f0, got 0x%llx",
+ fp->val64[0], fpu.fpr[0].val64[0]);
+
+ fpu.fpr[0].val64[0] += random();
+ fpu.fpr[0].val64[1] += random();
+ vcpu_fpu_set(vcpu, &fpu);
+ run_vcpu(vcpu);
+ vcpu_fpu_get(vcpu, &fpu);
+ sync_global_from_guest(vm, *fp);
+ TEST_ASSERT(!memcmp(fpu.fpr, fp, 16), "Wanted 0x%llx %llx from vr0, got 0x%llx %llx",
+ fp->val64[0], fp->val64[1],
+ fpu.fpr[0].val64[0], fpu.fpr[0].val64[1]);
+
+ fpu.fpr[0].val64[0] += random();
+ fpu.fpr[0].val64[1] += random();
+ fpu.fpr[0].val64[2] += random();
+ fpu.fpr[0].val64[3] += random();
+ vcpu_fpu_set(vcpu, &fpu);
+ run_vcpu(vcpu);
+ vcpu_fpu_get(vcpu, &fpu);
+ sync_global_from_guest(vm, *fp);
+ TEST_ASSERT(!memcmp(fpu.fpr, fp, 32),
+ "Wanted 0x%llx %llx %llx %llx from xr0, got 0x%llx %llx %llx %llx",
+ fp->val64[0], fp->val64[1], fp->val64[2], fp->val64[3],
+ fpu.fpr[0].val64[0], fpu.fpr[0].val64[1],
+ fpu.fpr[0].val64[2], fpu.fpr[0].val64[3]);
+
+ run_vcpu(vcpu);
+ kvm_vm_free(vm);
+ return 0;
+}
--
2.39.3
^ permalink raw reply related [flat|nested] 5+ messages in thread