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