1 /*
2 * Copyright (c) 2019 LK Trusty Authors. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <kernel/timer.h>
25 #include <lib/unittest/unittest.h>
26 #include <platform.h>
27 #include <stdatomic.h>
28
29 #define US2NS(us) ((us) * 1000LL)
30 #define MS2NS(ms) (US2NS(ms) * 1000LL)
31 #define S2NS(s) (MS2NS(s) * 1000LL)
32
33 /* Expect better than 1us timer resolution. */
34 #if GEM5
35 // In gem5 simulation CNTPCT register is updated with frequency less than
36 // 1MHz, so adjust target period for this test
37 #define TIMER_TEST_MAX_CLOCK_PERIOD (1200)
38 #elif defined(APP_TIMERTEST_MAX_CLOCK_PERIOD)
39 #define TIMER_TEST_MAX_CLOCK_PERIOD (APP_TIMERTEST_MAX_CLOCK_PERIOD)
40 #else
41 #define TIMER_TEST_MAX_CLOCK_PERIOD (900)
42 #endif
43
44 /*
45 * Expect much better than 1ms timer interrupt latency, but qemu currently has
46 * more than 100us latency in the best case, and Linux adds several milliseconds
47 * to this in the worst case.
48 */
49 #define TIMER_TEST_MAX_TIMER_LATENCY (MS2NS(10))
50
51 /* Periodic timers don't currently avoid drifting when the interrupt is late */
52 #define TIMER_TEST_MAX_TIMER_DRIFT TIMER_TEST_MAX_TIMER_LATENCY
53
54 #define TIMER_TEST_RETRY_COUNT (10)
55
TimerTestGetTimeNs(void)56 static int64_t TimerTestGetTimeNs(void) {
57 return current_time_ns();
58 }
59
TimerTestBusyWait(int64_t delay)60 static void TimerTestBusyWait(int64_t delay) {
61 int64_t end = TimerTestGetTimeNs() + delay;
62 while (TimerTestGetTimeNs() < end) {
63 }
64 }
65
66 struct TimerTestTimer {
67 struct timer timer;
68 int64_t delta;
69 int64_t before_start_time;
70 int64_t after_start_time;
71 size_t target_trigger_count;
72 atomic_size_t trigger_count;
73 int64_t trigger_time_passed;
74 int64_t handler_run_time;
75 void *arg_passed;
76 };
77
78 #define TIMER_TEST_TIMER_INITIAL_VALUE(t) { \
79 TIMER_INITIAL_VALUE(&t->timer), 0, 0, 0, 0, 0, 0, 0, NULL \
80 }
81
ToTimerTestTimer(struct timer * timer)82 static struct TimerTestTimer *ToTimerTestTimer(struct timer *timer) {
83 return containerof(timer, struct TimerTestTimer, timer);
84 }
85
86 /**
87 * TimerTestTimerCallback - Timer callback function.
88 * @timer: Timer object.
89 * @now: Current time passed from lk timer code.
90 * @arg: Argument passed to timer_set*.
91 *
92 * Common timer callback function used by tests to record how many times it was
93 * called, when it was last called and what arguments were passed. Stops
94 * periodic timer after a specified trigger count.
95 *
96 * Return: INT_NO_RESCHEDULE to tell the caller that the scheduler does not need
97 * to run.
98 */
TimerTestTimerCallback(struct timer * timer,lk_time_ns_t now,void * arg)99 static enum handler_return TimerTestTimerCallback(struct timer *timer,
100 lk_time_ns_t now,
101 void *arg) {
102 struct TimerTestTimer *t = ToTimerTestTimer(timer);
103 size_t trigger_count;
104
105 t->trigger_time_passed = now;
106 t->handler_run_time = TimerTestGetTimeNs();
107 t->arg_passed = arg;
108 trigger_count = atomic_fetch_add_explicit(&t->trigger_count, 1,
109 memory_order_release) + 1;
110 if (t->timer.periodic_time &&
111 trigger_count == t->target_trigger_count) {
112 timer_cancel(&t->timer);
113 }
114 return INT_NO_RESCHEDULE;
115 }
116
117 /**
118 * TimerTestTimerStart - Start test timer.
119 * @t: Test timer object.
120 * @delta: Delay in nanoseconds until timer callback should be called and
121 * interval between timer callback calls if @count is greater than one.
122 * @count: Number of times to call the timer callback.
123 */
TimerTestTimerStart(struct TimerTestTimer * t,int64_t delta,size_t count)124 static void TimerTestTimerStart(struct TimerTestTimer *t, int64_t delta,
125 size_t count) {
126 lk_time_ns_t lk_time = delta;
127 t->delta = delta;
128 t->target_trigger_count = count;
129 atomic_store(&t->trigger_count, 0);
130 t->before_start_time = TimerTestGetTimeNs();
131 if (count > 1) {
132 timer_set_periodic_ns(&t->timer, lk_time, TimerTestTimerCallback, t);
133 } else {
134 timer_set_oneshot_ns(&t->timer, lk_time, TimerTestTimerCallback, t);
135 }
136 t->after_start_time = TimerTestGetTimeNs();
137 }
138
139 /**
140 * TimerTestTimerCheck - Check that timer callback was called
141 * @t: Test timer object.
142 * @retry: If non-zero, return early if timer callback ran late.
143 *
144 * Return: @retry if timer callback ran late and test should run again, 0
145 * otherwise.
146 */
TimerTestTimerCheck(struct TimerTestTimer * t,size_t retry)147 static size_t TimerTestTimerCheck(struct TimerTestTimer *t, size_t retry) {
148 size_t trigger_count;
149 int64_t delta = t->delta * t->target_trigger_count;
150 int64_t min_delta = delta;
151 int64_t max_delta = delta + TIMER_TEST_MAX_TIMER_LATENCY +
152 TIMER_TEST_MAX_TIMER_DRIFT *
153 (t->target_trigger_count - 1);
154
155 trigger_count = atomic_load_explicit(&t->trigger_count,
156 memory_order_acquire);
157
158 EXPECT_EQ(trigger_count, t->target_trigger_count);
159 timer_cancel_sync(&t->timer);
160 if (trigger_count != t->target_trigger_count) {
161 return 0;
162 }
163
164 EXPECT_EQ(t->arg_passed, t);
165
166 if (retry && MAX(t->trigger_time_passed, t->handler_run_time) -
167 t->after_start_time >= max_delta) {
168 unittest_printf(" %lld/%lld > %lld, retry\n",
169 t->trigger_time_passed - t->after_start_time,
170 t->handler_run_time - t->after_start_time, max_delta);
171 return retry;
172 }
173
174 EXPECT_GE(t->trigger_time_passed - t->before_start_time, min_delta);
175 EXPECT_LT(t->trigger_time_passed - t->after_start_time, max_delta);
176 EXPECT_GE(t->handler_run_time - t->before_start_time, min_delta);
177 EXPECT_LT(t->handler_run_time - t->after_start_time, max_delta);
178
179 return 0;
180 }
181
182 /**
183 * TimerTestTimerPoll - Busy wait for timer callback to run.
184 * @t: Test timer object.
185 * @timeout: Timeout in nanoseconds to abort busy-wait.
186 *
187 * Return: %true if timer callback ran the expected number of times, %false
188 * otherwise.
189 */
TimerTestTimerPoll(struct TimerTestTimer * t,int64_t timeout)190 static bool TimerTestTimerPoll(struct TimerTestTimer *t, int64_t timeout) {
191 size_t trigger_count;
192 int64_t end_time = TimerTestGetTimeNs() + timeout;
193
194 do {
195 trigger_count = atomic_load_explicit(&t->trigger_count,
196 memory_order_acquire);
197 } while (trigger_count < t->target_trigger_count &&
198 TimerTestGetTimeNs() < end_time);
199
200 return trigger_count == t->target_trigger_count;
201 }
202
203 /* Test high resolution api to read timer */
TEST(TimerTest,GetTime)204 TEST(TimerTest, GetTime) {
205 int64_t t1;
206 int64_t t2;
207 size_t i;
208 const int timeout = 1000;
209 const int64_t max_delta = TIMER_TEST_MAX_CLOCK_PERIOD;
210
211 t2 = TimerTestGetTimeNs();
212 for (i = 0; i < timeout; i++) {
213 t1 = t2;
214 t2 = TimerTestGetTimeNs();
215 if (t2 != t1 && t2 - t1 <= max_delta) {
216 break;
217 }
218 }
219 EXPECT_GT(t2 - t1, 0);
220 EXPECT_LE(t2 - t1, max_delta);
221 }
222
223 /* Test one shot timer api */
TEST(TimerTest,TimerSetOneShot)224 TEST(TimerTest, TimerSetOneShot) {
225 struct TimerTestTimer t = TIMER_TEST_TIMER_INITIAL_VALUE(&t);
226 int retry = TIMER_TEST_RETRY_COUNT;
227 do {
228 TimerTestTimerStart(&t, MS2NS(1), 1);
229 TimerTestTimerPoll(&t, S2NS(10));
230 retry = TimerTestTimerCheck(&t, retry - 1);
231 } while(retry);
232 }
233
234 /* Test periodic timer api */
TEST(TimerTest,TimerSetPeriodic)235 TEST(TimerTest, TimerSetPeriodic) {
236 struct TimerTestTimer t = TIMER_TEST_TIMER_INITIAL_VALUE(&timer);
237 int retry = TIMER_TEST_RETRY_COUNT;
238 do {
239 TimerTestTimerStart(&t, MS2NS(1), 100);
240 TimerTestTimerPoll(&t, S2NS(10));
241 retry = TimerTestTimerCheck(&t, retry - 1);
242 } while(retry);
243 }
244
245 /* Test multiple timers (which could cause early wake up in old timer code) */
TEST(TimerTest,TimerSetOneShotMultipleEvenlySpaced)246 TEST(TimerTest, TimerSetOneShotMultipleEvenlySpaced) {
247 size_t i;
248 static struct TimerTestTimer tb[] = {
249 TIMER_TEST_TIMER_INITIAL_VALUE(&tb[0]),
250 TIMER_TEST_TIMER_INITIAL_VALUE(&tb[1]),
251 TIMER_TEST_TIMER_INITIAL_VALUE(&tb[2]),
252 TIMER_TEST_TIMER_INITIAL_VALUE(&tb[3]),
253 TIMER_TEST_TIMER_INITIAL_VALUE(&tb[4]),
254 TIMER_TEST_TIMER_INITIAL_VALUE(&tb[5]),
255 TIMER_TEST_TIMER_INITIAL_VALUE(&tb[6]),
256 TIMER_TEST_TIMER_INITIAL_VALUE(&tb[7]),
257 TIMER_TEST_TIMER_INITIAL_VALUE(&tb[8]),
258 TIMER_TEST_TIMER_INITIAL_VALUE(&tb[9]),
259 };
260 static struct TimerTestTimer ts[] = {
261 TIMER_TEST_TIMER_INITIAL_VALUE(&ts[0]),
262 TIMER_TEST_TIMER_INITIAL_VALUE(&ts[1]),
263 TIMER_TEST_TIMER_INITIAL_VALUE(&ts[2]),
264 TIMER_TEST_TIMER_INITIAL_VALUE(&ts[3]),
265 TIMER_TEST_TIMER_INITIAL_VALUE(&ts[4]),
266 TIMER_TEST_TIMER_INITIAL_VALUE(&ts[5]),
267 TIMER_TEST_TIMER_INITIAL_VALUE(&ts[6]),
268 TIMER_TEST_TIMER_INITIAL_VALUE(&ts[7]),
269 TIMER_TEST_TIMER_INITIAL_VALUE(&ts[8]),
270 TIMER_TEST_TIMER_INITIAL_VALUE(&ts[9]),
271 };
272 int retry = TIMER_TEST_RETRY_COUNT;
273 int next_retry;
274 do {
275 for (i = 0; i < countof(tb); i++) {
276 TimerTestTimerStart(&tb[i], MS2NS(1), 1);
277 }
278 for (i = 0; i < countof(ts); i++) {
279 TimerTestTimerStart(&ts[i], MS2NS(1), 1);
280 TimerTestBusyWait(MS2NS(1) / countof(ts));
281 timer_cancel_sync(&tb[i].timer);
282 }
283 TimerTestTimerPoll(&ts[countof(ts) - 1], S2NS(10));
284 for (i = 0; i < countof(ts); i++) {
285 /* thread may migrate to another cpu */
286 TimerTestTimerPoll(&ts[i], S2NS(1));
287 }
288 next_retry = retry - 1;
289 retry = 0;
290 for (i = 0; i < countof(ts); i++) {
291 int tmp_retry = TimerTestTimerCheck(&ts[i], next_retry);
292 if (tmp_retry) {
293 retry = tmp_retry;
294 }
295 }
296 } while(retry);
297 }
298
299 /*
300 * Test timer_cancel api. Call after a delay from alternating CPUs to try to
301 * cancel it while the timer callback is running.
302 */
TEST(TimerTest,TimerCancel)303 TEST(TimerTest, TimerCancel) {
304 struct TimerTestTimer t = TIMER_TEST_TIMER_INITIAL_VALUE(&t);
305 struct wait_queue wq = WAIT_QUEUE_INITIAL_VALUE(wq);
306 bool triggered;
307 int64_t wait_time = MS2NS(2);
308 int saved_pinned_cpu = thread_pinned_cpu(get_current_thread());
309 EXPECT_EQ(saved_pinned_cpu, -1);
310 for (int i = 0; i < 1000; i++) {
311 TimerTestTimerStart(&t, MS2NS(2), 1);
312 thread_set_pinned_cpu(get_current_thread(),
313 (arch_curr_cpu_num() + 1) % 2);
314 THREAD_LOCK(state);
315 wait_queue_block(&wq, 1);
316 THREAD_UNLOCK(state);
317 triggered = TimerTestTimerPoll(&t, wait_time);
318 if (!triggered) {
319 wait_time += US2NS(10);
320 } else {
321 wait_time -= US2NS(10);
322 }
323 timer_cancel_sync(&t.timer);
324 }
325 thread_set_pinned_cpu(get_current_thread(), saved_pinned_cpu);
326 }
327
328 PORT_TEST(TimerTest, "com.android.kernel.timertest");
329