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