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