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