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