Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/kvm/riscv/arch_timer.c
38245 views
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
16
static int timer_irq = IRQ_S_TIMER;
17
18
static 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
41
static 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
67
static 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
80
struct 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
106
void test_vm_cleanup(struct kvm_vm *vm)
107
{
108
kvm_vm_free(vm);
109
}
110
111