• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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