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