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