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