1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #if defined(UNIT_TESTS)
6 
7 #include <assert.h>
8 #include <hyptypes.h>
9 
10 #include <atomic.h>
11 #include <compiler.h>
12 #include <cpulocal.h>
13 #include <log.h>
14 #include <panic.h>
15 #include <preempt.h>
16 #include <timer_queue.h>
17 #include <trace.h>
18 
19 #include "event_handlers.h"
20 
21 #if defined(PLATFORM_QEMU)
22 #define MAX_TICKS_DIFFERENCE 0x500000
23 #else
24 // Leave enough slack for console messages to be printed
25 #define MAX_TICKS_DIFFERENCE 0x140
26 #endif
27 
28 CPULOCAL_DECLARE_STATIC(timer_t, timer1);
29 CPULOCAL_DECLARE_STATIC(timer_t, timer2);
30 CPULOCAL_DECLARE_STATIC(uint8_t, test_num);
31 CPULOCAL_DECLARE_STATIC(_Atomic bool, in_progress);
32 CPULOCAL_DECLARE_STATIC(ticks_t, expected_timeout);
33 
34 bool
tests_timer(void)35 tests_timer(void)
36 {
37 	ticks_t	 current_ticks;
38 	timer_t *timer1		  = &CPULOCAL(timer1);
39 	timer_t *timer2		  = &CPULOCAL(timer2);
40 	ticks_t *expected_timeout = &CPULOCAL(expected_timeout);
41 
42 	_Atomic bool *in_progress = &CPULOCAL(in_progress);
43 
44 	// Test 1
45 	// Enqueue a timer and make sure its expiry is received
46 	CPULOCAL(test_num) = 1;
47 	timer_init_object(timer1, TIMER_ACTION_TEST);
48 	timer_init_object(timer2, TIMER_ACTION_TEST);
49 	current_ticks = timer_get_current_timer_ticks();
50 	*expected_timeout =
51 		current_ticks + (0x100000 * (cpulocal_get_index() + 1));
52 	atomic_store_relaxed(&CPULOCAL(in_progress), true);
53 	timer_enqueue(timer1, *expected_timeout);
54 
55 	preempt_enable();
56 	while (atomic_load_relaxed(in_progress)) {
57 	}
58 	preempt_disable();
59 
60 	// Test 2
61 	// Enqueue two timers, dequeue the first one and make sure only the
62 	// expiry for the second one is received
63 	CPULOCAL(test_num)++;
64 	timer_init_object(timer1, TIMER_ACTION_TEST);
65 	timer_init_object(timer2, TIMER_ACTION_TEST);
66 	current_ticks = timer_get_current_timer_ticks();
67 	atomic_store_relaxed(&CPULOCAL(in_progress), true);
68 	timer_enqueue(timer1,
69 		      current_ticks + (0x100000 * (cpulocal_get_index() + 1)));
70 
71 	*expected_timeout =
72 		current_ticks + (0x200000 * (cpulocal_get_index() + 1));
73 	timer_enqueue(timer2, *expected_timeout);
74 
75 	timer_dequeue(timer1);
76 
77 	preempt_enable();
78 	while (atomic_load_relaxed(in_progress)) {
79 	}
80 	preempt_disable();
81 
82 	// TODO: Add more tests
83 
84 	LOG(DEBUG, INFO, "Timer tests successfully finished on core {:d}",
85 	    cpulocal_get_index());
86 	return false;
87 }
88 
89 bool
tests_timer_action(timer_t * timer)90 tests_timer_action(timer_t *timer)
91 {
92 	ticks_t *expected_timeout = &CPULOCAL(expected_timeout);
93 	ticks_t	 current_ticks	  = timer_get_current_timer_ticks();
94 
95 	assert(timer != NULL);
96 
97 	if (!atomic_load_relaxed(&CPULOCAL(in_progress))) {
98 		LOG(ERROR, PANIC,
99 		    "Unexpected timer expiry trigger on core {:d}",
100 		    cpulocal_get_index());
101 		panic("Unexpected timer expiry trigger");
102 	} else if (timer->timeout != *expected_timeout) {
103 		LOG(ERROR, PANIC,
104 		    "Timer expiry trigger (test {:d}) on core {:d}"
105 		    " arrived for the wrong timer; expected {:#x}, got {:#x}",
106 		    CPULOCAL(test_num), cpulocal_get_index(), *expected_timeout,
107 		    timer->timeout);
108 		panic("Timer expiry trigger arrived with wrong timeout");
109 	} else if (*expected_timeout > current_ticks) {
110 		LOG(ERROR, PANIC,
111 		    "Timer expiry trigger (test {:d}) on core {:d}"
112 		    " arrived too early; expected at {:#x}, arrived at {:#x}",
113 		    CPULOCAL(test_num), cpulocal_get_index(), *expected_timeout,
114 		    current_ticks);
115 		panic("Timer expiry trigger arrived too early");
116 	} else if (current_ticks - *expected_timeout > MAX_TICKS_DIFFERENCE) {
117 		LOG(ERROR, PANIC,
118 		    "Timer expiry trigger (test {:d}) on core {:d}"
119 		    " took too long to arrive; expected at"
120 		    "{:#x}, arrived at {:#x}, diff {:#x}",
121 		    CPULOCAL(test_num), cpulocal_get_index(), *expected_timeout,
122 		    current_ticks, current_ticks - *expected_timeout);
123 		panic("Timer expiry trigger arrived too late");
124 	} else {
125 		LOG(DEBUG, INFO,
126 		    "Timer interrupt (test {:d}): core {:d}, expected at {:#x}"
127 		    ", arrived at {:#x}, diff {:#x}",
128 		    CPULOCAL(test_num), cpulocal_get_index(), *expected_timeout,
129 		    current_ticks, current_ticks - *expected_timeout);
130 		atomic_store_relaxed(&CPULOCAL(in_progress), false);
131 	}
132 
133 	return true;
134 }
135 #else
136 
137 extern char unused;
138 
139 #endif
140