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