xref: /kvm-unit-tests/arm/timer.c (revision 56145eb8f7f6aa66b26e1d1232a5f3dfa7cdd058)
1 /*
2  * Timer tests for the ARM virt machine.
3  *
4  * Copyright (C) 2017, Alexander Graf <agraf@suse.de>
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2.
7  */
8 #include <libcflat.h>
9 #include <devicetree.h>
10 #include <errata.h>
11 #include <asm/delay.h>
12 #include <asm/processor.h>
13 #include <asm/gic.h>
14 #include <asm/io.h>
15 
16 #define ARCH_TIMER_CTL_ENABLE  (1 << 0)
17 #define ARCH_TIMER_CTL_IMASK   (1 << 1)
18 #define ARCH_TIMER_CTL_ISTATUS (1 << 2)
19 
20 static void *gic_isenabler;
21 static void *gic_icenabler;
22 
23 static bool ptimer_unsupported;
24 
25 static void ptimer_unsupported_handler(struct pt_regs *regs, unsigned int esr)
26 {
27 	ptimer_unsupported = true;
28 	regs->pc += 4;
29 }
30 
31 static u64 read_vtimer_counter(void)
32 {
33 	isb();
34 	return read_sysreg(cntvct_el0);
35 }
36 
37 static u64 read_vtimer_cval(void)
38 {
39 	return read_sysreg(cntv_cval_el0);
40 }
41 
42 static void write_vtimer_cval(u64 val)
43 {
44 	write_sysreg(val, cntv_cval_el0);
45 	isb();
46 }
47 
48 static s32 read_vtimer_tval(void)
49 {
50 	return read_sysreg(cntv_tval_el0);
51 }
52 
53 static void write_vtimer_tval(s32 val)
54 {
55 	write_sysreg(val, cntv_tval_el0);
56 	isb();
57 }
58 
59 static u64 read_vtimer_ctl(void)
60 {
61 	return read_sysreg(cntv_ctl_el0);
62 }
63 
64 static void write_vtimer_ctl(u64 val)
65 {
66 	write_sysreg(val, cntv_ctl_el0);
67 	isb();
68 }
69 
70 static u64 read_ptimer_counter(void)
71 {
72 	isb();
73 	return read_sysreg(cntpct_el0);
74 }
75 
76 static u64 read_ptimer_cval(void)
77 {
78 	return read_sysreg(cntp_cval_el0);
79 }
80 
81 static void write_ptimer_cval(u64 val)
82 {
83 	write_sysreg(val, cntp_cval_el0);
84 	isb();
85 }
86 
87 static s32 read_ptimer_tval(void)
88 {
89 	return read_sysreg(cntp_tval_el0);
90 }
91 
92 static void write_ptimer_tval(s32 val)
93 {
94 	write_sysreg(val, cntp_tval_el0);
95 	isb();
96 }
97 
98 static u64 read_ptimer_ctl(void)
99 {
100 	return read_sysreg(cntp_ctl_el0);
101 }
102 
103 static void write_ptimer_ctl(u64 val)
104 {
105 	write_sysreg(val, cntp_ctl_el0);
106 	isb();
107 }
108 
109 struct timer_info {
110 	u32 irq;
111 	u32 irq_flags;
112 	volatile bool irq_received;
113 	u64 (*read_counter)(void);
114 	u64 (*read_cval)(void);
115 	void (*write_cval)(u64);
116 	s32 (*read_tval)(void);
117 	void (*write_tval)(s32);
118 	u64 (*read_ctl)(void);
119 	void (*write_ctl)(u64);
120 };
121 
122 static struct timer_info vtimer_info = {
123 	.irq_received = false,
124 	.read_counter = read_vtimer_counter,
125 	.read_cval = read_vtimer_cval,
126 	.write_cval = write_vtimer_cval,
127 	.read_tval = read_vtimer_tval,
128 	.write_tval = write_vtimer_tval,
129 	.read_ctl = read_vtimer_ctl,
130 	.write_ctl = write_vtimer_ctl,
131 };
132 
133 static struct timer_info ptimer_info = {
134 	.irq_received = false,
135 	.read_counter = read_ptimer_counter,
136 	.read_cval = read_ptimer_cval,
137 	.write_cval = write_ptimer_cval,
138 	.read_tval = read_ptimer_tval,
139 	.write_tval = write_ptimer_tval,
140 	.read_ctl = read_ptimer_ctl,
141 	.write_ctl = write_ptimer_ctl,
142 };
143 
144 static void set_timer_irq_enabled(struct timer_info *info, bool enabled)
145 {
146 	u32 val = 1 << PPI(info->irq);
147 
148 	if (enabled)
149 		writel(val, gic_isenabler);
150 	else
151 		writel(val, gic_icenabler);
152 }
153 
154 static void irq_handler(struct pt_regs *regs)
155 {
156 	struct timer_info *info;
157 	u32 irqstat = gic_read_iar();
158 	u32 irqnr = gic_iar_irqnr(irqstat);
159 
160 	if (irqnr == PPI(vtimer_info.irq)) {
161 		info = &vtimer_info;
162 	} else if (irqnr == PPI(ptimer_info.irq)) {
163 		info = &ptimer_info;
164 	} else {
165 		if (irqnr != GICC_INT_SPURIOUS)
166 			gic_write_eoir(irqstat);
167 		report_info("Unexpected interrupt: %d\n", irqnr);
168 		return;
169 	}
170 
171 	info->write_ctl(ARCH_TIMER_CTL_IMASK | ARCH_TIMER_CTL_ENABLE);
172 	gic_write_eoir(irqstat);
173 
174 	info->irq_received = true;
175 }
176 
177 /* Check that the timer condition is met. */
178 static bool timer_pending(struct timer_info *info)
179 {
180 	return (info->read_ctl() & ARCH_TIMER_CTL_ENABLE) &&
181 		(info->read_ctl() & ARCH_TIMER_CTL_ISTATUS);
182 }
183 
184 static bool gic_timer_check_state(struct timer_info *info,
185 				  enum gic_irq_state expected_state)
186 {
187 	int i;
188 
189 	/* Wait for up to 1s for the GIC to sample the interrupt. */
190 	for (i = 0; i < 10; i++) {
191 		mdelay(100);
192 		if (gic_irq_state(PPI(info->irq)) == expected_state) {
193 			mdelay(100);
194 			if (gic_irq_state(PPI(info->irq)) == expected_state)
195 				return true;
196 		}
197 	}
198 
199 	return false;
200 }
201 
202 static bool test_cval_10msec(struct timer_info *info)
203 {
204 	u64 time_10ms = read_sysreg(cntfrq_el0) / 100;
205 	u64 time_1us = time_10ms / 10000;
206 	u64 before_timer, after_timer;
207 	s64 difference;
208 
209 	/* Program timer to fire in 10 ms */
210 	before_timer = info->read_counter();
211 	info->write_cval(before_timer + time_10ms);
212 	info->write_ctl(ARCH_TIMER_CTL_ENABLE);
213 
214 	/* Wait for the timer to fire */
215 	while (!timer_pending(info))
216 		;
217 
218 	/* It fired, check how long it took */
219 	after_timer = info->read_counter();
220 	difference = after_timer - (before_timer + time_10ms);
221 
222 	report_info("After timer: 0x%016lx", after_timer);
223 	report_info("Expected   : 0x%016lx", before_timer + time_10ms);
224 	report_info("Difference : %ld us", difference / time_1us);
225 
226 	if (difference < 0) {
227 		printf("ISTATUS set too early\n");
228 		return false;
229 	}
230 	return difference < time_10ms;
231 }
232 
233 static void test_timer(struct timer_info *info)
234 {
235 	u64 now = info->read_counter();
236 	u64 time_10s = read_sysreg(cntfrq_el0) * 10;
237 	u64 later = now + time_10s;
238 	s32 left;
239 
240 	/* We don't want the irq handler to fire because that will change the
241 	 * timer state and we want to test the timer output signal.  We can
242 	 * still read the pending state even if it's disabled. */
243 	set_timer_irq_enabled(info, false);
244 
245 	/* Enable the timer, but schedule it for much later */
246 	info->write_cval(later);
247 	info->write_ctl(ARCH_TIMER_CTL_ENABLE);
248 	report(!timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE),
249 			"not pending before");
250 
251 	info->write_cval(now - 1);
252 	report(timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_PENDING),
253 			"interrupt signal pending");
254 
255 	/* Disable the timer again and prepare to take interrupts */
256 	info->write_ctl(0);
257 	info->irq_received = false;
258 	set_timer_irq_enabled(info, true);
259 	report(!info->irq_received, "no interrupt when timer is disabled");
260 	report(!timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE),
261 			"interrupt signal no longer pending");
262 
263 	info->write_cval(now - 1);
264 	info->write_ctl(ARCH_TIMER_CTL_ENABLE | ARCH_TIMER_CTL_IMASK);
265 	report(timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE),
266 			"interrupt signal not pending");
267 
268 	report(test_cval_10msec(info), "latency within 10 ms");
269 	report(info->irq_received, "interrupt received");
270 
271 	/* Disable the timer again */
272 	info->write_ctl(0);
273 
274 	/* Test TVAL and IRQ trigger */
275 	info->irq_received = false;
276 	info->write_tval(read_sysreg(cntfrq_el0) / 100);	/* 10 ms */
277 	local_irq_disable();
278 	info->write_ctl(ARCH_TIMER_CTL_ENABLE);
279 	report_info("waiting for interrupt...");
280 	wfi();
281 	local_irq_enable();
282 	left = info->read_tval();
283 	report(info->irq_received, "interrupt received after TVAL/WFI");
284 	report(left < 0, "timer has expired");
285 	report_info("TVAL is %d ticks", left);
286 }
287 
288 static void test_vtimer(void)
289 {
290 	report_prefix_push("vtimer-busy-loop");
291 	test_timer(&vtimer_info);
292 	report_prefix_pop();
293 }
294 
295 static void test_ptimer(void)
296 {
297 	if (ptimer_unsupported)
298 		return;
299 
300 	report_prefix_push("ptimer-busy-loop");
301 	test_timer(&ptimer_info);
302 	report_prefix_pop();
303 }
304 
305 static void test_init(void)
306 {
307 	const struct fdt_property *prop;
308 	const void *fdt = dt_fdt();
309 	int node, len;
310 	u32 *data;
311 
312 	node = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer");
313 	assert(node >= 0);
314 	prop = fdt_get_property(fdt, node, "interrupts", &len);
315 	assert(prop && len == (4 * 3 * sizeof(u32)));
316 
317 	data = (u32 *)prop->data;
318 	assert(fdt32_to_cpu(data[3]) == 1);
319 	ptimer_info.irq = fdt32_to_cpu(data[4]);
320 	ptimer_info.irq_flags = fdt32_to_cpu(data[5]);
321 	assert(fdt32_to_cpu(data[6]) == 1);
322 	vtimer_info.irq = fdt32_to_cpu(data[7]);
323 	vtimer_info.irq_flags = fdt32_to_cpu(data[8]);
324 
325 	install_exception_handler(EL1H_SYNC, ESR_EL1_EC_UNKNOWN, ptimer_unsupported_handler);
326 	ptimer_info.read_ctl();
327 	install_exception_handler(EL1H_SYNC, ESR_EL1_EC_UNKNOWN, NULL);
328 
329 	if (ptimer_unsupported && !ERRATA(7b6b46311a85)) {
330 		report_skip("Skipping ptimer tests. Set ERRATA_7b6b46311a85=y to enable.");
331 	} else if (ptimer_unsupported) {
332 		report(false, "ptimer: read CNTP_CTL_EL0");
333 		report_info("ptimer: skipping remaining tests");
334 	}
335 
336 	gic_enable_defaults();
337 
338 	switch (gic_version()) {
339 	case 2:
340 		gic_isenabler = gicv2_dist_base() + GICD_ISENABLER;
341 		gic_icenabler = gicv2_dist_base() + GICD_ICENABLER;
342 		break;
343 	case 3:
344 		gic_isenabler = gicv3_sgi_base() + GICR_ISENABLER0;
345 		gic_icenabler = gicv3_sgi_base() + GICR_ICENABLER0;
346 		break;
347 	}
348 
349 	install_irq_handler(EL1H_IRQ, irq_handler);
350 	local_irq_enable();
351 }
352 
353 static void print_timer_info(void)
354 {
355 	printf("CNTFRQ_EL0   : 0x%016lx\n", read_sysreg(cntfrq_el0));
356 
357 	if (!ptimer_unsupported) {
358 		printf("CNTPCT_EL0   : 0x%016lx\n", ptimer_info.read_counter());
359 		printf("CNTP_CTL_EL0 : 0x%016lx\n", ptimer_info.read_ctl());
360 		printf("CNTP_CVAL_EL0: 0x%016lx\n", ptimer_info.read_cval());
361 	}
362 
363 	printf("CNTVCT_EL0   : 0x%016lx\n", vtimer_info.read_counter());
364 	printf("CNTV_CTL_EL0 : 0x%016lx\n", vtimer_info.read_ctl());
365 	printf("CNTV_CVAL_EL0: 0x%016lx\n", vtimer_info.read_cval());
366 }
367 
368 int main(int argc, char **argv)
369 {
370 	int i;
371 
372 	test_init();
373 
374 	print_timer_info();
375 
376 	if (argc == 1) {
377 		test_vtimer();
378 		test_ptimer();
379 	}
380 
381 	for (i = 1; i < argc; ++i) {
382 		if (strcmp(argv[i], "vtimer") == 0)
383 			test_vtimer();
384 		if (strcmp(argv[i], "ptimer") == 0)
385 			test_ptimer();
386 	}
387 
388 	return report_summary();
389 }
390