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