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