Path: blob/master/tools/testing/selftests/kvm/riscv/sbi_pmu_test.c
38223 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* sbi_pmu_test.c - Tests the riscv64 SBI PMU functionality.3*4* Copyright (c) 2024, Rivos Inc.5*/67#include <stdio.h>8#include <stdlib.h>9#include <string.h>10#include <unistd.h>11#include <sys/types.h>12#include "kvm_util.h"13#include "test_util.h"14#include "processor.h"15#include "sbi.h"16#include "arch_timer.h"17#include "ucall_common.h"1819/* Maximum counters(firmware + hardware) */20#define RISCV_MAX_PMU_COUNTERS 6421union sbi_pmu_ctr_info ctrinfo_arr[RISCV_MAX_PMU_COUNTERS];2223/* Snapshot shared memory data */24#define PMU_SNAPSHOT_GPA_BASE BIT(30)25static void *snapshot_gva;26static vm_paddr_t snapshot_gpa;2728static int vcpu_shared_irq_count;29static int counter_in_use;3031/* Cache the available counters in a bitmask */32static unsigned long counter_mask_available;3334static bool illegal_handler_invoked;3536#define SBI_PMU_TEST_BASIC BIT(0)37#define SBI_PMU_TEST_EVENTS BIT(1)38#define SBI_PMU_TEST_SNAPSHOT BIT(2)39#define SBI_PMU_TEST_OVERFLOW BIT(3)4041#define SBI_PMU_OVERFLOW_IRQNUM_DEFAULT 542struct test_args {43int disabled_tests;44int overflow_irqnum;45};4647static struct test_args targs;4849unsigned long pmu_csr_read_num(int csr_num)50{51#define switchcase_csr_read(__csr_num, __val) {\52case __csr_num: \53__val = csr_read(__csr_num); \54break; }55#define switchcase_csr_read_2(__csr_num, __val) {\56switchcase_csr_read(__csr_num + 0, __val) \57switchcase_csr_read(__csr_num + 1, __val)}58#define switchcase_csr_read_4(__csr_num, __val) {\59switchcase_csr_read_2(__csr_num + 0, __val) \60switchcase_csr_read_2(__csr_num + 2, __val)}61#define switchcase_csr_read_8(__csr_num, __val) {\62switchcase_csr_read_4(__csr_num + 0, __val) \63switchcase_csr_read_4(__csr_num + 4, __val)}64#define switchcase_csr_read_16(__csr_num, __val) {\65switchcase_csr_read_8(__csr_num + 0, __val) \66switchcase_csr_read_8(__csr_num + 8, __val)}67#define switchcase_csr_read_32(__csr_num, __val) {\68switchcase_csr_read_16(__csr_num + 0, __val) \69switchcase_csr_read_16(__csr_num + 16, __val)}7071unsigned long ret = 0;7273switch (csr_num) {74switchcase_csr_read_32(CSR_CYCLE, ret)75default :76break;77}7879return ret;80#undef switchcase_csr_read_3281#undef switchcase_csr_read_1682#undef switchcase_csr_read_883#undef switchcase_csr_read_484#undef switchcase_csr_read_285#undef switchcase_csr_read86}8788static inline void dummy_func_loop(uint64_t iter)89{90int i = 0;9192while (i < iter) {93asm volatile("nop");94i++;95}96}9798static void start_counter(unsigned long counter, unsigned long start_flags,99unsigned long ival)100{101struct sbiret ret;102103ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, counter, 1, start_flags,104ival, 0, 0);105__GUEST_ASSERT(ret.error == 0, "Unable to start counter %ld\n", counter);106}107108/* This should be invoked only for reset counter use case */109static void stop_reset_counter(unsigned long counter, unsigned long stop_flags)110{111struct sbiret ret;112113ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, counter, 1,114stop_flags | SBI_PMU_STOP_FLAG_RESET, 0, 0, 0);115__GUEST_ASSERT(ret.error == SBI_ERR_ALREADY_STOPPED,116"Unable to stop counter %ld\n", counter);117}118119static void stop_counter(unsigned long counter, unsigned long stop_flags)120{121struct sbiret ret;122123ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, counter, 1, stop_flags,1240, 0, 0);125__GUEST_ASSERT(ret.error == 0 || ret.error == SBI_ERR_ALREADY_STOPPED,126"Unable to stop counter %ld error %ld\n", counter, ret.error);127}128129static void guest_illegal_exception_handler(struct pt_regs *regs)130{131unsigned long insn;132int opcode, csr_num, funct3;133134__GUEST_ASSERT(regs->cause == EXC_INST_ILLEGAL,135"Unexpected exception handler %lx\n", regs->cause);136137insn = regs->badaddr;138opcode = (insn & INSN_OPCODE_MASK) >> INSN_OPCODE_SHIFT;139__GUEST_ASSERT(opcode == INSN_OPCODE_SYSTEM,140"Unexpected instruction with opcode 0x%x insn 0x%lx\n", opcode, insn);141142csr_num = GET_CSR_NUM(insn);143funct3 = GET_RM(insn);144/* Validate if it is a CSR read/write operation */145__GUEST_ASSERT(funct3 <= 7 && (funct3 != 0 && funct3 != 4),146"Unexpected system opcode with funct3 0x%x csr_num 0x%x\n",147funct3, csr_num);148149/* Validate if it is a HPMCOUNTER CSR operation */150__GUEST_ASSERT((csr_num >= CSR_CYCLE && csr_num <= CSR_HPMCOUNTER31),151"Unexpected csr_num 0x%x\n", csr_num);152153illegal_handler_invoked = true;154/* skip the trapping instruction */155regs->epc += 4;156}157158static void guest_irq_handler(struct pt_regs *regs)159{160unsigned int irq_num = regs->cause & ~CAUSE_IRQ_FLAG;161struct riscv_pmu_snapshot_data *snapshot_data = snapshot_gva;162unsigned long overflown_mask;163164/* Validate that we are in the correct irq handler */165GUEST_ASSERT_EQ(irq_num, IRQ_PMU_OVF);166167/* Stop all counters first to avoid further interrupts */168stop_counter(counter_in_use, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);169170csr_clear(CSR_SIP, BIT(IRQ_PMU_OVF));171172overflown_mask = READ_ONCE(snapshot_data->ctr_overflow_mask);173GUEST_ASSERT(overflown_mask & 0x01);174175WRITE_ONCE(vcpu_shared_irq_count, vcpu_shared_irq_count+1);176}177178static unsigned long get_counter_index(unsigned long cbase, unsigned long cmask,179unsigned long cflags,180unsigned long event)181{182struct sbiret ret;183184ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase, cmask,185cflags, event, 0, 0);186__GUEST_ASSERT(ret.error == 0, "config matching failed %ld\n", ret.error);187GUEST_ASSERT(ret.value < RISCV_MAX_PMU_COUNTERS);188GUEST_ASSERT(BIT(ret.value) & counter_mask_available);189190return ret.value;191}192193static unsigned long get_num_counters(void)194{195struct sbiret ret;196197ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_NUM_COUNTERS, 0, 0, 0, 0, 0, 0);198199__GUEST_ASSERT(ret.error == 0, "Unable to retrieve number of counters from SBI PMU");200__GUEST_ASSERT(ret.value < RISCV_MAX_PMU_COUNTERS,201"Invalid number of counters %ld\n", ret.value);202203return ret.value;204}205206static void update_counter_info(int num_counters)207{208int i = 0;209struct sbiret ret;210211for (i = 0; i < num_counters; i++) {212ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_GET_INFO, i, 0, 0, 0, 0, 0);213214/* There can be gaps in logical counter indicies*/215if (ret.error)216continue;217GUEST_ASSERT_NE(ret.value, 0);218219ctrinfo_arr[i].value = ret.value;220counter_mask_available |= BIT(i);221}222223GUEST_ASSERT(counter_mask_available > 0);224}225226static unsigned long read_fw_counter(int idx, union sbi_pmu_ctr_info ctrinfo)227{228struct sbiret ret;229230ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_FW_READ, idx, 0, 0, 0, 0, 0);231GUEST_ASSERT(ret.error == 0);232return ret.value;233}234235static unsigned long read_counter(int idx, union sbi_pmu_ctr_info ctrinfo)236{237unsigned long counter_val = 0;238239__GUEST_ASSERT(ctrinfo.type < 2, "Invalid counter type %d", ctrinfo.type);240241if (ctrinfo.type == SBI_PMU_CTR_TYPE_HW)242counter_val = pmu_csr_read_num(ctrinfo.csr);243else if (ctrinfo.type == SBI_PMU_CTR_TYPE_FW)244counter_val = read_fw_counter(idx, ctrinfo);245246return counter_val;247}248249static inline void verify_sbi_requirement_assert(void)250{251long out_val = 0;252bool probe;253254probe = guest_sbi_probe_extension(SBI_EXT_PMU, &out_val);255GUEST_ASSERT(probe && out_val == 1);256257if (get_host_sbi_spec_version() < sbi_mk_version(2, 0))258__GUEST_ASSERT(0, "SBI implementation version doesn't support PMU Snapshot");259}260261static void snapshot_set_shmem(vm_paddr_t gpa, unsigned long flags)262{263unsigned long lo = (unsigned long)gpa;264#if __riscv_xlen == 32265unsigned long hi = (unsigned long)(gpa >> 32);266#else267unsigned long hi = gpa == -1 ? -1 : 0;268#endif269struct sbiret ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_SNAPSHOT_SET_SHMEM,270lo, hi, flags, 0, 0, 0);271272GUEST_ASSERT(ret.value == 0 && ret.error == 0);273}274275static void test_pmu_event(unsigned long event)276{277unsigned long counter;278unsigned long counter_value_pre, counter_value_post;279unsigned long counter_init_value = 100;280281counter = get_counter_index(0, counter_mask_available, 0, event);282counter_value_pre = read_counter(counter, ctrinfo_arr[counter]);283284/* Do not set the initial value */285start_counter(counter, 0, 0);286dummy_func_loop(10000);287stop_counter(counter, 0);288289counter_value_post = read_counter(counter, ctrinfo_arr[counter]);290__GUEST_ASSERT(counter_value_post > counter_value_pre,291"Event update verification failed: post [%lx] pre [%lx]\n",292counter_value_post, counter_value_pre);293294/*295* We can't just update the counter without starting it.296* Do start/stop twice to simulate that by first initializing to a very297* high value and a low value after that.298*/299start_counter(counter, SBI_PMU_START_FLAG_SET_INIT_VALUE, ULONG_MAX/2);300stop_counter(counter, 0);301counter_value_pre = read_counter(counter, ctrinfo_arr[counter]);302303start_counter(counter, SBI_PMU_START_FLAG_SET_INIT_VALUE, counter_init_value);304stop_counter(counter, 0);305counter_value_post = read_counter(counter, ctrinfo_arr[counter]);306__GUEST_ASSERT(counter_value_pre > counter_value_post,307"Counter reinitialization verification failed : post [%lx] pre [%lx]\n",308counter_value_post, counter_value_pre);309310/* Now set the initial value and compare */311start_counter(counter, SBI_PMU_START_FLAG_SET_INIT_VALUE, counter_init_value);312dummy_func_loop(10000);313stop_counter(counter, 0);314315counter_value_post = read_counter(counter, ctrinfo_arr[counter]);316__GUEST_ASSERT(counter_value_post > counter_init_value,317"Event update verification failed: post [%lx] pre [%lx]\n",318counter_value_post, counter_init_value);319320stop_reset_counter(counter, 0);321}322323static void test_pmu_event_snapshot(unsigned long event)324{325unsigned long counter;326unsigned long counter_value_pre, counter_value_post;327unsigned long counter_init_value = 100;328struct riscv_pmu_snapshot_data *snapshot_data = snapshot_gva;329330counter = get_counter_index(0, counter_mask_available, 0, event);331counter_value_pre = read_counter(counter, ctrinfo_arr[counter]);332333/* Do not set the initial value */334start_counter(counter, 0, 0);335dummy_func_loop(10000);336stop_counter(counter, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);337338/* The counter value is updated w.r.t relative index of cbase */339counter_value_post = READ_ONCE(snapshot_data->ctr_values[0]);340__GUEST_ASSERT(counter_value_post > counter_value_pre,341"Event update verification failed: post [%lx] pre [%lx]\n",342counter_value_post, counter_value_pre);343344/*345* We can't just update the counter without starting it.346* Do start/stop twice to simulate that by first initializing to a very347* high value and a low value after that.348*/349WRITE_ONCE(snapshot_data->ctr_values[0], ULONG_MAX/2);350start_counter(counter, SBI_PMU_START_FLAG_INIT_SNAPSHOT, 0);351stop_counter(counter, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);352counter_value_pre = READ_ONCE(snapshot_data->ctr_values[0]);353354WRITE_ONCE(snapshot_data->ctr_values[0], counter_init_value);355start_counter(counter, SBI_PMU_START_FLAG_INIT_SNAPSHOT, 0);356stop_counter(counter, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);357counter_value_post = READ_ONCE(snapshot_data->ctr_values[0]);358__GUEST_ASSERT(counter_value_pre > counter_value_post,359"Counter reinitialization verification failed : post [%lx] pre [%lx]\n",360counter_value_post, counter_value_pre);361362/* Now set the initial value and compare */363WRITE_ONCE(snapshot_data->ctr_values[0], counter_init_value);364start_counter(counter, SBI_PMU_START_FLAG_INIT_SNAPSHOT, 0);365dummy_func_loop(10000);366stop_counter(counter, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);367368counter_value_post = READ_ONCE(snapshot_data->ctr_values[0]);369__GUEST_ASSERT(counter_value_post > counter_init_value,370"Event update verification failed: post [%lx] pre [%lx]\n",371counter_value_post, counter_init_value);372373stop_reset_counter(counter, 0);374}375376static void test_pmu_event_overflow(unsigned long event)377{378unsigned long counter;379unsigned long counter_value_post;380unsigned long counter_init_value = ULONG_MAX - 10000;381struct riscv_pmu_snapshot_data *snapshot_data = snapshot_gva;382383counter = get_counter_index(0, counter_mask_available, 0, event);384counter_in_use = counter;385386/* The counter value is updated w.r.t relative index of cbase passed to start/stop */387WRITE_ONCE(snapshot_data->ctr_values[0], counter_init_value);388start_counter(counter, SBI_PMU_START_FLAG_INIT_SNAPSHOT, 0);389dummy_func_loop(10000);390udelay(msecs_to_usecs(2000));391/* irq handler should have stopped the counter */392stop_counter(counter, SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT);393394counter_value_post = READ_ONCE(snapshot_data->ctr_values[0]);395/* The counter value after stopping should be less the init value due to overflow */396__GUEST_ASSERT(counter_value_post < counter_init_value,397"counter_value_post %lx counter_init_value %lx for counter\n",398counter_value_post, counter_init_value);399400stop_reset_counter(counter, 0);401}402403static void test_invalid_event(void)404{405struct sbiret ret;406unsigned long event = 0x1234; /* A random event */407408ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, 0,409counter_mask_available, 0, event, 0, 0);410GUEST_ASSERT_EQ(ret.error, SBI_ERR_NOT_SUPPORTED);411}412413static void test_pmu_events(void)414{415int num_counters = 0;416417/* Get the counter details */418num_counters = get_num_counters();419update_counter_info(num_counters);420421/* Sanity testing for any random invalid event */422test_invalid_event();423424/* Only these two events are guaranteed to be present */425test_pmu_event(SBI_PMU_HW_CPU_CYCLES);426test_pmu_event(SBI_PMU_HW_INSTRUCTIONS);427428GUEST_DONE();429}430431static void test_pmu_basic_sanity(void)432{433long out_val = 0;434bool probe;435struct sbiret ret;436int num_counters = 0, i;437union sbi_pmu_ctr_info ctrinfo;438439probe = guest_sbi_probe_extension(SBI_EXT_PMU, &out_val);440GUEST_ASSERT(probe && out_val == 1);441442num_counters = get_num_counters();443444for (i = 0; i < num_counters; i++) {445ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_GET_INFO, i,4460, 0, 0, 0, 0);447448/* There can be gaps in logical counter indicies*/449if (ret.error)450continue;451GUEST_ASSERT_NE(ret.value, 0);452453ctrinfo.value = ret.value;454455/**456* Accessibility check of hardware and read capability of firmware counters.457* The spec doesn't mandate any initial value. No need to check any value.458*/459if (ctrinfo.type == SBI_PMU_CTR_TYPE_HW) {460pmu_csr_read_num(ctrinfo.csr);461GUEST_ASSERT(illegal_handler_invoked);462} else if (ctrinfo.type == SBI_PMU_CTR_TYPE_FW) {463read_fw_counter(i, ctrinfo);464}465}466467GUEST_DONE();468}469470static void test_pmu_events_snaphost(void)471{472int num_counters = 0;473struct riscv_pmu_snapshot_data *snapshot_data = snapshot_gva;474int i;475476/* Verify presence of SBI PMU and minimum requrired SBI version */477verify_sbi_requirement_assert();478479snapshot_set_shmem(snapshot_gpa, 0);480481/* Get the counter details */482num_counters = get_num_counters();483update_counter_info(num_counters);484485/* Validate shared memory access */486GUEST_ASSERT_EQ(READ_ONCE(snapshot_data->ctr_overflow_mask), 0);487for (i = 0; i < num_counters; i++) {488if (counter_mask_available & (BIT(i)))489GUEST_ASSERT_EQ(READ_ONCE(snapshot_data->ctr_values[i]), 0);490}491/* Only these two events are guranteed to be present */492test_pmu_event_snapshot(SBI_PMU_HW_CPU_CYCLES);493test_pmu_event_snapshot(SBI_PMU_HW_INSTRUCTIONS);494495GUEST_DONE();496}497498static void test_pmu_events_overflow(void)499{500int num_counters = 0, i = 0;501502/* Verify presence of SBI PMU and minimum requrired SBI version */503verify_sbi_requirement_assert();504505snapshot_set_shmem(snapshot_gpa, 0);506csr_set(CSR_IE, BIT(IRQ_PMU_OVF));507local_irq_enable();508509/* Get the counter details */510num_counters = get_num_counters();511update_counter_info(num_counters);512513/*514* Qemu supports overflow for cycle/instruction.515* This test may fail on any platform that do not support overflow for these two events.516*/517for (i = 0; i < targs.overflow_irqnum; i++)518test_pmu_event_overflow(SBI_PMU_HW_CPU_CYCLES);519GUEST_ASSERT_EQ(vcpu_shared_irq_count, targs.overflow_irqnum);520521vcpu_shared_irq_count = 0;522523for (i = 0; i < targs.overflow_irqnum; i++)524test_pmu_event_overflow(SBI_PMU_HW_INSTRUCTIONS);525GUEST_ASSERT_EQ(vcpu_shared_irq_count, targs.overflow_irqnum);526527GUEST_DONE();528}529530static void run_vcpu(struct kvm_vcpu *vcpu)531{532struct ucall uc;533534vcpu_run(vcpu);535switch (get_ucall(vcpu, &uc)) {536case UCALL_ABORT:537REPORT_GUEST_ASSERT(uc);538break;539case UCALL_DONE:540case UCALL_SYNC:541break;542default:543TEST_FAIL("Unknown ucall %lu", uc.cmd);544break;545}546}547548void test_vm_destroy(struct kvm_vm *vm)549{550memset(ctrinfo_arr, 0, sizeof(union sbi_pmu_ctr_info) * RISCV_MAX_PMU_COUNTERS);551counter_mask_available = 0;552kvm_vm_free(vm);553}554555static void test_vm_basic_test(void *guest_code)556{557struct kvm_vm *vm;558struct kvm_vcpu *vcpu;559560vm = vm_create_with_one_vcpu(&vcpu, guest_code);561__TEST_REQUIRE(__vcpu_has_sbi_ext(vcpu, KVM_RISCV_SBI_EXT_PMU),562"SBI PMU not available, skipping test");563vm_init_vector_tables(vm);564/* Illegal instruction handler is required to verify read access without configuration */565vm_install_exception_handler(vm, EXC_INST_ILLEGAL, guest_illegal_exception_handler);566567vcpu_init_vector_tables(vcpu);568run_vcpu(vcpu);569570test_vm_destroy(vm);571}572573static void test_vm_events_test(void *guest_code)574{575struct kvm_vm *vm = NULL;576struct kvm_vcpu *vcpu = NULL;577578vm = vm_create_with_one_vcpu(&vcpu, guest_code);579__TEST_REQUIRE(__vcpu_has_sbi_ext(vcpu, KVM_RISCV_SBI_EXT_PMU),580"SBI PMU not available, skipping test");581run_vcpu(vcpu);582583test_vm_destroy(vm);584}585586static void test_vm_setup_snapshot_mem(struct kvm_vm *vm, struct kvm_vcpu *vcpu)587{588/* PMU Snapshot requires single page only */589vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, PMU_SNAPSHOT_GPA_BASE, 1, 1, 0);590/* PMU_SNAPSHOT_GPA_BASE is identity mapped */591virt_map(vm, PMU_SNAPSHOT_GPA_BASE, PMU_SNAPSHOT_GPA_BASE, 1);592593snapshot_gva = (void *)(PMU_SNAPSHOT_GPA_BASE);594snapshot_gpa = addr_gva2gpa(vcpu->vm, (vm_vaddr_t)snapshot_gva);595sync_global_to_guest(vcpu->vm, snapshot_gva);596sync_global_to_guest(vcpu->vm, snapshot_gpa);597}598599static void test_vm_events_snapshot_test(void *guest_code)600{601struct kvm_vm *vm = NULL;602struct kvm_vcpu *vcpu;603604vm = vm_create_with_one_vcpu(&vcpu, guest_code);605__TEST_REQUIRE(__vcpu_has_sbi_ext(vcpu, KVM_RISCV_SBI_EXT_PMU),606"SBI PMU not available, skipping test");607608test_vm_setup_snapshot_mem(vm, vcpu);609610run_vcpu(vcpu);611612test_vm_destroy(vm);613}614615static void test_vm_events_overflow(void *guest_code)616{617struct kvm_vm *vm = NULL;618struct kvm_vcpu *vcpu;619620vm = vm_create_with_one_vcpu(&vcpu, guest_code);621__TEST_REQUIRE(__vcpu_has_sbi_ext(vcpu, KVM_RISCV_SBI_EXT_PMU),622"SBI PMU not available, skipping test");623624__TEST_REQUIRE(__vcpu_has_isa_ext(vcpu, KVM_RISCV_ISA_EXT_SSCOFPMF),625"Sscofpmf is not available, skipping overflow test");626627test_vm_setup_snapshot_mem(vm, vcpu);628vm_init_vector_tables(vm);629vm_install_interrupt_handler(vm, guest_irq_handler);630631vcpu_init_vector_tables(vcpu);632/* Initialize guest timer frequency. */633timer_freq = vcpu_get_reg(vcpu, RISCV_TIMER_REG(frequency));634635/* Export the shared variables to the guest */636sync_global_to_guest(vm, timer_freq);637sync_global_to_guest(vm, vcpu_shared_irq_count);638sync_global_to_guest(vm, targs);639640run_vcpu(vcpu);641642test_vm_destroy(vm);643}644645static void test_print_help(char *name)646{647pr_info("Usage: %s [-h] [-t <test name>] [-n <number of LCOFI interrupt for overflow test>]\n",648name);649pr_info("\t-t: Test to run (default all). Available tests are 'basic', 'events', 'snapshot', 'overflow'\n");650pr_info("\t-n: Number of LCOFI interrupt to trigger for each event in overflow test (default: %d)\n",651SBI_PMU_OVERFLOW_IRQNUM_DEFAULT);652pr_info("\t-h: print this help screen\n");653}654655static bool parse_args(int argc, char *argv[])656{657int opt;658int temp_disabled_tests = SBI_PMU_TEST_BASIC | SBI_PMU_TEST_EVENTS | SBI_PMU_TEST_SNAPSHOT |659SBI_PMU_TEST_OVERFLOW;660int overflow_interrupts = 0;661662while ((opt = getopt(argc, argv, "ht:n:")) != -1) {663switch (opt) {664case 't':665if (!strncmp("basic", optarg, 5))666temp_disabled_tests &= ~SBI_PMU_TEST_BASIC;667else if (!strncmp("events", optarg, 6))668temp_disabled_tests &= ~SBI_PMU_TEST_EVENTS;669else if (!strncmp("snapshot", optarg, 8))670temp_disabled_tests &= ~SBI_PMU_TEST_SNAPSHOT;671else if (!strncmp("overflow", optarg, 8))672temp_disabled_tests &= ~SBI_PMU_TEST_OVERFLOW;673else674goto done;675targs.disabled_tests = temp_disabled_tests;676break;677case 'n':678overflow_interrupts = atoi_positive("Number of LCOFI", optarg);679break;680case 'h':681default:682goto done;683}684}685686if (overflow_interrupts > 0) {687if (targs.disabled_tests & SBI_PMU_TEST_OVERFLOW) {688pr_info("-n option is only available for overflow test\n");689goto done;690} else {691targs.overflow_irqnum = overflow_interrupts;692}693}694695return true;696done:697test_print_help(argv[0]);698return false;699}700701int main(int argc, char *argv[])702{703targs.disabled_tests = 0;704targs.overflow_irqnum = SBI_PMU_OVERFLOW_IRQNUM_DEFAULT;705706if (!parse_args(argc, argv))707exit(KSFT_SKIP);708709if (!(targs.disabled_tests & SBI_PMU_TEST_BASIC)) {710test_vm_basic_test(test_pmu_basic_sanity);711pr_info("SBI PMU basic test : PASS\n");712}713714if (!(targs.disabled_tests & SBI_PMU_TEST_EVENTS)) {715test_vm_events_test(test_pmu_events);716pr_info("SBI PMU event verification test : PASS\n");717}718719if (!(targs.disabled_tests & SBI_PMU_TEST_SNAPSHOT)) {720test_vm_events_snapshot_test(test_pmu_events_snaphost);721pr_info("SBI PMU event verification with snapshot test : PASS\n");722}723724if (!(targs.disabled_tests & SBI_PMU_TEST_OVERFLOW)) {725test_vm_events_overflow(test_pmu_events_overflow);726pr_info("SBI PMU event verification with overflow test : PASS\n");727}728729return 0;730}731732733