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 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 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 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 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 180 STATIC VOID HrtimerListScan(VOID) 181 { 182 HrtimerClockIrqClear(); 183 HrtimerHandlerRun(); 184 } 185 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 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 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 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 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 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 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 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 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 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 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 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 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 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