Path: blob/master/tools/testing/selftests/kvm/riscv/arch_timer.c
38245 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* arch_timer.c - Tests the riscv64 sstc timer IRQ functionality3*4* The test validates the sstc timer IRQs using vstimecmp registers.5* It's ported from the aarch64 arch_timer test.6*7* Copyright (c) 2024, Intel Corporation.8*/9#include "arch_timer.h"10#include "kvm_util.h"11#include "processor.h"12#include "timer_test.h"13#include "ucall_common.h"1415static int timer_irq = IRQ_S_TIMER;1617static void guest_irq_handler(struct pt_regs *regs)18{19uint64_t xcnt, xcnt_diff_us, cmp;20unsigned int intid = regs->cause & ~CAUSE_IRQ_FLAG;21uint32_t cpu = guest_get_vcpuid();22struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];2324timer_irq_disable();2526xcnt = timer_get_cycles();27cmp = timer_get_cmp();28xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt);2930/* Make sure we are dealing with the correct timer IRQ */31GUEST_ASSERT_EQ(intid, timer_irq);3233__GUEST_ASSERT(xcnt >= cmp,34"xcnt = 0x%"PRIx64", cmp = 0x%"PRIx64", xcnt_diff_us = 0x%" PRIx64,35xcnt, cmp, xcnt_diff_us);3637WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1);38}3940static void guest_run(struct test_vcpu_shared_data *shared_data)41{42uint32_t irq_iter, config_iter;4344shared_data->nr_iter = 0;45shared_data->guest_stage = 0;4647for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) {48/* Setup the next interrupt */49timer_set_next_cmp_ms(test_args.timer_period_ms);50shared_data->xcnt = timer_get_cycles();51timer_irq_enable();5253/* Setup a timeout for the interrupt to arrive */54udelay(msecs_to_usecs(test_args.timer_period_ms) +55test_args.timer_err_margin_us);5657irq_iter = READ_ONCE(shared_data->nr_iter);58__GUEST_ASSERT(config_iter + 1 == irq_iter,59"config_iter + 1 = 0x%x, irq_iter = 0x%x.\n"60" Guest timer interrupt was not triggered within the specified\n"61" interval, try to increase the error margin by [-e] option.\n",62config_iter + 1, irq_iter);63}64}6566static void guest_code(void)67{68uint32_t cpu = guest_get_vcpuid();69struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];7071timer_irq_disable();72local_irq_enable();7374guest_run(shared_data);7576GUEST_DONE();77}7879struct kvm_vm *test_vm_create(void)80{81struct kvm_vm *vm;82int nr_vcpus = test_args.nr_vcpus;8384vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);85__TEST_REQUIRE(__vcpu_has_isa_ext(vcpus[0], KVM_RISCV_ISA_EXT_SSTC),86"SSTC not available, skipping test\n");8788vm_init_vector_tables(vm);89vm_install_interrupt_handler(vm, guest_irq_handler);9091for (int i = 0; i < nr_vcpus; i++)92vcpu_init_vector_tables(vcpus[i]);9394/* Initialize guest timer frequency. */95timer_freq = vcpu_get_reg(vcpus[0], RISCV_TIMER_REG(frequency));96sync_global_to_guest(vm, timer_freq);97pr_debug("timer_freq: %lu\n", timer_freq);9899/* Make all the test's cmdline args visible to the guest */100sync_global_to_guest(vm, test_args);101102return vm;103}104105void test_vm_cleanup(struct kvm_vm *vm)106{107kvm_vm_free(vm);108}109110111