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 /* qdf timer multiplier */ 39 #ifdef QCA_WIFI_NAPIER_EMULATION 40 static uint32_t g_qdf_timer_multiplier = 100; 41 #else 42 static uint32_t g_qdf_timer_multiplier = 1; 43 #endif 44 45 inline void qdf_timer_set_multiplier(uint32_t multiplier) 46 { 47 g_qdf_timer_multiplier = multiplier; 48 } 49 qdf_export_symbol(qdf_timer_set_multiplier); 50 51 inline uint32_t qdf_timer_get_multiplier(void) 52 { 53 return g_qdf_timer_multiplier; 54 } 55 qdf_export_symbol(qdf_timer_get_multiplier); 56 57 /* Type declarations */ 58 59 /* Static Variable Definitions */ 60 static unsigned int persistent_timer_count; 61 static qdf_mutex_t persistent_timer_count_lock; 62 63 static void (*scheduler_timer_callback)(qdf_mc_timer_t *); 64 void qdf_register_mc_timer_callback(void (*callback) (qdf_mc_timer_t *)) 65 { 66 scheduler_timer_callback = callback; 67 } 68 69 qdf_export_symbol(qdf_register_mc_timer_callback); 70 71 /* Function declarations and documenation */ 72 73 /** 74 * qdf_try_allowing_sleep() - clean up timer states after it has been deactivated 75 * @type: timer type 76 * 77 * Clean up timer states after it has been deactivated check and try to allow 78 * sleep after a timer has been stopped or expired. 79 * 80 * Return: none 81 */ 82 void qdf_try_allowing_sleep(QDF_TIMER_TYPE type) 83 { 84 if (QDF_TIMER_TYPE_WAKE_APPS == type) { 85 86 persistent_timer_count--; 87 if (0 == persistent_timer_count) { 88 /* since the number of persistent timers has 89 * decreased from 1 to 0, the timer should allow 90 * sleep 91 */ 92 } 93 } 94 } 95 qdf_export_symbol(qdf_try_allowing_sleep); 96 97 /** 98 * qdf_mc_timer_get_current_state() - get the current state of the timer 99 * @timer: Pointer to timer object 100 * 101 * Return: 102 * QDF_TIMER_STATE - qdf timer state 103 */ 104 QDF_TIMER_STATE qdf_mc_timer_get_current_state(qdf_mc_timer_t *timer) 105 { 106 if (NULL == timer) { 107 QDF_ASSERT(0); 108 return QDF_TIMER_STATE_UNUSED; 109 } 110 111 switch (timer->state) { 112 case QDF_TIMER_STATE_STOPPED: 113 case QDF_TIMER_STATE_STARTING: 114 case QDF_TIMER_STATE_RUNNING: 115 case QDF_TIMER_STATE_UNUSED: 116 return timer->state; 117 default: 118 QDF_ASSERT(0); 119 return QDF_TIMER_STATE_UNUSED; 120 } 121 } 122 qdf_export_symbol(qdf_mc_timer_get_current_state); 123 124 /** 125 * qdf_timer_module_init() - initializes a QDF timer module. 126 * 127 * This API initializes the QDF timer module. This needs to be called 128 * exactly once prior to using any QDF timers. 129 * 130 * Return: none 131 */ 132 void qdf_timer_module_init(void) 133 { 134 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, 135 "Initializing the QDF MC timer module"); 136 qdf_mutex_create(&persistent_timer_count_lock); 137 } 138 qdf_export_symbol(qdf_timer_module_init); 139 140 #ifdef TIMER_MANAGER 141 142 static qdf_list_t qdf_timer_domains[QDF_DEBUG_DOMAIN_COUNT]; 143 static qdf_spinlock_t qdf_timer_list_lock; 144 145 static inline qdf_list_t *qdf_timer_list_get(enum qdf_debug_domain domain) 146 { 147 return &qdf_timer_domains[domain]; 148 } 149 150 /** 151 * qdf_mc_timer_manager_init() - initialize QDF debug timer manager 152 * 153 * This API initializes QDF timer debug functionality. 154 * 155 * Return: none 156 */ 157 void qdf_mc_timer_manager_init(void) 158 { 159 int i; 160 161 for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) 162 qdf_list_create(&qdf_timer_domains[i], 1000); 163 qdf_spinlock_create(&qdf_timer_list_lock); 164 } 165 qdf_export_symbol(qdf_mc_timer_manager_init); 166 167 static void qdf_mc_timer_print_list(qdf_list_t *timers) 168 { 169 QDF_STATUS status; 170 qdf_list_node_t *node; 171 172 qdf_spin_lock_irqsave(&qdf_timer_list_lock); 173 status = qdf_list_peek_front(timers, &node); 174 while (QDF_IS_STATUS_SUCCESS(status)) { 175 qdf_mc_timer_node_t *timer_node = (qdf_mc_timer_node_t *)node; 176 const char *filename = kbasename(timer_node->file_name); 177 uint32_t line = timer_node->line_num; 178 179 qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); 180 qdf_err("timer Leak@ File %s, @Line %u", filename, line); 181 qdf_spin_lock_irqsave(&qdf_timer_list_lock); 182 183 status = qdf_list_peek_next(timers, node, &node); 184 } 185 qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); 186 } 187 188 void qdf_mc_timer_check_for_leaks(void) 189 { 190 enum qdf_debug_domain current_domain = qdf_debug_domain_get(); 191 qdf_list_t *timers = qdf_timer_list_get(current_domain); 192 193 if (qdf_list_empty(timers)) 194 return; 195 196 qdf_err("Timer leaks detected in %s domain!", 197 qdf_debug_domain_name(current_domain)); 198 qdf_mc_timer_print_list(timers); 199 QDF_DEBUG_PANIC("Previously reported timer leaks detected"); 200 } 201 202 static void qdf_mc_timer_free_leaked_timers(qdf_list_t *timers) 203 { 204 QDF_STATUS status; 205 qdf_list_node_t *node; 206 207 qdf_spin_lock_irqsave(&qdf_timer_list_lock); 208 status = qdf_list_remove_front(timers, &node); 209 while (QDF_IS_STATUS_SUCCESS(status)) { 210 qdf_mem_free(node); 211 status = qdf_list_remove_front(timers, &node); 212 } 213 qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); 214 } 215 216 /** 217 * qdf_timer_clean() - clean up QDF timer debug functionality 218 * 219 * This API cleans up QDF timer debug functionality and prints which QDF timers 220 * are leaked. This is called during driver unload. 221 * 222 * Return: none 223 */ 224 static void qdf_timer_clean(void) 225 { 226 bool leaks_detected = false; 227 int i; 228 229 /* detect and print leaks */ 230 for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) { 231 qdf_list_t *timers = &qdf_timer_domains[i]; 232 233 if (qdf_list_empty(timers)) 234 continue; 235 236 leaks_detected = true; 237 238 qdf_err("\nTimer leaks detected in the %s (Id %d) domain!", 239 qdf_debug_domain_name(i), i); 240 qdf_mc_timer_print_list(timers); 241 } 242 243 /* we're done if there were no leaks */ 244 if (!leaks_detected) 245 return; 246 247 /* panic, if enabled */ 248 QDF_DEBUG_PANIC("Previously reported timer leaks detected"); 249 250 /* if we didn't crash, release the leaked timers */ 251 for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) 252 qdf_mc_timer_free_leaked_timers(&qdf_timer_domains[i]); 253 } 254 qdf_export_symbol(qdf_timer_clean); 255 256 /** 257 * qdf_mc_timer_manager_exit() - exit QDF timer debug functionality 258 * 259 * This API exists QDF timer debug functionality 260 * 261 * Return: none 262 */ 263 void qdf_mc_timer_manager_exit(void) 264 { 265 int i; 266 267 qdf_timer_clean(); 268 269 for (i = 0; i < QDF_DEBUG_DOMAIN_COUNT; ++i) 270 qdf_list_destroy(&qdf_timer_domains[i]); 271 272 qdf_spinlock_destroy(&qdf_timer_list_lock); 273 } 274 qdf_export_symbol(qdf_mc_timer_manager_exit); 275 #endif 276 277 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) 278 static void __os_mc_timer_shim(struct timer_list *os_timer) 279 { 280 qdf_mc_timer_platform_t *platform_info_ptr = 281 qdf_container_of(os_timer, 282 qdf_mc_timer_platform_t, 283 timer); 284 qdf_mc_timer_t *timer = qdf_container_of(platform_info_ptr, 285 qdf_mc_timer_t, 286 platform_info); 287 288 scheduler_timer_callback(timer); 289 } 290 291 static void qdf_mc_timer_setup(qdf_mc_timer_t *timer, 292 QDF_TIMER_TYPE timer_type) 293 { 294 uint32_t flags = 0; 295 296 if (QDF_TIMER_TYPE_SW == timer_type) 297 flags |= TIMER_DEFERRABLE; 298 299 timer_setup(&timer->platform_info.timer, 300 __os_mc_timer_shim, flags); 301 } 302 #else 303 static void __os_mc_timer_shim(unsigned long data) 304 { 305 qdf_mc_timer_t *timer = (qdf_mc_timer_t *)data; 306 307 scheduler_timer_callback(timer); 308 } 309 310 static void qdf_mc_timer_setup(qdf_mc_timer_t *timer, 311 QDF_TIMER_TYPE timer_type) 312 { 313 if (QDF_TIMER_TYPE_SW == timer_type) 314 init_timer_deferrable(&timer->platform_info.timer); 315 else 316 init_timer(&timer->platform_info.timer); 317 318 timer->platform_info.timer.function = __os_mc_timer_shim; 319 timer->platform_info.timer.data = (unsigned long)timer; 320 } 321 #endif 322 /** 323 * qdf_mc_timer_init() - initialize a QDF timer 324 * @timer: Pointer to timer object 325 * @timer_type: Type of timer 326 * @callback: Callback to be called after timer expiry 327 * @ser_data: User data which will be passed to callback function 328 * 329 * This API initializes a QDF timer object. 330 * 331 * qdf_mc_timer_init() initializes a QDF timer object. A timer must be 332 * initialized by calling qdf_mc_timer_initialize() before it may be used in 333 * any other timer functions. 334 * 335 * Attempting to initialize timer that is already initialized results in 336 * a failure. A destroyed timer object can be re-initialized with a call to 337 * qdf_mc_timer_init(). The results of otherwise referencing the object 338 * after it has been destroyed are undefined. 339 * 340 * Calls to QDF timer functions to manipulate the timer such 341 * as qdf_mc_timer_set() will fail if the timer is not initialized or has 342 * been destroyed. Therefore, don't use the timer after it has been 343 * destroyed until it has been re-initialized. 344 * 345 * All callback will be executed within the CDS main thread unless it is 346 * initialized from the Tx thread flow, in which case it will be executed 347 * within the tx thread flow. 348 * 349 * Return: 350 * QDF_STATUS_SUCCESS: timer is initialized successfully 351 * QDF failure status: timer initialization failed 352 */ 353 #ifdef TIMER_MANAGER 354 QDF_STATUS qdf_mc_timer_init_debug(qdf_mc_timer_t *timer, 355 QDF_TIMER_TYPE timer_type, 356 qdf_mc_timer_callback_t callback, 357 void *user_data, char *file_name, 358 uint32_t line_num) 359 { 360 enum qdf_debug_domain current_domain = qdf_debug_domain_get(); 361 qdf_list_t *active_timers = qdf_timer_list_get(current_domain); 362 QDF_STATUS qdf_status; 363 364 /* check for invalid pointer */ 365 if ((timer == NULL) || (callback == NULL)) { 366 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 367 "%s: Null params being passed", __func__); 368 QDF_ASSERT(0); 369 return QDF_STATUS_E_FAULT; 370 } 371 372 timer->timer_node = qdf_mem_malloc(sizeof(qdf_mc_timer_node_t)); 373 374 if (timer->timer_node == NULL) { 375 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 376 "%s: Not able to allocate memory for time_node", 377 __func__); 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 == NULL) || (callback == NULL)) { 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 (NULL == 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 (NULL == 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 (NULL == 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 /* update expiration time based on if emulation platform */ 674 expiration_time *= qdf_timer_get_multiplier(); 675 676 /* make sure the remainer of the logic isn't interrupted */ 677 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 678 679 /* ensure if the timer can be started */ 680 if (QDF_TIMER_STATE_STOPPED != timer->state) { 681 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 682 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 683 "%s: Cannot start timer in state = %d ", __func__, 684 timer->state); 685 return QDF_STATUS_E_ALREADY; 686 } 687 688 /* start the timer */ 689 mod_timer(&(timer->platform_info.timer), 690 jiffies + msecs_to_jiffies(expiration_time)); 691 692 timer->state = QDF_TIMER_STATE_RUNNING; 693 694 /* get the thread ID on which the timer is being started */ 695 timer->platform_info.thread_id = current->pid; 696 697 if (QDF_TIMER_TYPE_WAKE_APPS == timer->type) { 698 persistent_timer_count++; 699 if (1 == persistent_timer_count) { 700 /* since we now have one persistent timer, 701 * we need to disallow sleep 702 * sleep_negate_okts(sleep_client_handle); 703 */ 704 } 705 } 706 707 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 708 709 return QDF_STATUS_SUCCESS; 710 } 711 qdf_export_symbol(qdf_mc_timer_start); 712 713 /** 714 * qdf_mc_timer_stop() - stop a QDF timer 715 * @timer: Pointer to timer object 716 * qdf_mc_timer_stop() function stops a timer that has been started but 717 * has not expired, essentially cancelling the 'start' request. 718 * 719 * After a timer is stopped, it goes back to the state it was in after it 720 * was created and can be started again via a call to qdf_mc_timer_start(). 721 * 722 * Return: 723 * QDF_STATUS_SUCCESS: timer is initialized successfully 724 * QDF failure status: timer initialization failed 725 */ 726 QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer) 727 { 728 /* check for invalid pointer */ 729 if (NULL == timer) { 730 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 731 "%s Null timer pointer being passed", __func__); 732 QDF_ASSERT(0); 733 return QDF_STATUS_E_INVAL; 734 } 735 736 /* check if timer refers to an uninitialized object */ 737 if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { 738 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 739 "%s: Cannot stop uninitialized timer", __func__); 740 QDF_ASSERT(0); 741 742 return QDF_STATUS_E_INVAL; 743 } 744 745 /* ensure the timer state is correct */ 746 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 747 748 if (QDF_TIMER_STATE_RUNNING != timer->state) { 749 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 750 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, 751 "%s: Cannot stop timer in state = %d", 752 __func__, timer->state); 753 return QDF_STATUS_SUCCESS; 754 } 755 756 timer->state = QDF_TIMER_STATE_STOPPED; 757 758 del_timer(&(timer->platform_info.timer)); 759 760 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 761 762 qdf_try_allowing_sleep(timer->type); 763 764 return QDF_STATUS_SUCCESS; 765 } 766 qdf_export_symbol(qdf_mc_timer_stop); 767 768 /** 769 * qdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks 770 771 * qdf_mc_timer_get_system_ticks() function returns the current number 772 * of timer ticks in 10msec intervals. This function is suitable timestamping 773 * and calculating time intervals by calculating the difference between two 774 * timestamps. 775 * 776 * Return: 777 * The current system tick count (in 10msec intervals). This 778 * function cannot fail. 779 */ 780 unsigned long qdf_mc_timer_get_system_ticks(void) 781 { 782 return jiffies_to_msecs(jiffies) / 10; 783 } 784 qdf_export_symbol(qdf_mc_timer_get_system_ticks); 785 786 /** 787 * qdf_mc_timer_get_system_time() - Get the system time in milliseconds 788 * 789 * qdf_mc_timer_get_system_time() function returns the number of milliseconds 790 * that have elapsed since the system was started 791 * 792 * Return: 793 * The current system time in milliseconds 794 */ 795 unsigned long qdf_mc_timer_get_system_time(void) 796 { 797 struct timeval tv; 798 799 do_gettimeofday(&tv); 800 return tv.tv_sec * 1000 + tv.tv_usec / 1000; 801 } 802 qdf_export_symbol(qdf_mc_timer_get_system_time); 803 804 s64 qdf_get_monotonic_boottime_ns(void) 805 { 806 struct timespec ts; 807 808 get_monotonic_boottime(&ts); 809 810 return timespec_to_ns(&ts); 811 } 812 qdf_export_symbol(qdf_get_monotonic_boottime_ns); 813 814 qdf_time_t qdf_get_time_of_the_day_ms(void) 815 { 816 struct timeval tv; 817 qdf_time_t local_time; 818 struct rtc_time tm; 819 820 do_gettimeofday(&tv); 821 local_time = (qdf_time_t)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); 822 rtc_time_to_tm(local_time, &tm); 823 824 return (tm.tm_hour * 60 * 60 * 1000) + 825 (tm.tm_min * 60 * 1000) + (tm.tm_sec * 1000) + 826 (tv.tv_usec / 1000); 827 } 828 qdf_export_symbol(qdf_get_time_of_the_day_ms); 829 830 /** 831 * qdf_timer_module_deinit() - Deinitializes a QDF timer module. 832 * 833 * This API deinitializes the QDF timer module. 834 * Return: none 835 */ 836 void qdf_timer_module_deinit(void) 837 { 838 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, 839 "De-Initializing the QDF MC timer module"); 840 qdf_mutex_destroy(&persistent_timer_count_lock); 841 } 842 qdf_export_symbol(qdf_timer_module_deinit); 843 844 void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len) 845 { 846 struct timeval tv; 847 struct rtc_time tm; 848 unsigned long local_time; 849 850 /* Format the Log time R#: [hr:min:sec.microsec] */ 851 do_gettimeofday(&tv); 852 /* Convert rtc to local time */ 853 local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); 854 rtc_time_to_tm(local_time, &tm); 855 scnprintf(tbuf, len, 856 "[%02d:%02d:%02d.%06lu]", 857 tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); 858 } 859 qdf_export_symbol(qdf_get_time_of_the_day_in_hr_min_sec_usec); 860