110 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * arch_timer.c - Tests the riscv64 sstc timer IRQ functionality4 *5 * The test validates the sstc timer IRQs using vstimecmp registers.6 * It's ported from the aarch64 arch_timer test.7 *8 * Copyright (c) 2024, Intel Corporation.9 */10#include "arch_timer.h"11#include "kvm_util.h"12#include "processor.h"13#include "timer_test.h"14#include "ucall_common.h"15 16static int timer_irq = IRQ_S_TIMER;17 18static void guest_irq_handler(struct ex_regs *regs)19{20 uint64_t xcnt, xcnt_diff_us, cmp;21 unsigned int intid = regs->cause & ~CAUSE_IRQ_FLAG;22 uint32_t cpu = guest_get_vcpuid();23 struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];24 25 timer_irq_disable();26 27 xcnt = timer_get_cycles();28 cmp = timer_get_cmp();29 xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt);30 31 /* Make sure we are dealing with the correct timer IRQ */32 GUEST_ASSERT_EQ(intid, timer_irq);33 34 __GUEST_ASSERT(xcnt >= cmp,35 "xcnt = 0x%"PRIx64", cmp = 0x%"PRIx64", xcnt_diff_us = 0x%" PRIx64,36 xcnt, cmp, xcnt_diff_us);37 38 WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1);39}40 41static void guest_run(struct test_vcpu_shared_data *shared_data)42{43 uint32_t irq_iter, config_iter;44 45 shared_data->nr_iter = 0;46 shared_data->guest_stage = 0;47 48 for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) {49 /* Setup the next interrupt */50 timer_set_next_cmp_ms(test_args.timer_period_ms);51 shared_data->xcnt = timer_get_cycles();52 timer_irq_enable();53 54 /* Setup a timeout for the interrupt to arrive */55 udelay(msecs_to_usecs(test_args.timer_period_ms) +56 test_args.timer_err_margin_us);57 58 irq_iter = READ_ONCE(shared_data->nr_iter);59 __GUEST_ASSERT(config_iter + 1 == irq_iter,60 "config_iter + 1 = 0x%x, irq_iter = 0x%x.\n"61 " Guest timer interrupt was not triggered within the specified\n"62 " interval, try to increase the error margin by [-e] option.\n",63 config_iter + 1, irq_iter);64 }65}66 67static void guest_code(void)68{69 uint32_t cpu = guest_get_vcpuid();70 struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];71 72 timer_irq_disable();73 local_irq_enable();74 75 guest_run(shared_data);76 77 GUEST_DONE();78}79 80struct kvm_vm *test_vm_create(void)81{82 struct kvm_vm *vm;83 int nr_vcpus = test_args.nr_vcpus;84 85 vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);86 __TEST_REQUIRE(__vcpu_has_isa_ext(vcpus[0], KVM_RISCV_ISA_EXT_SSTC),87 "SSTC not available, skipping test\n");88 89 vm_init_vector_tables(vm);90 vm_install_interrupt_handler(vm, guest_irq_handler);91 92 for (int i = 0; i < nr_vcpus; i++)93 vcpu_init_vector_tables(vcpus[i]);94 95 /* Initialize guest timer frequency. */96 vcpu_get_reg(vcpus[0], RISCV_TIMER_REG(frequency), &timer_freq);97 sync_global_to_guest(vm, timer_freq);98 pr_debug("timer_freq: %lu\n", timer_freq);99 100 /* Make all the test's cmdline args visible to the guest */101 sync_global_to_guest(vm, test_args);102 103 return vm;104}105 106void test_vm_cleanup(struct kvm_vm *vm)107{108 kvm_vm_free(vm);109}110