mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 16:01:44 -04:00
Use u32 instead of uint32_t to make the KVM selftests code more concise and more similar to the kernel (since selftests are primarily developed by kernel developers). This commit was generated with the following command: git ls-files tools/testing/selftests/kvm | xargs sed -i 's/uint32_t/u32/g' Then by manually adjusting whitespace to make checkpatch.pl happy. No functional change intended. Signed-off-by: David Matlack <dmatlack@google.com> Link: https://patch.msgid.link/20260420212004.3938325-7-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
110 lines
2.9 KiB
C
110 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* arch_timer.c - Tests the riscv64 sstc timer IRQ functionality
|
|
*
|
|
* The test validates the sstc timer IRQs using vstimecmp registers.
|
|
* It's ported from the aarch64 arch_timer test.
|
|
*
|
|
* Copyright (c) 2024, Intel Corporation.
|
|
*/
|
|
#include "arch_timer.h"
|
|
#include "kvm_util.h"
|
|
#include "processor.h"
|
|
#include "timer_test.h"
|
|
#include "ucall_common.h"
|
|
|
|
static int timer_irq = IRQ_S_TIMER;
|
|
|
|
static void guest_irq_handler(struct pt_regs *regs)
|
|
{
|
|
u64 xcnt, xcnt_diff_us, cmp;
|
|
unsigned int intid = regs->cause & ~CAUSE_IRQ_FLAG;
|
|
u32 cpu = guest_get_vcpuid();
|
|
struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];
|
|
|
|
timer_irq_disable();
|
|
|
|
xcnt = timer_get_cycles();
|
|
cmp = timer_get_cmp();
|
|
xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt);
|
|
|
|
/* Make sure we are dealing with the correct timer IRQ */
|
|
GUEST_ASSERT_EQ(intid, timer_irq);
|
|
|
|
__GUEST_ASSERT(xcnt >= cmp,
|
|
"xcnt = 0x%"PRIx64", cmp = 0x%"PRIx64", xcnt_diff_us = 0x%" PRIx64,
|
|
xcnt, cmp, xcnt_diff_us);
|
|
|
|
WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1);
|
|
}
|
|
|
|
static void guest_run(struct test_vcpu_shared_data *shared_data)
|
|
{
|
|
u32 irq_iter, config_iter;
|
|
|
|
shared_data->nr_iter = 0;
|
|
shared_data->guest_stage = 0;
|
|
|
|
for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) {
|
|
/* Setup the next interrupt */
|
|
timer_set_next_cmp_ms(test_args.timer_period_ms);
|
|
shared_data->xcnt = timer_get_cycles();
|
|
timer_irq_enable();
|
|
|
|
/* Setup a timeout for the interrupt to arrive */
|
|
udelay(msecs_to_usecs(test_args.timer_period_ms) +
|
|
test_args.timer_err_margin_us);
|
|
|
|
irq_iter = READ_ONCE(shared_data->nr_iter);
|
|
__GUEST_ASSERT(config_iter + 1 == irq_iter,
|
|
"config_iter + 1 = 0x%x, irq_iter = 0x%x.\n"
|
|
" Guest timer interrupt was not triggered within the specified\n"
|
|
" interval, try to increase the error margin by [-e] option.\n",
|
|
config_iter + 1, irq_iter);
|
|
}
|
|
}
|
|
|
|
static void guest_code(void)
|
|
{
|
|
u32 cpu = guest_get_vcpuid();
|
|
struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];
|
|
|
|
timer_irq_disable();
|
|
local_irq_enable();
|
|
|
|
guest_run(shared_data);
|
|
|
|
GUEST_DONE();
|
|
}
|
|
|
|
struct kvm_vm *test_vm_create(void)
|
|
{
|
|
struct kvm_vm *vm;
|
|
int nr_vcpus = test_args.nr_vcpus;
|
|
|
|
vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
|
|
__TEST_REQUIRE(__vcpu_has_isa_ext(vcpus[0], KVM_RISCV_ISA_EXT_SSTC),
|
|
"SSTC not available, skipping test\n");
|
|
|
|
vm_init_vector_tables(vm);
|
|
vm_install_interrupt_handler(vm, guest_irq_handler);
|
|
|
|
for (int i = 0; i < nr_vcpus; i++)
|
|
vcpu_init_vector_tables(vcpus[i]);
|
|
|
|
/* Initialize guest timer frequency. */
|
|
timer_freq = vcpu_get_reg(vcpus[0], RISCV_TIMER_REG(frequency));
|
|
sync_global_to_guest(vm, timer_freq);
|
|
pr_debug("timer_freq: %lu\n", timer_freq);
|
|
|
|
/* Make all the test's cmdline args visible to the guest */
|
|
sync_global_to_guest(vm, test_args);
|
|
|
|
return vm;
|
|
}
|
|
|
|
void test_vm_cleanup(struct kvm_vm *vm)
|
|
{
|
|
kvm_vm_free(vm);
|
|
}
|