1 /* 2 * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: qdf_mc_timer 21 * QCA driver framework timer APIs serialized to MC thread 22 */ 23 24 /* Include Files */ 25 #include <qdf_debug_domain.h> 26 #include <qdf_mc_timer.h> 27 #include <qdf_lock.h> 28 #include "qdf_lock.h" 29 #include "qdf_list.h" 30 #include "qdf_mem.h" 31 #include <qdf_module.h> 32 #include "qdf_timer.h" 33 #include <linux/time64.h> 34 35 /* Preprocessor definitions and constants */ 36 #define LINUX_TIMER_COOKIE 0x12341234 37 #define LINUX_INVALID_TIMER_COOKIE 0xfeedface 38 #define TMR_INVALID_ID (0) 39 40 #ifdef QDF_TIMER_MULTIPLIER_FRAC 41 static uint32_t g_qdf_timer_multiplier = QDF_TIMER_MULTIPLIER_FRAC; 42 #else 43 static uint32_t g_qdf_timer_multiplier = 1; 44 #endif 45 46 inline void qdf_timer_set_multiplier(uint32_t multiplier) 47 { 48 g_qdf_timer_multiplier = multiplier; 49 } 50 qdf_export_symbol(qdf_timer_set_multiplier); 51 52 inline uint32_t qdf_timer_get_multiplier(void) 53 { 54 return g_qdf_timer_multiplier; 55 } 56 qdf_export_symbol(qdf_timer_get_multiplier); 57 58 /* Type declarations */ 59 60 /* Static Variable Definitions */ 61 static unsigned int persistent_timer_count; 62 static qdf_mutex_t persistent_timer_count_lock; 63 64 static void (*scheduler_timer_callback)(qdf_mc_timer_t *); 65 void qdf_register_mc_timer_callback(void (*callback) (qdf_mc_timer_t *)) 66 { 67 scheduler_timer_callback = callback; 68 } 69 70 qdf_export_symbol(qdf_register_mc_timer_callback); 71 72 /* Function declarations and documenation */ 73 74 /** 75 * qdf_try_allowing_sleep() - clean up timer states after it has been deactivated 76 * @type: timer type 77 * 78 * Clean up timer states after it has been deactivated check and try to allow 79 * sleep after a timer has been stopped or expired. 80 * 81 * Return: none 82 */ 83 void qdf_try_allowing_sleep(QDF_TIMER_TYPE type) 84 { 85 if (QDF_TIMER_TYPE_WAKE_APPS == type) { 86 87 persistent_timer_count--; 88 if (0 == persistent_timer_count) { 89 /* since the number of persistent timers has 90 * decreased from 1 to 0, the timer should allow 91 * sleep 92 */ 93 } 94 } 95 } 96 qdf_export_symbol(qdf_try_allowing_sleep); 97 98 /** 99 * qdf_mc_timer_get_current_state() - get the current state of the timer 100 * @timer: Pointer to timer object 101 * 102 * Return: 103 * QDF_TIMER_STATE - qdf timer state 104 */ 105 QDF_TIMER_STATE qdf_mc_timer_get_current_state(qdf_mc_timer_t *timer) 106 { 107 QDF_TIMER_STATE timer_state = QDF_TIMER_STATE_UNUSED; 108 109 if (!timer) { 110 QDF_ASSERT(0); 111 return timer_state; 112 } 113 114 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 115 116 switch (timer->state) { 117 case QDF_TIMER_STATE_STOPPED: 118 case QDF_TIMER_STATE_STARTING: 119 case QDF_TIMER_STATE_RUNNING: 120 case QDF_TIMER_STATE_UNUSED: 121 timer_state = timer->state; 122 break; 123 default: 124 QDF_ASSERT(0); 125 } 126 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 127 return timer_state; 128 } 129 qdf_export_symbol(qdf_mc_timer_get_current_state); 130 131 /** 132 * qdf_timer_module_init() - initializes a QDF timer module. 133 * 134 * This API initializes the QDF timer module. This needs to be called 135 * exactly once prior to using any QDF timers. 136 * 137 * Return: none 138 */ 139 void qdf_timer_module_init(void) 140 { 141 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, 142 "Initializing the QDF MC timer module"); 143 qdf_mutex_create(&persistent_timer_count_lock); 144 } 145 qdf_export_symbol(qdf_timer_module_init); 146 147 #ifdef TIMER_MANAGER 148 149 static qdf_list_t qdf_timer_domains[QDF_DEBUG_DOMAIN_COUNT]; 150 static qdf_spinlock_t qdf_timer_list_lock; 151 152 static inline qdf_list_t *qdf_timer_list_get(enum qdf_debug_domain domain) 153 { 154 return &qdf_timer_domains[domain]; 155 } 156 157 /** 158 * qdf_mc_timer_manager_init() - initialize QDF debug timer manager 159 * 160 * This API initializes QDF timer debug functionality. 161 * 162 * Return: none 163 */ 164 void qdf_mc_timer_manager_init(void) 165 { 166 int i; 167 168 for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) 169 qdf_list_create(&qdf_timer_domains[i], 1000); 170 qdf_spinlock_create(&qdf_timer_list_lock); 171 } 172 qdf_export_symbol(qdf_mc_timer_manager_init); 173 174 static void qdf_mc_timer_print_list(qdf_list_t *timers) 175 { 176 QDF_STATUS status; 177 qdf_list_node_t *node; 178 179 qdf_spin_lock_irqsave(&qdf_timer_list_lock); 180 status = qdf_list_peek_front(timers, &node); 181 while (QDF_IS_STATUS_SUCCESS(status)) { 182 qdf_mc_timer_node_t *timer_node = (qdf_mc_timer_node_t *)node; 183 const char *filename = kbasename(timer_node->file_name); 184 uint32_t line = timer_node->line_num; 185 186 qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); 187 qdf_err("timer Leak@ File %s, @Line %u", filename, line); 188 qdf_spin_lock_irqsave(&qdf_timer_list_lock); 189 190 status = qdf_list_peek_next(timers, node, &node); 191 } 192 qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); 193 } 194 195 void qdf_mc_timer_check_for_leaks(void) 196 { 197 enum qdf_debug_domain current_domain = qdf_debug_domain_get(); 198 qdf_list_t *timers = qdf_timer_list_get(current_domain); 199 200 if (qdf_list_empty(timers)) 201 return; 202 203 qdf_err("Timer leaks detected in %s domain!", 204 qdf_debug_domain_name(current_domain)); 205 qdf_mc_timer_print_list(timers); 206 QDF_DEBUG_PANIC("Previously reported timer leaks detected"); 207 } 208 209 static void qdf_mc_timer_free_leaked_timers(qdf_list_t *timers) 210 { 211 QDF_STATUS status; 212 qdf_list_node_t *node; 213 214 qdf_spin_lock_irqsave(&qdf_timer_list_lock); 215 status = qdf_list_remove_front(timers, &node); 216 while (QDF_IS_STATUS_SUCCESS(status)) { 217 qdf_mem_free(node); 218 status = qdf_list_remove_front(timers, &node); 219 } 220 qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); 221 } 222 223 /** 224 * qdf_timer_clean() - clean up QDF timer debug functionality 225 * 226 * This API cleans up QDF timer debug functionality and prints which QDF timers 227 * are leaked. This is called during driver unload. 228 * 229 * Return: none 230 */ 231 static void qdf_timer_clean(void) 232 { 233 bool leaks_detected = false; 234 int i; 235 236 /* detect and print leaks */ 237 for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) { 238 qdf_list_t *timers = &qdf_timer_domains[i]; 239 240 if (qdf_list_empty(timers)) 241 continue; 242 243 leaks_detected = true; 244 245 qdf_err("\nTimer leaks detected in the %s (Id %d) domain!", 246 qdf_debug_domain_name(i), i); 247 qdf_mc_timer_print_list(timers); 248 } 249 250 /* we're done if there were no leaks */ 251 if (!leaks_detected) 252 return; 253 254 /* panic, if enabled */ 255 QDF_DEBUG_PANIC("Previously reported timer leaks detected"); 256 257 /* if we didn't crash, release the leaked timers */ 258 for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) 259 qdf_mc_timer_free_leaked_timers(&qdf_timer_domains[i]); 260 } 261 qdf_export_symbol(qdf_timer_clean); 262 263 /** 264 * qdf_mc_timer_manager_exit() - exit QDF timer debug functionality 265 * 266 * This API exists QDF timer debug functionality 267 * 268 * Return: none 269 */ 270 void qdf_mc_timer_manager_exit(void) 271 { 272 int i; 273 274 qdf_timer_clean(); 275 276 for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) 277 qdf_list_destroy(&qdf_timer_domains[i]); 278 279 qdf_spinlock_destroy(&qdf_timer_list_lock); 280 } 281 qdf_export_symbol(qdf_mc_timer_manager_exit); 282 #endif 283 284 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) 285 static void __os_mc_timer_shim(struct timer_list *os_timer) 286 { 287 qdf_mc_timer_platform_t *platform_info_ptr = 288 qdf_container_of(os_timer, 289 qdf_mc_timer_platform_t, 290 timer); 291 qdf_mc_timer_t *timer = qdf_container_of(platform_info_ptr, 292 qdf_mc_timer_t, 293 platform_info); 294 295 scheduler_timer_callback(timer); 296 } 297 298 static void qdf_mc_timer_setup(qdf_mc_timer_t *timer, 299 QDF_TIMER_TYPE timer_type) 300 { 301 uint32_t flags = 0; 302 303 if (QDF_TIMER_TYPE_SW == timer_type) 304 flags |= TIMER_DEFERRABLE; 305 306 timer_setup(&timer->platform_info.timer, 307 __os_mc_timer_shim, flags); 308 } 309 #else 310 static void __os_mc_timer_shim(unsigned long data) 311 { 312 qdf_mc_timer_t *timer = (qdf_mc_timer_t *)data; 313 314 scheduler_timer_callback(timer); 315 } 316 317 static void qdf_mc_timer_setup(qdf_mc_timer_t *timer, 318 QDF_TIMER_TYPE timer_type) 319 { 320 if (QDF_TIMER_TYPE_SW == timer_type) 321 init_timer_deferrable(&timer->platform_info.timer); 322 else 323 init_timer(&timer->platform_info.timer); 324 325 timer->platform_info.timer.function = __os_mc_timer_shim; 326 timer->platform_info.timer.data = (unsigned long)timer; 327 } 328 #endif 329 /** 330 * qdf_mc_timer_init() - initialize a QDF timer 331 * @timer: Pointer to timer object 332 * @timer_type: Type of timer 333 * @callback: Callback to be called after timer expiry 334 * @ser_data: User data which will be passed to callback function 335 * 336 * This API initializes a QDF timer object. 337 * 338 * qdf_mc_timer_init() initializes a QDF timer object. A timer must be 339 * initialized by calling qdf_mc_timer_initialize() before it may be used in 340 * any other timer functions. 341 * 342 * Attempting to initialize timer that is already initialized results in 343 * a failure. A destroyed timer object can be re-initialized with a call to 344 * qdf_mc_timer_init(). The results of otherwise referencing the object 345 * after it has been destroyed are undefined. 346 * 347 * Calls to QDF timer functions to manipulate the timer such 348 * as qdf_mc_timer_set() will fail if the timer is not initialized or has 349 * been destroyed. Therefore, don't use the timer after it has been 350 * destroyed until it has been re-initialized. 351 * 352 * All callback will be executed within the CDS main thread unless it is 353 * initialized from the Tx thread flow, in which case it will be executed 354 * within the tx thread flow. 355 * 356 * Return: 357 * QDF_STATUS_SUCCESS: timer is initialized successfully 358 * QDF failure status: timer initialization failed 359 */ 360 #ifdef TIMER_MANAGER 361 QDF_STATUS qdf_mc_timer_init_debug(qdf_mc_timer_t *timer, 362 QDF_TIMER_TYPE timer_type, 363 qdf_mc_timer_callback_t callback, 364 void *user_data, char *file_name, 365 uint32_t line_num) 366 { 367 enum qdf_debug_domain current_domain = qdf_debug_domain_get(); 368 qdf_list_t *active_timers = qdf_timer_list_get(current_domain); 369 QDF_STATUS qdf_status; 370 371 /* check for invalid pointer */ 372 if ((!timer) || (!callback)) { 373 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 374 "%s: Null params being passed", __func__); 375 QDF_ASSERT(0); 376 return QDF_STATUS_E_FAULT; 377 } 378 379 timer->timer_node = qdf_mem_malloc(sizeof(qdf_mc_timer_node_t)); 380 381 if (!timer->timer_node) { 382 QDF_ASSERT(0); 383 return QDF_STATUS_E_NOMEM; 384 } 385 386 timer->timer_node->file_name = file_name; 387 timer->timer_node->line_num = line_num; 388 timer->timer_node->qdf_timer = timer; 389 390 qdf_spin_lock_irqsave(&qdf_timer_list_lock); 391 qdf_status = qdf_list_insert_front(active_timers, 392 &timer->timer_node->node); 393 qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); 394 if (QDF_STATUS_SUCCESS != qdf_status) { 395 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 396 "%s: Unable to insert node into List qdf_status %d", 397 __func__, qdf_status); 398 } 399 400 /* set the various members of the timer structure 401 * with arguments passed or with default values 402 */ 403 qdf_spinlock_create(&timer->platform_info.spinlock); 404 qdf_mc_timer_setup(timer, timer_type); 405 timer->callback = callback; 406 timer->user_data = user_data; 407 timer->type = timer_type; 408 timer->platform_info.cookie = LINUX_TIMER_COOKIE; 409 timer->platform_info.thread_id = 0; 410 timer->state = QDF_TIMER_STATE_STOPPED; 411 412 return QDF_STATUS_SUCCESS; 413 } 414 qdf_export_symbol(qdf_mc_timer_init_debug); 415 #else 416 QDF_STATUS qdf_mc_timer_init(qdf_mc_timer_t *timer, QDF_TIMER_TYPE timer_type, 417 qdf_mc_timer_callback_t callback, 418 void *user_data) 419 { 420 /* check for invalid pointer */ 421 if ((!timer) || (!callback)) { 422 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 423 "%s: Null params being passed", __func__); 424 QDF_ASSERT(0); 425 return QDF_STATUS_E_FAULT; 426 } 427 428 /* set the various members of the timer structure 429 * with arguments passed or with default values 430 */ 431 qdf_spinlock_create(&timer->platform_info.spinlock); 432 qdf_mc_timer_setup(timer, timer_type); 433 timer->callback = callback; 434 timer->user_data = user_data; 435 timer->type = timer_type; 436 timer->platform_info.cookie = LINUX_TIMER_COOKIE; 437 timer->platform_info.thread_id = 0; 438 timer->state = QDF_TIMER_STATE_STOPPED; 439 440 return QDF_STATUS_SUCCESS; 441 } 442 qdf_export_symbol(qdf_mc_timer_init); 443 #endif 444 445 /** 446 * qdf_mc_timer_destroy() - destroy QDF timer 447 * @timer: Pointer to timer object 448 * 449 * qdf_mc_timer_destroy() function shall destroy the timer object. 450 * After a successful return from \a qdf_mc_timer_destroy() the timer 451 * object becomes, in effect, uninitialized. 452 * 453 * A destroyed timer object can be re-initialized by calling 454 * qdf_mc_timer_init(). The results of otherwise referencing the object 455 * after it has been destroyed are undefined. 456 * 457 * Calls to QDF timer functions to manipulate the timer, such 458 * as qdf_mc_timer_set() will fail if the lock is destroyed. Therefore, 459 * don't use the timer after it has been destroyed until it has 460 * been re-initialized. 461 * 462 * Return: 463 * QDF_STATUS_SUCCESS - timer is initialized successfully 464 * QDF failure status - timer initialization failed 465 */ 466 #ifdef TIMER_MANAGER 467 QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer) 468 { 469 enum qdf_debug_domain current_domain = qdf_debug_domain_get(); 470 qdf_list_t *active_timers = qdf_timer_list_get(current_domain); 471 QDF_STATUS v_status = QDF_STATUS_SUCCESS; 472 473 /* check for invalid pointer */ 474 if (!timer) { 475 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 476 "%s: Null timer pointer being passed", __func__); 477 QDF_ASSERT(0); 478 return QDF_STATUS_E_FAULT; 479 } 480 481 /* Check if timer refers to an uninitialized object */ 482 if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { 483 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 484 "%s: Cannot destroy uninitialized timer", __func__); 485 QDF_ASSERT(0); 486 return QDF_STATUS_E_INVAL; 487 } 488 489 qdf_spin_lock_irqsave(&qdf_timer_list_lock); 490 v_status = qdf_list_remove_node(active_timers, 491 &timer->timer_node->node); 492 qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); 493 if (v_status != QDF_STATUS_SUCCESS) { 494 QDF_ASSERT(0); 495 return QDF_STATUS_E_INVAL; 496 } 497 qdf_mem_free(timer->timer_node); 498 499 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 500 501 switch (timer->state) { 502 503 case QDF_TIMER_STATE_STARTING: 504 v_status = QDF_STATUS_E_BUSY; 505 break; 506 507 case QDF_TIMER_STATE_RUNNING: 508 /* Stop the timer first */ 509 del_timer(&(timer->platform_info.timer)); 510 v_status = QDF_STATUS_SUCCESS; 511 break; 512 case QDF_TIMER_STATE_STOPPED: 513 v_status = QDF_STATUS_SUCCESS; 514 break; 515 516 case QDF_TIMER_STATE_UNUSED: 517 v_status = QDF_STATUS_E_ALREADY; 518 break; 519 520 default: 521 v_status = QDF_STATUS_E_FAULT; 522 break; 523 } 524 525 if (QDF_STATUS_SUCCESS == v_status) { 526 timer->platform_info.cookie = LINUX_INVALID_TIMER_COOKIE; 527 timer->state = QDF_TIMER_STATE_UNUSED; 528 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 529 qdf_spinlock_destroy(&timer->platform_info.spinlock); 530 return v_status; 531 } 532 533 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 534 535 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, 536 "%s: Cannot destroy timer in state = %d", __func__, 537 timer->state); 538 QDF_ASSERT(0); 539 540 return v_status; 541 } 542 qdf_export_symbol(qdf_mc_timer_destroy); 543 544 #else 545 546 /** 547 * qdf_mc_timer_destroy() - destroy QDF timer 548 * @timer: Pointer to timer object 549 * 550 * qdf_mc_timer_destroy() function shall destroy the timer object. 551 * After a successful return from \a qdf_mc_timer_destroy() the timer 552 * object becomes, in effect, uninitialized. 553 * 554 * A destroyed timer object can be re-initialized by calling 555 * qdf_mc_timer_init(). The results of otherwise referencing the object 556 * after it has been destroyed are undefined. 557 * 558 * Calls to QDF timer functions to manipulate the timer, such 559 * as qdf_mc_timer_set() will fail if the lock is destroyed. Therefore, 560 * don't use the timer after it has been destroyed until it has 561 * been re-initialized. 562 * 563 * Return: 564 * QDF_STATUS_SUCCESS - timer is initialized successfully 565 * QDF failure status - timer initialization failed 566 */ 567 QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer) 568 { 569 QDF_STATUS v_status = QDF_STATUS_SUCCESS; 570 571 /* check for invalid pointer */ 572 if (!timer) { 573 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 574 "%s: Null timer pointer being passed", __func__); 575 QDF_ASSERT(0); 576 return QDF_STATUS_E_FAULT; 577 } 578 579 /* check if timer refers to an uninitialized object */ 580 if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { 581 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 582 "%s: Cannot destroy uninitialized timer", __func__); 583 QDF_ASSERT(0); 584 return QDF_STATUS_E_INVAL; 585 } 586 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 587 588 switch (timer->state) { 589 590 case QDF_TIMER_STATE_STARTING: 591 v_status = QDF_STATUS_E_BUSY; 592 break; 593 594 case QDF_TIMER_STATE_RUNNING: 595 /* Stop the timer first */ 596 del_timer(&(timer->platform_info.timer)); 597 v_status = QDF_STATUS_SUCCESS; 598 break; 599 600 case QDF_TIMER_STATE_STOPPED: 601 v_status = QDF_STATUS_SUCCESS; 602 break; 603 604 case QDF_TIMER_STATE_UNUSED: 605 v_status = QDF_STATUS_E_ALREADY; 606 break; 607 608 default: 609 v_status = QDF_STATUS_E_FAULT; 610 break; 611 } 612 613 if (QDF_STATUS_SUCCESS == v_status) { 614 timer->platform_info.cookie = LINUX_INVALID_TIMER_COOKIE; 615 timer->state = QDF_TIMER_STATE_UNUSED; 616 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 617 return v_status; 618 } 619 620 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 621 622 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, 623 "%s: Cannot destroy timer in state = %d", __func__, 624 timer->state); 625 QDF_ASSERT(0); 626 627 return v_status; 628 } 629 qdf_export_symbol(qdf_mc_timer_destroy); 630 #endif 631 632 /** 633 * qdf_mc_timer_start() - start a QDF timer object 634 * @timer: Pointer to timer object 635 * @expiration_time: Time to expire 636 * 637 * qdf_mc_timer_start() function starts a timer to expire after the 638 * specified interval, thus running the timer callback function when 639 * the interval expires. 640 * 641 * A timer only runs once (a one-shot timer). To re-start the 642 * timer, qdf_mc_timer_start() has to be called after the timer runs 643 * or has been cancelled. 644 * 645 * Return: 646 * QDF_STATUS_SUCCESS: timer is initialized successfully 647 * QDF failure status: timer initialization failed 648 */ 649 QDF_STATUS qdf_mc_timer_start(qdf_mc_timer_t *timer, uint32_t expiration_time) 650 { 651 /* check for invalid pointer */ 652 if (!timer) { 653 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 654 "%s Null timer pointer being passed", __func__); 655 QDF_ASSERT(0); 656 return QDF_STATUS_E_INVAL; 657 } 658 659 /* check if timer refers to an uninitialized object */ 660 if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { 661 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 662 "%s: Cannot start uninitialized timer", __func__); 663 QDF_ASSERT(0); 664 665 return QDF_STATUS_E_INVAL; 666 } 667 668 /* check if timer has expiration time less than 10 ms */ 669 if (expiration_time < 10) { 670 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 671 "%s: Cannot start a timer with expiration less than 10 ms", 672 __func__); 673 QDF_ASSERT(0); 674 return QDF_STATUS_E_INVAL; 675 } 676 677 /* make sure the remainer of the logic isn't interrupted */ 678 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 679 680 /* ensure if the timer can be started */ 681 if (QDF_TIMER_STATE_STOPPED != timer->state) { 682 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 683 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 684 "%s: Cannot start timer in state = %d %ps", 685 __func__, timer->state, (void *)timer->callback); 686 return QDF_STATUS_E_ALREADY; 687 } 688 689 /* start the timer */ 690 mod_timer(&(timer->platform_info.timer), 691 jiffies + __qdf_scaled_msecs_to_jiffies(expiration_time)); 692 693 timer->state = QDF_TIMER_STATE_RUNNING; 694 695 /* get the thread ID on which the timer is being started */ 696 timer->platform_info.thread_id = current->pid; 697 698 if (QDF_TIMER_TYPE_WAKE_APPS == timer->type) { 699 persistent_timer_count++; 700 if (1 == persistent_timer_count) { 701 /* since we now have one persistent timer, 702 * we need to disallow sleep 703 * sleep_negate_okts(sleep_client_handle); 704 */ 705 } 706 } 707 708 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 709 710 return QDF_STATUS_SUCCESS; 711 } 712 qdf_export_symbol(qdf_mc_timer_start); 713 714 /** 715 * qdf_mc_timer_stop() - stop a QDF timer 716 * @timer: Pointer to timer object 717 * qdf_mc_timer_stop() function stops a timer that has been started but 718 * has not expired, essentially cancelling the 'start' request. 719 * 720 * After a timer is stopped, it goes back to the state it was in after it 721 * was created and can be started again via a call to qdf_mc_timer_start(). 722 * 723 * Return: 724 * QDF_STATUS_SUCCESS: timer is initialized successfully 725 * QDF failure status: timer initialization failed 726 */ 727 QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer) 728 { 729 /* check for invalid pointer */ 730 if (!timer) { 731 QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF, 732 "%s Null timer pointer", __func__); 733 QDF_ASSERT(0); 734 return QDF_STATUS_E_INVAL; 735 } 736 737 /* check if timer refers to an uninitialized object */ 738 if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { 739 QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF, 740 "%s: Cannot stop uninit timer", __func__); 741 QDF_ASSERT(0); 742 743 return QDF_STATUS_E_INVAL; 744 } 745 746 /* ensure the timer state is correct */ 747 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 748 749 if (QDF_TIMER_STATE_RUNNING != timer->state) { 750 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 751 return QDF_STATUS_SUCCESS; 752 } 753 754 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 755 756 del_timer(&(timer->platform_info.timer)); 757 758 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 759 timer->state = QDF_TIMER_STATE_STOPPED; 760 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 761 762 qdf_try_allowing_sleep(timer->type); 763 764 return QDF_STATUS_SUCCESS; 765 } 766 qdf_export_symbol(qdf_mc_timer_stop); 767 768 QDF_STATUS qdf_mc_timer_stop_sync(qdf_mc_timer_t *timer) 769 { 770 /* check for invalid pointer */ 771 if (!timer) { 772 QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF, 773 "%s Null timer pointer", __func__); 774 QDF_ASSERT(0); 775 return QDF_STATUS_E_INVAL; 776 } 777 778 /* check if timer refers to an uninitialized object */ 779 if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { 780 QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF, 781 "%s: Cannot stop uninit timer", __func__); 782 QDF_ASSERT(0); 783 784 return QDF_STATUS_E_INVAL; 785 } 786 787 /* ensure the timer state is correct */ 788 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 789 790 if (QDF_TIMER_STATE_RUNNING != timer->state) { 791 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 792 return QDF_STATUS_SUCCESS; 793 } 794 795 timer->state = QDF_TIMER_STATE_STOPPED; 796 797 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 798 del_timer_sync(&(timer->platform_info.timer)); 799 800 qdf_try_allowing_sleep(timer->type); 801 802 return QDF_STATUS_SUCCESS; 803 } 804 qdf_export_symbol(qdf_mc_timer_stop_sync); 805 /** 806 * qdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks 807 808 * qdf_mc_timer_get_system_ticks() function returns the current number 809 * of timer ticks in 10msec intervals. This function is suitable timestamping 810 * and calculating time intervals by calculating the difference between two 811 * timestamps. 812 * 813 * Return: 814 * The current system tick count (in 10msec intervals). This 815 * function cannot fail. 816 */ 817 unsigned long qdf_mc_timer_get_system_ticks(void) 818 { 819 return jiffies_to_msecs(jiffies) / 10; 820 } 821 qdf_export_symbol(qdf_mc_timer_get_system_ticks); 822 823 /** 824 * qdf_mc_timer_get_system_time() - Get the system time in milliseconds 825 * 826 * qdf_mc_timer_get_system_time() function returns the number of milliseconds 827 * that have elapsed since the system was started 828 * 829 * Return: 830 * The current system time in milliseconds 831 */ 832 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) 833 unsigned long qdf_mc_timer_get_system_time(void) 834 { 835 struct timespec64 tv; 836 837 ktime_get_real_ts64(&tv); 838 return tv.tv_sec * 1000 + tv.tv_nsec / 1000000; 839 } 840 qdf_export_symbol(qdf_mc_timer_get_system_time); 841 842 #else 843 unsigned long qdf_mc_timer_get_system_time(void) 844 { 845 struct timeval tv; 846 847 do_gettimeofday(&tv); 848 return tv.tv_sec * 1000 + tv.tv_usec / 1000; 849 } 850 qdf_export_symbol(qdf_mc_timer_get_system_time); 851 #endif 852 853 s64 qdf_get_monotonic_boottime_ns(void) 854 { 855 return ktime_to_ns(ktime_get_boottime()); 856 } 857 qdf_export_symbol(qdf_get_monotonic_boottime_ns); 858 859 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) 860 qdf_time_t qdf_get_time_of_the_day_ms(void) 861 { 862 struct timespec64 tv; 863 qdf_time_t local_time; 864 struct rtc_time tm; 865 866 ktime_get_real_ts64(&tv); 867 local_time = (qdf_time_t)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); 868 rtc_time64_to_tm(local_time, &tm); 869 870 return (tm.tm_hour * 60 * 60 * 1000) + 871 (tm.tm_min * 60 * 1000) + (tm.tm_sec * 1000) + 872 (tv.tv_nsec / 1000000); 873 } 874 875 qdf_export_symbol(qdf_get_time_of_the_day_ms); 876 877 #else 878 qdf_time_t qdf_get_time_of_the_day_ms(void) 879 { 880 struct timeval tv; 881 qdf_time_t local_time; 882 struct rtc_time tm; 883 884 do_gettimeofday(&tv); 885 local_time = (qdf_time_t)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); 886 rtc_time_to_tm(local_time, &tm); 887 888 return (tm.tm_hour * 60 * 60 * 1000) + 889 (tm.tm_min * 60 * 1000) + (tm.tm_sec * 1000) + 890 (tv.tv_usec / 1000); 891 } 892 qdf_export_symbol(qdf_get_time_of_the_day_ms); 893 #endif 894 895 /** 896 * qdf_timer_module_deinit() - Deinitializes a QDF timer module. 897 * 898 * This API deinitializes the QDF timer module. 899 * Return: none 900 */ 901 void qdf_timer_module_deinit(void) 902 { 903 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, 904 "De-Initializing the QDF MC timer module"); 905 qdf_mutex_destroy(&persistent_timer_count_lock); 906 } 907 qdf_export_symbol(qdf_timer_module_deinit); 908 909 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) 910 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len) 911 { 912 struct timespec64 tv; 913 struct rtc_time tm; 914 unsigned long local_time; 915 916 /* Format the Log time R#: [hr:min:sec.microsec] */ 917 ktime_get_real_ts64(&tv); 918 /* Convert rtc to local time */ 919 local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); 920 rtc_time64_to_tm(local_time, &tm); 921 scnprintf(tbuf, len, 922 "[%02d:%02d:%02d.%06lu]", 923 tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_nsec / 1000); 924 } 925 926 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec); 927 928 #else 929 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len) 930 { 931 struct timeval tv; 932 struct rtc_time tm; 933 unsigned long local_time; 934 935 /* Format the Log time R#: [hr:min:sec.microsec] */ 936 do_gettimeofday(&tv); 937 /* Convert rtc to local time */ 938 local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); 939 rtc_time_to_tm(local_time, &tm); 940 scnprintf(tbuf, len, 941 "[%02d:%02d:%02d.%06lu]", 942 tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); 943 } 944 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec); 945 #endif 946