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