1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2022 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 "los_swtmr_pri.h"
33 #include "los_init.h"
34 #include "los_process_pri.h"
35 #include "los_queue_pri.h"
36 #include "los_sched_pri.h"
37 #include "los_sortlink_pri.h"
38 #include "los_task_pri.h"
39 #include "los_hook.h"
40
41 #ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
42 #if (LOSCFG_BASE_CORE_SWTMR_LIMIT <= 0)
43 #error "swtmr maxnum cannot be zero"
44 #endif /* LOSCFG_BASE_CORE_SWTMR_LIMIT <= 0 */
45
46 STATIC INLINE VOID SwtmrDelete(SWTMR_CTRL_S *swtmr);
47 STATIC INLINE UINT64 SwtmrToStart(SWTMR_CTRL_S *swtmr, UINT16 cpuid);
48
49 LITE_OS_SEC_BSS SWTMR_CTRL_S *g_swtmrCBArray = NULL; /* First address in Timer memory space */
50 LITE_OS_SEC_BSS UINT8 *g_swtmrHandlerPool = NULL; /* Pool of Swtmr Handler */
51 LITE_OS_SEC_BSS LOS_DL_LIST g_swtmrFreeList; /* Free list of Software Timer */
52
53 /* spinlock for swtmr module, only available on SMP mode */
54 LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_swtmrSpin);
55 #define SWTMR_LOCK(state) LOS_SpinLockSave(&g_swtmrSpin, &(state))
56 #define SWTMR_UNLOCK(state) LOS_SpinUnlockRestore(&g_swtmrSpin, (state))
57
58 typedef struct {
59 SortLinkAttribute swtmrSortLink;
60 LosTaskCB *swtmrTask; /* software timer task id */
61 LOS_DL_LIST swtmrHandlerQueue; /* software timer timeout queue id */
62 } SwtmrRunqueue;
63
64 STATIC SwtmrRunqueue g_swtmrRunqueue[LOSCFG_KERNEL_CORE_NUM];
65
66 #ifdef LOSCFG_SWTMR_DEBUG
67 #define OS_SWTMR_PERIOD_TO_CYCLE(period) (((UINT64)(period) * OS_NS_PER_TICK) / OS_NS_PER_CYCLE)
68 STATIC SwtmrDebugData *g_swtmrDebugData = NULL;
69
OsSwtmrDebugDataUsed(UINT32 swtmrID)70 BOOL OsSwtmrDebugDataUsed(UINT32 swtmrID)
71 {
72 if (swtmrID > LOSCFG_BASE_CORE_SWTMR_LIMIT) {
73 return FALSE;
74 }
75
76 return g_swtmrDebugData[swtmrID].swtmrUsed;
77 }
78
OsSwtmrDebugDataGet(UINT32 swtmrID,SwtmrDebugData * data,UINT32 len,UINT8 * mode)79 UINT32 OsSwtmrDebugDataGet(UINT32 swtmrID, SwtmrDebugData *data, UINT32 len, UINT8 *mode)
80 {
81 UINT32 intSave;
82 errno_t ret;
83
84 if ((swtmrID > LOSCFG_BASE_CORE_SWTMR_LIMIT) || (data == NULL) ||
85 (mode == NULL) || (len < sizeof(SwtmrDebugData))) {
86 return LOS_NOK;
87 }
88
89 SWTMR_CTRL_S *swtmr = &g_swtmrCBArray[swtmrID];
90 SWTMR_LOCK(intSave);
91 ret = memcpy_s(data, len, &g_swtmrDebugData[swtmrID], sizeof(SwtmrDebugData));
92 *mode = swtmr->ucMode;
93 SWTMR_UNLOCK(intSave);
94 if (ret != EOK) {
95 return LOS_NOK;
96 }
97 return LOS_OK;
98 }
99 #endif
100
SwtmrDebugDataInit(VOID)101 STATIC VOID SwtmrDebugDataInit(VOID)
102 {
103 #ifdef LOSCFG_SWTMR_DEBUG
104 UINT32 size = sizeof(SwtmrDebugData) * LOSCFG_BASE_CORE_SWTMR_LIMIT;
105 g_swtmrDebugData = (SwtmrDebugData *)LOS_MemAlloc(m_aucSysMem1, size);
106 if (g_swtmrDebugData == NULL) {
107 PRINT_ERR("SwtmrDebugDataInit malloc failed!\n");
108 return;
109 }
110 (VOID)memset_s(g_swtmrDebugData, size, 0, size);
111 #endif
112 }
113
SwtmrDebugDataUpdate(SWTMR_CTRL_S * swtmr,UINT32 ticks,UINT32 times)114 STATIC INLINE VOID SwtmrDebugDataUpdate(SWTMR_CTRL_S *swtmr, UINT32 ticks, UINT32 times)
115 {
116 #ifdef LOSCFG_SWTMR_DEBUG
117 SwtmrDebugData *data = &g_swtmrDebugData[swtmr->usTimerID];
118 if (data->period != ticks) {
119 (VOID)memset_s(&data->base, sizeof(SwtmrDebugBase), 0, sizeof(SwtmrDebugBase));
120 data->period = ticks;
121 }
122 data->base.startTime = swtmr->startTime;
123 data->base.times += times;
124 #endif
125 }
126
SwtmrDebugDataStart(SWTMR_CTRL_S * swtmr,UINT16 cpuid)127 STATIC INLINE VOID SwtmrDebugDataStart(SWTMR_CTRL_S *swtmr, UINT16 cpuid)
128 {
129 #ifdef LOSCFG_SWTMR_DEBUG
130 SwtmrDebugData *data = &g_swtmrDebugData[swtmr->usTimerID];
131 data->swtmrUsed = TRUE;
132 data->handler = swtmr->pfnHandler;
133 data->cpuid = cpuid;
134 #endif
135 }
136
SwtmrDebugWaitTimeCalculate(UINT32 swtmrID,SwtmrHandlerItemPtr swtmrHandler)137 STATIC INLINE VOID SwtmrDebugWaitTimeCalculate(UINT32 swtmrID, SwtmrHandlerItemPtr swtmrHandler)
138 {
139 #ifdef LOSCFG_SWTMR_DEBUG
140 SwtmrDebugBase *data = &g_swtmrDebugData[swtmrID].base;
141 swtmrHandler->swtmrID = swtmrID;
142 UINT64 currTime = OsGetCurrSchedTimeCycle();
143 UINT64 waitTime = currTime - data->startTime;
144 data->waitTime += waitTime;
145 if (waitTime > data->waitTimeMax) {
146 data->waitTimeMax = waitTime;
147 }
148 data->readyStartTime = currTime;
149 data->waitCount++;
150 #endif
151 }
152
SwtmrDebugDataClear(UINT32 swtmrID)153 STATIC INLINE VOID SwtmrDebugDataClear(UINT32 swtmrID)
154 {
155 #ifdef LOSCFG_SWTMR_DEBUG
156 (VOID)memset_s(&g_swtmrDebugData[swtmrID], sizeof(SwtmrDebugData), 0, sizeof(SwtmrDebugData));
157 #endif
158 }
159
SwtmrHandler(SwtmrHandlerItemPtr swtmrHandle)160 STATIC INLINE VOID SwtmrHandler(SwtmrHandlerItemPtr swtmrHandle)
161 {
162 #ifdef LOSCFG_SWTMR_DEBUG
163 UINT32 intSave;
164 SwtmrDebugBase *data = &g_swtmrDebugData[swtmrHandle->swtmrID].base;
165 UINT64 startTime = OsGetCurrSchedTimeCycle();
166 #endif
167 swtmrHandle->handler(swtmrHandle->arg);
168 #ifdef LOSCFG_SWTMR_DEBUG
169 UINT64 runTime = OsGetCurrSchedTimeCycle() - startTime;
170 SWTMR_LOCK(intSave);
171 data->runTime += runTime;
172 if (runTime > data->runTimeMax) {
173 data->runTimeMax = runTime;
174 }
175 runTime = startTime - data->readyStartTime;
176 data->readyTime += runTime;
177 if (runTime > data->readyTimeMax) {
178 data->readyTimeMax = runTime;
179 }
180 data->runCount++;
181 SWTMR_UNLOCK(intSave);
182 #endif
183 }
184
SwtmrWake(SwtmrRunqueue * srq,UINT64 startTime,SortLinkList * sortList)185 STATIC INLINE VOID SwtmrWake(SwtmrRunqueue *srq, UINT64 startTime, SortLinkList *sortList)
186 {
187 UINT32 intSave;
188 SWTMR_CTRL_S *swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);
189 SwtmrHandlerItemPtr swtmrHandler = (SwtmrHandlerItemPtr)LOS_MemboxAlloc(g_swtmrHandlerPool);
190 LOS_ASSERT(swtmrHandler != NULL);
191
192 OsHookCall(LOS_HOOK_TYPE_SWTMR_EXPIRED, swtmr);
193
194 SWTMR_LOCK(intSave);
195 swtmrHandler->handler = swtmr->pfnHandler;
196 swtmrHandler->arg = swtmr->uwArg;
197 LOS_ListTailInsert(&srq->swtmrHandlerQueue, &swtmrHandler->node);
198 SwtmrDebugWaitTimeCalculate(swtmr->usTimerID, swtmrHandler);
199
200 if (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) {
201 SwtmrDelete(swtmr);
202
203 if (swtmr->usTimerID < (OS_SWTMR_MAX_TIMERID - LOSCFG_BASE_CORE_SWTMR_LIMIT)) {
204 swtmr->usTimerID += LOSCFG_BASE_CORE_SWTMR_LIMIT;
205 } else {
206 swtmr->usTimerID %= LOSCFG_BASE_CORE_SWTMR_LIMIT;
207 }
208 } else if (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE) {
209 swtmr->ucState = OS_SWTMR_STATUS_CREATED;
210 } else {
211 swtmr->uwOverrun++;
212 swtmr->startTime = startTime;
213 (VOID)SwtmrToStart(swtmr, ArchCurrCpuid());
214 }
215
216 SWTMR_UNLOCK(intSave);
217 }
218
ScanSwtmrTimeList(SwtmrRunqueue * srq)219 STATIC INLINE VOID ScanSwtmrTimeList(SwtmrRunqueue *srq)
220 {
221 UINT32 intSave;
222 SortLinkAttribute *swtmrSortLink = &srq->swtmrSortLink;
223 LOS_DL_LIST *listObject = &swtmrSortLink->sortLink;
224
225 /*
226 * it needs to be carefully coped with, since the swtmr is in specific sortlink
227 * while other cores still has the chance to process it, like stop the timer.
228 */
229 LOS_SpinLockSave(&swtmrSortLink->spinLock, &intSave);
230
231 if (LOS_ListEmpty(listObject)) {
232 LOS_SpinUnlockRestore(&swtmrSortLink->spinLock, intSave);
233 return;
234 }
235 SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
236
237 UINT64 currTime = OsGetCurrSchedTimeCycle();
238 while (sortList->responseTime <= currTime) {
239 sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
240 UINT64 startTime = GET_SORTLIST_VALUE(sortList);
241 OsDeleteNodeSortLink(swtmrSortLink, sortList);
242 LOS_SpinUnlockRestore(&swtmrSortLink->spinLock, intSave);
243
244 SwtmrWake(srq, startTime, sortList);
245
246 LOS_SpinLockSave(&swtmrSortLink->spinLock, &intSave);
247 if (LOS_ListEmpty(listObject)) {
248 break;
249 }
250
251 sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
252 }
253
254 LOS_SpinUnlockRestore(&swtmrSortLink->spinLock, intSave);
255 return;
256 }
257
SwtmrTask(VOID)258 STATIC VOID SwtmrTask(VOID)
259 {
260 SwtmrHandlerItem swtmrHandle;
261 UINT32 intSave;
262 UINT64 waitTime;
263
264 SwtmrRunqueue *srq = &g_swtmrRunqueue[ArchCurrCpuid()];
265 LOS_DL_LIST *head = &srq->swtmrHandlerQueue;
266 for (;;) {
267 waitTime = OsSortLinkGetNextExpireTime(OsGetCurrSchedTimeCycle(), &srq->swtmrSortLink);
268 if (waitTime != 0) {
269 SCHEDULER_LOCK(intSave);
270 srq->swtmrTask->ops->delay(srq->swtmrTask, waitTime);
271 OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTODELAYEDLIST, srq->swtmrTask);
272 SCHEDULER_UNLOCK(intSave);
273 }
274
275 ScanSwtmrTimeList(srq);
276
277 while (!LOS_ListEmpty(head)) {
278 SwtmrHandlerItemPtr swtmrHandlePtr = LOS_DL_LIST_ENTRY(LOS_DL_LIST_FIRST(head), SwtmrHandlerItem, node);
279 LOS_ListDelete(&swtmrHandlePtr->node);
280
281 (VOID)memcpy_s(&swtmrHandle, sizeof(SwtmrHandlerItem), swtmrHandlePtr, sizeof(SwtmrHandlerItem));
282 (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandlePtr);
283 SwtmrHandler(&swtmrHandle);
284 }
285 }
286 }
287
SwtmrTaskCreate(UINT16 cpuid,UINT32 * swtmrTaskID)288 STATIC UINT32 SwtmrTaskCreate(UINT16 cpuid, UINT32 *swtmrTaskID)
289 {
290 UINT32 ret;
291 TSK_INIT_PARAM_S swtmrTask;
292
293 (VOID)memset_s(&swtmrTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
294 swtmrTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SwtmrTask;
295 swtmrTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
296 swtmrTask.pcName = "Swt_Task";
297 swtmrTask.usTaskPrio = 0;
298 swtmrTask.uwResved = LOS_TASK_STATUS_DETACHED;
299 #ifdef LOSCFG_KERNEL_SMP
300 swtmrTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(cpuid);
301 #endif
302 ret = LOS_TaskCreate(swtmrTaskID, &swtmrTask);
303 if (ret == LOS_OK) {
304 OS_TCB_FROM_TID(*swtmrTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;
305 }
306
307 return ret;
308 }
309
OsSwtmrTaskIDGetByCpuid(UINT16 cpuid)310 UINT32 OsSwtmrTaskIDGetByCpuid(UINT16 cpuid)
311 {
312 return g_swtmrRunqueue[cpuid].swtmrTask->taskID;
313 }
314
OsIsSwtmrTask(const LosTaskCB * taskCB)315 BOOL OsIsSwtmrTask(const LosTaskCB *taskCB)
316 {
317 if (taskCB->taskEntry == (TSK_ENTRY_FUNC)SwtmrTask) {
318 return TRUE;
319 }
320 return FALSE;
321 }
322
OsSwtmrRecycle(UINT32 processID)323 LITE_OS_SEC_TEXT_INIT VOID OsSwtmrRecycle(UINT32 processID)
324 {
325 for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++) {
326 if (g_swtmrCBArray[index].uwOwnerPid == processID) {
327 LOS_SwtmrDelete(index);
328 }
329 }
330 }
331
SwtmrBaseInit(VOID)332 STATIC UINT32 SwtmrBaseInit(VOID)
333 {
334 UINT32 ret;
335 UINT32 size = sizeof(SWTMR_CTRL_S) * LOSCFG_BASE_CORE_SWTMR_LIMIT;
336 SWTMR_CTRL_S *swtmr = (SWTMR_CTRL_S *)LOS_MemAlloc(m_aucSysMem0, size); /* system resident resource */
337 if (swtmr == NULL) {
338 return LOS_ERRNO_SWTMR_NO_MEMORY;
339 }
340
341 (VOID)memset_s(swtmr, size, 0, size);
342 g_swtmrCBArray = swtmr;
343 LOS_ListInit(&g_swtmrFreeList);
344 for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) {
345 swtmr->usTimerID = index;
346 LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);
347 }
348
349 size = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE);
350 g_swtmrHandlerPool = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, size); /* system resident resource */
351 if (g_swtmrHandlerPool == NULL) {
352 return LOS_ERRNO_SWTMR_NO_MEMORY;
353 }
354
355 ret = LOS_MemboxInit(g_swtmrHandlerPool, size, sizeof(SwtmrHandlerItem));
356 if (ret != LOS_OK) {
357 return LOS_ERRNO_SWTMR_HANDLER_POOL_NO_MEM;
358 }
359
360 for (UINT16 index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
361 SwtmrRunqueue *srq = &g_swtmrRunqueue[index];
362 /* The linked list of all cores must be initialized at core 0 startup for load balancing */
363 OsSortLinkInit(&srq->swtmrSortLink);
364 LOS_ListInit(&srq->swtmrHandlerQueue);
365 srq->swtmrTask = NULL;
366 }
367
368 SwtmrDebugDataInit();
369
370 return LOS_OK;
371 }
372
OsSwtmrInit(VOID)373 LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrInit(VOID)
374 {
375 UINT32 ret;
376 UINT32 cpuid = ArchCurrCpuid();
377 UINT32 swtmrTaskID;
378
379 if (cpuid == 0) {
380 ret = SwtmrBaseInit();
381 if (ret != LOS_OK) {
382 goto ERROR;
383 }
384 }
385
386 ret = SwtmrTaskCreate(cpuid, &swtmrTaskID);
387 if (ret != LOS_OK) {
388 ret = LOS_ERRNO_SWTMR_TASK_CREATE_FAILED;
389 goto ERROR;
390 }
391
392 SwtmrRunqueue *srq = &g_swtmrRunqueue[cpuid];
393 srq->swtmrTask = OsGetTaskCB(swtmrTaskID);
394 return LOS_OK;
395
396 ERROR:
397 PRINT_ERR("OsSwtmrInit error! ret = %u\n", ret);
398 (VOID)LOS_MemFree(m_aucSysMem0, g_swtmrCBArray);
399 g_swtmrCBArray = NULL;
400 (VOID)LOS_MemFree(m_aucSysMem1, g_swtmrHandlerPool);
401 g_swtmrHandlerPool = NULL;
402 return ret;
403 }
404
405 #ifdef LOSCFG_KERNEL_SMP
FindIdleSwtmrRunqueue(UINT16 * idleCpuid)406 STATIC INLINE VOID FindIdleSwtmrRunqueue(UINT16 *idleCpuid)
407 {
408 SwtmrRunqueue *idleRq = &g_swtmrRunqueue[0];
409 UINT32 nodeNum = OsGetSortLinkNodeNum(&idleRq->swtmrSortLink);
410 UINT16 cpuid = 1;
411 do {
412 SwtmrRunqueue *srq = &g_swtmrRunqueue[cpuid];
413 UINT32 temp = OsGetSortLinkNodeNum(&srq->swtmrSortLink);
414 if (nodeNum > temp) {
415 *idleCpuid = cpuid;
416 nodeNum = temp;
417 }
418 cpuid++;
419 } while (cpuid < LOSCFG_KERNEL_CORE_NUM);
420 }
421 #endif
422
AddSwtmr2TimeList(SortLinkList * node,UINT64 responseTime,UINT16 cpuid)423 STATIC INLINE VOID AddSwtmr2TimeList(SortLinkList *node, UINT64 responseTime, UINT16 cpuid)
424 {
425 SwtmrRunqueue *srq = &g_swtmrRunqueue[cpuid];
426 OsAdd2SortLink(&srq->swtmrSortLink, node, responseTime, cpuid);
427 }
428
DeSwtmrFromTimeList(SortLinkList * node)429 STATIC INLINE VOID DeSwtmrFromTimeList(SortLinkList *node)
430 {
431 #ifdef LOSCFG_KERNEL_SMP
432 UINT16 cpuid = OsGetSortLinkNodeCpuid(node);
433 #else
434 UINT16 cpuid = 0;
435 #endif
436 SwtmrRunqueue *srq = &g_swtmrRunqueue[cpuid];
437 OsDeleteFromSortLink(&srq->swtmrSortLink, node);
438 return;
439 }
440
SwtmrAdjustCheck(UINT16 cpuid,UINT64 responseTime)441 STATIC VOID SwtmrAdjustCheck(UINT16 cpuid, UINT64 responseTime)
442 {
443 UINT32 ret;
444 UINT32 intSave;
445 SwtmrRunqueue *srq = &g_swtmrRunqueue[cpuid];
446 SCHEDULER_LOCK(intSave);
447 if ((srq->swtmrTask == NULL) || !OsTaskIsBlocked(srq->swtmrTask)) {
448 SCHEDULER_UNLOCK(intSave);
449 return;
450 }
451
452 if (responseTime >= GET_SORTLIST_VALUE(&srq->swtmrTask->sortList)) {
453 SCHEDULER_UNLOCK(intSave);
454 return;
455 }
456
457 ret = OsSchedTimeoutQueueAdjust(srq->swtmrTask, responseTime);
458 SCHEDULER_UNLOCK(intSave);
459 if (ret != LOS_OK) {
460 return;
461 }
462
463 if (cpuid == ArchCurrCpuid()) {
464 OsSchedExpireTimeUpdate();
465 } else {
466 LOS_MpSchedule(CPUID_TO_AFFI_MASK(cpuid));
467 }
468 }
469
SwtmrToStart(SWTMR_CTRL_S * swtmr,UINT16 cpuid)470 STATIC UINT64 SwtmrToStart(SWTMR_CTRL_S *swtmr, UINT16 cpuid)
471 {
472 UINT32 ticks;
473 UINT32 times = 0;
474
475 if ((swtmr->uwOverrun == 0) && ((swtmr->ucMode == LOS_SWTMR_MODE_ONCE) ||
476 (swtmr->ucMode == LOS_SWTMR_MODE_OPP) ||
477 (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE))) {
478 ticks = swtmr->uwExpiry;
479 } else {
480 ticks = swtmr->uwInterval;
481 }
482 swtmr->ucState = OS_SWTMR_STATUS_TICKING;
483
484 UINT64 period = (UINT64)ticks * OS_CYCLE_PER_TICK;
485 UINT64 responseTime = swtmr->startTime + period;
486 UINT64 currTime = OsGetCurrSchedTimeCycle();
487 if (responseTime < currTime) {
488 times = (UINT32)((currTime - swtmr->startTime) / period);
489 swtmr->startTime += times * period;
490 responseTime = swtmr->startTime + period;
491 PRINT_WARN("Swtmr already timeout! SwtmrID: %u\n", swtmr->usTimerID);
492 }
493
494 AddSwtmr2TimeList(&swtmr->stSortList, responseTime, cpuid);
495 SwtmrDebugDataUpdate(swtmr, ticks, times);
496 return responseTime;
497 }
498
499 /*
500 * Description: Start Software Timer
501 * Input : swtmr --- Need to start software timer
502 */
SwtmrStart(SWTMR_CTRL_S * swtmr)503 STATIC INLINE VOID SwtmrStart(SWTMR_CTRL_S *swtmr)
504 {
505 UINT64 responseTime;
506 UINT16 idleCpu = 0;
507 #ifdef LOSCFG_KERNEL_SMP
508 FindIdleSwtmrRunqueue(&idleCpu);
509 #endif
510 swtmr->startTime = OsGetCurrSchedTimeCycle();
511 responseTime = SwtmrToStart(swtmr, idleCpu);
512
513 SwtmrDebugDataStart(swtmr, idleCpu);
514
515 SwtmrAdjustCheck(idleCpu, responseTime);
516 }
517
518 /*
519 * Description: Delete Software Timer
520 * Input : swtmr --- Need to delete software timer, When using, Ensure that it can't be NULL.
521 */
SwtmrDelete(SWTMR_CTRL_S * swtmr)522 STATIC INLINE VOID SwtmrDelete(SWTMR_CTRL_S *swtmr)
523 {
524 /* insert to free list */
525 LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);
526 swtmr->ucState = OS_SWTMR_STATUS_UNUSED;
527 swtmr->uwOwnerPid = 0;
528
529 SwtmrDebugDataClear(swtmr->usTimerID);
530 }
531
SwtmrRestart(UINT64 startTime,SortLinkList * sortList,UINT16 cpuid)532 STATIC INLINE VOID SwtmrRestart(UINT64 startTime, SortLinkList *sortList, UINT16 cpuid)
533 {
534 UINT32 intSave;
535
536 SWTMR_CTRL_S *swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);
537 SWTMR_LOCK(intSave);
538 swtmr->startTime = startTime;
539 (VOID)SwtmrToStart(swtmr, cpuid);
540 SWTMR_UNLOCK(intSave);
541 }
542
OsSwtmrResponseTimeReset(UINT64 startTime)543 VOID OsSwtmrResponseTimeReset(UINT64 startTime)
544 {
545 UINT16 cpuid = ArchCurrCpuid();
546 SortLinkAttribute *swtmrSortLink = &g_swtmrRunqueue[cpuid].swtmrSortLink;
547 LOS_DL_LIST *listHead = &swtmrSortLink->sortLink;
548 LOS_DL_LIST *listNext = listHead->pstNext;
549
550 LOS_SpinLock(&swtmrSortLink->spinLock);
551 while (listNext != listHead) {
552 SortLinkList *sortList = LOS_DL_LIST_ENTRY(listNext, SortLinkList, sortLinkNode);
553 OsDeleteNodeSortLink(swtmrSortLink, sortList);
554 LOS_SpinUnlock(&swtmrSortLink->spinLock);
555
556 SwtmrRestart(startTime, sortList, cpuid);
557
558 LOS_SpinLock(&swtmrSortLink->spinLock);
559 listNext = listNext->pstNext;
560 }
561 LOS_SpinUnlock(&swtmrSortLink->spinLock);
562 }
563
SwtmrRunqueueFind(SortLinkAttribute * swtmrSortLink,SCHED_TL_FIND_FUNC checkFunc,UINTPTR arg)564 STATIC INLINE BOOL SwtmrRunqueueFind(SortLinkAttribute *swtmrSortLink, SCHED_TL_FIND_FUNC checkFunc, UINTPTR arg)
565 {
566 LOS_DL_LIST *listObject = &swtmrSortLink->sortLink;
567 LOS_DL_LIST *list = listObject->pstNext;
568
569 LOS_SpinLock(&swtmrSortLink->spinLock);
570 while (list != listObject) {
571 SortLinkList *listSorted = LOS_DL_LIST_ENTRY(list, SortLinkList, sortLinkNode);
572 if (checkFunc((UINTPTR)listSorted, arg)) {
573 LOS_SpinUnlock(&swtmrSortLink->spinLock);
574 return TRUE;
575 }
576 list = list->pstNext;
577 }
578
579 LOS_SpinUnlock(&swtmrSortLink->spinLock);
580 return FALSE;
581 }
582
SwtmrTimeListFind(SCHED_TL_FIND_FUNC checkFunc,UINTPTR arg)583 STATIC BOOL SwtmrTimeListFind(SCHED_TL_FIND_FUNC checkFunc, UINTPTR arg)
584 {
585 for (UINT16 cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) {
586 SortLinkAttribute *swtmrSortLink = &g_swtmrRunqueue[cpuid].swtmrSortLink;
587 if (SwtmrRunqueueFind(swtmrSortLink, checkFunc, arg)) {
588 return TRUE;
589 }
590 }
591 return FALSE;
592 }
593
OsSwtmrWorkQueueFind(SCHED_TL_FIND_FUNC checkFunc,UINTPTR arg)594 BOOL OsSwtmrWorkQueueFind(SCHED_TL_FIND_FUNC checkFunc, UINTPTR arg)
595 {
596 UINT32 intSave;
597
598 SWTMR_LOCK(intSave);
599 BOOL find = SwtmrTimeListFind(checkFunc, arg);
600 SWTMR_UNLOCK(intSave);
601 return find;
602 }
603
604 /*
605 * Description: Get next timeout
606 * Return : Count of the Timer list
607 */
OsSwtmrGetNextTimeout(VOID)608 LITE_OS_SEC_TEXT UINT32 OsSwtmrGetNextTimeout(VOID)
609 {
610 UINT64 currTime = OsGetCurrSchedTimeCycle();
611 SwtmrRunqueue *srq = &g_swtmrRunqueue[ArchCurrCpuid()];
612 UINT64 time = (OsSortLinkGetNextExpireTime(currTime, &srq->swtmrSortLink) / OS_CYCLE_PER_TICK);
613 if (time > OS_INVALID_VALUE) {
614 time = OS_INVALID_VALUE;
615 }
616 return (UINT32)time;
617 }
618
619 /*
620 * Description: Stop of Software Timer interface
621 * Input : swtmr --- the software timer control handler
622 */
SwtmrStop(SWTMR_CTRL_S * swtmr)623 STATIC VOID SwtmrStop(SWTMR_CTRL_S *swtmr)
624 {
625 swtmr->ucState = OS_SWTMR_STATUS_CREATED;
626 swtmr->uwOverrun = 0;
627
628 DeSwtmrFromTimeList(&swtmr->stSortList);
629 }
630
631 /*
632 * Description: Get next software timer expiretime
633 * Input : swtmr --- the software timer control handler
634 */
OsSwtmrTimeGet(const SWTMR_CTRL_S * swtmr)635 LITE_OS_SEC_TEXT STATIC UINT32 OsSwtmrTimeGet(const SWTMR_CTRL_S *swtmr)
636 {
637 UINT64 currTime = OsGetCurrSchedTimeCycle();
638 UINT64 time = (OsSortLinkGetTargetExpireTime(currTime, &swtmr->stSortList) / OS_CYCLE_PER_TICK);
639 if (time > OS_INVALID_VALUE) {
640 time = OS_INVALID_VALUE;
641 }
642 return (UINT32)time;
643 }
644
LOS_SwtmrCreate(UINT32 interval,UINT8 mode,SWTMR_PROC_FUNC handler,UINT16 * swtmrID,UINTPTR arg)645 LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval,
646 UINT8 mode,
647 SWTMR_PROC_FUNC handler,
648 UINT16 *swtmrID,
649 UINTPTR arg)
650 {
651 SWTMR_CTRL_S *swtmr = NULL;
652 UINT32 intSave;
653 SortLinkList *sortList = NULL;
654
655 if (interval == 0) {
656 return LOS_ERRNO_SWTMR_INTERVAL_NOT_SUITED;
657 }
658
659 if ((mode != LOS_SWTMR_MODE_ONCE) && (mode != LOS_SWTMR_MODE_PERIOD) &&
660 (mode != LOS_SWTMR_MODE_NO_SELFDELETE)) {
661 return LOS_ERRNO_SWTMR_MODE_INVALID;
662 }
663
664 if (handler == NULL) {
665 return LOS_ERRNO_SWTMR_PTR_NULL;
666 }
667
668 if (swtmrID == NULL) {
669 return LOS_ERRNO_SWTMR_RET_PTR_NULL;
670 }
671
672 SWTMR_LOCK(intSave);
673 if (LOS_ListEmpty(&g_swtmrFreeList)) {
674 SWTMR_UNLOCK(intSave);
675 return LOS_ERRNO_SWTMR_MAXSIZE;
676 }
677
678 sortList = LOS_DL_LIST_ENTRY(g_swtmrFreeList.pstNext, SortLinkList, sortLinkNode);
679 swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);
680 LOS_ListDelete(LOS_DL_LIST_FIRST(&g_swtmrFreeList));
681 SWTMR_UNLOCK(intSave);
682
683 swtmr->uwOwnerPid = OsCurrProcessGet()->processID;
684 swtmr->pfnHandler = handler;
685 swtmr->ucMode = mode;
686 swtmr->uwOverrun = 0;
687 swtmr->uwInterval = interval;
688 swtmr->uwExpiry = interval;
689 swtmr->uwArg = arg;
690 swtmr->ucState = OS_SWTMR_STATUS_CREATED;
691 SET_SORTLIST_VALUE(&swtmr->stSortList, OS_SORT_LINK_INVALID_TIME);
692 *swtmrID = swtmr->usTimerID;
693 OsHookCall(LOS_HOOK_TYPE_SWTMR_CREATE, swtmr);
694 return LOS_OK;
695 }
696
LOS_SwtmrStart(UINT16 swtmrID)697 LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID)
698 {
699 SWTMR_CTRL_S *swtmr = NULL;
700 UINT32 intSave;
701 UINT32 ret = LOS_OK;
702 UINT16 swtmrCBID;
703
704 if (swtmrID >= OS_SWTMR_MAX_TIMERID) {
705 return LOS_ERRNO_SWTMR_ID_INVALID;
706 }
707
708 swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
709 swtmr = g_swtmrCBArray + swtmrCBID;
710
711 SWTMR_LOCK(intSave);
712 if (swtmr->usTimerID != swtmrID) {
713 SWTMR_UNLOCK(intSave);
714 return LOS_ERRNO_SWTMR_ID_INVALID;
715 }
716
717 switch (swtmr->ucState) {
718 case OS_SWTMR_STATUS_UNUSED:
719 ret = LOS_ERRNO_SWTMR_NOT_CREATED;
720 break;
721 /*
722 * If the status of swtmr is timing, it should stop the swtmr first,
723 * then start the swtmr again.
724 */
725 case OS_SWTMR_STATUS_TICKING:
726 SwtmrStop(swtmr);
727 /* fall-through */
728 case OS_SWTMR_STATUS_CREATED:
729 SwtmrStart(swtmr);
730 break;
731 default:
732 ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
733 break;
734 }
735
736 SWTMR_UNLOCK(intSave);
737 OsHookCall(LOS_HOOK_TYPE_SWTMR_START, swtmr);
738 return ret;
739 }
740
LOS_SwtmrStop(UINT16 swtmrID)741 LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID)
742 {
743 SWTMR_CTRL_S *swtmr = NULL;
744 UINT32 intSave;
745 UINT32 ret = LOS_OK;
746 UINT16 swtmrCBID;
747
748 if (swtmrID >= OS_SWTMR_MAX_TIMERID) {
749 return LOS_ERRNO_SWTMR_ID_INVALID;
750 }
751
752 swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
753 swtmr = g_swtmrCBArray + swtmrCBID;
754 SWTMR_LOCK(intSave);
755
756 if (swtmr->usTimerID != swtmrID) {
757 SWTMR_UNLOCK(intSave);
758 return LOS_ERRNO_SWTMR_ID_INVALID;
759 }
760
761 switch (swtmr->ucState) {
762 case OS_SWTMR_STATUS_UNUSED:
763 ret = LOS_ERRNO_SWTMR_NOT_CREATED;
764 break;
765 case OS_SWTMR_STATUS_CREATED:
766 ret = LOS_ERRNO_SWTMR_NOT_STARTED;
767 break;
768 case OS_SWTMR_STATUS_TICKING:
769 SwtmrStop(swtmr);
770 break;
771 default:
772 ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
773 break;
774 }
775
776 SWTMR_UNLOCK(intSave);
777 OsHookCall(LOS_HOOK_TYPE_SWTMR_STOP, swtmr);
778 return ret;
779 }
780
LOS_SwtmrTimeGet(UINT16 swtmrID,UINT32 * tick)781 LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick)
782 {
783 SWTMR_CTRL_S *swtmr = NULL;
784 UINT32 intSave;
785 UINT32 ret = LOS_OK;
786 UINT16 swtmrCBID;
787
788 if (swtmrID >= OS_SWTMR_MAX_TIMERID) {
789 return LOS_ERRNO_SWTMR_ID_INVALID;
790 }
791
792 if (tick == NULL) {
793 return LOS_ERRNO_SWTMR_TICK_PTR_NULL;
794 }
795
796 swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
797 swtmr = g_swtmrCBArray + swtmrCBID;
798 SWTMR_LOCK(intSave);
799
800 if (swtmr->usTimerID != swtmrID) {
801 SWTMR_UNLOCK(intSave);
802 return LOS_ERRNO_SWTMR_ID_INVALID;
803 }
804 switch (swtmr->ucState) {
805 case OS_SWTMR_STATUS_UNUSED:
806 ret = LOS_ERRNO_SWTMR_NOT_CREATED;
807 break;
808 case OS_SWTMR_STATUS_CREATED:
809 ret = LOS_ERRNO_SWTMR_NOT_STARTED;
810 break;
811 case OS_SWTMR_STATUS_TICKING:
812 *tick = OsSwtmrTimeGet(swtmr);
813 break;
814 default:
815 ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
816 break;
817 }
818 SWTMR_UNLOCK(intSave);
819 return ret;
820 }
821
LOS_SwtmrDelete(UINT16 swtmrID)822 LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 swtmrID)
823 {
824 SWTMR_CTRL_S *swtmr = NULL;
825 UINT32 intSave;
826 UINT32 ret = LOS_OK;
827 UINT16 swtmrCBID;
828
829 if (swtmrID >= OS_SWTMR_MAX_TIMERID) {
830 return LOS_ERRNO_SWTMR_ID_INVALID;
831 }
832
833 swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
834 swtmr = g_swtmrCBArray + swtmrCBID;
835 SWTMR_LOCK(intSave);
836
837 if (swtmr->usTimerID != swtmrID) {
838 SWTMR_UNLOCK(intSave);
839 return LOS_ERRNO_SWTMR_ID_INVALID;
840 }
841
842 switch (swtmr->ucState) {
843 case OS_SWTMR_STATUS_UNUSED:
844 ret = LOS_ERRNO_SWTMR_NOT_CREATED;
845 break;
846 case OS_SWTMR_STATUS_TICKING:
847 SwtmrStop(swtmr);
848 /* fall-through */
849 case OS_SWTMR_STATUS_CREATED:
850 SwtmrDelete(swtmr);
851 break;
852 default:
853 ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
854 break;
855 }
856
857 SWTMR_UNLOCK(intSave);
858 OsHookCall(LOS_HOOK_TYPE_SWTMR_DELETE, swtmr);
859 return ret;
860 }
861
862 #endif /* LOSCFG_BASE_CORE_SWTMR_ENABLE */
863