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