xref: /linux/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c (revision 95826e1ed3592cb81262c7e533ddea60751095c9)
154306f56SColton Lewis // SPDX-License-Identifier: GPL-2.0-only
254306f56SColton Lewis /*
354306f56SColton Lewis  * arch_timer_edge_cases.c - Tests the aarch64 timer IRQ functionality.
454306f56SColton Lewis  *
554306f56SColton Lewis  * The test validates some edge cases related to the arch-timer:
654306f56SColton Lewis  * - timers above the max TVAL value.
754306f56SColton Lewis  * - timers in the past
854306f56SColton Lewis  * - moving counters ahead and behind pending timers.
954306f56SColton Lewis  * - reprograming timers.
1054306f56SColton Lewis  * - timers fired multiple times.
1154306f56SColton Lewis  * - masking/unmasking using the timer control mask.
1254306f56SColton Lewis  *
1354306f56SColton Lewis  * Copyright (c) 2021, Google LLC.
1454306f56SColton Lewis  */
1554306f56SColton Lewis 
1654306f56SColton Lewis #define _GNU_SOURCE
1754306f56SColton Lewis 
1854306f56SColton Lewis #include <pthread.h>
1954306f56SColton Lewis #include <sys/sysinfo.h>
2054306f56SColton Lewis 
2154306f56SColton Lewis #include "arch_timer.h"
2254306f56SColton Lewis #include "gic.h"
2354306f56SColton Lewis #include "vgic.h"
2454306f56SColton Lewis 
25fad4cf94SSebastian Ott /* Depends on counter width. */
26fad4cf94SSebastian Ott static uint64_t CVAL_MAX;
2754306f56SColton Lewis /* tval is a signed 32-bit int. */
2854306f56SColton Lewis static const int32_t TVAL_MAX = INT32_MAX;
2954306f56SColton Lewis static const int32_t TVAL_MIN = INT32_MIN;
3054306f56SColton Lewis 
3154306f56SColton Lewis /* After how much time we say there is no IRQ. */
3254306f56SColton Lewis static const uint32_t TIMEOUT_NO_IRQ_US = 50000;
3354306f56SColton Lewis 
34fad4cf94SSebastian Ott /* Counter value to use as the starting one for most tests. Set to CVAL_MAX/2 */
35fad4cf94SSebastian Ott static uint64_t DEF_CNT;
3654306f56SColton Lewis 
3754306f56SColton Lewis /* Number of runs. */
3854306f56SColton Lewis static const uint32_t NR_TEST_ITERS_DEF = 5;
3954306f56SColton Lewis 
4054306f56SColton Lewis /* Default wait test time in ms. */
4154306f56SColton Lewis static const uint32_t WAIT_TEST_MS = 10;
4254306f56SColton Lewis 
4354306f56SColton Lewis /* Default "long" wait test time in ms. */
4454306f56SColton Lewis static const uint32_t LONG_WAIT_TEST_MS = 100;
4554306f56SColton Lewis 
4654306f56SColton Lewis /* Shared with IRQ handler. */
4754306f56SColton Lewis struct test_vcpu_shared_data {
4854306f56SColton Lewis 	atomic_t handled;
4954306f56SColton Lewis 	atomic_t spurious;
5054306f56SColton Lewis } shared_data;
5154306f56SColton Lewis 
5254306f56SColton Lewis struct test_args {
5354306f56SColton Lewis 	/* Virtual or physical timer and counter tests. */
5454306f56SColton Lewis 	enum arch_timer timer;
5554306f56SColton Lewis 	/* Delay used for most timer tests. */
5654306f56SColton Lewis 	uint64_t wait_ms;
5754306f56SColton Lewis 	/* Delay used in the test_long_timer_delays test. */
5854306f56SColton Lewis 	uint64_t long_wait_ms;
5954306f56SColton Lewis 	/* Number of iterations. */
6054306f56SColton Lewis 	int iterations;
6154306f56SColton Lewis 	/* Whether to test the physical timer. */
6254306f56SColton Lewis 	bool test_physical;
6354306f56SColton Lewis 	/* Whether to test the virtual timer. */
6454306f56SColton Lewis 	bool test_virtual;
6554306f56SColton Lewis };
6654306f56SColton Lewis 
6754306f56SColton Lewis struct test_args test_args = {
6854306f56SColton Lewis 	.wait_ms = WAIT_TEST_MS,
6954306f56SColton Lewis 	.long_wait_ms = LONG_WAIT_TEST_MS,
7054306f56SColton Lewis 	.iterations = NR_TEST_ITERS_DEF,
7154306f56SColton Lewis 	.test_physical = true,
7254306f56SColton Lewis 	.test_virtual = true,
7354306f56SColton Lewis };
7454306f56SColton Lewis 
7554306f56SColton Lewis static int vtimer_irq, ptimer_irq;
7654306f56SColton Lewis 
7754306f56SColton Lewis enum sync_cmd {
7854306f56SColton Lewis 	SET_COUNTER_VALUE,
7954306f56SColton Lewis 	USERSPACE_USLEEP,
8054306f56SColton Lewis 	USERSPACE_SCHED_YIELD,
8154306f56SColton Lewis 	USERSPACE_MIGRATE_SELF,
8254306f56SColton Lewis 	NO_USERSPACE_CMD,
8354306f56SColton Lewis };
8454306f56SColton Lewis 
8554306f56SColton Lewis typedef void (*sleep_method_t)(enum arch_timer timer, uint64_t usec);
8654306f56SColton Lewis 
8754306f56SColton Lewis static void sleep_poll(enum arch_timer timer, uint64_t usec);
8854306f56SColton Lewis static void sleep_sched_poll(enum arch_timer timer, uint64_t usec);
8954306f56SColton Lewis static void sleep_in_userspace(enum arch_timer timer, uint64_t usec);
9054306f56SColton Lewis static void sleep_migrate(enum arch_timer timer, uint64_t usec);
9154306f56SColton Lewis 
9254306f56SColton Lewis sleep_method_t sleep_method[] = {
9354306f56SColton Lewis 	sleep_poll,
9454306f56SColton Lewis 	sleep_sched_poll,
9554306f56SColton Lewis 	sleep_migrate,
9654306f56SColton Lewis 	sleep_in_userspace,
9754306f56SColton Lewis };
9854306f56SColton Lewis 
9954306f56SColton Lewis typedef void (*irq_wait_method_t)(void);
10054306f56SColton Lewis 
10154306f56SColton Lewis static void wait_for_non_spurious_irq(void);
10254306f56SColton Lewis static void wait_poll_for_irq(void);
10354306f56SColton Lewis static void wait_sched_poll_for_irq(void);
10454306f56SColton Lewis static void wait_migrate_poll_for_irq(void);
10554306f56SColton Lewis 
10654306f56SColton Lewis irq_wait_method_t irq_wait_method[] = {
10754306f56SColton Lewis 	wait_for_non_spurious_irq,
10854306f56SColton Lewis 	wait_poll_for_irq,
10954306f56SColton Lewis 	wait_sched_poll_for_irq,
11054306f56SColton Lewis 	wait_migrate_poll_for_irq,
11154306f56SColton Lewis };
11254306f56SColton Lewis 
11354306f56SColton Lewis enum timer_view {
11454306f56SColton Lewis 	TIMER_CVAL,
11554306f56SColton Lewis 	TIMER_TVAL,
11654306f56SColton Lewis };
11754306f56SColton Lewis 
assert_irqs_handled(uint32_t n)11854306f56SColton Lewis static void assert_irqs_handled(uint32_t n)
11954306f56SColton Lewis {
12054306f56SColton Lewis 	int h = atomic_read(&shared_data.handled);
12154306f56SColton Lewis 
12254306f56SColton Lewis 	__GUEST_ASSERT(h == n, "Handled %d IRQS but expected %d", h, n);
12354306f56SColton Lewis }
12454306f56SColton Lewis 
userspace_cmd(uint64_t cmd)12554306f56SColton Lewis static void userspace_cmd(uint64_t cmd)
12654306f56SColton Lewis {
12754306f56SColton Lewis 	GUEST_SYNC_ARGS(cmd, 0, 0, 0, 0);
12854306f56SColton Lewis }
12954306f56SColton Lewis 
userspace_migrate_vcpu(void)13054306f56SColton Lewis static void userspace_migrate_vcpu(void)
13154306f56SColton Lewis {
13254306f56SColton Lewis 	userspace_cmd(USERSPACE_MIGRATE_SELF);
13354306f56SColton Lewis }
13454306f56SColton Lewis 
userspace_sleep(uint64_t usecs)13554306f56SColton Lewis static void userspace_sleep(uint64_t usecs)
13654306f56SColton Lewis {
13754306f56SColton Lewis 	GUEST_SYNC_ARGS(USERSPACE_USLEEP, usecs, 0, 0, 0);
13854306f56SColton Lewis }
13954306f56SColton Lewis 
set_counter(enum arch_timer timer,uint64_t counter)14054306f56SColton Lewis static void set_counter(enum arch_timer timer, uint64_t counter)
14154306f56SColton Lewis {
14254306f56SColton Lewis 	GUEST_SYNC_ARGS(SET_COUNTER_VALUE, counter, timer, 0, 0);
14354306f56SColton Lewis }
14454306f56SColton Lewis 
guest_irq_handler(struct ex_regs * regs)14554306f56SColton Lewis static void guest_irq_handler(struct ex_regs *regs)
14654306f56SColton Lewis {
14754306f56SColton Lewis 	unsigned int intid = gic_get_and_ack_irq();
14854306f56SColton Lewis 	enum arch_timer timer;
14954306f56SColton Lewis 	uint64_t cnt, cval;
15054306f56SColton Lewis 	uint32_t ctl;
15154306f56SColton Lewis 	bool timer_condition, istatus;
15254306f56SColton Lewis 
15354306f56SColton Lewis 	if (intid == IAR_SPURIOUS) {
15454306f56SColton Lewis 		atomic_inc(&shared_data.spurious);
15554306f56SColton Lewis 		goto out;
15654306f56SColton Lewis 	}
15754306f56SColton Lewis 
15854306f56SColton Lewis 	if (intid == ptimer_irq)
15954306f56SColton Lewis 		timer = PHYSICAL;
16054306f56SColton Lewis 	else if (intid == vtimer_irq)
16154306f56SColton Lewis 		timer = VIRTUAL;
16254306f56SColton Lewis 	else
16354306f56SColton Lewis 		goto out;
16454306f56SColton Lewis 
16554306f56SColton Lewis 	ctl = timer_get_ctl(timer);
16654306f56SColton Lewis 	cval = timer_get_cval(timer);
16754306f56SColton Lewis 	cnt = timer_get_cntct(timer);
16854306f56SColton Lewis 	timer_condition = cnt >= cval;
16954306f56SColton Lewis 	istatus = (ctl & CTL_ISTATUS) && (ctl & CTL_ENABLE);
17054306f56SColton Lewis 	GUEST_ASSERT_EQ(timer_condition, istatus);
17154306f56SColton Lewis 
17254306f56SColton Lewis 	/* Disable and mask the timer. */
17354306f56SColton Lewis 	timer_set_ctl(timer, CTL_IMASK);
17454306f56SColton Lewis 
17554306f56SColton Lewis 	atomic_inc(&shared_data.handled);
17654306f56SColton Lewis 
17754306f56SColton Lewis out:
17854306f56SColton Lewis 	gic_set_eoi(intid);
17954306f56SColton Lewis }
18054306f56SColton Lewis 
set_cval_irq(enum arch_timer timer,uint64_t cval_cycles,uint32_t ctl)18154306f56SColton Lewis static void set_cval_irq(enum arch_timer timer, uint64_t cval_cycles,
18254306f56SColton Lewis 			 uint32_t ctl)
18354306f56SColton Lewis {
18454306f56SColton Lewis 	atomic_set(&shared_data.handled, 0);
18554306f56SColton Lewis 	atomic_set(&shared_data.spurious, 0);
18654306f56SColton Lewis 	timer_set_cval(timer, cval_cycles);
18754306f56SColton Lewis 	timer_set_ctl(timer, ctl);
18854306f56SColton Lewis }
18954306f56SColton Lewis 
set_tval_irq(enum arch_timer timer,uint64_t tval_cycles,uint32_t ctl)19054306f56SColton Lewis static void set_tval_irq(enum arch_timer timer, uint64_t tval_cycles,
19154306f56SColton Lewis 			 uint32_t ctl)
19254306f56SColton Lewis {
19354306f56SColton Lewis 	atomic_set(&shared_data.handled, 0);
19454306f56SColton Lewis 	atomic_set(&shared_data.spurious, 0);
19554306f56SColton Lewis 	timer_set_tval(timer, tval_cycles);
19605ce38d4SSebastian Ott 	timer_set_ctl(timer, ctl);
19754306f56SColton Lewis }
19854306f56SColton Lewis 
set_xval_irq(enum arch_timer timer,uint64_t xval,uint32_t ctl,enum timer_view tv)19954306f56SColton Lewis static void set_xval_irq(enum arch_timer timer, uint64_t xval, uint32_t ctl,
20054306f56SColton Lewis 			 enum timer_view tv)
20154306f56SColton Lewis {
20254306f56SColton Lewis 	switch (tv) {
20354306f56SColton Lewis 	case TIMER_CVAL:
20454306f56SColton Lewis 		set_cval_irq(timer, xval, ctl);
20554306f56SColton Lewis 		break;
20654306f56SColton Lewis 	case TIMER_TVAL:
20754306f56SColton Lewis 		set_tval_irq(timer, xval, ctl);
20854306f56SColton Lewis 		break;
20954306f56SColton Lewis 	default:
21054306f56SColton Lewis 		GUEST_FAIL("Could not get timer %d", timer);
21154306f56SColton Lewis 	}
21254306f56SColton Lewis }
21354306f56SColton Lewis 
21454306f56SColton Lewis /*
21554306f56SColton Lewis  * Note that this can theoretically hang forever, so we rely on having
21654306f56SColton Lewis  * a timeout mechanism in the "runner", like:
21754306f56SColton Lewis  * tools/testing/selftests/kselftest/runner.sh.
21854306f56SColton Lewis  */
wait_for_non_spurious_irq(void)21954306f56SColton Lewis static void wait_for_non_spurious_irq(void)
22054306f56SColton Lewis {
22154306f56SColton Lewis 	int h;
22254306f56SColton Lewis 
22354306f56SColton Lewis 	local_irq_disable();
22454306f56SColton Lewis 
22554306f56SColton Lewis 	for (h = atomic_read(&shared_data.handled); h == atomic_read(&shared_data.handled);) {
22654306f56SColton Lewis 		wfi();
22754306f56SColton Lewis 		local_irq_enable();
22854306f56SColton Lewis 		isb(); /* handle IRQ */
22954306f56SColton Lewis 		local_irq_disable();
23054306f56SColton Lewis 	}
23154306f56SColton Lewis }
23254306f56SColton Lewis 
23354306f56SColton Lewis /*
23454306f56SColton Lewis  * Wait for an non-spurious IRQ by polling in the guest or in
23554306f56SColton Lewis  * userspace (e.g. userspace_cmd=USERSPACE_SCHED_YIELD).
23654306f56SColton Lewis  *
23754306f56SColton Lewis  * Note that this can theoretically hang forever, so we rely on having
23854306f56SColton Lewis  * a timeout mechanism in the "runner", like:
23954306f56SColton Lewis  * tools/testing/selftests/kselftest/runner.sh.
24054306f56SColton Lewis  */
poll_for_non_spurious_irq(enum sync_cmd usp_cmd)24154306f56SColton Lewis static void poll_for_non_spurious_irq(enum sync_cmd usp_cmd)
24254306f56SColton Lewis {
24354306f56SColton Lewis 	int h;
24454306f56SColton Lewis 
24554306f56SColton Lewis 	local_irq_disable();
24654306f56SColton Lewis 
24754306f56SColton Lewis 	h = atomic_read(&shared_data.handled);
24854306f56SColton Lewis 
24954306f56SColton Lewis 	local_irq_enable();
25054306f56SColton Lewis 	while (h == atomic_read(&shared_data.handled)) {
25154306f56SColton Lewis 		if (usp_cmd == NO_USERSPACE_CMD)
25254306f56SColton Lewis 			cpu_relax();
25354306f56SColton Lewis 		else
25454306f56SColton Lewis 			userspace_cmd(usp_cmd);
25554306f56SColton Lewis 	}
25654306f56SColton Lewis 	local_irq_disable();
25754306f56SColton Lewis }
25854306f56SColton Lewis 
wait_poll_for_irq(void)25954306f56SColton Lewis static void wait_poll_for_irq(void)
26054306f56SColton Lewis {
26154306f56SColton Lewis 	poll_for_non_spurious_irq(NO_USERSPACE_CMD);
26254306f56SColton Lewis }
26354306f56SColton Lewis 
wait_sched_poll_for_irq(void)26454306f56SColton Lewis static void wait_sched_poll_for_irq(void)
26554306f56SColton Lewis {
26654306f56SColton Lewis 	poll_for_non_spurious_irq(USERSPACE_SCHED_YIELD);
26754306f56SColton Lewis }
26854306f56SColton Lewis 
wait_migrate_poll_for_irq(void)26954306f56SColton Lewis static void wait_migrate_poll_for_irq(void)
27054306f56SColton Lewis {
27154306f56SColton Lewis 	poll_for_non_spurious_irq(USERSPACE_MIGRATE_SELF);
27254306f56SColton Lewis }
27354306f56SColton Lewis 
27454306f56SColton Lewis /*
27554306f56SColton Lewis  * Sleep for usec microseconds by polling in the guest or in
27654306f56SColton Lewis  * userspace (e.g. userspace_cmd=USERSPACE_SCHEDULE).
27754306f56SColton Lewis  */
guest_poll(enum arch_timer test_timer,uint64_t usec,enum sync_cmd usp_cmd)27854306f56SColton Lewis static void guest_poll(enum arch_timer test_timer, uint64_t usec,
27954306f56SColton Lewis 		       enum sync_cmd usp_cmd)
28054306f56SColton Lewis {
28154306f56SColton Lewis 	uint64_t cycles = usec_to_cycles(usec);
28254306f56SColton Lewis 	/* Whichever timer we are testing with, sleep with the other. */
28354306f56SColton Lewis 	enum arch_timer sleep_timer = 1 - test_timer;
28454306f56SColton Lewis 	uint64_t start = timer_get_cntct(sleep_timer);
28554306f56SColton Lewis 
28654306f56SColton Lewis 	while ((timer_get_cntct(sleep_timer) - start) < cycles) {
28754306f56SColton Lewis 		if (usp_cmd == NO_USERSPACE_CMD)
28854306f56SColton Lewis 			cpu_relax();
28954306f56SColton Lewis 		else
29054306f56SColton Lewis 			userspace_cmd(usp_cmd);
29154306f56SColton Lewis 	}
29254306f56SColton Lewis }
29354306f56SColton Lewis 
sleep_poll(enum arch_timer timer,uint64_t usec)29454306f56SColton Lewis static void sleep_poll(enum arch_timer timer, uint64_t usec)
29554306f56SColton Lewis {
29654306f56SColton Lewis 	guest_poll(timer, usec, NO_USERSPACE_CMD);
29754306f56SColton Lewis }
29854306f56SColton Lewis 
sleep_sched_poll(enum arch_timer timer,uint64_t usec)29954306f56SColton Lewis static void sleep_sched_poll(enum arch_timer timer, uint64_t usec)
30054306f56SColton Lewis {
30154306f56SColton Lewis 	guest_poll(timer, usec, USERSPACE_SCHED_YIELD);
30254306f56SColton Lewis }
30354306f56SColton Lewis 
sleep_migrate(enum arch_timer timer,uint64_t usec)30454306f56SColton Lewis static void sleep_migrate(enum arch_timer timer, uint64_t usec)
30554306f56SColton Lewis {
30654306f56SColton Lewis 	guest_poll(timer, usec, USERSPACE_MIGRATE_SELF);
30754306f56SColton Lewis }
30854306f56SColton Lewis 
sleep_in_userspace(enum arch_timer timer,uint64_t usec)30954306f56SColton Lewis static void sleep_in_userspace(enum arch_timer timer, uint64_t usec)
31054306f56SColton Lewis {
31154306f56SColton Lewis 	userspace_sleep(usec);
31254306f56SColton Lewis }
31354306f56SColton Lewis 
31454306f56SColton Lewis /*
31554306f56SColton Lewis  * Reset the timer state to some nice values like the counter not being close
31654306f56SColton Lewis  * to the edge, and the control register masked and disabled.
31754306f56SColton Lewis  */
reset_timer_state(enum arch_timer timer,uint64_t cnt)31854306f56SColton Lewis static void reset_timer_state(enum arch_timer timer, uint64_t cnt)
31954306f56SColton Lewis {
32054306f56SColton Lewis 	set_counter(timer, cnt);
32154306f56SColton Lewis 	timer_set_ctl(timer, CTL_IMASK);
32254306f56SColton Lewis }
32354306f56SColton Lewis 
test_timer_xval(enum arch_timer timer,uint64_t xval,enum timer_view tv,irq_wait_method_t wm,bool reset_state,uint64_t reset_cnt)32454306f56SColton Lewis static void test_timer_xval(enum arch_timer timer, uint64_t xval,
32554306f56SColton Lewis 			    enum timer_view tv, irq_wait_method_t wm, bool reset_state,
32654306f56SColton Lewis 			    uint64_t reset_cnt)
32754306f56SColton Lewis {
32854306f56SColton Lewis 	local_irq_disable();
32954306f56SColton Lewis 
33054306f56SColton Lewis 	if (reset_state)
33154306f56SColton Lewis 		reset_timer_state(timer, reset_cnt);
33254306f56SColton Lewis 
33354306f56SColton Lewis 	set_xval_irq(timer, xval, CTL_ENABLE, tv);
33454306f56SColton Lewis 
33554306f56SColton Lewis 	/* This method re-enables IRQs to handle the one we're looking for. */
33654306f56SColton Lewis 	wm();
33754306f56SColton Lewis 
33854306f56SColton Lewis 	assert_irqs_handled(1);
33954306f56SColton Lewis 	local_irq_enable();
34054306f56SColton Lewis }
34154306f56SColton Lewis 
34254306f56SColton Lewis /*
34354306f56SColton Lewis  * The test_timer_* functions will program the timer, wait for it, and assert
34454306f56SColton Lewis  * the firing of the correct IRQ.
34554306f56SColton Lewis  *
34654306f56SColton Lewis  * These functions don't have a timeout and return as soon as they receive an
34754306f56SColton Lewis  * IRQ. They can hang (forever), so we rely on having a timeout mechanism in
34854306f56SColton Lewis  * the "runner", like: tools/testing/selftests/kselftest/runner.sh.
34954306f56SColton Lewis  */
35054306f56SColton Lewis 
test_timer_cval(enum arch_timer timer,uint64_t cval,irq_wait_method_t wm,bool reset_state,uint64_t reset_cnt)35154306f56SColton Lewis static void test_timer_cval(enum arch_timer timer, uint64_t cval,
35254306f56SColton Lewis 			    irq_wait_method_t wm, bool reset_state,
35354306f56SColton Lewis 			    uint64_t reset_cnt)
35454306f56SColton Lewis {
35554306f56SColton Lewis 	test_timer_xval(timer, cval, TIMER_CVAL, wm, reset_state, reset_cnt);
35654306f56SColton Lewis }
35754306f56SColton Lewis 
test_timer_tval(enum arch_timer timer,int32_t tval,irq_wait_method_t wm,bool reset_state,uint64_t reset_cnt)35854306f56SColton Lewis static void test_timer_tval(enum arch_timer timer, int32_t tval,
35954306f56SColton Lewis 			    irq_wait_method_t wm, bool reset_state,
36054306f56SColton Lewis 			    uint64_t reset_cnt)
36154306f56SColton Lewis {
36254306f56SColton Lewis 	test_timer_xval(timer, (uint64_t) tval, TIMER_TVAL, wm, reset_state,
36354306f56SColton Lewis 			reset_cnt);
36454306f56SColton Lewis }
36554306f56SColton Lewis 
test_xval_check_no_irq(enum arch_timer timer,uint64_t xval,uint64_t usec,enum timer_view timer_view,sleep_method_t guest_sleep)36654306f56SColton Lewis static void test_xval_check_no_irq(enum arch_timer timer, uint64_t xval,
36754306f56SColton Lewis 				   uint64_t usec, enum timer_view timer_view,
36854306f56SColton Lewis 				   sleep_method_t guest_sleep)
36954306f56SColton Lewis {
37054306f56SColton Lewis 	local_irq_disable();
37154306f56SColton Lewis 
37254306f56SColton Lewis 	set_xval_irq(timer, xval, CTL_ENABLE | CTL_IMASK, timer_view);
37354306f56SColton Lewis 	guest_sleep(timer, usec);
37454306f56SColton Lewis 
37554306f56SColton Lewis 	local_irq_enable();
37654306f56SColton Lewis 	isb();
37754306f56SColton Lewis 
37854306f56SColton Lewis 	/* Assume success (no IRQ) after waiting usec microseconds */
37954306f56SColton Lewis 	assert_irqs_handled(0);
38054306f56SColton Lewis }
38154306f56SColton Lewis 
test_cval_no_irq(enum arch_timer timer,uint64_t cval,uint64_t usec,sleep_method_t wm)38254306f56SColton Lewis static void test_cval_no_irq(enum arch_timer timer, uint64_t cval,
38354306f56SColton Lewis 			     uint64_t usec, sleep_method_t wm)
38454306f56SColton Lewis {
38554306f56SColton Lewis 	test_xval_check_no_irq(timer, cval, usec, TIMER_CVAL, wm);
38654306f56SColton Lewis }
38754306f56SColton Lewis 
test_tval_no_irq(enum arch_timer timer,int32_t tval,uint64_t usec,sleep_method_t wm)38854306f56SColton Lewis static void test_tval_no_irq(enum arch_timer timer, int32_t tval, uint64_t usec,
38954306f56SColton Lewis 			     sleep_method_t wm)
39054306f56SColton Lewis {
39154306f56SColton Lewis 	/* tval will be cast to an int32_t in test_xval_check_no_irq */
39254306f56SColton Lewis 	test_xval_check_no_irq(timer, (uint64_t) tval, usec, TIMER_TVAL, wm);
39354306f56SColton Lewis }
39454306f56SColton Lewis 
39554306f56SColton Lewis /* Test masking/unmasking a timer using the timer mask (not the IRQ mask). */
test_timer_control_mask_then_unmask(enum arch_timer timer)39654306f56SColton Lewis static void test_timer_control_mask_then_unmask(enum arch_timer timer)
39754306f56SColton Lewis {
39854306f56SColton Lewis 	reset_timer_state(timer, DEF_CNT);
39954306f56SColton Lewis 	set_tval_irq(timer, -1, CTL_ENABLE | CTL_IMASK);
40054306f56SColton Lewis 
40154306f56SColton Lewis 	/* Unmask the timer, and then get an IRQ. */
40254306f56SColton Lewis 	local_irq_disable();
40354306f56SColton Lewis 	timer_set_ctl(timer, CTL_ENABLE);
40454306f56SColton Lewis 	/* This method re-enables IRQs to handle the one we're looking for. */
40554306f56SColton Lewis 	wait_for_non_spurious_irq();
40654306f56SColton Lewis 
40754306f56SColton Lewis 	assert_irqs_handled(1);
40854306f56SColton Lewis 	local_irq_enable();
40954306f56SColton Lewis }
41054306f56SColton Lewis 
41154306f56SColton Lewis /* Check that timer control masks actually mask a timer being fired. */
test_timer_control_masks(enum arch_timer timer)41254306f56SColton Lewis static void test_timer_control_masks(enum arch_timer timer)
41354306f56SColton Lewis {
41454306f56SColton Lewis 	reset_timer_state(timer, DEF_CNT);
41554306f56SColton Lewis 
41654306f56SColton Lewis 	/* Local IRQs are not masked at this point. */
41754306f56SColton Lewis 
41854306f56SColton Lewis 	set_tval_irq(timer, -1, CTL_ENABLE | CTL_IMASK);
41954306f56SColton Lewis 
42054306f56SColton Lewis 	/* Assume no IRQ after waiting TIMEOUT_NO_IRQ_US microseconds */
42154306f56SColton Lewis 	sleep_poll(timer, TIMEOUT_NO_IRQ_US);
42254306f56SColton Lewis 
42354306f56SColton Lewis 	assert_irqs_handled(0);
42454306f56SColton Lewis 	timer_set_ctl(timer, CTL_IMASK);
42554306f56SColton Lewis }
42654306f56SColton Lewis 
test_fire_a_timer_multiple_times(enum arch_timer timer,irq_wait_method_t wm,int num)42754306f56SColton Lewis static void test_fire_a_timer_multiple_times(enum arch_timer timer,
42854306f56SColton Lewis 					     irq_wait_method_t wm, int num)
42954306f56SColton Lewis {
43054306f56SColton Lewis 	int i;
43154306f56SColton Lewis 
43254306f56SColton Lewis 	local_irq_disable();
43354306f56SColton Lewis 	reset_timer_state(timer, DEF_CNT);
43454306f56SColton Lewis 
43554306f56SColton Lewis 	set_tval_irq(timer, 0, CTL_ENABLE);
43654306f56SColton Lewis 
43754306f56SColton Lewis 	for (i = 1; i <= num; i++) {
43854306f56SColton Lewis 		/* This method re-enables IRQs to handle the one we're looking for. */
43954306f56SColton Lewis 		wm();
44054306f56SColton Lewis 
44154306f56SColton Lewis 		/* The IRQ handler masked and disabled the timer.
44254306f56SColton Lewis 		 * Enable and unmmask it again.
44354306f56SColton Lewis 		 */
44454306f56SColton Lewis 		timer_set_ctl(timer, CTL_ENABLE);
44554306f56SColton Lewis 
44654306f56SColton Lewis 		assert_irqs_handled(i);
44754306f56SColton Lewis 	}
44854306f56SColton Lewis 
44954306f56SColton Lewis 	local_irq_enable();
45054306f56SColton Lewis }
45154306f56SColton Lewis 
test_timers_fired_multiple_times(enum arch_timer timer)45254306f56SColton Lewis static void test_timers_fired_multiple_times(enum arch_timer timer)
45354306f56SColton Lewis {
45454306f56SColton Lewis 	int i;
45554306f56SColton Lewis 
45654306f56SColton Lewis 	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++)
45754306f56SColton Lewis 		test_fire_a_timer_multiple_times(timer, irq_wait_method[i], 10);
45854306f56SColton Lewis }
45954306f56SColton Lewis 
46054306f56SColton Lewis /*
46154306f56SColton Lewis  * Set a timer for tval=delta_1_ms then reprogram it to
46254306f56SColton Lewis  * tval=delta_2_ms. Check that we get the timer fired. There is no
46354306f56SColton Lewis  * timeout for the wait: we use the wfi instruction.
46454306f56SColton Lewis  */
test_reprogramming_timer(enum arch_timer timer,irq_wait_method_t wm,int32_t delta_1_ms,int32_t delta_2_ms)46554306f56SColton Lewis static void test_reprogramming_timer(enum arch_timer timer, irq_wait_method_t wm,
46654306f56SColton Lewis 				     int32_t delta_1_ms, int32_t delta_2_ms)
46754306f56SColton Lewis {
46854306f56SColton Lewis 	local_irq_disable();
46954306f56SColton Lewis 	reset_timer_state(timer, DEF_CNT);
47054306f56SColton Lewis 
47154306f56SColton Lewis 	/* Program the timer to DEF_CNT + delta_1_ms. */
47254306f56SColton Lewis 	set_tval_irq(timer, msec_to_cycles(delta_1_ms), CTL_ENABLE);
47354306f56SColton Lewis 
47454306f56SColton Lewis 	/* Reprogram the timer to DEF_CNT + delta_2_ms. */
47554306f56SColton Lewis 	timer_set_tval(timer, msec_to_cycles(delta_2_ms));
47654306f56SColton Lewis 
47754306f56SColton Lewis 	/* This method re-enables IRQs to handle the one we're looking for. */
47854306f56SColton Lewis 	wm();
47954306f56SColton Lewis 
48054306f56SColton Lewis 	/* The IRQ should arrive at DEF_CNT + delta_2_ms (or after). */
48154306f56SColton Lewis 	GUEST_ASSERT(timer_get_cntct(timer) >=
48254306f56SColton Lewis 		     DEF_CNT + msec_to_cycles(delta_2_ms));
48354306f56SColton Lewis 
48454306f56SColton Lewis 	local_irq_enable();
48554306f56SColton Lewis 	assert_irqs_handled(1);
48654306f56SColton Lewis };
48754306f56SColton Lewis 
test_reprogram_timers(enum arch_timer timer)48854306f56SColton Lewis static void test_reprogram_timers(enum arch_timer timer)
48954306f56SColton Lewis {
49054306f56SColton Lewis 	int i;
49154306f56SColton Lewis 	uint64_t base_wait = test_args.wait_ms;
49254306f56SColton Lewis 
49354306f56SColton Lewis 	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {
49454306f56SColton Lewis 		/*
49554306f56SColton Lewis 		 * Ensure reprogramming works whether going from a
49654306f56SColton Lewis 		 * longer time to a shorter or vice versa.
49754306f56SColton Lewis 		 */
49854306f56SColton Lewis 		test_reprogramming_timer(timer, irq_wait_method[i], 2 * base_wait,
49954306f56SColton Lewis 					 base_wait);
50054306f56SColton Lewis 		test_reprogramming_timer(timer, irq_wait_method[i], base_wait,
50154306f56SColton Lewis 					 2 * base_wait);
50254306f56SColton Lewis 	}
50354306f56SColton Lewis }
50454306f56SColton Lewis 
test_basic_functionality(enum arch_timer timer)50554306f56SColton Lewis static void test_basic_functionality(enum arch_timer timer)
50654306f56SColton Lewis {
50754306f56SColton Lewis 	int32_t tval = (int32_t) msec_to_cycles(test_args.wait_ms);
50854306f56SColton Lewis 	uint64_t cval = DEF_CNT + msec_to_cycles(test_args.wait_ms);
50954306f56SColton Lewis 	int i;
51054306f56SColton Lewis 
51154306f56SColton Lewis 	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {
51254306f56SColton Lewis 		irq_wait_method_t wm = irq_wait_method[i];
51354306f56SColton Lewis 
51454306f56SColton Lewis 		test_timer_cval(timer, cval, wm, true, DEF_CNT);
51554306f56SColton Lewis 		test_timer_tval(timer, tval, wm, true, DEF_CNT);
51654306f56SColton Lewis 	}
51754306f56SColton Lewis }
51854306f56SColton Lewis 
51954306f56SColton Lewis /*
52054306f56SColton Lewis  * This test checks basic timer behavior without actually firing timers, things
52154306f56SColton Lewis  * like: the relationship between cval and tval, tval down-counting.
52254306f56SColton Lewis  */
timers_sanity_checks(enum arch_timer timer,bool use_sched)52354306f56SColton Lewis static void timers_sanity_checks(enum arch_timer timer, bool use_sched)
52454306f56SColton Lewis {
52554306f56SColton Lewis 	reset_timer_state(timer, DEF_CNT);
52654306f56SColton Lewis 
52754306f56SColton Lewis 	local_irq_disable();
52854306f56SColton Lewis 
52954306f56SColton Lewis 	/* cval in the past */
53054306f56SColton Lewis 	timer_set_cval(timer,
53154306f56SColton Lewis 		       timer_get_cntct(timer) -
53254306f56SColton Lewis 		       msec_to_cycles(test_args.wait_ms));
53354306f56SColton Lewis 	if (use_sched)
53454306f56SColton Lewis 		userspace_migrate_vcpu();
53554306f56SColton Lewis 	GUEST_ASSERT(timer_get_tval(timer) < 0);
53654306f56SColton Lewis 
53754306f56SColton Lewis 	/* tval in the past */
53854306f56SColton Lewis 	timer_set_tval(timer, -1);
53954306f56SColton Lewis 	if (use_sched)
54054306f56SColton Lewis 		userspace_migrate_vcpu();
54154306f56SColton Lewis 	GUEST_ASSERT(timer_get_cval(timer) < timer_get_cntct(timer));
54254306f56SColton Lewis 
54354306f56SColton Lewis 	/* tval larger than TVAL_MAX. This requires programming with
54454306f56SColton Lewis 	 * timer_set_cval instead so the value is expressible
54554306f56SColton Lewis 	 */
54654306f56SColton Lewis 	timer_set_cval(timer,
54754306f56SColton Lewis 		       timer_get_cntct(timer) + TVAL_MAX +
54854306f56SColton Lewis 		       msec_to_cycles(test_args.wait_ms));
54954306f56SColton Lewis 	if (use_sched)
55054306f56SColton Lewis 		userspace_migrate_vcpu();
55154306f56SColton Lewis 	GUEST_ASSERT(timer_get_tval(timer) <= 0);
55254306f56SColton Lewis 
55354306f56SColton Lewis 	/*
55454306f56SColton Lewis 	 * tval larger than 2 * TVAL_MAX.
55554306f56SColton Lewis 	 * Twice the TVAL_MAX completely loops around the TVAL.
55654306f56SColton Lewis 	 */
55754306f56SColton Lewis 	timer_set_cval(timer,
55854306f56SColton Lewis 		       timer_get_cntct(timer) + 2ULL * TVAL_MAX +
55954306f56SColton Lewis 		       msec_to_cycles(test_args.wait_ms));
56054306f56SColton Lewis 	if (use_sched)
56154306f56SColton Lewis 		userspace_migrate_vcpu();
56254306f56SColton Lewis 	GUEST_ASSERT(timer_get_tval(timer) <=
56354306f56SColton Lewis 		       msec_to_cycles(test_args.wait_ms));
56454306f56SColton Lewis 
56554306f56SColton Lewis 	/* negative tval that rollovers from 0. */
56654306f56SColton Lewis 	set_counter(timer, msec_to_cycles(1));
56754306f56SColton Lewis 	timer_set_tval(timer, -1 * msec_to_cycles(test_args.wait_ms));
56854306f56SColton Lewis 	if (use_sched)
56954306f56SColton Lewis 		userspace_migrate_vcpu();
57054306f56SColton Lewis 	GUEST_ASSERT(timer_get_cval(timer) >= (CVAL_MAX - msec_to_cycles(test_args.wait_ms)));
57154306f56SColton Lewis 
57254306f56SColton Lewis 	/* tval should keep down-counting from 0 to -1. */
57354306f56SColton Lewis 	timer_set_tval(timer, 0);
57454306f56SColton Lewis 	sleep_poll(timer, 1);
57554306f56SColton Lewis 	GUEST_ASSERT(timer_get_tval(timer) < 0);
57654306f56SColton Lewis 
57754306f56SColton Lewis 	local_irq_enable();
57854306f56SColton Lewis 
57954306f56SColton Lewis 	/* Mask and disable any pending timer. */
58054306f56SColton Lewis 	timer_set_ctl(timer, CTL_IMASK);
58154306f56SColton Lewis }
58254306f56SColton Lewis 
test_timers_sanity_checks(enum arch_timer timer)58354306f56SColton Lewis static void test_timers_sanity_checks(enum arch_timer timer)
58454306f56SColton Lewis {
58554306f56SColton Lewis 	timers_sanity_checks(timer, false);
58654306f56SColton Lewis 	/* Check how KVM saves/restores these edge-case values. */
58754306f56SColton Lewis 	timers_sanity_checks(timer, true);
58854306f56SColton Lewis }
58954306f56SColton Lewis 
test_set_cnt_after_tval_max(enum arch_timer timer,irq_wait_method_t wm)59054306f56SColton Lewis static void test_set_cnt_after_tval_max(enum arch_timer timer, irq_wait_method_t wm)
59154306f56SColton Lewis {
59254306f56SColton Lewis 	local_irq_disable();
59354306f56SColton Lewis 	reset_timer_state(timer, DEF_CNT);
59454306f56SColton Lewis 
59554306f56SColton Lewis 	set_cval_irq(timer,
59654306f56SColton Lewis 		     (uint64_t) TVAL_MAX +
59754306f56SColton Lewis 		     msec_to_cycles(test_args.wait_ms) / 2, CTL_ENABLE);
59854306f56SColton Lewis 
59954306f56SColton Lewis 	set_counter(timer, TVAL_MAX);
60054306f56SColton Lewis 
60154306f56SColton Lewis 	/* This method re-enables IRQs to handle the one we're looking for. */
60254306f56SColton Lewis 	wm();
60354306f56SColton Lewis 
60454306f56SColton Lewis 	assert_irqs_handled(1);
60554306f56SColton Lewis 	local_irq_enable();
60654306f56SColton Lewis }
60754306f56SColton Lewis 
60854306f56SColton Lewis /* Test timers set for: cval = now + TVAL_MAX + wait_ms / 2 */
test_timers_above_tval_max(enum arch_timer timer)60954306f56SColton Lewis static void test_timers_above_tval_max(enum arch_timer timer)
61054306f56SColton Lewis {
61154306f56SColton Lewis 	uint64_t cval;
61254306f56SColton Lewis 	int i;
61354306f56SColton Lewis 
61454306f56SColton Lewis 	/*
61554306f56SColton Lewis 	 * Test that the system is not implementing cval in terms of
61654306f56SColton Lewis 	 * tval.  If that was the case, setting a cval to "cval = now
61754306f56SColton Lewis 	 * + TVAL_MAX + wait_ms" would wrap to "cval = now +
61854306f56SColton Lewis 	 * wait_ms", and the timer would fire immediately. Test that it
61954306f56SColton Lewis 	 * doesn't.
62054306f56SColton Lewis 	 */
62154306f56SColton Lewis 	for (i = 0; i < ARRAY_SIZE(sleep_method); i++) {
62254306f56SColton Lewis 		reset_timer_state(timer, DEF_CNT);
62354306f56SColton Lewis 		cval = timer_get_cntct(timer) + TVAL_MAX +
62454306f56SColton Lewis 			msec_to_cycles(test_args.wait_ms);
62554306f56SColton Lewis 		test_cval_no_irq(timer, cval,
62654306f56SColton Lewis 				 msecs_to_usecs(test_args.wait_ms) +
62754306f56SColton Lewis 				 TIMEOUT_NO_IRQ_US, sleep_method[i]);
62854306f56SColton Lewis 	}
62954306f56SColton Lewis 
63054306f56SColton Lewis 	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {
63154306f56SColton Lewis 		/* Get the IRQ by moving the counter forward. */
63254306f56SColton Lewis 		test_set_cnt_after_tval_max(timer, irq_wait_method[i]);
63354306f56SColton Lewis 	}
63454306f56SColton Lewis }
63554306f56SColton Lewis 
63654306f56SColton Lewis /*
63754306f56SColton Lewis  * Template function to be used by the test_move_counter_ahead_* tests.  It
63854306f56SColton Lewis  * sets the counter to cnt_1, the [c|t]val, the counter to cnt_2, and
63954306f56SColton Lewis  * then waits for an IRQ.
64054306f56SColton Lewis  */
test_set_cnt_after_xval(enum arch_timer timer,uint64_t cnt_1,uint64_t xval,uint64_t cnt_2,irq_wait_method_t wm,enum timer_view tv)64154306f56SColton Lewis static void test_set_cnt_after_xval(enum arch_timer timer, uint64_t cnt_1,
64254306f56SColton Lewis 				    uint64_t xval, uint64_t cnt_2,
64354306f56SColton Lewis 				    irq_wait_method_t wm, enum timer_view tv)
64454306f56SColton Lewis {
64554306f56SColton Lewis 	local_irq_disable();
64654306f56SColton Lewis 
64754306f56SColton Lewis 	set_counter(timer, cnt_1);
64854306f56SColton Lewis 	timer_set_ctl(timer, CTL_IMASK);
64954306f56SColton Lewis 
65054306f56SColton Lewis 	set_xval_irq(timer, xval, CTL_ENABLE, tv);
65154306f56SColton Lewis 	set_counter(timer, cnt_2);
65254306f56SColton Lewis 	/* This method re-enables IRQs to handle the one we're looking for. */
65354306f56SColton Lewis 	wm();
65454306f56SColton Lewis 
65554306f56SColton Lewis 	assert_irqs_handled(1);
65654306f56SColton Lewis 	local_irq_enable();
65754306f56SColton Lewis }
65854306f56SColton Lewis 
65954306f56SColton Lewis /*
66054306f56SColton Lewis  * Template function to be used by the test_move_counter_ahead_* tests.  It
66154306f56SColton Lewis  * sets the counter to cnt_1, the [c|t]val, the counter to cnt_2, and
66254306f56SColton Lewis  * then waits for an IRQ.
66354306f56SColton Lewis  */
test_set_cnt_after_xval_no_irq(enum arch_timer timer,uint64_t cnt_1,uint64_t xval,uint64_t cnt_2,sleep_method_t guest_sleep,enum timer_view tv)66454306f56SColton Lewis static void test_set_cnt_after_xval_no_irq(enum arch_timer timer,
66554306f56SColton Lewis 					   uint64_t cnt_1, uint64_t xval,
66654306f56SColton Lewis 					   uint64_t cnt_2,
66754306f56SColton Lewis 					   sleep_method_t guest_sleep,
66854306f56SColton Lewis 					   enum timer_view tv)
66954306f56SColton Lewis {
67054306f56SColton Lewis 	local_irq_disable();
67154306f56SColton Lewis 
67254306f56SColton Lewis 	set_counter(timer, cnt_1);
67354306f56SColton Lewis 	timer_set_ctl(timer, CTL_IMASK);
67454306f56SColton Lewis 
67554306f56SColton Lewis 	set_xval_irq(timer, xval, CTL_ENABLE, tv);
67654306f56SColton Lewis 	set_counter(timer, cnt_2);
67754306f56SColton Lewis 	guest_sleep(timer, TIMEOUT_NO_IRQ_US);
67854306f56SColton Lewis 
67954306f56SColton Lewis 	local_irq_enable();
68054306f56SColton Lewis 	isb();
68154306f56SColton Lewis 
68254306f56SColton Lewis 	/* Assume no IRQ after waiting TIMEOUT_NO_IRQ_US microseconds */
68354306f56SColton Lewis 	assert_irqs_handled(0);
68454306f56SColton Lewis 	timer_set_ctl(timer, CTL_IMASK);
68554306f56SColton Lewis }
68654306f56SColton Lewis 
test_set_cnt_after_tval(enum arch_timer timer,uint64_t cnt_1,int32_t tval,uint64_t cnt_2,irq_wait_method_t wm)68754306f56SColton Lewis static void test_set_cnt_after_tval(enum arch_timer timer, uint64_t cnt_1,
68854306f56SColton Lewis 				    int32_t tval, uint64_t cnt_2,
68954306f56SColton Lewis 				    irq_wait_method_t wm)
69054306f56SColton Lewis {
69154306f56SColton Lewis 	test_set_cnt_after_xval(timer, cnt_1, tval, cnt_2, wm, TIMER_TVAL);
69254306f56SColton Lewis }
69354306f56SColton Lewis 
test_set_cnt_after_cval(enum arch_timer timer,uint64_t cnt_1,uint64_t cval,uint64_t cnt_2,irq_wait_method_t wm)69454306f56SColton Lewis static void test_set_cnt_after_cval(enum arch_timer timer, uint64_t cnt_1,
69554306f56SColton Lewis 				    uint64_t cval, uint64_t cnt_2,
69654306f56SColton Lewis 				    irq_wait_method_t wm)
69754306f56SColton Lewis {
69854306f56SColton Lewis 	test_set_cnt_after_xval(timer, cnt_1, cval, cnt_2, wm, TIMER_CVAL);
69954306f56SColton Lewis }
70054306f56SColton Lewis 
test_set_cnt_after_tval_no_irq(enum arch_timer timer,uint64_t cnt_1,int32_t tval,uint64_t cnt_2,sleep_method_t wm)70154306f56SColton Lewis static void test_set_cnt_after_tval_no_irq(enum arch_timer timer,
70254306f56SColton Lewis 					   uint64_t cnt_1, int32_t tval,
70354306f56SColton Lewis 					   uint64_t cnt_2, sleep_method_t wm)
70454306f56SColton Lewis {
70554306f56SColton Lewis 	test_set_cnt_after_xval_no_irq(timer, cnt_1, tval, cnt_2, wm,
70654306f56SColton Lewis 				       TIMER_TVAL);
70754306f56SColton Lewis }
70854306f56SColton Lewis 
test_set_cnt_after_cval_no_irq(enum arch_timer timer,uint64_t cnt_1,uint64_t cval,uint64_t cnt_2,sleep_method_t wm)70954306f56SColton Lewis static void test_set_cnt_after_cval_no_irq(enum arch_timer timer,
71054306f56SColton Lewis 					   uint64_t cnt_1, uint64_t cval,
71154306f56SColton Lewis 					   uint64_t cnt_2, sleep_method_t wm)
71254306f56SColton Lewis {
71354306f56SColton Lewis 	test_set_cnt_after_xval_no_irq(timer, cnt_1, cval, cnt_2, wm,
71454306f56SColton Lewis 				       TIMER_CVAL);
71554306f56SColton Lewis }
71654306f56SColton Lewis 
71754306f56SColton Lewis /* Set a timer and then move the counter ahead of it. */
test_move_counters_ahead_of_timers(enum arch_timer timer)71854306f56SColton Lewis static void test_move_counters_ahead_of_timers(enum arch_timer timer)
71954306f56SColton Lewis {
72054306f56SColton Lewis 	int i;
72154306f56SColton Lewis 	int32_t tval;
72254306f56SColton Lewis 
72354306f56SColton Lewis 	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {
72454306f56SColton Lewis 		irq_wait_method_t wm = irq_wait_method[i];
72554306f56SColton Lewis 
72654306f56SColton Lewis 		test_set_cnt_after_cval(timer, 0, DEF_CNT, DEF_CNT + 1, wm);
72754306f56SColton Lewis 		test_set_cnt_after_cval(timer, CVAL_MAX, 1, 2, wm);
72854306f56SColton Lewis 
72954306f56SColton Lewis 		/* Move counter ahead of negative tval. */
73054306f56SColton Lewis 		test_set_cnt_after_tval(timer, 0, -1, DEF_CNT + 1, wm);
73154306f56SColton Lewis 		test_set_cnt_after_tval(timer, 0, -1, TVAL_MAX, wm);
73254306f56SColton Lewis 		tval = TVAL_MAX;
73354306f56SColton Lewis 		test_set_cnt_after_tval(timer, 0, tval, (uint64_t) tval + 1,
73454306f56SColton Lewis 					wm);
73554306f56SColton Lewis 	}
73654306f56SColton Lewis }
73754306f56SColton Lewis 
73854306f56SColton Lewis /*
73954306f56SColton Lewis  * Program a timer, mask it, and then change the tval or counter to cancel it.
74054306f56SColton Lewis  * Unmask it and check that nothing fires.
74154306f56SColton Lewis  */
test_move_counters_behind_timers(enum arch_timer timer)74254306f56SColton Lewis static void test_move_counters_behind_timers(enum arch_timer timer)
74354306f56SColton Lewis {
74454306f56SColton Lewis 	int i;
74554306f56SColton Lewis 
74654306f56SColton Lewis 	for (i = 0; i < ARRAY_SIZE(sleep_method); i++) {
74754306f56SColton Lewis 		sleep_method_t sm = sleep_method[i];
74854306f56SColton Lewis 
74954306f56SColton Lewis 		test_set_cnt_after_cval_no_irq(timer, DEF_CNT, DEF_CNT - 1, 0,
75054306f56SColton Lewis 					       sm);
75154306f56SColton Lewis 		test_set_cnt_after_tval_no_irq(timer, DEF_CNT, -1, 0, sm);
75254306f56SColton Lewis 	}
75354306f56SColton Lewis }
75454306f56SColton Lewis 
test_timers_in_the_past(enum arch_timer timer)75554306f56SColton Lewis static void test_timers_in_the_past(enum arch_timer timer)
75654306f56SColton Lewis {
75754306f56SColton Lewis 	int32_t tval = -1 * (int32_t) msec_to_cycles(test_args.wait_ms);
75854306f56SColton Lewis 	uint64_t cval;
75954306f56SColton Lewis 	int i;
76054306f56SColton Lewis 
76154306f56SColton Lewis 	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {
76254306f56SColton Lewis 		irq_wait_method_t wm = irq_wait_method[i];
76354306f56SColton Lewis 
76454306f56SColton Lewis 		/* set a timer wait_ms the past. */
76554306f56SColton Lewis 		cval = DEF_CNT - msec_to_cycles(test_args.wait_ms);
76654306f56SColton Lewis 		test_timer_cval(timer, cval, wm, true, DEF_CNT);
76754306f56SColton Lewis 		test_timer_tval(timer, tval, wm, true, DEF_CNT);
76854306f56SColton Lewis 
76954306f56SColton Lewis 		/* Set a timer to counter=0 (in the past) */
77054306f56SColton Lewis 		test_timer_cval(timer, 0, wm, true, DEF_CNT);
77154306f56SColton Lewis 
77254306f56SColton Lewis 		/* Set a time for tval=0 (now) */
77354306f56SColton Lewis 		test_timer_tval(timer, 0, wm, true, DEF_CNT);
77454306f56SColton Lewis 
77554306f56SColton Lewis 		/* Set a timer to as far in the past as possible */
77654306f56SColton Lewis 		test_timer_tval(timer, TVAL_MIN, wm, true, DEF_CNT);
77754306f56SColton Lewis 	}
77854306f56SColton Lewis 
77954306f56SColton Lewis 	/*
78054306f56SColton Lewis 	 * Set the counter to wait_ms, and a tval to -wait_ms. There should be no
78154306f56SColton Lewis 	 * IRQ as that tval means cval=CVAL_MAX-wait_ms.
78254306f56SColton Lewis 	 */
78354306f56SColton Lewis 	for (i = 0; i < ARRAY_SIZE(sleep_method); i++) {
78454306f56SColton Lewis 		sleep_method_t sm = sleep_method[i];
78554306f56SColton Lewis 
78654306f56SColton Lewis 		set_counter(timer, msec_to_cycles(test_args.wait_ms));
78754306f56SColton Lewis 		test_tval_no_irq(timer, tval, TIMEOUT_NO_IRQ_US, sm);
78854306f56SColton Lewis 	}
78954306f56SColton Lewis }
79054306f56SColton Lewis 
test_long_timer_delays(enum arch_timer timer)79154306f56SColton Lewis static void test_long_timer_delays(enum arch_timer timer)
79254306f56SColton Lewis {
79354306f56SColton Lewis 	int32_t tval = (int32_t) msec_to_cycles(test_args.long_wait_ms);
79454306f56SColton Lewis 	uint64_t cval = DEF_CNT + msec_to_cycles(test_args.long_wait_ms);
79554306f56SColton Lewis 	int i;
79654306f56SColton Lewis 
79754306f56SColton Lewis 	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {
79854306f56SColton Lewis 		irq_wait_method_t wm = irq_wait_method[i];
79954306f56SColton Lewis 
80054306f56SColton Lewis 		test_timer_cval(timer, cval, wm, true, DEF_CNT);
80154306f56SColton Lewis 		test_timer_tval(timer, tval, wm, true, DEF_CNT);
80254306f56SColton Lewis 	}
80354306f56SColton Lewis }
80454306f56SColton Lewis 
guest_run_iteration(enum arch_timer timer)80554306f56SColton Lewis static void guest_run_iteration(enum arch_timer timer)
80654306f56SColton Lewis {
80754306f56SColton Lewis 	test_basic_functionality(timer);
80854306f56SColton Lewis 	test_timers_sanity_checks(timer);
80954306f56SColton Lewis 
81054306f56SColton Lewis 	test_timers_above_tval_max(timer);
81154306f56SColton Lewis 	test_timers_in_the_past(timer);
81254306f56SColton Lewis 
81354306f56SColton Lewis 	test_move_counters_ahead_of_timers(timer);
81454306f56SColton Lewis 	test_move_counters_behind_timers(timer);
81554306f56SColton Lewis 	test_reprogram_timers(timer);
81654306f56SColton Lewis 
81754306f56SColton Lewis 	test_timers_fired_multiple_times(timer);
81854306f56SColton Lewis 
81954306f56SColton Lewis 	test_timer_control_mask_then_unmask(timer);
82054306f56SColton Lewis 	test_timer_control_masks(timer);
82154306f56SColton Lewis }
82254306f56SColton Lewis 
guest_code(enum arch_timer timer)82354306f56SColton Lewis static void guest_code(enum arch_timer timer)
82454306f56SColton Lewis {
82554306f56SColton Lewis 	int i;
82654306f56SColton Lewis 
82754306f56SColton Lewis 	local_irq_disable();
82854306f56SColton Lewis 
82954306f56SColton Lewis 	gic_init(GIC_V3, 1);
83054306f56SColton Lewis 
83154306f56SColton Lewis 	timer_set_ctl(VIRTUAL, CTL_IMASK);
83254306f56SColton Lewis 	timer_set_ctl(PHYSICAL, CTL_IMASK);
83354306f56SColton Lewis 
83454306f56SColton Lewis 	gic_irq_enable(vtimer_irq);
83554306f56SColton Lewis 	gic_irq_enable(ptimer_irq);
83654306f56SColton Lewis 	local_irq_enable();
83754306f56SColton Lewis 
83854306f56SColton Lewis 	for (i = 0; i < test_args.iterations; i++) {
83954306f56SColton Lewis 		GUEST_SYNC(i);
84054306f56SColton Lewis 		guest_run_iteration(timer);
84154306f56SColton Lewis 	}
84254306f56SColton Lewis 
84354306f56SColton Lewis 	test_long_timer_delays(timer);
84454306f56SColton Lewis 	GUEST_DONE();
84554306f56SColton Lewis }
84654306f56SColton Lewis 
847050632aeSSebastian Ott static cpu_set_t default_cpuset;
848050632aeSSebastian Ott 
next_pcpu(void)84954306f56SColton Lewis static uint32_t next_pcpu(void)
85054306f56SColton Lewis {
85154306f56SColton Lewis 	uint32_t max = get_nprocs();
85254306f56SColton Lewis 	uint32_t cur = sched_getcpu();
85354306f56SColton Lewis 	uint32_t next = cur;
854050632aeSSebastian Ott 	cpu_set_t cpuset = default_cpuset;
85554306f56SColton Lewis 
85654306f56SColton Lewis 	TEST_ASSERT(max > 1, "Need at least two physical cpus");
85754306f56SColton Lewis 
85854306f56SColton Lewis 	do {
85954306f56SColton Lewis 		next = (next + 1) % CPU_SETSIZE;
86054306f56SColton Lewis 	} while (!CPU_ISSET(next, &cpuset));
86154306f56SColton Lewis 
86254306f56SColton Lewis 	return next;
86354306f56SColton Lewis }
86454306f56SColton Lewis 
kvm_set_cntxct(struct kvm_vcpu * vcpu,uint64_t cnt,enum arch_timer timer)86554306f56SColton Lewis static void kvm_set_cntxct(struct kvm_vcpu *vcpu, uint64_t cnt,
86654306f56SColton Lewis 			   enum arch_timer timer)
86754306f56SColton Lewis {
86854306f56SColton Lewis 	if (timer == PHYSICAL)
86954306f56SColton Lewis 		vcpu_set_reg(vcpu, KVM_REG_ARM_PTIMER_CNT, cnt);
87054306f56SColton Lewis 	else
87154306f56SColton Lewis 		vcpu_set_reg(vcpu, KVM_REG_ARM_TIMER_CNT, cnt);
87254306f56SColton Lewis }
87354306f56SColton Lewis 
handle_sync(struct kvm_vcpu * vcpu,struct ucall * uc)87454306f56SColton Lewis static void handle_sync(struct kvm_vcpu *vcpu, struct ucall *uc)
87554306f56SColton Lewis {
87654306f56SColton Lewis 	enum sync_cmd cmd = uc->args[1];
87754306f56SColton Lewis 	uint64_t val = uc->args[2];
87854306f56SColton Lewis 	enum arch_timer timer = uc->args[3];
87954306f56SColton Lewis 
88054306f56SColton Lewis 	switch (cmd) {
88154306f56SColton Lewis 	case SET_COUNTER_VALUE:
88254306f56SColton Lewis 		kvm_set_cntxct(vcpu, val, timer);
88354306f56SColton Lewis 		break;
88454306f56SColton Lewis 	case USERSPACE_USLEEP:
88554306f56SColton Lewis 		usleep(val);
88654306f56SColton Lewis 		break;
88754306f56SColton Lewis 	case USERSPACE_SCHED_YIELD:
88854306f56SColton Lewis 		sched_yield();
88954306f56SColton Lewis 		break;
89054306f56SColton Lewis 	case USERSPACE_MIGRATE_SELF:
891*95826e1eSSean Christopherson 		pin_self_to_cpu(next_pcpu());
89254306f56SColton Lewis 		break;
89354306f56SColton Lewis 	default:
89454306f56SColton Lewis 		break;
89554306f56SColton Lewis 	}
89654306f56SColton Lewis }
89754306f56SColton Lewis 
test_run(struct kvm_vm * vm,struct kvm_vcpu * vcpu)89854306f56SColton Lewis static void test_run(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
89954306f56SColton Lewis {
90054306f56SColton Lewis 	struct ucall uc;
90154306f56SColton Lewis 
90254306f56SColton Lewis 	/* Start on CPU 0 */
903*95826e1eSSean Christopherson 	pin_self_to_cpu(0);
90454306f56SColton Lewis 
90554306f56SColton Lewis 	while (true) {
90654306f56SColton Lewis 		vcpu_run(vcpu);
90754306f56SColton Lewis 		switch (get_ucall(vcpu, &uc)) {
90854306f56SColton Lewis 		case UCALL_SYNC:
90954306f56SColton Lewis 			handle_sync(vcpu, &uc);
91054306f56SColton Lewis 			break;
91154306f56SColton Lewis 		case UCALL_DONE:
91254306f56SColton Lewis 			goto out;
91354306f56SColton Lewis 		case UCALL_ABORT:
91454306f56SColton Lewis 			REPORT_GUEST_ASSERT(uc);
91554306f56SColton Lewis 			goto out;
91654306f56SColton Lewis 		default:
91754306f56SColton Lewis 			TEST_FAIL("Unexpected guest exit\n");
91854306f56SColton Lewis 		}
91954306f56SColton Lewis 	}
92054306f56SColton Lewis 
92154306f56SColton Lewis  out:
92254306f56SColton Lewis 	return;
92354306f56SColton Lewis }
92454306f56SColton Lewis 
test_init_timer_irq(struct kvm_vm * vm,struct kvm_vcpu * vcpu)92554306f56SColton Lewis static void test_init_timer_irq(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
92654306f56SColton Lewis {
92754306f56SColton Lewis 	vcpu_device_attr_get(vcpu, KVM_ARM_VCPU_TIMER_CTRL,
92854306f56SColton Lewis 			     KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq);
92954306f56SColton Lewis 	vcpu_device_attr_get(vcpu, KVM_ARM_VCPU_TIMER_CTRL,
93054306f56SColton Lewis 			     KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq);
93154306f56SColton Lewis 
93254306f56SColton Lewis 	sync_global_to_guest(vm, ptimer_irq);
93354306f56SColton Lewis 	sync_global_to_guest(vm, vtimer_irq);
93454306f56SColton Lewis 
93554306f56SColton Lewis 	pr_debug("ptimer_irq: %d; vtimer_irq: %d\n", ptimer_irq, vtimer_irq);
93654306f56SColton Lewis }
93754306f56SColton Lewis 
93856a14984SZenghui Yu static int gic_fd;
93956a14984SZenghui Yu 
test_vm_create(struct kvm_vm ** vm,struct kvm_vcpu ** vcpu,enum arch_timer timer)94054306f56SColton Lewis static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu,
94154306f56SColton Lewis 			   enum arch_timer timer)
94254306f56SColton Lewis {
94354306f56SColton Lewis 	*vm = vm_create_with_one_vcpu(vcpu, guest_code);
94454306f56SColton Lewis 	TEST_ASSERT(*vm, "Failed to create the test VM\n");
94554306f56SColton Lewis 
94654306f56SColton Lewis 	vm_init_descriptor_tables(*vm);
94754306f56SColton Lewis 	vm_install_exception_handler(*vm, VECTOR_IRQ_CURRENT,
94854306f56SColton Lewis 				     guest_irq_handler);
94954306f56SColton Lewis 
95054306f56SColton Lewis 	vcpu_init_descriptor_tables(*vcpu);
95154306f56SColton Lewis 	vcpu_args_set(*vcpu, 1, timer);
95254306f56SColton Lewis 
95354306f56SColton Lewis 	test_init_timer_irq(*vm, *vcpu);
95456a14984SZenghui Yu 	gic_fd = vgic_v3_setup(*vm, 1, 64);
95556a14984SZenghui Yu 	__TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3");
95656a14984SZenghui Yu 
95754306f56SColton Lewis 	sync_global_to_guest(*vm, test_args);
958fad4cf94SSebastian Ott 	sync_global_to_guest(*vm, CVAL_MAX);
959fad4cf94SSebastian Ott 	sync_global_to_guest(*vm, DEF_CNT);
96054306f56SColton Lewis }
96154306f56SColton Lewis 
test_vm_cleanup(struct kvm_vm * vm)96256a14984SZenghui Yu static void test_vm_cleanup(struct kvm_vm *vm)
96356a14984SZenghui Yu {
96456a14984SZenghui Yu 	close(gic_fd);
96556a14984SZenghui Yu 	kvm_vm_free(vm);
96656a14984SZenghui Yu }
96756a14984SZenghui Yu 
test_print_help(char * name)96854306f56SColton Lewis static void test_print_help(char *name)
96954306f56SColton Lewis {
97054306f56SColton Lewis 	pr_info("Usage: %s [-h] [-b] [-i iterations] [-l long_wait_ms] [-p] [-v]\n"
97154306f56SColton Lewis 		, name);
97254306f56SColton Lewis 	pr_info("\t-i: Number of iterations (default: %u)\n",
97354306f56SColton Lewis 		NR_TEST_ITERS_DEF);
97454306f56SColton Lewis 	pr_info("\t-b: Test both physical and virtual timers (default: true)\n");
97554306f56SColton Lewis 	pr_info("\t-l: Delta (in ms) used for long wait time test (default: %u)\n",
97654306f56SColton Lewis 	     LONG_WAIT_TEST_MS);
9779a9864fdSSebastian Ott 	pr_info("\t-w: Delta (in ms) used for wait times (default: %u)\n",
97854306f56SColton Lewis 		WAIT_TEST_MS);
97954306f56SColton Lewis 	pr_info("\t-p: Test physical timer (default: true)\n");
98054306f56SColton Lewis 	pr_info("\t-v: Test virtual timer (default: true)\n");
98154306f56SColton Lewis 	pr_info("\t-h: Print this help message\n");
98254306f56SColton Lewis }
98354306f56SColton Lewis 
parse_args(int argc,char * argv[])98454306f56SColton Lewis static bool parse_args(int argc, char *argv[])
98554306f56SColton Lewis {
98654306f56SColton Lewis 	int opt;
98754306f56SColton Lewis 
98854306f56SColton Lewis 	while ((opt = getopt(argc, argv, "bhi:l:pvw:")) != -1) {
98954306f56SColton Lewis 		switch (opt) {
99054306f56SColton Lewis 		case 'b':
99154306f56SColton Lewis 			test_args.test_physical = true;
99254306f56SColton Lewis 			test_args.test_virtual = true;
99354306f56SColton Lewis 			break;
99454306f56SColton Lewis 		case 'i':
99554306f56SColton Lewis 			test_args.iterations =
99654306f56SColton Lewis 			    atoi_positive("Number of iterations", optarg);
99754306f56SColton Lewis 			break;
99854306f56SColton Lewis 		case 'l':
99954306f56SColton Lewis 			test_args.long_wait_ms =
100054306f56SColton Lewis 			    atoi_positive("Long wait time", optarg);
100154306f56SColton Lewis 			break;
100254306f56SColton Lewis 		case 'p':
100354306f56SColton Lewis 			test_args.test_physical = true;
100454306f56SColton Lewis 			test_args.test_virtual = false;
100554306f56SColton Lewis 			break;
100654306f56SColton Lewis 		case 'v':
100754306f56SColton Lewis 			test_args.test_virtual = true;
100854306f56SColton Lewis 			test_args.test_physical = false;
100954306f56SColton Lewis 			break;
101054306f56SColton Lewis 		case 'w':
101154306f56SColton Lewis 			test_args.wait_ms = atoi_positive("Wait time", optarg);
101254306f56SColton Lewis 			break;
101354306f56SColton Lewis 		case 'h':
101454306f56SColton Lewis 		default:
101554306f56SColton Lewis 			goto err;
101654306f56SColton Lewis 		}
101754306f56SColton Lewis 	}
101854306f56SColton Lewis 
101954306f56SColton Lewis 	return true;
102054306f56SColton Lewis 
102154306f56SColton Lewis  err:
102254306f56SColton Lewis 	test_print_help(argv[0]);
102354306f56SColton Lewis 	return false;
102454306f56SColton Lewis }
102554306f56SColton Lewis 
set_counter_defaults(void)1026fad4cf94SSebastian Ott static void set_counter_defaults(void)
1027fad4cf94SSebastian Ott {
1028fad4cf94SSebastian Ott 	const uint64_t MIN_ROLLOVER_SECS = 40ULL * 365 * 24 * 3600;
1029fad4cf94SSebastian Ott 	uint64_t freq = read_sysreg(CNTFRQ_EL0);
1030fad4cf94SSebastian Ott 	uint64_t width = ilog2(MIN_ROLLOVER_SECS * freq);
1031fad4cf94SSebastian Ott 
1032fad4cf94SSebastian Ott 	width = clamp(width, 56, 64);
1033fad4cf94SSebastian Ott 	CVAL_MAX = GENMASK_ULL(width - 1, 0);
1034fad4cf94SSebastian Ott 	DEF_CNT = CVAL_MAX / 2;
1035fad4cf94SSebastian Ott }
1036fad4cf94SSebastian Ott 
main(int argc,char * argv[])103754306f56SColton Lewis int main(int argc, char *argv[])
103854306f56SColton Lewis {
103954306f56SColton Lewis 	struct kvm_vcpu *vcpu;
104054306f56SColton Lewis 	struct kvm_vm *vm;
104154306f56SColton Lewis 
104254306f56SColton Lewis 	/* Tell stdout not to buffer its content */
104354306f56SColton Lewis 	setbuf(stdout, NULL);
104454306f56SColton Lewis 
104554306f56SColton Lewis 	if (!parse_args(argc, argv))
104654306f56SColton Lewis 		exit(KSFT_SKIP);
104754306f56SColton Lewis 
1048050632aeSSebastian Ott 	sched_getaffinity(0, sizeof(default_cpuset), &default_cpuset);
1049fad4cf94SSebastian Ott 	set_counter_defaults();
1050050632aeSSebastian Ott 
105154306f56SColton Lewis 	if (test_args.test_virtual) {
105254306f56SColton Lewis 		test_vm_create(&vm, &vcpu, VIRTUAL);
105354306f56SColton Lewis 		test_run(vm, vcpu);
105456a14984SZenghui Yu 		test_vm_cleanup(vm);
105554306f56SColton Lewis 	}
105654306f56SColton Lewis 
105754306f56SColton Lewis 	if (test_args.test_physical) {
105854306f56SColton Lewis 		test_vm_create(&vm, &vcpu, PHYSICAL);
105954306f56SColton Lewis 		test_run(vm, vcpu);
106056a14984SZenghui Yu 		test_vm_cleanup(vm);
106154306f56SColton Lewis 	}
106254306f56SColton Lewis 
106354306f56SColton Lewis 	return 0;
106454306f56SColton Lewis }
1065