File Index
Files and directories
Sign in
FILE

arch_timer.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/kvm/riscv/arch_timer.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * arch_timer.c - Tests the riscv64 sstc timer IRQ functionality
  4 *
  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 pt_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	timer_freq = vcpu_get_reg(vcpus[0], RISCV_TIMER_REG(frequency));
 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}
~/ Read-only file preview.