From: Song Gao Date: Thu, 9 Apr 2026 10:56:38 +0000 (+0800) Subject: KVM: LoongArch: selftests: Add PMU overflow interrupt test X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;h=e47b8e1db9a9bbef6765e85b11e87f48e6b56846;p=thirdparty%2Fkernel%2Flinux.git KVM: LoongArch: selftests: Add PMU overflow interrupt test 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 Signed-off-by: Huacai Chen --- diff --git a/tools/testing/selftests/kvm/include/loongarch/pmu.h b/tools/testing/selftests/kvm/include/loongarch/pmu.h index 2f734a1d1ae41..478e6a9bbb2b4 100644 --- a/tools/testing/selftests/kvm/include/loongarch/pmu.h +++ b/tools/testing/selftests/kvm/include/loongarch/pmu.h @@ -29,6 +29,7 @@ #define CSR_PERFCTRL_PLV1 BIT(17) #define CSR_PERFCTRL_PLV2 BIT(18) #define CSR_PERFCTRL_PLV3 BIT(19) +#define CSR_PERFCTRL_PMIE BIT(20) #define PMU_ENVENT_ENABLED (CSR_PERFCTRL_PLV0 | CSR_PERFCTRL_PLV1 | CSR_PERFCTRL_PLV2 | CSR_PERFCTRL_PLV3) /* Hardware event codes (from LoongArch perf_event.c */ @@ -42,4 +43,24 @@ #define EXPECTED_CYCLES_MIN NUM_LOOPS /* At least 1 cycle per iteration */ #define UPPER_BOUND (10 * NUM_LOOPS) +#define PMU_OVERFLOW (1ULL << 63) + +static inline void pmu_irq_enable(void) +{ + unsigned long val; + + val = csr_read(LOONGARCH_CSR_ECFG); + val |= ECFGF_PMU; + csr_write(val, LOONGARCH_CSR_ECFG); +} + +static inline void pmu_irq_disable(void) +{ + unsigned long val; + + val = csr_read(LOONGARCH_CSR_ECFG); + val &= ~ECFGF_PMU; + csr_write(val, LOONGARCH_CSR_ECFG); +} + #endif diff --git a/tools/testing/selftests/kvm/include/loongarch/processor.h b/tools/testing/selftests/kvm/include/loongarch/processor.h index 916426707c867..93dc1fbd2e79d 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/pmu_test.c b/tools/testing/selftests/kvm/loongarch/pmu_test.c index c0f25976b160d..88bb530e336e1 100644 --- a/tools/testing/selftests/kvm/loongarch/pmu_test.c +++ b/tools/testing/selftests/kvm/loongarch/pmu_test.c @@ -10,6 +10,8 @@ #include "pmu.h" #include "loongarch/processor.h" +static int pmu_irq_count; + /* Check PMU support */ static bool has_pmu_support(void) { @@ -99,10 +101,41 @@ static void guest_pmu_base_test(void) GUEST_ASSERT(cnt[3] > 0 && cnt[3] < UPPER_BOUND); } +static void guest_irq_handler(struct ex_regs *regs) +{ + unsigned int intid; + + pmu_irq_disable(); + intid = !!(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); +} + +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 = csr_read(LOONGARCH_CSR_PERFCNTR0); + GUEST_PRINTF("csr_perfcntr0 is %lx\n", cnt); + GUEST_PRINTF("PMU interrupt test success\n"); + +} + static void guest_code(void) { guest_pmu_base_test(); + pmu_irq_enable(); + local_irq_enable(); + guest_pmu_interrupt_test(); + GUEST_DONE(); } @@ -128,8 +161,11 @@ int main(int argc, char *argv[]) vm = vm_create(VM_MODE_P47V47_16K); vcpu = vm_vcpu_add(vm, 0, guest_code); + pmu_irq_count = 0; vm_init_descriptor_tables(vm); loongarch_vcpu_setup(vcpu); + vm_install_exception_handler(vm, EXCCODE_INT, guest_irq_handler); + sync_global_to_guest(vm, pmu_irq_count); attr.group = KVM_LOONGARCH_VM_FEAT_CTRL, attr.attr = KVM_LOONGARCH_VM_FEAT_PMU,