1 /*-
2 * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice unmodified, this list of conditions, and the following
9 * disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "linux/hrtimer.h"
27
28 #include "los_task_pri.h"
29 #include "los_spinlock.h"
30 #include "target_config.h"
31 #include "los_init.h"
32
33 #define US_PER_SECOND 1000000
34
35 /* spinlock for hrtimer module only available on SMP mode */
36 LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_hrtimerSpin);
37
38 LITE_OS_SEC_BSS struct hrtimer_list_node *g_hrtimerList;
39
HandlerNodeAdd(struct hrtimer_list_node * htrimer,struct handler_list_node * handlerNode)40 STATIC VOID HandlerNodeAdd(struct hrtimer_list_node *htrimer, struct handler_list_node *handlerNode)
41 {
42 struct handler_list_node *tmpNode = NULL;
43
44 if (htrimer == NULL) {
45 return;
46 }
47
48 tmpNode = htrimer->HandlerHead;
49 if (tmpNode == NULL) {
50 htrimer->HandlerHead = handlerNode;
51 } else {
52 while (tmpNode->pstNext != NULL) {
53 tmpNode = tmpNode->pstNext;
54 }
55 tmpNode->pstNext = handlerNode;
56 } /* FIFO */
57 }
58
HrtimerNodeAdd(struct hrtimer_list_node * htrimer,struct handler_list_node * handlerNode)59 STATIC VOID HrtimerNodeAdd(struct hrtimer_list_node *htrimer, struct handler_list_node *handlerNode)
60 {
61 struct hrtimer_list_node *prevNode = NULL;
62 struct hrtimer_list_node *curNode = NULL;
63 struct hrtimer_list_node *tmpNode = NULL;
64 UINT32 temp;
65
66 if (g_hrtimerList == NULL) {
67 g_hrtimerList = htrimer;
68 HrtimerClockStart(htrimer->set_time_reload);
69 } else {
70 temp = HrtimerClockValueGet();
71 g_hrtimerList->set_time_reload = temp;
72 curNode = g_hrtimerList;
73 while (curNode != NULL) {
74 if (curNode->set_time_reload > htrimer->set_time_reload) {
75 break;
76 }
77 if (curNode->set_time_reload == htrimer->set_time_reload) {
78 HandlerNodeAdd(curNode, handlerNode);
79 (VOID)LOS_MemFree(m_aucSysMem0, htrimer);
80 return;
81 }
82 htrimer->set_time_reload -= curNode->set_time_reload;
83 prevNode = curNode;
84 curNode = curNode->pstNext;
85 }
86 if (curNode == g_hrtimerList) {
87 tmpNode = g_hrtimerList;
88 HrtimerClockStop();
89 HrtimerClockStart(htrimer->set_time_reload);
90
91 tmpNode->set_time_reload -= htrimer->set_time_reload;
92 htrimer->pstNext = curNode;
93 g_hrtimerList = htrimer;
94 } else if (curNode == NULL) {
95 prevNode->pstNext = htrimer;
96 } else {
97 htrimer->pstNext = curNode;
98 prevNode->pstNext = htrimer;
99 curNode->set_time_reload -= htrimer->set_time_reload;
100 }
101 }
102 if (handlerNode != NULL) {
103 HandlerNodeAdd(htrimer, handlerNode);
104 }
105 }
106
HrtimerHandlerRunAddNode(struct hrtimer_list_node * hrtimer,struct handler_list_node * handlerHead)107 STATIC VOID HrtimerHandlerRunAddNode(struct hrtimer_list_node *hrtimer, struct handler_list_node *handlerHead)
108 {
109 if (handlerHead == NULL) {
110 (VOID)LOS_MemFree(m_aucSysMem0, hrtimer);
111 } else {
112 hrtimer->set_time_reload = (UINT32)((hrtimer->_softexpires.tv.sec * US_PER_SECOND +
113 hrtimer->_softexpires.tv.usec) * HRTIMER_PERUS);
114 LOS_SpinLock(&g_hrtimerSpin);
115 HrtimerNodeAdd(hrtimer, handlerHead);
116 LOS_SpinUnlock(&g_hrtimerSpin);
117 }
118 }
119
HrtimerHandlerRun(VOID)120 STATIC VOID HrtimerHandlerRun(VOID)
121 {
122 struct hrtimer_list_node *hrtimer = NULL;
123 struct handler_list_node *curNode = NULL;
124 struct handler_list_node *handler = NULL;
125 struct handler_list_node *handlerTail = NULL;
126 struct handler_list_node *handlerHead = NULL;
127 struct hrtimer timer;
128 enum hrtimer_restart restart;
129
130 LOS_SpinLock(&g_hrtimerSpin);
131 if (g_hrtimerList == NULL) {
132 LOS_SpinUnlock(&g_hrtimerSpin);
133 return;
134 }
135 hrtimer = g_hrtimerList;
136 g_hrtimerList = hrtimer->pstNext;
137 if (g_hrtimerList != NULL) {
138 HrtimerClockStop();
139 HrtimerClockStart(g_hrtimerList->set_time_reload);
140 }
141 LOS_SpinUnlock(&g_hrtimerSpin);
142
143 timer._softexpires.tv.usec = hrtimer->_softexpires.tv.usec;
144 timer._softexpires.tv.sec = hrtimer->_softexpires.tv.sec;
145 handler = hrtimer->HandlerHead;
146 hrtimer->pstNext = NULL;
147 hrtimer->HandlerHead = NULL;
148
149 while ((handler != NULL) && (handler->pfnHandler != NULL)) {
150 timer.function = handler->pfnHandler;
151 restart = handler->pfnHandler(&timer);
152 curNode = handler;
153 handler = handler->pstNext;
154 curNode->pstNext = NULL;
155
156 if (restart == HRTIMER_NORESTART) {
157 (VOID)LOS_MemFree(m_aucSysMem0, curNode);
158 } else if (restart == HRTIMER_RESTART) {
159 if (handlerHead != NULL) {
160 handlerTail->pstNext = curNode;
161 handlerTail = curNode;
162 } else {
163 handlerHead = curNode;
164 handlerTail = curNode;
165 }
166 } else {
167 PRINT_ERR("The return value of hrtimer function is not defined!\n");
168 }
169 }
170
171 HrtimerHandlerRunAddNode(hrtimer, handlerHead);
172 }
173
HrtimerListScan(VOID)174 STATIC VOID HrtimerListScan(VOID)
175 {
176 HrtimerClockIrqClear();
177 HrtimerHandlerRun();
178 }
179
GetHandlerNodePosition(const struct hrtimer * timer,struct hrtimer_list_node * hrtimerNode,struct handler_list_node ** prevNode,struct handler_list_node ** curNode)180 STATIC VOID GetHandlerNodePosition(const struct hrtimer *timer, struct hrtimer_list_node *hrtimerNode,
181 struct handler_list_node **prevNode, struct handler_list_node **curNode)
182 {
183 struct handler_list_node *curHandler = NULL;
184 struct handler_list_node *prevHandler = NULL;
185
186 curHandler = hrtimerNode->HandlerHead;
187 while (curHandler != NULL) {
188 if ((curHandler->pfnHandler == timer->function) &&
189 (curHandler->_softexpires.tv.sec == timer->_softexpires.tv.sec) &&
190 (curHandler->_softexpires.tv.usec == timer->_softexpires.tv.usec)) {
191 *prevNode = prevHandler;
192 *curNode = curHandler;
193 return;
194 }
195 prevHandler = curHandler;
196 curHandler = curHandler->pstNext;
197 }
198 }
199
GetHrtimerNodePosition(const struct hrtimer * timer,struct hrtimer_list_node ** prevNode,struct hrtimer_list_node ** curNode)200 STATIC VOID GetHrtimerNodePosition(const struct hrtimer *timer, struct hrtimer_list_node **prevNode,
201 struct hrtimer_list_node **curNode)
202 {
203 struct handler_list_node *curHandler = NULL;
204
205 *curNode = g_hrtimerList;
206 while (*curNode != NULL) {
207 curHandler = (*curNode)->HandlerHead;
208 while (curHandler != NULL) {
209 if ((curHandler->pfnHandler == timer->function) &&
210 (curHandler->_softexpires.tv.sec == timer->_softexpires.tv.sec) &&
211 (curHandler->_softexpires.tv.usec == timer->_softexpires.tv.usec)) {
212 return;
213 }
214 curHandler = curHandler->pstNext;
215 }
216 *prevNode = *curNode;
217 *curNode = (*curNode)->pstNext;
218 }
219 }
220
HrtimerListNodeInit(union ktime time)221 STATIC struct hrtimer_list_node *HrtimerListNodeInit(union ktime time)
222 {
223 struct hrtimer_list_node *hrtimer = (struct hrtimer_list_node *)LOS_MemAlloc(m_aucSysMem0,
224 sizeof(struct hrtimer_list_node));
225 if (hrtimer == NULL) {
226 return NULL;
227 }
228 hrtimer->_softexpires = time;
229 hrtimer->set_time_reload = (UINT32)((time.tv.sec * US_PER_SECOND + time.tv.usec) * HRTIMER_PERUS);
230 hrtimer->HandlerHead = NULL;
231 hrtimer->pstNext = NULL;
232 return hrtimer;
233 }
234
ChangeNodePosition(struct hrtimer_list_node * prevNode,struct hrtimer_list_node * curNode,struct handler_list_node * prevHandler,struct handler_list_node * curHandler,union ktime time)235 STATIC UINT32 ChangeNodePosition(struct hrtimer_list_node *prevNode, struct hrtimer_list_node *curNode,
236 struct handler_list_node *prevHandler, struct handler_list_node *curHandler,
237 union ktime time)
238 {
239 struct hrtimer_list_node *htrimer = NULL;
240
241 if ((prevHandler != NULL) || (curHandler->pstNext != NULL)) {
242 if (prevHandler == NULL) {
243 curNode->HandlerHead = curHandler->pstNext;
244 } else {
245 prevHandler->pstNext = curHandler->pstNext;
246 }
247
248 curHandler->pstNext = NULL;
249 curHandler->_softexpires = time;
250
251 htrimer = HrtimerListNodeInit(time);
252 if (htrimer == NULL) {
253 return LOS_NOK;
254 }
255
256 HrtimerNodeAdd(htrimer, curHandler);
257 } else {
258 if (curNode->pstNext != NULL) {
259 if (curNode == g_hrtimerList) {
260 g_hrtimerList = curNode->pstNext;
261 g_hrtimerList->set_time_reload += HrtimerClockValueGet();
262 HrtimerClockStop();
263 HrtimerClockStart(g_hrtimerList->set_time_reload);
264 } else {
265 prevNode->pstNext = curNode->pstNext;
266 curNode->pstNext->set_time_reload += curNode->set_time_reload;
267 }
268 } else {
269 if (curNode == g_hrtimerList) {
270 g_hrtimerList = NULL;
271 HrtimerClockStop();
272 } else {
273 prevNode->pstNext = NULL;
274 }
275 }
276 curNode->pstNext = NULL;
277 curNode->_softexpires = time;
278 curNode->set_time_reload = (UINT32)((time.tv.sec * US_PER_SECOND + time.tv.usec) * HRTIMER_PERUS);
279 curNode->HandlerHead->_softexpires = time;
280 HrtimerNodeAdd(curNode, NULL);
281 }
282
283 return LOS_OK;
284 }
285
CancelHandlerNode(const struct hrtimer * timer,struct hrtimer_list_node * curNode)286 STATIC VOID CancelHandlerNode(const struct hrtimer *timer, struct hrtimer_list_node *curNode)
287 {
288 struct handler_list_node *curHandler = curNode->HandlerHead;
289 struct handler_list_node *prevHandler = curHandler;
290
291 while (curHandler != NULL) {
292 if ((curHandler->pfnHandler == timer->function) &&
293 (curHandler->_softexpires.tv.sec == timer->_softexpires.tv.sec) &&
294 (curHandler->_softexpires.tv.usec == timer->_softexpires.tv.usec)) {
295 if (curHandler == curNode->HandlerHead) {
296 curNode->HandlerHead = curHandler->pstNext;
297 } else {
298 prevHandler->pstNext = curHandler->pstNext;
299 }
300 curHandler->pstNext = NULL;
301 (VOID)LOS_MemFree(m_aucSysMem0, curHandler);
302 break;
303 }
304 prevHandler = curHandler;
305 curHandler = curHandler->pstNext;
306 }
307 }
308
CheckTime(union ktime * time)309 STATIC UINT32 CheckTime(union ktime *time)
310 {
311 if ((time->tv.sec == 0) && (time->tv.usec == 0)) {
312 return LOS_NOK;
313 }
314
315 if (time->tv.usec >= US_PER_SECOND) {
316 time->tv.sec += time->tv.usec / US_PER_SECOND;
317 time->tv.usec = time->tv.usec % US_PER_SECOND;
318 }
319
320 return LOS_OK;
321 }
322
linux_hrtimer_init(struct hrtimer * timer,clockid_t clockID,enum hrtimer_mode mode)323 void linux_hrtimer_init(struct hrtimer *timer, clockid_t clockID, enum hrtimer_mode mode)
324 {
325 (VOID)clockID;
326 if ((timer == NULL) || (mode != HRTIMER_MODE_REL)) {
327 PRINT_ERR("The timer is NULL OR The mode is not HRTIMER_MODE_REL!\n");
328 }
329 return;
330 }
331
linux_hrtimer_create(struct hrtimer * timer,union ktime time,Handler handler)332 int linux_hrtimer_create(struct hrtimer *timer, union ktime time, Handler handler)
333 {
334 UINT32 ret;
335
336 if ((timer == NULL) || (handler == NULL)) {
337 return -1;
338 }
339
340 ret = CheckTime(&time);
341 if (ret != LOS_OK) {
342 return -1;
343 }
344
345 timer->_softexpires.tv.sec = time.tv.sec;
346 timer->_softexpires.tv.usec = time.tv.usec;
347 timer->function = handler;
348
349 return 0;
350 }
351
HandleNodeInit(union ktime time,struct hrtimer * timer)352 STATIC struct handler_list_node *HandleNodeInit(union ktime time, struct hrtimer *timer)
353 {
354 struct handler_list_node *handler = NULL;
355 handler = (struct handler_list_node *)LOS_MemAlloc(m_aucSysMem0, sizeof(struct handler_list_node));
356 if (handler == NULL) {
357 return NULL;
358 }
359 handler->_softexpires = time;
360 handler->pfnHandler = timer->function;
361 handler->pstNext = NULL;
362 return handler;
363 }
364
linux_hrtimer_start(struct hrtimer * timer,union ktime time,const enum hrtimer_mode mode)365 int linux_hrtimer_start(struct hrtimer *timer, union ktime time, const enum hrtimer_mode mode)
366 {
367 struct hrtimer_list_node *hrtimer = NULL;
368 struct hrtimer_list_node *prevNode = NULL;
369 struct hrtimer_list_node *curNode = NULL;
370 struct handler_list_node *handler = NULL;
371 struct handler_list_node *prevHandler = NULL;
372 struct handler_list_node *curHandler = NULL;
373 UINT32 intSave;
374
375 if ((timer == NULL) || (mode != HRTIMER_MODE_REL)) {
376 return -1;
377 }
378
379 if (CheckTime(&time) != LOS_OK) {
380 return -1;
381 }
382
383 LOS_SpinLockSave(&g_hrtimerSpin, &intSave);
384 GetHrtimerNodePosition(timer, &prevNode, &curNode);
385 if (curNode == NULL) {
386 LOS_SpinUnlockRestore(&g_hrtimerSpin, intSave);
387 if (timer->function == NULL) {
388 return -1;
389 }
390 hrtimer = HrtimerListNodeInit(time);
391 if (hrtimer == NULL) {
392 return -1;
393 }
394 handler = HandleNodeInit(time, timer);
395 if (handler == NULL) {
396 (VOID)LOS_MemFree(m_aucSysMem0, hrtimer);
397 return -1;
398 }
399
400 LOS_SpinLockSave(&g_hrtimerSpin, &intSave);
401 HrtimerNodeAdd(hrtimer, handler);
402 LOS_SpinUnlockRestore(&g_hrtimerSpin, intSave);
403 return 0;
404 } else {
405 GetHandlerNodePosition(timer, curNode, &prevHandler, &curHandler);
406 if (ChangeNodePosition(prevNode, curNode, prevHandler, curHandler, time) == LOS_OK) {
407 LOS_SpinUnlockRestore(&g_hrtimerSpin, intSave);
408 return 1;
409 }
410 }
411
412 LOS_SpinUnlockRestore(&g_hrtimerSpin, intSave);
413 return -1;
414 }
415
linux_hrtimer_cancel(struct hrtimer * timer)416 int linux_hrtimer_cancel(struct hrtimer *timer)
417 {
418 struct hrtimer_list_node *prevNode = NULL;
419 struct hrtimer_list_node *curNode = NULL;
420 UINT32 intSave;
421
422 if (timer == NULL) {
423 return -1;
424 }
425
426 LOS_SpinLockSave(&g_hrtimerSpin, &intSave);
427 curNode = g_hrtimerList;
428 if (curNode == NULL) {
429 LOS_SpinUnlockRestore(&g_hrtimerSpin, intSave);
430 return 0;
431 }
432
433 GetHrtimerNodePosition(timer, &prevNode, &curNode);
434
435 if (curNode == NULL) {
436 LOS_SpinUnlockRestore(&g_hrtimerSpin, intSave);
437 return 0;
438 } else if (curNode == g_hrtimerList) {
439 CancelHandlerNode(timer, curNode);
440
441 if (curNode->HandlerHead == NULL) {
442 g_hrtimerList = curNode->pstNext;
443 if (g_hrtimerList != NULL) {
444 g_hrtimerList->set_time_reload += HrtimerClockValueGet();
445 HrtimerClockStop();
446 HrtimerClockStart(g_hrtimerList->set_time_reload);
447 } else {
448 HrtimerClockStop();
449 }
450 curNode->pstNext = NULL;
451 (VOID)LOS_MemFree(m_aucSysMem0, curNode);
452 }
453 } else {
454 CancelHandlerNode(timer, curNode);
455
456 if (curNode->HandlerHead == NULL) {
457 if (curNode->pstNext == NULL) {
458 prevNode->pstNext = NULL;
459 } else {
460 prevNode->pstNext = curNode->pstNext;
461 prevNode->pstNext->set_time_reload += curNode->set_time_reload;
462 }
463 curNode->pstNext = NULL;
464 (VOID)LOS_MemFree(m_aucSysMem0, curNode);
465 }
466 }
467 LOS_SpinUnlockRestore(&g_hrtimerSpin, intSave);
468 return 1;
469 }
470
linux_hrtimer_forward(struct hrtimer * timer,union ktime interval)471 u64 linux_hrtimer_forward(struct hrtimer *timer, union ktime interval)
472 {
473 struct hrtimer_list_node *prevNode = NULL;
474 struct hrtimer_list_node *curNode = NULL;
475 struct handler_list_node *prevHandler = NULL;
476 struct handler_list_node *curHandler = NULL;
477 UINT32 intSave;
478 UINT32 ret;
479
480 if (timer == NULL) {
481 return 0;
482 }
483
484 ret = CheckTime(&interval);
485 if (ret != LOS_OK) {
486 return 0;
487 }
488
489 LOS_SpinLockSave(&g_hrtimerSpin, &intSave);
490 GetHrtimerNodePosition(timer, &prevNode, &curNode);
491 if (curNode == NULL) {
492 LOS_SpinUnlockRestore(&g_hrtimerSpin, intSave);
493 return 0;
494 }
495 GetHandlerNodePosition(timer, curNode, &prevHandler, &curHandler);
496 timer->_softexpires = interval;
497 ret = ChangeNodePosition(prevNode, curNode, prevHandler, curHandler, interval);
498 LOS_SpinUnlockRestore(&g_hrtimerSpin, intSave);
499 if (ret != LOS_OK) {
500 return 0;
501 } else {
502 return (u64)((interval.tv.sec * US_PER_SECOND + interval.tv.usec) * HRTIMER_PERUS);
503 }
504 }
505
linux_hrtimer_is_queued(struct hrtimer * timer)506 int linux_hrtimer_is_queued(struct hrtimer *timer)
507 {
508 struct hrtimer_list_node *curNode = NULL;
509 struct handler_list_node *handler = NULL;
510 INT32 ret = LOS_NOK;
511 UINT32 intSave;
512
513 if (timer == NULL) {
514 return -1;
515 }
516
517 LOS_SpinLockSave(&g_hrtimerSpin, &intSave);
518 curNode = g_hrtimerList;
519 while (curNode != NULL) {
520 handler = curNode->HandlerHead;
521 while (handler != NULL) {
522 if (handler->pfnHandler == timer->function) {
523 break;
524 }
525 handler = handler->pstNext;
526 }
527
528 if ((handler != NULL) && (handler->pfnHandler == timer->function) &&
529 (handler->_softexpires.tv.sec == timer->_softexpires.tv.sec) &&
530 (handler->_softexpires.tv.usec == timer->_softexpires.tv.usec)) {
531 ret = LOS_OK;
532 break;
533 }
534 curNode = curNode->pstNext;
535 }
536 LOS_SpinUnlockRestore(&g_hrtimerSpin, intSave);
537
538 return ret;
539 }
540
HrtimersInit(VOID)541 UINT32 HrtimersInit(VOID)
542 {
543 UINT32 ret;
544
545 g_hrtimerList = NULL;
546 /* Initialize the timer */
547 HrtimerClockInit();
548 /* Create interrupt of the timer */
549 ret = LOS_HwiCreate(NUM_HAL_INTERRUPT_HRTIMER, 0, 0, HrtimerListScan, 0);
550 if (ret != LOS_OK) {
551 return LOS_NOK;
552 }
553 HalIrqUnmask(NUM_HAL_INTERRUPT_HRTIMER);
554
555 return LOS_OK;
556 }
557
558 LOS_MODULE_INIT(HrtimersInit, LOS_INIT_LEVEL_PLATFROM_EARLY);
559