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