1 /* 2 * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 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 #include <linux/module.h> 21 #include <qdf_lock.h> 22 #include <qdf_trace.h> 23 #include <qdf_module.h> 24 25 #include <qdf_types.h> 26 #include <i_host_diag_core_event.h> 27 #ifdef FEATURE_RUNTIME_PM 28 #include <cds_api.h> 29 #include <hif.h> 30 #endif 31 #include <i_qdf_lock.h> 32 #include <linux/suspend.h> 33 34 /** 35 * qdf_mutex_create() - Initialize a mutex 36 * @m: mutex to initialize 37 * 38 * Returns: QDF_STATUS 39 * =0 success 40 * else fail status 41 */ 42 #undef qdf_mutex_create 43 QDF_STATUS qdf_mutex_create(qdf_mutex_t *lock, const char *func, int line) 44 { 45 /* check for invalid pointer */ 46 if (!lock) { 47 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 48 "%s: NULL pointer passed in", __func__); 49 return QDF_STATUS_E_FAULT; 50 } 51 /* check for 'already initialized' lock */ 52 if (LINUX_LOCK_COOKIE == lock->cookie) { 53 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 54 "%s: already initialized lock", __func__); 55 return QDF_STATUS_E_BUSY; 56 } 57 58 if (in_interrupt()) { 59 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 60 "%s cannot be called from interrupt context!!!", 61 __func__); 62 return QDF_STATUS_E_FAULT; 63 } 64 65 qdf_lock_stats_create(&lock->stats, func, line); 66 67 /* initialize new lock */ 68 mutex_init(&lock->m_lock); 69 lock->cookie = LINUX_LOCK_COOKIE; 70 lock->state = LOCK_RELEASED; 71 lock->process_id = 0; 72 lock->refcount = 0; 73 74 return QDF_STATUS_SUCCESS; 75 } 76 qdf_export_symbol(qdf_mutex_create); 77 78 /** 79 * qdf_mutex_acquire() - acquire a QDF lock 80 * @lock: Pointer to the opaque lock object to acquire 81 * 82 * A lock object is acquired by calling qdf_mutex_acquire(). If the lock 83 * is already locked, the calling thread shall block until the lock becomes 84 * available. This operation shall return with the lock object referenced by 85 * lock in the locked state with the calling thread as its owner. 86 * 87 * Return: 88 * QDF_STATUS_SUCCESS: lock was successfully initialized 89 * QDF failure reason codes: lock is not initialized and can't be used 90 */ 91 QDF_STATUS qdf_mutex_acquire(qdf_mutex_t *lock) 92 { 93 int rc; 94 /* check for invalid pointer */ 95 if (!lock) { 96 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 97 "%s: NULL pointer passed in", __func__); 98 QDF_ASSERT(0); 99 return QDF_STATUS_E_FAULT; 100 } 101 /* check if lock refers to an initialized object */ 102 if (LINUX_LOCK_COOKIE != lock->cookie) { 103 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 104 "%s: uninitialized lock", __func__); 105 QDF_ASSERT(0); 106 return QDF_STATUS_E_INVAL; 107 } 108 109 if (in_interrupt()) { 110 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 111 "%s cannot be called from interrupt context!!!", 112 __func__); 113 QDF_ASSERT(0); 114 return QDF_STATUS_E_FAULT; 115 } 116 if ((lock->process_id == current->pid) && 117 (lock->state == LOCK_ACQUIRED)) { 118 lock->refcount++; 119 #ifdef QDF_NESTED_LOCK_DEBUG 120 pe_err("%s: %x %d %d", __func__, lock, current->pid, 121 lock->refcount); 122 #endif 123 return QDF_STATUS_SUCCESS; 124 } 125 126 BEFORE_LOCK(lock, mutex_is_locked(&lock->m_lock)); 127 /* acquire a Lock */ 128 mutex_lock(&lock->m_lock); 129 AFTER_LOCK(lock, __func__); 130 rc = mutex_is_locked(&lock->m_lock); 131 if (rc == 0) { 132 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 133 "%s: unable to lock mutex (rc = %d)", __func__, rc); 134 QDF_ASSERT(0); 135 return QDF_STATUS_E_FAILURE; 136 } 137 #ifdef QDF_NESTED_LOCK_DEBUG 138 pe_err("%s: %x %d", __func__, lock, current->pid); 139 #endif 140 if (LOCK_DESTROYED != lock->state) { 141 lock->process_id = current->pid; 142 lock->refcount++; 143 lock->state = LOCK_ACQUIRED; 144 return QDF_STATUS_SUCCESS; 145 } 146 147 /* lock is already destroyed */ 148 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 149 "%s: Lock is already destroyed", __func__); 150 mutex_unlock(&lock->m_lock); 151 QDF_ASSERT(0); 152 return QDF_STATUS_E_FAILURE; 153 } 154 qdf_export_symbol(qdf_mutex_acquire); 155 156 /** 157 * qdf_mutex_release() - release a QDF lock 158 * @lock: Pointer to the opaque lock object to be released 159 * 160 * qdf_mutex_release() function shall release the lock object 161 * referenced by 'lock'. 162 * 163 * If a thread attempts to release a lock that it unlocked or is not 164 * initialized, an error is returned. 165 * 166 * Return: 167 * QDF_STATUS_SUCCESS: lock was successfully initialized 168 * QDF failure reason codes: lock is not initialized and can't be used 169 */ 170 QDF_STATUS qdf_mutex_release(qdf_mutex_t *lock) 171 { 172 /* check for invalid pointer */ 173 if (!lock) { 174 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 175 "%s: NULL pointer passed in", __func__); 176 QDF_ASSERT(0); 177 return QDF_STATUS_E_FAULT; 178 } 179 180 /* check if lock refers to an uninitialized object */ 181 if (LINUX_LOCK_COOKIE != lock->cookie) { 182 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 183 "%s: uninitialized lock", __func__); 184 QDF_ASSERT(0); 185 return QDF_STATUS_E_INVAL; 186 } 187 188 if (in_interrupt()) { 189 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 190 "%s cannot be called from interrupt context!!!", 191 __func__); 192 QDF_ASSERT(0); 193 return QDF_STATUS_E_FAULT; 194 } 195 196 /* current_thread = get_current_thread_id(); 197 * Check thread ID of caller against thread ID 198 * of the thread which acquire the lock 199 */ 200 if (lock->process_id != current->pid) { 201 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 202 "%s: current task pid does not match original task pid!!", 203 __func__); 204 #ifdef QDF_NESTED_LOCK_DEBUG 205 pe_err("%s: Lock held by=%d being released by=%d", 206 __func__, lock->process_id, current->pid); 207 #endif 208 QDF_ASSERT(0); 209 return QDF_STATUS_E_PERM; 210 } 211 if ((lock->process_id == current->pid) && 212 (lock->state == LOCK_ACQUIRED)) { 213 if (lock->refcount > 0) 214 lock->refcount--; 215 } 216 #ifdef QDF_NESTED_LOCK_DEBUG 217 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: %x %d %d", __func__, lock, lock->process_id, 218 lock->refcount); 219 #endif 220 if (lock->refcount) 221 return QDF_STATUS_SUCCESS; 222 223 lock->process_id = 0; 224 lock->refcount = 0; 225 lock->state = LOCK_RELEASED; 226 /* release a Lock */ 227 BEFORE_UNLOCK(lock, 0); 228 mutex_unlock(&lock->m_lock); 229 #ifdef QDF_NESTED_LOCK_DEBUG 230 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: Freeing lock %x %d %d", lock, lock->process_id, 231 lock->refcount); 232 #endif 233 return QDF_STATUS_SUCCESS; 234 } 235 qdf_export_symbol(qdf_mutex_release); 236 237 #ifdef WLAN_WAKE_LOCK_DEBUG 238 #include "qdf_tracker.h" 239 240 #define qdf_wake_lock_tracker_bits 2 /* 4 buckets */ 241 static qdf_tracker_declare(qdf_wake_lock_tracker, qdf_wake_lock_tracker_bits, 242 "wake lock leaks", "wake lock create", 243 "wake lock destroy"); 244 245 void qdf_wake_lock_feature_init(void) 246 { 247 qdf_tracker_init(&qdf_wake_lock_tracker); 248 } 249 250 void qdf_wake_lock_feature_deinit(void) 251 { 252 qdf_tracker_deinit(&qdf_wake_lock_tracker); 253 } 254 255 void qdf_wake_lock_check_for_leaks(void) 256 { 257 qdf_tracker_check_for_leaks(&qdf_wake_lock_tracker); 258 } 259 260 static inline QDF_STATUS qdf_wake_lock_dbg_track(qdf_wake_lock_t *lock, 261 const char *func, 262 uint32_t line) 263 { 264 return qdf_tracker_track(&qdf_wake_lock_tracker, lock, func, line); 265 } 266 267 static inline void qdf_wake_lock_dbg_untrack(qdf_wake_lock_t *lock, 268 const char *func, uint32_t line) 269 { 270 qdf_tracker_untrack(&qdf_wake_lock_tracker, lock, func, line); 271 } 272 #else 273 static inline QDF_STATUS qdf_wake_lock_dbg_track(qdf_wake_lock_t *lock, 274 const char *func, 275 uint32_t line) 276 { 277 return QDF_STATUS_SUCCESS; 278 } 279 280 static inline void qdf_wake_lock_dbg_untrack(qdf_wake_lock_t *lock, 281 const char *func, uint32_t line) 282 { } 283 #endif /* WLAN_WAKE_LOCK_DEBUG */ 284 285 /** 286 * qdf_wake_lock_name() - This function returns the name of the wakelock 287 * @lock: Pointer to the wakelock 288 * 289 * This function returns the name of the wakelock 290 * 291 * Return: Pointer to the name if it is valid or a default string 292 */ 293 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) 294 const char *qdf_wake_lock_name(qdf_wake_lock_t *lock) 295 { 296 if (lock) 297 return lock->lock.name; 298 return "UNNAMED_WAKELOCK"; 299 } 300 #else 301 const char *qdf_wake_lock_name(qdf_wake_lock_t *lock) 302 { 303 return "NO_WAKELOCK_SUPPORT"; 304 } 305 #endif 306 qdf_export_symbol(qdf_wake_lock_name); 307 308 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 110)) || \ 309 defined(WAKEUP_SOURCE_DEV) 310 QDF_STATUS __qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name, 311 const char *func, uint32_t line) 312 { 313 QDF_STATUS status; 314 315 status = qdf_wake_lock_dbg_track(lock, func, line); 316 if (QDF_IS_STATUS_ERROR(status)) 317 return status; 318 319 qdf_mem_zero(lock, sizeof(*lock)); 320 lock->priv = wakeup_source_register(lock->lock.dev, name); 321 if (!(lock->priv)) { 322 QDF_BUG(0); 323 return QDF_STATUS_E_FAILURE; 324 } 325 326 lock->lock = *(lock->priv); 327 328 return QDF_STATUS_SUCCESS; 329 } 330 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) 331 QDF_STATUS __qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name, 332 const char *func, uint32_t line) 333 { 334 QDF_STATUS status; 335 336 status = qdf_wake_lock_dbg_track(lock, func, line); 337 if (QDF_IS_STATUS_ERROR(status)) 338 return status; 339 340 wakeup_source_init(&(lock->lock), name); 341 lock->priv = &(lock->lock); 342 343 return QDF_STATUS_SUCCESS; 344 } 345 #else 346 QDF_STATUS __qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name, 347 const char *func, uint32_t line) 348 { 349 return QDF_STATUS_SUCCESS; 350 } 351 #endif 352 qdf_export_symbol(__qdf_wake_lock_create); 353 354 /** 355 * qdf_wake_lock_acquire() - acquires a wake lock 356 * @lock: The wake lock to acquire 357 * @reason: Reason for wakelock 358 * 359 * Return: 360 * QDF status success: if wake lock is acquired 361 * QDF status failure: if wake lock was not acquired 362 */ 363 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) 364 QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason) 365 { 366 host_diag_log_wlock(reason, qdf_wake_lock_name(lock), 367 WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT, 368 WIFI_POWER_EVENT_WAKELOCK_TAKEN); 369 __pm_stay_awake(lock->priv); 370 371 return QDF_STATUS_SUCCESS; 372 } 373 #else 374 QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason) 375 { 376 return QDF_STATUS_SUCCESS; 377 } 378 #endif 379 qdf_export_symbol(qdf_wake_lock_acquire); 380 381 /** 382 * qdf_wake_lock_timeout_acquire() - acquires a wake lock with a timeout 383 * @lock: The wake lock to acquire 384 * @reason: Reason for wakelock 385 * 386 * Return: 387 * QDF status success: if wake lock is acquired 388 * QDF status failure: if wake lock was not acquired 389 */ 390 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) 391 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec) 392 { 393 pm_wakeup_ws_event(lock->priv, msec, true); 394 return QDF_STATUS_SUCCESS; 395 } 396 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) 397 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec) 398 { 399 /* Wakelock for Rx is frequent. 400 * It is reported only during active debug 401 */ 402 __pm_wakeup_event(&(lock->lock), msec); 403 return QDF_STATUS_SUCCESS; 404 } 405 #else /* LINUX_VERSION_CODE */ 406 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec) 407 { 408 return QDF_STATUS_SUCCESS; 409 } 410 #endif /* LINUX_VERSION_CODE */ 411 qdf_export_symbol(qdf_wake_lock_timeout_acquire); 412 413 /** 414 * qdf_wake_lock_release() - releases a wake lock 415 * @lock: the wake lock to release 416 * @reason: Reason for wakelock 417 * 418 * Return: 419 * QDF status success: if wake lock is acquired 420 * QDF status failure: if wake lock was not acquired 421 */ 422 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) 423 QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason) 424 { 425 host_diag_log_wlock(reason, qdf_wake_lock_name(lock), 426 WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT, 427 WIFI_POWER_EVENT_WAKELOCK_RELEASED); 428 __pm_relax(lock->priv); 429 430 return QDF_STATUS_SUCCESS; 431 } 432 #else 433 QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason) 434 { 435 return QDF_STATUS_SUCCESS; 436 } 437 #endif 438 qdf_export_symbol(qdf_wake_lock_release); 439 440 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 110)) || \ 441 defined(WAKEUP_SOURCE_DEV) 442 void __qdf_wake_lock_destroy(qdf_wake_lock_t *lock, 443 const char *func, uint32_t line) 444 { 445 wakeup_source_unregister(lock->priv); 446 qdf_wake_lock_dbg_untrack(lock, func, line); 447 } 448 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) 449 void __qdf_wake_lock_destroy(qdf_wake_lock_t *lock, 450 const char *func, uint32_t line) 451 { 452 wakeup_source_trash(&(lock->lock)); 453 qdf_wake_lock_dbg_untrack(lock, func, line); 454 } 455 #else 456 void __qdf_wake_lock_destroy(qdf_wake_lock_t *lock, 457 const char *func, uint32_t line) 458 { 459 } 460 #endif 461 qdf_export_symbol(__qdf_wake_lock_destroy); 462 463 /** 464 * qdf_pm_system_wakeup() - wakeup system 465 * 466 * Return: None 467 */ 468 void qdf_pm_system_wakeup(void) 469 { 470 pm_system_wakeup(); 471 } 472 473 qdf_export_symbol(qdf_pm_system_wakeup); 474 475 #ifdef FEATURE_RUNTIME_PM 476 /** 477 * qdf_runtime_pm_get() - do a get opperation on the device 478 * 479 * A get opperation will prevent a runtime suspend until a 480 * corresponding put is done. This api should be used when sending 481 * data. 482 * 483 * CONTRARY TO THE REGULAR RUNTIME PM, WHEN THE BUS IS SUSPENDED, 484 * THIS API WILL ONLY REQUEST THE RESUME AND NOT TO A GET!!! 485 * 486 * return: success if the bus is up and a get has been issued 487 * otherwise an error code. 488 */ 489 QDF_STATUS qdf_runtime_pm_get(void) 490 { 491 void *ol_sc; 492 int ret; 493 494 ol_sc = cds_get_context(QDF_MODULE_ID_HIF); 495 496 if (!ol_sc) { 497 QDF_ASSERT(0); 498 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 499 "%s: HIF context is null!", __func__); 500 return QDF_STATUS_E_INVAL; 501 } 502 503 ret = hif_pm_runtime_get(ol_sc, RTPM_ID_RESVERD, false); 504 505 if (ret) 506 return QDF_STATUS_E_FAILURE; 507 return QDF_STATUS_SUCCESS; 508 } 509 qdf_export_symbol(qdf_runtime_pm_get); 510 511 /** 512 * qdf_runtime_pm_put() - do a put opperation on the device 513 * 514 * A put opperation will allow a runtime suspend after a corresponding 515 * get was done. This api should be used when sending data. 516 * 517 * This api will return a failure if the hif module hasn't been 518 * initialized 519 * 520 * return: QDF_STATUS_SUCCESS if the put is performed 521 */ 522 QDF_STATUS qdf_runtime_pm_put(void) 523 { 524 void *ol_sc; 525 int ret; 526 527 ol_sc = cds_get_context(QDF_MODULE_ID_HIF); 528 529 if (!ol_sc) { 530 QDF_ASSERT(0); 531 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 532 "%s: HIF context is null!", __func__); 533 return QDF_STATUS_E_INVAL; 534 } 535 536 ret = hif_pm_runtime_put(ol_sc, RTPM_ID_RESVERD); 537 538 if (ret) 539 return QDF_STATUS_E_FAILURE; 540 return QDF_STATUS_SUCCESS; 541 } 542 qdf_export_symbol(qdf_runtime_pm_put); 543 544 /** 545 * qdf_runtime_pm_prevent_suspend() - prevent a runtime bus suspend 546 * @lock: an opaque context for tracking 547 * 548 * The lock can only be acquired once per lock context and is tracked. 549 * 550 * return: QDF_STATUS_SUCCESS or failure code. 551 */ 552 QDF_STATUS qdf_runtime_pm_prevent_suspend(qdf_runtime_lock_t *lock) 553 { 554 void *ol_sc; 555 int ret; 556 557 ol_sc = cds_get_context(QDF_MODULE_ID_HIF); 558 559 if (!ol_sc) { 560 QDF_ASSERT(0); 561 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 562 "%s: HIF context is null!", __func__); 563 return QDF_STATUS_E_INVAL; 564 } 565 566 ret = hif_pm_runtime_prevent_suspend(ol_sc, lock->lock); 567 568 if (ret) 569 return QDF_STATUS_E_FAILURE; 570 return QDF_STATUS_SUCCESS; 571 } 572 qdf_export_symbol(qdf_runtime_pm_prevent_suspend); 573 574 /** 575 * qdf_runtime_pm_allow_suspend() - prevent a runtime bus suspend 576 * @lock: an opaque context for tracking 577 * 578 * The lock can only be acquired once per lock context and is tracked. 579 * 580 * return: QDF_STATUS_SUCCESS or failure code. 581 */ 582 QDF_STATUS qdf_runtime_pm_allow_suspend(qdf_runtime_lock_t *lock) 583 { 584 void *ol_sc; 585 int ret; 586 587 ol_sc = cds_get_context(QDF_MODULE_ID_HIF); 588 if (!ol_sc) { 589 QDF_ASSERT(0); 590 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 591 "%s: HIF context is null!", __func__); 592 return QDF_STATUS_E_INVAL; 593 } 594 595 ret = hif_pm_runtime_allow_suspend(ol_sc, lock->lock); 596 if (ret) 597 return QDF_STATUS_E_FAILURE; 598 599 return QDF_STATUS_SUCCESS; 600 } 601 qdf_export_symbol(qdf_runtime_pm_allow_suspend); 602 603 /** 604 * qdf_runtime_lock_init() - initialize runtime lock 605 * @name: name of the runtime lock 606 * 607 * Initialize a runtime pm lock. This lock can be used 608 * to prevent the runtime pm system from putting the bus 609 * to sleep. 610 * 611 * Return: runtime_pm_lock_t 612 */ 613 QDF_STATUS __qdf_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name) 614 { 615 int ret = hif_runtime_lock_init(lock, name); 616 617 if (ret) 618 return QDF_STATUS_E_NOMEM; 619 620 return QDF_STATUS_SUCCESS; 621 } 622 qdf_export_symbol(__qdf_runtime_lock_init); 623 624 /** 625 * qdf_runtime_lock_deinit() - deinitialize runtime pm lock 626 * @lock: the lock to deinitialize 627 * 628 * Ensures the lock is released. Frees the runtime lock. 629 * 630 * Return: void 631 */ 632 void qdf_runtime_lock_deinit(qdf_runtime_lock_t *lock) 633 { 634 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); 635 636 if (!hif_ctx) 637 return; 638 639 if (!lock) 640 return; 641 642 hif_runtime_lock_deinit(hif_ctx, lock->lock); 643 } 644 qdf_export_symbol(qdf_runtime_lock_deinit); 645 646 #else 647 648 QDF_STATUS qdf_runtime_pm_get(void) 649 { 650 return QDF_STATUS_SUCCESS; 651 } 652 qdf_export_symbol(qdf_runtime_pm_get); 653 654 QDF_STATUS qdf_runtime_pm_put(void) 655 { 656 return QDF_STATUS_SUCCESS; 657 } 658 qdf_export_symbol(qdf_runtime_pm_put); 659 660 QDF_STATUS qdf_runtime_pm_prevent_suspend(qdf_runtime_lock_t *lock) 661 { 662 return QDF_STATUS_SUCCESS; 663 } 664 qdf_export_symbol(qdf_runtime_pm_prevent_suspend); 665 666 QDF_STATUS qdf_runtime_pm_allow_suspend(qdf_runtime_lock_t *lock) 667 { 668 return QDF_STATUS_SUCCESS; 669 } 670 qdf_export_symbol(qdf_runtime_pm_allow_suspend); 671 672 QDF_STATUS __qdf_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name) 673 { 674 return QDF_STATUS_SUCCESS; 675 } 676 qdf_export_symbol(__qdf_runtime_lock_init); 677 678 void qdf_runtime_lock_deinit(qdf_runtime_lock_t *lock) 679 { 680 } 681 qdf_export_symbol(qdf_runtime_lock_deinit); 682 683 #endif /* FEATURE_RUNTIME_PM */ 684 685 /** 686 * qdf_spinlock_acquire() - acquires a spin lock 687 * @lock: Spin lock to acquire 688 * 689 * Return: 690 * QDF status success: if wake lock is acquired 691 */ 692 QDF_STATUS qdf_spinlock_acquire(qdf_spinlock_t *lock) 693 { 694 spin_lock(&lock->lock.spinlock); 695 return QDF_STATUS_SUCCESS; 696 } 697 qdf_export_symbol(qdf_spinlock_acquire); 698 699 700 /** 701 * qdf_spinlock_release() - release a spin lock 702 * @lock: Spin lock to release 703 * 704 * Return: 705 * QDF status success : if wake lock is acquired 706 */ 707 QDF_STATUS qdf_spinlock_release(qdf_spinlock_t *lock) 708 { 709 spin_unlock(&lock->lock.spinlock); 710 return QDF_STATUS_SUCCESS; 711 } 712 qdf_export_symbol(qdf_spinlock_release); 713 714 /** 715 * qdf_mutex_destroy() - destroy a QDF lock 716 * @lock: Pointer to the opaque lock object to be destroyed 717 * 718 * function shall destroy the lock object referenced by lock. After a 719 * successful return from qdf_mutex_destroy() 720 * the lock object becomes, in effect, uninitialized. 721 * 722 * A destroyed lock object can be reinitialized using qdf_mutex_create(); 723 * the results of otherwise referencing the object after it has been destroyed 724 * are undefined. Calls to QDF lock functions to manipulate the lock such 725 * as qdf_mutex_acquire() will fail if the lock is destroyed. Therefore, 726 * don't use the lock after it has been destroyed until it has 727 * been re-initialized. 728 * 729 * Return: 730 * QDF_STATUS_SUCCESS: lock was successfully initialized 731 * QDF failure reason codes: lock is not initialized and can't be used 732 */ 733 QDF_STATUS qdf_mutex_destroy(qdf_mutex_t *lock) 734 { 735 /* check for invalid pointer */ 736 if (!lock) { 737 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 738 "%s: NULL pointer passed in", __func__); 739 return QDF_STATUS_E_FAULT; 740 } 741 742 if (LINUX_LOCK_COOKIE != lock->cookie) { 743 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 744 "%s: uninitialized lock", __func__); 745 return QDF_STATUS_E_INVAL; 746 } 747 748 if (in_interrupt()) { 749 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 750 "%s cannot be called from interrupt context!!!", 751 __func__); 752 return QDF_STATUS_E_FAULT; 753 } 754 755 /* check if lock is released */ 756 if (!mutex_trylock(&lock->m_lock)) { 757 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 758 "%s: lock is not released", __func__); 759 return QDF_STATUS_E_BUSY; 760 } 761 lock->cookie = 0; 762 lock->state = LOCK_DESTROYED; 763 lock->process_id = 0; 764 lock->refcount = 0; 765 766 qdf_lock_stats_destroy(&lock->stats); 767 mutex_unlock(&lock->m_lock); 768 769 return QDF_STATUS_SUCCESS; 770 } 771 qdf_export_symbol(qdf_mutex_destroy); 772 773 #if QDF_LOCK_STATS_LIST 774 struct qdf_lock_cookie { 775 union { 776 struct { 777 struct lock_stats *stats; 778 const char *func; 779 int line; 780 } cookie; 781 struct { 782 struct qdf_lock_cookie *next; 783 } empty_node; 784 } u; 785 }; 786 787 #ifndef QDF_LOCK_STATS_LIST_SIZE 788 #define QDF_LOCK_STATS_LIST_SIZE 256 789 #endif 790 791 static qdf_spinlock_t qdf_lock_list_spinlock; 792 static struct qdf_lock_cookie lock_cookies[QDF_LOCK_STATS_LIST_SIZE]; 793 static struct qdf_lock_cookie *lock_cookie_freelist; 794 static qdf_atomic_t lock_cookie_get_failures; 795 static qdf_atomic_t lock_cookie_untracked_num; 796 /* dummy value */ 797 #define DUMMY_LOCK_COOKIE 0xc00c1e 798 799 /** 800 * qdf_is_lock_cookie - check if memory is a valid lock cookie 801 * 802 * return true if the memory is within the range of the lock cookie 803 * memory. 804 */ 805 static bool qdf_is_lock_cookie(struct qdf_lock_cookie *lock_cookie) 806 { 807 return lock_cookie >= &lock_cookies[0] && 808 lock_cookie <= &lock_cookies[QDF_LOCK_STATS_LIST_SIZE-1]; 809 } 810 811 /** 812 * qdf_is_lock_cookie_free() - check if the lock cookie is on the freelist 813 * @lock_cookie: lock cookie to check 814 * 815 * Check that the next field of the lock cookie points to a lock cookie. 816 * currently this is only true if the cookie is on the freelist. 817 * 818 * Checking for the function and line being NULL and 0 should also have worked. 819 */ 820 static bool qdf_is_lock_cookie_free(struct qdf_lock_cookie *lock_cookie) 821 { 822 struct qdf_lock_cookie *tmp = lock_cookie->u.empty_node.next; 823 824 return qdf_is_lock_cookie(tmp) || (!tmp); 825 } 826 827 static struct qdf_lock_cookie *qdf_get_lock_cookie(void) 828 { 829 struct qdf_lock_cookie *lock_cookie; 830 831 qdf_spin_lock_bh(&qdf_lock_list_spinlock); 832 lock_cookie = lock_cookie_freelist; 833 if (lock_cookie_freelist) 834 lock_cookie_freelist = lock_cookie_freelist->u.empty_node.next; 835 qdf_spin_unlock_bh(&qdf_lock_list_spinlock); 836 return lock_cookie; 837 } 838 839 static void __qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie) 840 { 841 if (!qdf_is_lock_cookie(lock_cookie)) 842 QDF_BUG(0); 843 844 lock_cookie->u.empty_node.next = lock_cookie_freelist; 845 lock_cookie_freelist = lock_cookie; 846 } 847 848 static void qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie) 849 { 850 qdf_spin_lock_bh(&qdf_lock_list_spinlock); 851 __qdf_put_lock_cookie(lock_cookie); 852 qdf_spin_unlock_bh(&qdf_lock_list_spinlock); 853 } 854 855 void qdf_lock_stats_init(void) 856 { 857 int i; 858 859 for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++) 860 __qdf_put_lock_cookie(&lock_cookies[i]); 861 862 /* stats must be allocated for the spinlock before the cookie, 863 * otherwise this qdf_lock_list_spinlock wouldnt get initialized 864 * properly 865 */ 866 qdf_spinlock_create(&qdf_lock_list_spinlock); 867 qdf_atomic_init(&lock_cookie_get_failures); 868 qdf_atomic_init(&lock_cookie_untracked_num); 869 } 870 871 void qdf_lock_stats_deinit(void) 872 { 873 int i; 874 875 qdf_spinlock_destroy(&qdf_lock_list_spinlock); 876 for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++) { 877 if (!qdf_is_lock_cookie_free(&lock_cookies[i])) 878 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, 879 "%s: lock_not_destroyed, fun: %s, line %d", 880 __func__, lock_cookies[i].u.cookie.func, 881 lock_cookies[i].u.cookie.line); 882 } 883 lock_cookie_freelist = NULL; 884 } 885 886 /* allocated separate memory in case the lock memory is freed without 887 * running the deinitialization code. The cookie list will not be 888 * corrupted. 889 */ 890 void qdf_lock_stats_cookie_create(struct lock_stats *stats, 891 const char *func, int line) 892 { 893 struct qdf_lock_cookie *cookie = qdf_get_lock_cookie(); 894 895 if (!cookie) { 896 int count; 897 898 qdf_atomic_inc(&lock_cookie_get_failures); 899 count = qdf_atomic_inc_return(&lock_cookie_untracked_num); 900 stats->cookie = (void *) DUMMY_LOCK_COOKIE; 901 return; 902 } 903 904 stats->cookie = cookie; 905 stats->cookie->u.cookie.stats = stats; 906 stats->cookie->u.cookie.func = func; 907 stats->cookie->u.cookie.line = line; 908 } 909 910 qdf_export_symbol(qdf_lock_stats_cookie_create); 911 912 void qdf_lock_stats_cookie_destroy(struct lock_stats *stats) 913 { 914 struct qdf_lock_cookie *cookie = stats->cookie; 915 916 if (!cookie) { 917 QDF_DEBUG_PANIC("Lock destroyed twice or never created"); 918 return; 919 } 920 921 stats->cookie = NULL; 922 if (cookie == (void *)DUMMY_LOCK_COOKIE) { 923 qdf_atomic_dec(&lock_cookie_untracked_num); 924 return; 925 } 926 927 cookie->u.cookie.stats = NULL; 928 cookie->u.cookie.func = NULL; 929 cookie->u.cookie.line = 0; 930 931 qdf_put_lock_cookie(cookie); 932 } 933 934 qdf_export_symbol(qdf_lock_stats_cookie_destroy); 935 #endif 936