mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 01:53:29 +02:00
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 <gaosong@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
parent
11c8401927
commit
e47b8e1db9
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user