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