From nobody Thu Apr 9 07:18:18 2026 Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by smtp.subspace.kernel.org (Postfix) with ESMTP id EA35244105C; Tue, 10 Mar 2026 09:52:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=114.242.206.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773136347; cv=none; b=BP3An6lj6q6sDEMM610gEWmSJydeK1WsyVEUorQFc6MU7xo6UYU7LVIY+ivaDnOXavjsPICXdVwsTg7nrs5Yq9Ko2QWeah4NCapCIVzsMplvmv68kumyI7B3h+imTp8Eseem9QHQTL1gdMHdq2P0xTC5JCnMOS/8bsBqjpti2aU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773136347; c=relaxed/simple; bh=aDK2zjIo/VGAi78xisCb95IxYzIab8mD5RWmB9xKoaU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ik01EF1KZWQy2T1NQFH5qGkwA41a4VR53QfqX3yQf/tCNJROcXcG7lMF1syeEYwSv7fnXkMxjhXnthPn0GeZLQzlkQBDsJNBdRKnx0e/pCPLoGI5bY0YEzcY3fadtIdRmD5gFpKA0Ym7h2fBwCjNRdqNT45h8y8g8+7uUqhBq8c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn; spf=pass smtp.mailfrom=loongson.cn; arc=none smtp.client-ip=114.242.206.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=loongson.cn Received: from loongson.cn (unknown [10.2.5.185]) by gateway (Coremail) with SMTP id _____8Axw8DQ6a9pDXcZAA--.15654S3; Tue, 10 Mar 2026 17:52:16 +0800 (CST) Received: from localhost.localdomain (unknown [10.2.5.185]) by front1 (Coremail) with SMTP id qMiowJDxzsLP6a9p7gVSAA--.24922S3; Tue, 10 Mar 2026 17:52:15 +0800 (CST) From: Song Gao To: chenhuacai@kernel.org, maobibo@loongson.cn Cc: loongarch@lists.linux.dev, kernel@xen0n.name, kvm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/3] KVM: LoongArch: selftests: Add cpucfg read/write helpers Date: Tue, 10 Mar 2026 17:26:55 +0800 Message-Id: <20260310092657.1023650-2-gaosong@loongson.cn> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20260310092657.1023650-1-gaosong@loongson.cn> References: <20260310092657.1023650-1-gaosong@loongson.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: qMiowJDxzsLP6a9p7gVSAA--.24922S3 X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ X-Coremail-Antispam: 1Uk129KBjDUn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7KY7 ZEXasCq-sGcSsGvfJ3UbIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnUUvcSsGvfC2Kfnx nUUI43ZEXa7xR_UUUUUUUUU== Content-Type: text/plain; charset="utf-8" Add helper macros and functions to read and write CPU configuration registers (cpucfg) from within the guest and from the VMM. This interface is required for querying and setting CPU features, such as PMU capabilities, in upcoming selftests. Signed-off-by: Song Gao --- .../selftests/kvm/include/loongarch/processor.h | 11 +++++++++++ tools/testing/selftests/kvm/lib/loongarch/processor.c | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/tools/testing/selftests/kvm/include/loongarch/processor.h b/to= ols/testing/selftests/kvm/include/loongarch/processor.h index 76840ddda57d..b8f6c3348ddd 100644 --- a/tools/testing/selftests/kvm/include/loongarch/processor.h +++ b/tools/testing/selftests/kvm/include/loongarch/processor.h @@ -150,6 +150,17 @@ __v; \ }) =20 +#define read_cpucfg(reg) \ +({ \ + register unsigned long __v; \ + __asm__ __volatile__( \ + "cpucfg %0, %1\n\t" \ + : "=3Dr" (__v) \ + : "r" (reg) \ + : "memory"); \ + __v; \ +}) + #define EXREGS_GPRS (32) =20 #ifndef __ASSEMBLER__ diff --git a/tools/testing/selftests/kvm/lib/loongarch/processor.c b/tools/= testing/selftests/kvm/lib/loongarch/processor.c index 17aa55a2047a..68eb34032a99 100644 --- a/tools/testing/selftests/kvm/lib/loongarch/processor.c +++ b/tools/testing/selftests/kvm/lib/loongarch/processor.c @@ -267,6 +267,14 @@ static void loongarch_set_csr(struct kvm_vcpu *vcpu, u= int64_t id, uint64_t val) __vcpu_set_reg(vcpu, csrid, val); } =20 +static void loongarch_set_cpucfg(struct kvm_vcpu *vcpu, uint64_t id, uint6= 4_t val) +{ + uint64_t cfgid; + + cfgid =3D KVM_REG_LOONGARCH_CPUCFG | KVM_REG_SIZE_U64 | 8 * id; + __vcpu_set_reg(vcpu, cfgid, val); +} + static void loongarch_vcpu_setup(struct kvm_vcpu *vcpu) { int width; --=20 2.47.3 From nobody Thu Apr 9 07:18:18 2026 Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9B97F44E05C; Tue, 10 Mar 2026 09:52:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=114.242.206.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773136352; cv=none; b=ViEt7pnVqbhZn1YutYkAmxdJqojzWpwvvkQM1nVl+XVrS/wOBGcvArjvimYW+HGC3tqGwuYZNMa9gIWMC8GOe1yFtbMLSsIf/qpsRx20stL+Bjhd+qPTQ13lkk1mV/BCvbduBbquDck2Mgn8yQyCbHsWHSxbWWslICKx7ij8rl4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773136352; c=relaxed/simple; bh=a1uKxUjJubkgg11olvLlobm//6jTJ9MXX1VV2jbmJIg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=uj1Gvr7gC+LV6ZedTvCWKNGZ3QmpBwpgc1dw2ryxsaO210zgGSE9K7ATIkv12sf9SQ+P+IJ1XnOJuUhTsm4i8HkDdWG3/90fKD5t7zH4qeOl3fOq1rbjCRnf2gMkpxn5dvKI6RTtTrfbb4qgnuIC9QNxexdfcy3c6xa/BpD006A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn; spf=pass smtp.mailfrom=loongson.cn; arc=none smtp.client-ip=114.242.206.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=loongson.cn Received: from loongson.cn (unknown [10.2.5.185]) by gateway (Coremail) with SMTP id _____8Cx68LQ6a9pE3cZAA--.9031S3; Tue, 10 Mar 2026 17:52:16 +0800 (CST) Received: from localhost.localdomain (unknown [10.2.5.185]) by front1 (Coremail) with SMTP id qMiowJDxzsLP6a9p7gVSAA--.24922S4; Tue, 10 Mar 2026 17:52:16 +0800 (CST) From: Song Gao To: chenhuacai@kernel.org, maobibo@loongson.cn Cc: loongarch@lists.linux.dev, kernel@xen0n.name, kvm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/3] KVM: LoongArch: selftests: Add basic PMU event counting test Date: Tue, 10 Mar 2026 17:26:56 +0800 Message-Id: <20260310092657.1023650-3-gaosong@loongson.cn> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20260310092657.1023650-1-gaosong@loongson.cn> References: <20260310092657.1023650-1-gaosong@loongson.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: qMiowJDxzsLP6a9p7gVSAA--.24922S4 X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ X-Coremail-Antispam: 1Uk129KBjDUn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7KY7 ZEXasCq-sGcSsGvfJ3UbIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnUUvcSsGvfC2Kfnx nUUI43ZEXa7xR_UUUUUUUUU== Content-Type: text/plain; charset="utf-8" Introduce a basic PMU test that verifies hardware event counting for four performance counters. The test enables events for CPU cycles, instructions retired, branch instructions, and branch misses, runs a fixed number of loops, and checks that the counter values fall within expected ranges. It also validates that the host supports PMU and that the VM feature is enabled. Signed-off-by: Song Gao --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../selftests/kvm/include/loongarch/pmu.h | 46 +++++ .../kvm/include/loongarch/processor.h | 1 + .../selftests/kvm/lib/loongarch/processor.c | 6 +- .../selftests/kvm/loongarch/guest_pmu_test.c | 171 ++++++++++++++++++ 5 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/kvm/include/loongarch/pmu.h create mode 100644 tools/testing/selftests/kvm/loongarch/guest_pmu_test.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index fdec90e85467..137f97ad34c0 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -221,6 +221,7 @@ TEST_GEN_PROGS_riscv +=3D rseq_test TEST_GEN_PROGS_riscv +=3D steal_time =20 TEST_GEN_PROGS_loongarch =3D arch_timer +TEST_GEN_PROGS_loongarch +=3D loongarch/guest_pmu_test TEST_GEN_PROGS_loongarch +=3D coalesced_io_test TEST_GEN_PROGS_loongarch +=3D demand_paging_test TEST_GEN_PROGS_loongarch +=3D dirty_log_perf_test diff --git a/tools/testing/selftests/kvm/include/loongarch/pmu.h b/tools/te= sting/selftests/kvm/include/loongarch/pmu.h new file mode 100644 index 000000000000..0d9ecb9de8c3 --- /dev/null +++ b/tools/testing/selftests/kvm/include/loongarch/pmu.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * LoongArch PMU specific interface + */ +#ifndef SELFTEST_KVM_LOONGARCH_PMU_H +#define SELFTEST_KVM_LOONGARCH_PMU_H + +#include "processor.h" + +/* Performance Counter registers */ +#define LOONGARCH_CSR_PERFCTRL0 0x200 /* perf event 0 config */ +#define LOONGARCH_CSR_PERFCNTR0 0x201 /* perf event 0 count value */ +#define LOONGARCH_CSR_PERFCTRL1 0x202 /* perf event 1 config */ +#define LOONGARCH_CSR_PERFCNTR1 0x203 /* perf event 1 count value */ +#define LOONGARCH_CSR_PERFCTRL2 0x204 /* perf event 2 config */ +#define LOONGARCH_CSR_PERFCNTR2 0x205 /* perf event 2 count value */ +#define LOONGARCH_CSR_PERFCTRL3 0x206 /* perf event 3 config */ +#define LOONGARCH_CSR_PERFCNTR3 0x207 /* perf event 3 count value */ +#define CSR_PERFCTRL_PLV0 BIT(16) +#define CSR_PERFCTRL_PLV1 BIT(17) +#define CSR_PERFCTRL_PLV2 BIT(18) +#define CSR_PERFCTRL_PLV3 BIT(19) +#define PMU_ENVENT_ENABLED (CSR_PERFCTRL_PLV0 | CSR_PERFCTRL_PLV1 |\ + CSR_PERFCTRL_PLV2 | CSR_PERFCTRL_PLV3) + +#define LOONGARCH_CPUCFG6 0x6 +#define CPUCFG6_PMP BIT(0) +#define CPUCFG6_PAMVER GENMASK(3, 1) +#define CPUCFG6_PMNUM GENMASK(7, 4) +#define CPUCFG6_PMNUM_SHIFT 4 +#define CPUCFG6_PMBITS GENMASK(13, 8) +#define CPUCFG6_PMBITS_SHIFT 8 +#define CPUCFG6_UPM BIT(14) + +/* Hardware event codes (from LoongArch perf_event.c */ +#define LOONGARCH_PMU_EVENT_CYCLES 0x00 /* CPU cycles */ +#define LOONGARCH_PMU_EVENT_INSTR_RETIRED 0x01 /* Instructions retired */ +#define PERF_COUNT_HW_BRANCH_INSTRUCTIONS 0x02 /* Branch instructions */ +#define PERF_COUNT_HW_BRANCH_MISSES 0x03 /* Branch misses */ + +#define NUM_LOOPS 1000 +#define EXPECTED_INSTR_MIN (NUM_LOOPS + 10) /* Loop = + overhead */ +#define EXPECTED_CYCLES_MIN NUM_LOOPS /* At leas= t 1 cycle per iteration */ +#define UPPER_BOUND (10 * NUM_LOOPS) + +#endif diff --git a/tools/testing/selftests/kvm/include/loongarch/processor.h b/to= ols/testing/selftests/kvm/include/loongarch/processor.h index b8f6c3348ddd..af8d05820961 100644 --- a/tools/testing/selftests/kvm/include/loongarch/processor.h +++ b/tools/testing/selftests/kvm/include/loongarch/processor.h @@ -189,6 +189,7 @@ struct handlers { handler_fn exception_handlers[VECTOR_NUM]; }; =20 +void loongarch_vcpu_setup(struct kvm_vcpu *vcpu); void vm_init_descriptor_tables(struct kvm_vm *vm); void vm_install_exception_handler(struct kvm_vm *vm, int vector, handler_f= n handler); =20 diff --git a/tools/testing/selftests/kvm/lib/loongarch/processor.c b/tools/= testing/selftests/kvm/lib/loongarch/processor.c index 68eb34032a99..a64d47ad6ce8 100644 --- a/tools/testing/selftests/kvm/lib/loongarch/processor.c +++ b/tools/testing/selftests/kvm/lib/loongarch/processor.c @@ -7,6 +7,7 @@ #include "kvm_util.h" #include "processor.h" #include "ucall_common.h" +#include "pmu.h" =20 #define LOONGARCH_PAGE_TABLE_PHYS_MIN 0x200000 #define LOONGARCH_GUEST_STACK_VADDR_MIN 0x200000 @@ -275,11 +276,12 @@ static void loongarch_set_cpucfg(struct kvm_vcpu *vcp= u, uint64_t id, uint64_t va __vcpu_set_reg(vcpu, cfgid, val); } =20 -static void loongarch_vcpu_setup(struct kvm_vcpu *vcpu) +void loongarch_vcpu_setup(struct kvm_vcpu *vcpu) { int width; unsigned long val; struct kvm_vm *vm =3D vcpu->vm; + uint32_t cfg6; =20 switch (vm->mode) { case VM_MODE_P36V47_16K: @@ -290,6 +292,8 @@ static void loongarch_vcpu_setup(struct kvm_vcpu *vcpu) TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode); } =20 + cfg6 =3D read_cpucfg(LOONGARCH_CPUCFG6); + loongarch_set_cpucfg(vcpu, LOONGARCH_CPUCFG6, cfg6); /* kernel mode and page enable mode */ val =3D PLV_KERN | CSR_CRMD_PG; loongarch_set_csr(vcpu, LOONGARCH_CSR_CRMD, val); diff --git a/tools/testing/selftests/kvm/loongarch/guest_pmu_test.c b/tools= /testing/selftests/kvm/loongarch/guest_pmu_test.c new file mode 100644 index 000000000000..59ec945b6e05 --- /dev/null +++ b/tools/testing/selftests/kvm/loongarch/guest_pmu_test.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LoongArch KVM PMU event counting test + * + * Test hardware event counting: CPU_CYCLES, INSTR_RETIRED, + * BRANCH_INSTRUCTIONS and BRANCH_MISSES. + * + */ +#include "kvm_util.h" +#include "loongarch/processor.h" +#include "pmu.h" +#include + +/* Guest test code - runs inside VM */ +static void guest_pmu_base_test(void) +{ + uint64_t cnt[4]; + int i; + uint32_t cfg6, pmnum; + + cfg6 =3D read_cpucfg(LOONGARCH_CPUCFG6); + pmnum =3D (cfg6 >> 4) & 0xf; + GUEST_PRINTF("CPUCFG6 =3D 0x%x\n", cfg6); + GUEST_PRINTF("PMP enabled: %s\n", (cfg6 & 0x1) ? "YES" : "NO"); + GUEST_PRINTF("Number of counters (PMNUM): %x\n", pmnum + 1); + GUEST_ASSERT(pmnum =3D=3D 3); + + GUEST_PRINTF("Clean csr_perfcntr0-3\n"); + csr_write(0, LOONGARCH_CSR_PERFCNTR0); + csr_write(0, LOONGARCH_CSR_PERFCNTR1); + csr_write(0, LOONGARCH_CSR_PERFCNTR2); + csr_write(0, LOONGARCH_CSR_PERFCNTR3); + GUEST_PRINTF("Set csr_perfctrl0 for cycles event\n"); + csr_write(PMU_ENVENT_ENABLED | + LOONGARCH_PMU_EVENT_CYCLES, LOONGARCH_CSR_PERFCTRL0); + GUEST_PRINTF("Set csr_perfctrl1 for instr_retired event\n"); + csr_write(PMU_ENVENT_ENABLED | + LOONGARCH_PMU_EVENT_INSTR_RETIRED, LOONGARCH_CSR_PERFCTRL1); + GUEST_PRINTF("Set csr_perfctrl2 for branch_instructions event\n"); + csr_write(PMU_ENVENT_ENABLED | + PERF_COUNT_HW_BRANCH_INSTRUCTIONS, LOONGARCH_CSR_PERFCTRL2); + GUEST_PRINTF("Set csr_perfctrl3 for branch_misses event\n"); + csr_write(PMU_ENVENT_ENABLED | + PERF_COUNT_HW_BRANCH_MISSES, LOONGARCH_CSR_PERFCTRL3); + + for (i =3D 0; i < NUM_LOOPS; i++) + cpu_relax(); + + cnt[0] =3D csr_read(LOONGARCH_CSR_PERFCNTR0); + GUEST_PRINTF("csr_perfcntr0 is %lx\n", cnt[0]); + cnt[1] =3D csr_read(LOONGARCH_CSR_PERFCNTR1); + GUEST_PRINTF("csr_perfcntr1 is %lx\n", cnt[1]); + cnt[2] =3D csr_read(LOONGARCH_CSR_PERFCNTR2); + GUEST_PRINTF("csr_perfcntr2 is %lx\n", cnt[2]); + cnt[3] =3D csr_read(LOONGARCH_CSR_PERFCNTR3); + GUEST_PRINTF("csr_perfcntr3 is %lx\n", cnt[3]); + + GUEST_PRINTF("assert csr_perfcntr0 >EXPECTED_CYCLES_MIN && csr_perfcntr0 = < UPPER_BOUND\n"); + GUEST_ASSERT(cnt[0] > EXPECTED_CYCLES_MIN && cnt[0] < UPPER_BOUND); + GUEST_PRINTF("assert csr_perfcntr1 > EXPECTED_INSTR_MIN && csr_perfcntr1 = < UPPER_BOUND\n"); + GUEST_ASSERT(cnt[1] > EXPECTED_INSTR_MIN && cnt[1] < UPPER_BOUND); + GUEST_PRINTF("assert csr_perfcntr2 > 0 && csr_perfcntr2 < UPPER_BOUND\n"); + GUEST_ASSERT(cnt[2] > 0 && cnt[2] < UPPER_BOUND); + GUEST_PRINTF("assert csr_perfcntr3 > 0 && csr_perfcntr3 < UPPER_BOUND\n"); + GUEST_ASSERT(cnt[3] > 0 && cnt[3] < UPPER_BOUND); + +} + +static void guest_code(void) +{ + guest_pmu_base_test(); + + GUEST_DONE(); +} + +/* check PMU support */ +static bool kvm_has_pmu_support(void) +{ + uint32_t cfg6; + + /* Read CPUCFG6 to check PMU */ + cfg6 =3D read_cpucfg(LOONGARCH_CPUCFG6); + + /* Check PMU present bit */ + if (!(cfg6 & CPUCFG6_PMP)) + return false; + + /* Check that at least one counter exists */ + if (((cfg6 & CPUCFG6_PMNUM) >> CPUCFG6_PMNUM_SHIFT) =3D=3D 0) + return false; + + return true; +} +/* Dump PMU capabilities */ +static void dump_pmu_caps(void) +{ + uint32_t cfg6; + int nr_counters, counter_bits; + + cfg6 =3D read_cpucfg(LOONGARCH_CPUCFG6); + nr_counters =3D ((cfg6 & CPUCFG6_PMNUM) >> CPUCFG6_PMNUM_SHIFT) + 1; + counter_bits =3D ((cfg6 & CPUCFG6_PMBITS) >> CPUCFG6_PMBITS_SHIFT) + 1; + + pr_info("PMU capabilities:\n"); + pr_info(" Counters present: %s\n", cfg6 & CPUCFG6_PMP ? "yes" : "no"); + pr_info(" Number of counters: %d\n", nr_counters); + pr_info(" Counter width: %d bits\n", counter_bits); +} + +int main(int argc, char *argv[]) +{ + struct kvm_device_attr attr; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int ret =3D 0; + struct ucall uc; + + /* Check host KVM PMU support */ + if (!kvm_has_pmu_support()) { + print_skip("PMU not supported by host hardware\n"); + dump_pmu_caps(); + return KSFT_SKIP; + } + pr_info("Host support PMU\n"); + + /* Dump PMU capabilities */ + dump_pmu_caps(); + + vm =3D vm_create(VM_MODE_P47V47_16K); + vcpu =3D vm_vcpu_add(vm, 0, guest_code); + + vm_init_descriptor_tables(vm); + loongarch_vcpu_setup(vcpu); + + attr.group =3D KVM_LOONGARCH_VM_FEAT_CTRL, + attr.attr =3D KVM_LOONGARCH_VM_FEAT_PMU, + + ret =3D ioctl(vm->fd, KVM_HAS_DEVICE_ATTR, &attr); + + if (ret =3D=3D 0) { + pr_info("PMU is enabled in VM\n"); + } else { + print_skip("PMU not enabled by VM config\n"); + return KSFT_SKIP; + } + + while (1) { + vcpu_run(vcpu); + switch (get_ucall(vcpu, &uc)) { + case UCALL_PRINTF: + printf("%s", (const char *)uc.buffer); + break; + case UCALL_DONE: + printf("PMU test PASSED\n"); + goto done; + case UCALL_ABORT: + printf("PMU test FAILED\n"); + ret =3D -1; + goto done; + default: + printf("Unexpected exit\n"); + ret =3D -1; + goto done; + } + } + +done: + kvm_vm_free(vm); + return ret; +} + --=20 2.47.3 From nobody Thu Apr 9 07:18:18 2026 Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3505C44CACB; Tue, 10 Mar 2026 09:52:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=114.242.206.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773136346; cv=none; b=saePiiZmUKAQz5CMUvBK/BTZnIfVRf61jvO1eko5LU2Tc1/5/w6ds2GbVW9aX1ZOizHzj/pYwyXJeRIPgWhgmwr05kJdzzTC3nppg0DCIezlUPvr+lbWTr28AmDR/Kx6sNsjkvNgitNXUbLCNtY8OqgwkJGGYR6f7SVVgtdcKho= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773136346; c=relaxed/simple; bh=ctXQiTZW13quB11/yeg5Pmi6ZLAOVK7tZ/Okfn+1Il4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=NH0GyrfPOTVeKk1QBaHXBgThooWcG02GtODV6k1ivaXEEwSpPmMWImFvN1uLINCW1yWBpTmkOhTZ6jSlcma8NVwVr5wYJST0hAD6GCue+6JqZMSMnJxrZFwL7mjFPvP3sD7Au38Kv2D66Q5E+Hi9g3q6zLp9h6ZS74hfi3DOqAQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn; spf=pass smtp.mailfrom=loongson.cn; arc=none smtp.client-ip=114.242.206.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=loongson.cn Received: from loongson.cn (unknown [10.2.5.185]) by gateway (Coremail) with SMTP id _____8BxEMDR6a9pF3cZAA--.15824S3; Tue, 10 Mar 2026 17:52:17 +0800 (CST) Received: from localhost.localdomain (unknown [10.2.5.185]) by front1 (Coremail) with SMTP id qMiowJDxzsLP6a9p7gVSAA--.24922S5; Tue, 10 Mar 2026 17:52:16 +0800 (CST) From: Song Gao To: chenhuacai@kernel.org, maobibo@loongson.cn Cc: loongarch@lists.linux.dev, kernel@xen0n.name, kvm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/3] KVM: LoongArch: selftests: Add PMU overflow interrupt test Date: Tue, 10 Mar 2026 17:26:57 +0800 Message-Id: <20260310092657.1023650-4-gaosong@loongson.cn> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20260310092657.1023650-1-gaosong@loongson.cn> References: <20260310092657.1023650-1-gaosong@loongson.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: qMiowJDxzsLP6a9p7gVSAA--.24922S5 X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ X-Coremail-Antispam: 1Uk129KBjDUn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7KY7 ZEXasCq-sGcSsGvfJ3UbIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnUUvcSsGvfC2Kfnx nUUI43ZEXa7xR_UUUUUUUUU== Content-Type: text/plain; charset="utf-8" Extend the PMU test suite to cover overflow interrupts. The test enables the PMI (Performance Monitor Interrupt), sets counter 0 to one less than the overflow value, and verifies that an interrupt is raised when the counter overflows. A guest interrupt handler checks the interrupt cause and disables further PMU interrupts upon success. Signed-off-by: Song Gao --- .../selftests/kvm/include/loongarch/pmu.h | 20 +++++++++++ .../kvm/include/loongarch/processor.h | 3 ++ .../selftests/kvm/loongarch/guest_pmu_test.c | 36 ++++++++++++++++++- 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/include/loongarch/pmu.h b/tools/te= sting/selftests/kvm/include/loongarch/pmu.h index 0d9ecb9de8c3..6009811ad4ca 100644 --- a/tools/testing/selftests/kvm/include/loongarch/pmu.h +++ b/tools/testing/selftests/kvm/include/loongarch/pmu.h @@ -22,6 +22,7 @@ #define CSR_PERFCTRL_PLV3 BIT(19) #define PMU_ENVENT_ENABLED (CSR_PERFCTRL_PLV0 | CSR_PERFCTRL_PLV1 |\ CSR_PERFCTRL_PLV2 | CSR_PERFCTRL_PLV3) +#define CSR_PERFCTRL_PMIE BIT(20) =20 #define LOONGARCH_CPUCFG6 0x6 #define CPUCFG6_PMP BIT(0) @@ -43,4 +44,23 @@ #define EXPECTED_CYCLES_MIN NUM_LOOPS /* At leas= t 1 cycle per iteration */ #define UPPER_BOUND (10 * NUM_LOOPS) =20 +#define PMU_OVERFLOW (1ULL << 63) +static inline void pmu_irq_enable(void) +{ + unsigned long val; + + val =3D csr_read(LOONGARCH_CSR_ECFG); + val |=3D ECFGF_PMU; + csr_write(val, LOONGARCH_CSR_ECFG); +} + +static inline void pmu_irq_disable(void) +{ + unsigned long val; + + val =3D csr_read(LOONGARCH_CSR_ECFG); + val &=3D ~ECFGF_PMU; + csr_write(val, LOONGARCH_CSR_ECFG); +} + #endif diff --git a/tools/testing/selftests/kvm/include/loongarch/processor.h b/to= ols/testing/selftests/kvm/include/loongarch/processor.h index af8d05820961..9b5859831ba8 100644 --- a/tools/testing/selftests/kvm/include/loongarch/processor.h +++ b/tools/testing/selftests/kvm/include/loongarch/processor.h @@ -83,6 +83,8 @@ #define LOONGARCH_CSR_PRMD 0x1 #define LOONGARCH_CSR_EUEN 0x2 #define LOONGARCH_CSR_ECFG 0x4 +#define ECFGB_PMU 10 +#define ECFGF_PMU (BIT_ULL(ECFGB_PMU)) #define ECFGB_TIMER 11 #define ECFGF_TIMER (BIT_ULL(ECFGB_TIMER)) #define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ @@ -90,6 +92,7 @@ #define CSR_ESTAT_EXC_WIDTH 6 #define CSR_ESTAT_EXC (0x3f << CSR_ESTAT_EXC_SHIFT) #define EXCCODE_INT 0 /* Interrupt */ +#define INT_PMI 10 /* PMU interrupt */ #define INT_TI 11 /* Timer interrupt*/ #define LOONGARCH_CSR_ERA 0x6 /* ERA */ #define LOONGARCH_CSR_BADV 0x7 /* Bad virtual address */ diff --git a/tools/testing/selftests/kvm/loongarch/guest_pmu_test.c b/tools= /testing/selftests/kvm/loongarch/guest_pmu_test.c index 59ec945b6e05..598ab96ed237 100644 --- a/tools/testing/selftests/kvm/loongarch/guest_pmu_test.c +++ b/tools/testing/selftests/kvm/loongarch/guest_pmu_test.c @@ -11,6 +11,7 @@ #include "pmu.h" #include =20 +static int pmu_irq_count; /* Guest test code - runs inside VM */ static void guest_pmu_base_test(void) { @@ -66,10 +67,40 @@ static void guest_pmu_base_test(void) =20 } =20 +static void guest_pmu_interrupt_test(void) +{ + uint64_t cnt; + + csr_write(PMU_OVERFLOW - 1, LOONGARCH_CSR_PERFCNTR0); + csr_write(PMU_ENVENT_ENABLED | CSR_PERFCTRL_PMIE | + LOONGARCH_PMU_EVENT_CYCLES, LOONGARCH_CSR_PERFCTRL0); + + cpu_relax(); + + GUEST_ASSERT_EQ(pmu_irq_count, 1); + cnt =3D csr_read(LOONGARCH_CSR_PERFCNTR0); + GUEST_PRINTF("PMU interrupt test success\n"); + GUEST_PRINTF("csr_perfcntr0 is %lx\n", cnt); + +} + +static void guest_irq_handler(struct ex_regs *regs) +{ + unsigned int intid; + + intid =3D !!(regs->estat & BIT(INT_PMI)); + GUEST_ASSERT_EQ(intid, 1); + GUEST_PRINTF("get PMU interrupt\n"); + WRITE_ONCE(pmu_irq_count, pmu_irq_count + 1); + pmu_irq_disable(); +} + static void guest_code(void) { guest_pmu_base_test(); - + pmu_irq_enable(); + local_irq_enable(); + guest_pmu_interrupt_test(); GUEST_DONE(); } =20 @@ -131,6 +162,9 @@ int main(int argc, char *argv[]) =20 vm_init_descriptor_tables(vm); loongarch_vcpu_setup(vcpu); + vm_install_exception_handler(vm, EXCCODE_INT, guest_irq_handler); + pmu_irq_count =3D 0; + sync_global_to_guest(vm, pmu_irq_count); =20 attr.group =3D KVM_LOONGARCH_VM_FEAT_CTRL, attr.attr =3D KVM_LOONGARCH_VM_FEAT_PMU, --=20 2.47.3