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