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