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