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 documentation */ 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 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 remainder 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 /* Save the jiffies value in a per-timer context in qdf_mc_timer_t 696 * It will help the debugger to know the exact time at which the host 697 * starts the QDF timer. 698 */ 699 timer->timer_start_jiffies = jiffies; 700 701 /* get the thread ID on which the timer is being started */ 702 timer->platform_info.thread_id = current->pid; 703 704 if (QDF_TIMER_TYPE_WAKE_APPS == timer->type) { 705 persistent_timer_count++; 706 if (1 == persistent_timer_count) { 707 /* since we now have one persistent timer, 708 * we need to disallow sleep 709 * sleep_negate_okts(sleep_client_handle); 710 */ 711 } 712 } 713 714 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 715 716 return QDF_STATUS_SUCCESS; 717 } 718 qdf_export_symbol(qdf_mc_timer_start); 719 720 /** 721 * qdf_mc_timer_stop() - stop a QDF timer 722 * @timer: Pointer to timer object 723 * qdf_mc_timer_stop() function stops a timer that has been started but 724 * has not expired, essentially cancelling the 'start' request. 725 * 726 * After a timer is stopped, it goes back to the state it was in after it 727 * was created and can be started again via a call to qdf_mc_timer_start(). 728 * 729 * Return: 730 * QDF_STATUS_SUCCESS: timer is initialized successfully 731 * QDF failure status: timer initialization failed 732 */ 733 QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer) 734 { 735 /* check for invalid pointer */ 736 if (!timer) { 737 QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF, 738 "%s Null timer pointer", __func__); 739 QDF_ASSERT(0); 740 return QDF_STATUS_E_INVAL; 741 } 742 743 /* check if timer refers to an uninitialized object */ 744 if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { 745 QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF, 746 "%s: Cannot stop uninit timer", __func__); 747 QDF_ASSERT(0); 748 749 return QDF_STATUS_E_INVAL; 750 } 751 752 /* ensure the timer state is correct */ 753 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 754 755 if (QDF_TIMER_STATE_RUNNING != timer->state) { 756 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 757 return QDF_STATUS_SUCCESS; 758 } 759 760 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 761 762 del_timer(&(timer->platform_info.timer)); 763 764 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 765 timer->state = QDF_TIMER_STATE_STOPPED; 766 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 767 768 qdf_try_allowing_sleep(timer->type); 769 770 return QDF_STATUS_SUCCESS; 771 } 772 qdf_export_symbol(qdf_mc_timer_stop); 773 774 QDF_STATUS qdf_mc_timer_stop_sync(qdf_mc_timer_t *timer) 775 { 776 /* check for invalid pointer */ 777 if (!timer) { 778 QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF, 779 "%s Null timer pointer", __func__); 780 QDF_ASSERT(0); 781 return QDF_STATUS_E_INVAL; 782 } 783 784 /* check if timer refers to an uninitialized object */ 785 if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { 786 QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QDF, 787 "%s: Cannot stop uninit timer", __func__); 788 QDF_ASSERT(0); 789 790 return QDF_STATUS_E_INVAL; 791 } 792 793 /* ensure the timer state is correct */ 794 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 795 796 if (QDF_TIMER_STATE_RUNNING != timer->state) { 797 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 798 return QDF_STATUS_SUCCESS; 799 } 800 801 timer->state = QDF_TIMER_STATE_STOPPED; 802 803 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 804 del_timer_sync(&(timer->platform_info.timer)); 805 806 qdf_try_allowing_sleep(timer->type); 807 808 return QDF_STATUS_SUCCESS; 809 } 810 qdf_export_symbol(qdf_mc_timer_stop_sync); 811 /** 812 * qdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks 813 814 * qdf_mc_timer_get_system_ticks() function returns the current number 815 * of timer ticks in 10msec intervals. This function is suitable timestamping 816 * and calculating time intervals by calculating the difference between two 817 * timestamps. 818 * 819 * Return: 820 * The current system tick count (in 10msec intervals). This 821 * function cannot fail. 822 */ 823 unsigned long qdf_mc_timer_get_system_ticks(void) 824 { 825 return jiffies_to_msecs(jiffies) / 10; 826 } 827 qdf_export_symbol(qdf_mc_timer_get_system_ticks); 828 829 /** 830 * qdf_mc_timer_get_system_time() - Get the system time in milliseconds 831 * 832 * qdf_mc_timer_get_system_time() function returns the number of milliseconds 833 * that have elapsed since the system was started 834 * 835 * Return: 836 * The current system time in milliseconds 837 */ 838 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) 839 unsigned long qdf_mc_timer_get_system_time(void) 840 { 841 struct timespec64 tv; 842 843 ktime_get_real_ts64(&tv); 844 return tv.tv_sec * 1000 + tv.tv_nsec / 1000000; 845 } 846 qdf_export_symbol(qdf_mc_timer_get_system_time); 847 848 #else 849 unsigned long qdf_mc_timer_get_system_time(void) 850 { 851 struct timeval tv; 852 853 do_gettimeofday(&tv); 854 return tv.tv_sec * 1000 + tv.tv_usec / 1000; 855 } 856 qdf_export_symbol(qdf_mc_timer_get_system_time); 857 #endif 858 859 s64 qdf_get_monotonic_boottime_ns(void) 860 { 861 return ktime_to_ns(ktime_get_boottime()); 862 } 863 qdf_export_symbol(qdf_get_monotonic_boottime_ns); 864 865 /** 866 * qdf_timer_module_deinit() - Deinitializes a QDF timer module. 867 * 868 * This API deinitializes the QDF timer module. 869 * Return: none 870 */ 871 void qdf_timer_module_deinit(void) 872 { 873 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, 874 "De-Initializing the QDF MC timer module"); 875 qdf_mutex_destroy(&persistent_timer_count_lock); 876 } 877 qdf_export_symbol(qdf_timer_module_deinit); 878 879 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) 880 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len) 881 { 882 struct timespec64 tv; 883 struct rtc_time tm; 884 unsigned long local_time; 885 886 /* Format the Log time R#: [hr:min:sec.microsec] */ 887 ktime_get_real_ts64(&tv); 888 /* Convert rtc to local time */ 889 local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); 890 rtc_time64_to_tm(local_time, &tm); 891 scnprintf(tbuf, len, 892 "[%02d:%02d:%02d.%06lu]", 893 tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_nsec / 1000); 894 } 895 896 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec); 897 898 uint64_t qdf_get_time_of_the_day_us(void) 899 { 900 struct timespec64 tv; 901 struct rtc_time tm; 902 unsigned long local_time; 903 uint64_t time_of_day_us = 0; 904 905 ktime_get_real_ts64(&tv); 906 /* Convert rtc to local time */ 907 local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); 908 rtc_time64_to_tm(local_time, &tm); 909 910 time_of_day_us += (uint64_t)tm.tm_hour * 60 * 60 * 1000 * 1000; 911 time_of_day_us += (uint64_t)tm.tm_min * 60 * 1000 * 1000; 912 time_of_day_us += (uint64_t)tm.tm_sec * 1000 * 1000; 913 time_of_day_us += qdf_do_div((uint64_t)tv.tv_nsec, 1000); 914 915 return time_of_day_us; 916 } 917 918 qdf_export_symbol(qdf_get_time_of_the_day_us); 919 #else 920 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len) 921 { 922 struct timeval tv; 923 struct rtc_time tm; 924 unsigned long local_time; 925 926 /* Format the Log time R#: [hr:min:sec.microsec] */ 927 do_gettimeofday(&tv); 928 /* Convert rtc to local time */ 929 local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); 930 rtc_time_to_tm(local_time, &tm); 931 scnprintf(tbuf, len, 932 "[%02d:%02d:%02d.%06lu]", 933 tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); 934 } 935 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec); 936 937 uint64_t qdf_get_time_of_the_day_us(void) 938 { 939 struct timeval tv; 940 struct rtc_time tm; 941 unsigned long local_time; 942 uint64_t time_of_day_us = 0; 943 944 do_gettimeofday(&tv); 945 /* Convert rtc to local time */ 946 local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); 947 rtc_time_to_tm(local_time, &tm); 948 949 time_of_day_us += (uint64_t)tm.tm_hour * 60 * 60 * 1000 * 1000; 950 time_of_day_us += (uint64_t)tm.tm_min * 60 * 1000 * 1000; 951 time_of_day_us += (uint64_t)tm.tm_sec * 1000 * 1000; 952 time_of_day_us += (uint64_t)tv.tv_usec; 953 954 return time_of_day_us; 955 } 956 957 qdf_export_symbol(qdf_get_time_of_the_day_us); 958 #endif 959 960 qdf_time_t qdf_get_time_of_the_day_ms(void) 961 { 962 qdf_time_t time_of_the_day_ms; 963 964 time_of_the_day_ms = qdf_do_div(qdf_get_time_of_the_day_us(), 1000); 965 966 return time_of_the_day_ms; 967 } 968 969 qdf_export_symbol(qdf_get_time_of_the_day_ms); 970