1 // SPDX-License-Identifier: GPL-2.0-only
3 * The test validates both the virtual and physical timer IRQs using
4 * CVAL and TVAL registers.
6 * Copyright (c) 2021, Google LLC.
10 #include "arch_timer.h"
13 #include "processor.h"
14 #include "timer_test.h"
17 #define GICD_BASE_GPA 0x8000000ULL
18 #define GICR_BASE_GPA 0x80A0000ULL
21 GUEST_STAGE_VTIMER_CVAL
= 1,
22 GUEST_STAGE_VTIMER_TVAL
,
23 GUEST_STAGE_PTIMER_CVAL
,
24 GUEST_STAGE_PTIMER_TVAL
,
28 static int vtimer_irq
, ptimer_irq
;
31 guest_configure_timer_action(struct test_vcpu_shared_data
*shared_data
)
33 switch (shared_data
->guest_stage
) {
34 case GUEST_STAGE_VTIMER_CVAL
:
35 timer_set_next_cval_ms(VIRTUAL
, test_args
.timer_period_ms
);
36 shared_data
->xcnt
= timer_get_cntct(VIRTUAL
);
37 timer_set_ctl(VIRTUAL
, CTL_ENABLE
);
39 case GUEST_STAGE_VTIMER_TVAL
:
40 timer_set_next_tval_ms(VIRTUAL
, test_args
.timer_period_ms
);
41 shared_data
->xcnt
= timer_get_cntct(VIRTUAL
);
42 timer_set_ctl(VIRTUAL
, CTL_ENABLE
);
44 case GUEST_STAGE_PTIMER_CVAL
:
45 timer_set_next_cval_ms(PHYSICAL
, test_args
.timer_period_ms
);
46 shared_data
->xcnt
= timer_get_cntct(PHYSICAL
);
47 timer_set_ctl(PHYSICAL
, CTL_ENABLE
);
49 case GUEST_STAGE_PTIMER_TVAL
:
50 timer_set_next_tval_ms(PHYSICAL
, test_args
.timer_period_ms
);
51 shared_data
->xcnt
= timer_get_cntct(PHYSICAL
);
52 timer_set_ctl(PHYSICAL
, CTL_ENABLE
);
59 static void guest_validate_irq(unsigned int intid
,
60 struct test_vcpu_shared_data
*shared_data
)
62 enum guest_stage stage
= shared_data
->guest_stage
;
63 uint64_t xcnt
= 0, xcnt_diff_us
, cval
= 0;
64 unsigned long xctl
= 0;
65 unsigned int timer_irq
= 0;
66 unsigned int accessor
;
68 if (intid
== IAR_SPURIOUS
)
72 case GUEST_STAGE_VTIMER_CVAL
:
73 case GUEST_STAGE_VTIMER_TVAL
:
75 timer_irq
= vtimer_irq
;
77 case GUEST_STAGE_PTIMER_CVAL
:
78 case GUEST_STAGE_PTIMER_TVAL
:
80 timer_irq
= ptimer_irq
;
87 xctl
= timer_get_ctl(accessor
);
88 if ((xctl
& CTL_IMASK
) || !(xctl
& CTL_ENABLE
))
91 timer_set_ctl(accessor
, CTL_IMASK
);
92 xcnt
= timer_get_cntct(accessor
);
93 cval
= timer_get_cval(accessor
);
95 xcnt_diff_us
= cycles_to_usec(xcnt
- shared_data
->xcnt
);
97 /* Make sure we are dealing with the correct timer IRQ */
98 GUEST_ASSERT_EQ(intid
, timer_irq
);
100 /* Basic 'timer condition met' check */
101 __GUEST_ASSERT(xcnt
>= cval
,
102 "xcnt = 0x%lx, cval = 0x%lx, xcnt_diff_us = 0x%lx",
103 xcnt
, cval
, xcnt_diff_us
);
104 __GUEST_ASSERT(xctl
& CTL_ISTATUS
, "xctl = 0x%lx", xctl
);
106 WRITE_ONCE(shared_data
->nr_iter
, shared_data
->nr_iter
+ 1);
109 static void guest_irq_handler(struct ex_regs
*regs
)
111 unsigned int intid
= gic_get_and_ack_irq();
112 uint32_t cpu
= guest_get_vcpuid();
113 struct test_vcpu_shared_data
*shared_data
= &vcpu_shared_data
[cpu
];
115 guest_validate_irq(intid
, shared_data
);
120 static void guest_run_stage(struct test_vcpu_shared_data
*shared_data
,
121 enum guest_stage stage
)
123 uint32_t irq_iter
, config_iter
;
125 shared_data
->guest_stage
= stage
;
126 shared_data
->nr_iter
= 0;
128 for (config_iter
= 0; config_iter
< test_args
.nr_iter
; config_iter
++) {
129 /* Setup the next interrupt */
130 guest_configure_timer_action(shared_data
);
132 /* Setup a timeout for the interrupt to arrive */
133 udelay(msecs_to_usecs(test_args
.timer_period_ms
) +
134 test_args
.timer_err_margin_us
);
136 irq_iter
= READ_ONCE(shared_data
->nr_iter
);
137 __GUEST_ASSERT(config_iter
+ 1 == irq_iter
,
138 "config_iter + 1 = 0x%x, irq_iter = 0x%x.\n"
139 " Guest timer interrupt was not trigged within the specified\n"
140 " interval, try to increase the error margin by [-e] option.\n",
141 config_iter
+ 1, irq_iter
);
145 static void guest_code(void)
147 uint32_t cpu
= guest_get_vcpuid();
148 struct test_vcpu_shared_data
*shared_data
= &vcpu_shared_data
[cpu
];
152 gic_init(GIC_V3
, test_args
.nr_vcpus
,
153 (void *)GICD_BASE_GPA
, (void *)GICR_BASE_GPA
);
155 timer_set_ctl(VIRTUAL
, CTL_IMASK
);
156 timer_set_ctl(PHYSICAL
, CTL_IMASK
);
158 gic_irq_enable(vtimer_irq
);
159 gic_irq_enable(ptimer_irq
);
162 guest_run_stage(shared_data
, GUEST_STAGE_VTIMER_CVAL
);
163 guest_run_stage(shared_data
, GUEST_STAGE_VTIMER_TVAL
);
164 guest_run_stage(shared_data
, GUEST_STAGE_PTIMER_CVAL
);
165 guest_run_stage(shared_data
, GUEST_STAGE_PTIMER_TVAL
);
170 static void test_init_timer_irq(struct kvm_vm
*vm
)
172 /* Timer initid should be same for all the vCPUs, so query only vCPU-0 */
173 vcpu_device_attr_get(vcpus
[0], KVM_ARM_VCPU_TIMER_CTRL
,
174 KVM_ARM_VCPU_TIMER_IRQ_PTIMER
, &ptimer_irq
);
175 vcpu_device_attr_get(vcpus
[0], KVM_ARM_VCPU_TIMER_CTRL
,
176 KVM_ARM_VCPU_TIMER_IRQ_VTIMER
, &vtimer_irq
);
178 sync_global_to_guest(vm
, ptimer_irq
);
179 sync_global_to_guest(vm
, vtimer_irq
);
181 pr_debug("ptimer_irq: %d; vtimer_irq: %d\n", ptimer_irq
, vtimer_irq
);
186 struct kvm_vm
*test_vm_create(void)
190 int nr_vcpus
= test_args
.nr_vcpus
;
192 vm
= vm_create_with_vcpus(nr_vcpus
, guest_code
, vcpus
);
194 vm_init_descriptor_tables(vm
);
195 vm_install_exception_handler(vm
, VECTOR_IRQ_CURRENT
, guest_irq_handler
);
197 if (!test_args
.reserved
) {
198 if (kvm_has_cap(KVM_CAP_COUNTER_OFFSET
)) {
199 struct kvm_arm_counter_offset offset
= {
200 .counter_offset
= test_args
.counter_offset
,
203 vm_ioctl(vm
, KVM_ARM_SET_COUNTER_OFFSET
, &offset
);
205 TEST_FAIL("no support for global offset");
208 for (i
= 0; i
< nr_vcpus
; i
++)
209 vcpu_init_descriptor_tables(vcpus
[i
]);
211 test_init_timer_irq(vm
);
212 gic_fd
= vgic_v3_setup(vm
, nr_vcpus
, 64, GICD_BASE_GPA
, GICR_BASE_GPA
);
213 __TEST_REQUIRE(gic_fd
>= 0, "Failed to create vgic-v3");
215 /* Make all the test's cmdline args visible to the guest */
216 sync_global_to_guest(vm
, test_args
);
221 void test_vm_cleanup(struct kvm_vm
*vm
)