Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/kvm/loongarch/arch_timer.c
38245 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* The test validates periodic/one-shot constant timer IRQ using
4
* CSR.TCFG and CSR.TVAL registers.
5
*/
6
#include "arch_timer.h"
7
#include "kvm_util.h"
8
#include "processor.h"
9
#include "timer_test.h"
10
#include "ucall_common.h"
11
12
static void do_idle(void)
13
{
14
unsigned int intid;
15
unsigned long estat;
16
17
__asm__ __volatile__("idle 0" : : : "memory");
18
19
estat = csr_read(LOONGARCH_CSR_ESTAT);
20
intid = !!(estat & BIT(INT_TI));
21
22
/* Make sure pending timer IRQ arrived */
23
GUEST_ASSERT_EQ(intid, 1);
24
csr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR);
25
}
26
27
static void guest_irq_handler(struct ex_regs *regs)
28
{
29
unsigned int intid;
30
uint32_t cpu = guest_get_vcpuid();
31
uint64_t xcnt, val, cfg, xcnt_diff_us;
32
struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];
33
34
intid = !!(regs->estat & BIT(INT_TI));
35
36
/* Make sure we are dealing with the correct timer IRQ */
37
GUEST_ASSERT_EQ(intid, 1);
38
39
cfg = timer_get_cfg();
40
if (cfg & CSR_TCFG_PERIOD) {
41
WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter - 1);
42
if (shared_data->nr_iter == 0)
43
disable_timer();
44
csr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR);
45
return;
46
}
47
48
/*
49
* On real machine, value of LOONGARCH_CSR_TVAL is BIT_ULL(48) - 1
50
* On virtual machine, its value counts down from BIT_ULL(48) - 1
51
*/
52
val = timer_get_val();
53
xcnt = timer_get_cycles();
54
xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt);
55
56
/* Basic 'timer condition met' check */
57
__GUEST_ASSERT(val > cfg,
58
"val = 0x%lx, cfg = 0x%lx, xcnt_diff_us = 0x%lx",
59
val, cfg, xcnt_diff_us);
60
61
csr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR);
62
WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1);
63
}
64
65
static void guest_test_period_timer(uint32_t cpu)
66
{
67
uint32_t irq_iter, config_iter;
68
uint64_t us;
69
struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];
70
71
shared_data->nr_iter = test_args.nr_iter;
72
shared_data->xcnt = timer_get_cycles();
73
us = msecs_to_usecs(test_args.timer_period_ms) + test_args.timer_err_margin_us;
74
timer_set_next_cmp_ms(test_args.timer_period_ms, true);
75
76
for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) {
77
/* Setup a timeout for the interrupt to arrive */
78
udelay(us);
79
}
80
81
irq_iter = READ_ONCE(shared_data->nr_iter);
82
__GUEST_ASSERT(irq_iter == 0,
83
"irq_iter = 0x%x.\n"
84
" Guest period timer interrupt was not triggered within the specified\n"
85
" interval, try to increase the error margin by [-e] option.\n",
86
irq_iter);
87
}
88
89
static void guest_test_oneshot_timer(uint32_t cpu)
90
{
91
uint32_t irq_iter, config_iter;
92
uint64_t us;
93
struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];
94
95
shared_data->nr_iter = 0;
96
shared_data->guest_stage = 0;
97
us = msecs_to_usecs(test_args.timer_period_ms) + test_args.timer_err_margin_us;
98
for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) {
99
shared_data->xcnt = timer_get_cycles();
100
101
/* Setup the next interrupt */
102
timer_set_next_cmp_ms(test_args.timer_period_ms, false);
103
/* Setup a timeout for the interrupt to arrive */
104
udelay(us);
105
106
irq_iter = READ_ONCE(shared_data->nr_iter);
107
__GUEST_ASSERT(config_iter + 1 == irq_iter,
108
"config_iter + 1 = 0x%x, irq_iter = 0x%x.\n"
109
" Guest timer interrupt was not triggered within the specified\n"
110
" interval, try to increase the error margin by [-e] option.\n",
111
config_iter + 1, irq_iter);
112
}
113
}
114
115
static void guest_test_emulate_timer(uint32_t cpu)
116
{
117
uint32_t config_iter;
118
uint64_t xcnt_diff_us, us;
119
struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];
120
121
local_irq_disable();
122
shared_data->nr_iter = 0;
123
us = msecs_to_usecs(test_args.timer_period_ms);
124
for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) {
125
shared_data->xcnt = timer_get_cycles();
126
127
/* Setup the next interrupt */
128
timer_set_next_cmp_ms(test_args.timer_period_ms, false);
129
do_idle();
130
131
xcnt_diff_us = cycles_to_usec(timer_get_cycles() - shared_data->xcnt);
132
__GUEST_ASSERT(xcnt_diff_us >= us,
133
"xcnt_diff_us = 0x%lx, us = 0x%lx.\n",
134
xcnt_diff_us, us);
135
}
136
local_irq_enable();
137
}
138
139
static void guest_time_count_test(uint32_t cpu)
140
{
141
uint32_t config_iter;
142
unsigned long start, end, prev, us;
143
144
/* Assuming that test case starts to run in 1 second */
145
start = timer_get_cycles();
146
us = msec_to_cycles(1000);
147
__GUEST_ASSERT(start <= us,
148
"start = 0x%lx, us = 0x%lx.\n",
149
start, us);
150
151
us = msec_to_cycles(test_args.timer_period_ms);
152
for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) {
153
start = timer_get_cycles();
154
end = start + us;
155
/* test time count growing up always */
156
while (start < end) {
157
prev = start;
158
start = timer_get_cycles();
159
__GUEST_ASSERT(prev <= start,
160
"prev = 0x%lx, start = 0x%lx.\n",
161
prev, start);
162
}
163
}
164
}
165
166
static void guest_code(void)
167
{
168
uint32_t cpu = guest_get_vcpuid();
169
170
/* must run at first */
171
guest_time_count_test(cpu);
172
173
timer_irq_enable();
174
local_irq_enable();
175
guest_test_period_timer(cpu);
176
guest_test_oneshot_timer(cpu);
177
guest_test_emulate_timer(cpu);
178
179
GUEST_DONE();
180
}
181
182
struct kvm_vm *test_vm_create(void)
183
{
184
struct kvm_vm *vm;
185
int nr_vcpus = test_args.nr_vcpus;
186
187
vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
188
vm_init_descriptor_tables(vm);
189
vm_install_exception_handler(vm, EXCCODE_INT, guest_irq_handler);
190
191
/* Make all the test's cmdline args visible to the guest */
192
sync_global_to_guest(vm, test_args);
193
194
return vm;
195
}
196
197
void test_vm_cleanup(struct kvm_vm *vm)
198
{
199
kvm_vm_free(vm);
200
}
201
202