123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837 |
- /*
- * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- *
- * Permission to use, copy, modify, and/or distribute this software for
- * any purpose with or without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
- #include <linux/module.h>
- #include <qdf_lock.h>
- #include <qdf_trace.h>
- #include <qdf_module.h>
- #include <qdf_types.h>
- #include <i_host_diag_core_event.h>
- #ifdef FEATURE_RUNTIME_PM
- #include <cds_api.h>
- #include <hif.h>
- #endif
- #include <i_qdf_lock.h>
- #include <linux/suspend.h>
- /**
- * qdf_mutex_create() - Initialize a mutex
- * @m: mutex to initialize
- *
- * Returns: QDF_STATUS
- * =0 success
- * else fail status
- */
- #undef qdf_mutex_create
- QDF_STATUS qdf_mutex_create(qdf_mutex_t *lock, const char *func, int line)
- {
- /* check for invalid pointer */
- if (!lock) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: NULL pointer passed in", __func__);
- return QDF_STATUS_E_FAULT;
- }
- /* check for 'already initialized' lock */
- if (LINUX_LOCK_COOKIE == lock->cookie) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: already initialized lock", __func__);
- return QDF_STATUS_E_BUSY;
- }
- if (in_interrupt()) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s cannot be called from interrupt context!!!",
- __func__);
- return QDF_STATUS_E_FAULT;
- }
- qdf_lock_stats_create(&lock->stats, func, line);
- /* initialize new lock */
- mutex_init(&lock->m_lock);
- lock->cookie = LINUX_LOCK_COOKIE;
- lock->state = LOCK_RELEASED;
- lock->process_id = 0;
- lock->refcount = 0;
- return QDF_STATUS_SUCCESS;
- }
- qdf_export_symbol(qdf_mutex_create);
- /**
- * qdf_mutex_acquire() - acquire a QDF lock
- * @lock: Pointer to the opaque lock object to acquire
- *
- * A lock object is acquired by calling qdf_mutex_acquire(). If the lock
- * is already locked, the calling thread shall block until the lock becomes
- * available. This operation shall return with the lock object referenced by
- * lock in the locked state with the calling thread as its owner.
- *
- * Return:
- * QDF_STATUS_SUCCESS: lock was successfully initialized
- * QDF failure reason codes: lock is not initialized and can't be used
- */
- QDF_STATUS qdf_mutex_acquire(qdf_mutex_t *lock)
- {
- int rc;
- /* check for invalid pointer */
- if (!lock) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: NULL pointer passed in", __func__);
- QDF_ASSERT(0);
- return QDF_STATUS_E_FAULT;
- }
- /* check if lock refers to an initialized object */
- if (LINUX_LOCK_COOKIE != lock->cookie) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: uninitialized lock", __func__);
- QDF_ASSERT(0);
- return QDF_STATUS_E_INVAL;
- }
- if (in_interrupt()) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s cannot be called from interrupt context!!!",
- __func__);
- QDF_ASSERT(0);
- return QDF_STATUS_E_FAULT;
- }
- if ((lock->process_id == current->pid) &&
- (lock->state == LOCK_ACQUIRED)) {
- lock->refcount++;
- #ifdef QDF_NESTED_LOCK_DEBUG
- pe_err("%s: %x %d %d", __func__, lock, current->pid,
- lock->refcount);
- #endif
- return QDF_STATUS_SUCCESS;
- }
- BEFORE_LOCK(lock, mutex_is_locked(&lock->m_lock));
- /* acquire a Lock */
- mutex_lock(&lock->m_lock);
- AFTER_LOCK(lock, __func__);
- rc = mutex_is_locked(&lock->m_lock);
- if (rc == 0) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: unable to lock mutex (rc = %d)", __func__, rc);
- QDF_ASSERT(0);
- return QDF_STATUS_E_FAILURE;
- }
- #ifdef QDF_NESTED_LOCK_DEBUG
- pe_err("%s: %x %d", __func__, lock, current->pid);
- #endif
- if (LOCK_DESTROYED != lock->state) {
- lock->process_id = current->pid;
- lock->refcount++;
- lock->state = LOCK_ACQUIRED;
- return QDF_STATUS_SUCCESS;
- }
- /* lock is already destroyed */
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: Lock is already destroyed", __func__);
- mutex_unlock(&lock->m_lock);
- QDF_ASSERT(0);
- return QDF_STATUS_E_FAILURE;
- }
- qdf_export_symbol(qdf_mutex_acquire);
- /**
- * qdf_mutex_release() - release a QDF lock
- * @lock: Pointer to the opaque lock object to be released
- *
- * qdf_mutex_release() function shall release the lock object
- * referenced by 'lock'.
- *
- * If a thread attempts to release a lock that it unlocked or is not
- * initialized, an error is returned.
- *
- * Return:
- * QDF_STATUS_SUCCESS: lock was successfully initialized
- * QDF failure reason codes: lock is not initialized and can't be used
- */
- QDF_STATUS qdf_mutex_release(qdf_mutex_t *lock)
- {
- /* check for invalid pointer */
- if (!lock) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: NULL pointer passed in", __func__);
- QDF_ASSERT(0);
- return QDF_STATUS_E_FAULT;
- }
- /* check if lock refers to an uninitialized object */
- if (LINUX_LOCK_COOKIE != lock->cookie) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: uninitialized lock", __func__);
- QDF_ASSERT(0);
- return QDF_STATUS_E_INVAL;
- }
- if (in_interrupt()) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s cannot be called from interrupt context!!!",
- __func__);
- QDF_ASSERT(0);
- return QDF_STATUS_E_FAULT;
- }
- /* current_thread = get_current_thread_id();
- * Check thread ID of caller against thread ID
- * of the thread which acquire the lock
- */
- if (lock->process_id != current->pid) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: current task pid does not match original task pid!!",
- __func__);
- #ifdef QDF_NESTED_LOCK_DEBUG
- pe_err("%s: Lock held by=%d being released by=%d",
- __func__, lock->process_id, current->pid);
- #endif
- QDF_ASSERT(0);
- return QDF_STATUS_E_PERM;
- }
- if ((lock->process_id == current->pid) &&
- (lock->state == LOCK_ACQUIRED)) {
- if (lock->refcount > 0)
- lock->refcount--;
- }
- #ifdef QDF_NESTED_LOCK_DEBUG
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: %x %d %d", __func__, lock, lock->process_id,
- lock->refcount);
- #endif
- if (lock->refcount)
- return QDF_STATUS_SUCCESS;
- lock->process_id = 0;
- lock->refcount = 0;
- lock->state = LOCK_RELEASED;
- /* release a Lock */
- BEFORE_UNLOCK(lock, 0);
- mutex_unlock(&lock->m_lock);
- #ifdef QDF_NESTED_LOCK_DEBUG
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: Freeing lock %x %d %d", lock, lock->process_id,
- lock->refcount);
- #endif
- return QDF_STATUS_SUCCESS;
- }
- qdf_export_symbol(qdf_mutex_release);
- #ifdef WLAN_WAKE_LOCK_DEBUG
- #include "qdf_tracker.h"
- #define qdf_wake_lock_tracker_bits 2 /* 4 buckets */
- static qdf_tracker_declare(qdf_wake_lock_tracker, qdf_wake_lock_tracker_bits,
- "wake lock leaks", "wake lock create",
- "wake lock destroy");
- void qdf_wake_lock_feature_init(void)
- {
- qdf_tracker_init(&qdf_wake_lock_tracker);
- }
- void qdf_wake_lock_feature_deinit(void)
- {
- qdf_tracker_deinit(&qdf_wake_lock_tracker);
- }
- void qdf_wake_lock_check_for_leaks(void)
- {
- qdf_tracker_check_for_leaks(&qdf_wake_lock_tracker);
- }
- static inline QDF_STATUS qdf_wake_lock_dbg_track(qdf_wake_lock_t *lock,
- const char *func,
- uint32_t line)
- {
- return qdf_tracker_track(&qdf_wake_lock_tracker, lock, func, line);
- }
- static inline void qdf_wake_lock_dbg_untrack(qdf_wake_lock_t *lock,
- const char *func, uint32_t line)
- {
- qdf_tracker_untrack(&qdf_wake_lock_tracker, lock, func, line);
- }
- #else
- static inline QDF_STATUS qdf_wake_lock_dbg_track(qdf_wake_lock_t *lock,
- const char *func,
- uint32_t line)
- {
- return QDF_STATUS_SUCCESS;
- }
- static inline void qdf_wake_lock_dbg_untrack(qdf_wake_lock_t *lock,
- const char *func, uint32_t line)
- { }
- #endif /* WLAN_WAKE_LOCK_DEBUG */
- /**
- * qdf_wake_lock_name() - This function returns the name of the wakelock
- * @lock: Pointer to the wakelock
- *
- * This function returns the name of the wakelock
- *
- * Return: Pointer to the name if it is valid or a default string
- */
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
- const char *qdf_wake_lock_name(qdf_wake_lock_t *lock)
- {
- if (lock)
- return lock->lock.name;
- return "UNNAMED_WAKELOCK";
- }
- #else
- const char *qdf_wake_lock_name(qdf_wake_lock_t *lock)
- {
- return "NO_WAKELOCK_SUPPORT";
- }
- #endif
- qdf_export_symbol(qdf_wake_lock_name);
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 110)) || \
- defined(WAKEUP_SOURCE_DEV)
- QDF_STATUS __qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name,
- const char *func, uint32_t line)
- {
- QDF_STATUS status;
- status = qdf_wake_lock_dbg_track(lock, func, line);
- if (QDF_IS_STATUS_ERROR(status))
- return status;
- qdf_mem_zero(lock, sizeof(*lock));
- lock->priv = wakeup_source_register(lock->lock.dev, name);
- if (!(lock->priv)) {
- QDF_BUG(0);
- return QDF_STATUS_E_FAILURE;
- }
- lock->lock = *(lock->priv);
- return QDF_STATUS_SUCCESS;
- }
- #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
- QDF_STATUS __qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name,
- const char *func, uint32_t line)
- {
- QDF_STATUS status;
- status = qdf_wake_lock_dbg_track(lock, func, line);
- if (QDF_IS_STATUS_ERROR(status))
- return status;
- wakeup_source_init(&(lock->lock), name);
- lock->priv = &(lock->lock);
- return QDF_STATUS_SUCCESS;
- }
- #else
- QDF_STATUS __qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name,
- const char *func, uint32_t line)
- {
- return QDF_STATUS_SUCCESS;
- }
- #endif
- qdf_export_symbol(__qdf_wake_lock_create);
- /**
- * qdf_wake_lock_acquire() - acquires a wake lock
- * @lock: The wake lock to acquire
- * @reason: Reason for wakelock
- *
- * Return:
- * QDF status success: if wake lock is acquired
- * QDF status failure: if wake lock was not acquired
- */
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
- QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason)
- {
- host_diag_log_wlock(reason, qdf_wake_lock_name(lock),
- WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT,
- WIFI_POWER_EVENT_WAKELOCK_TAKEN);
- __pm_stay_awake(lock->priv);
- return QDF_STATUS_SUCCESS;
- }
- #else
- QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason)
- {
- return QDF_STATUS_SUCCESS;
- }
- #endif
- qdf_export_symbol(qdf_wake_lock_acquire);
- /**
- * qdf_wake_lock_timeout_acquire() - acquires a wake lock with a timeout
- * @lock: The wake lock to acquire
- * @reason: Reason for wakelock
- *
- * Return:
- * QDF status success: if wake lock is acquired
- * QDF status failure: if wake lock was not acquired
- */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
- QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
- {
- pm_wakeup_ws_event(lock->priv, msec, true);
- return QDF_STATUS_SUCCESS;
- }
- #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
- QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
- {
- /* Wakelock for Rx is frequent.
- * It is reported only during active debug
- */
- __pm_wakeup_event(&(lock->lock), msec);
- return QDF_STATUS_SUCCESS;
- }
- #else /* LINUX_VERSION_CODE */
- QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
- {
- return QDF_STATUS_SUCCESS;
- }
- #endif /* LINUX_VERSION_CODE */
- qdf_export_symbol(qdf_wake_lock_timeout_acquire);
- /**
- * qdf_wake_lock_release() - releases a wake lock
- * @lock: the wake lock to release
- * @reason: Reason for wakelock
- *
- * Return:
- * QDF status success: if wake lock is acquired
- * QDF status failure: if wake lock was not acquired
- */
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
- QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason)
- {
- host_diag_log_wlock(reason, qdf_wake_lock_name(lock),
- WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT,
- WIFI_POWER_EVENT_WAKELOCK_RELEASED);
- __pm_relax(lock->priv);
- return QDF_STATUS_SUCCESS;
- }
- #else
- QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason)
- {
- return QDF_STATUS_SUCCESS;
- }
- #endif
- qdf_export_symbol(qdf_wake_lock_release);
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 110)) || \
- defined(WAKEUP_SOURCE_DEV)
- void __qdf_wake_lock_destroy(qdf_wake_lock_t *lock,
- const char *func, uint32_t line)
- {
- wakeup_source_unregister(lock->priv);
- qdf_wake_lock_dbg_untrack(lock, func, line);
- }
- #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
- void __qdf_wake_lock_destroy(qdf_wake_lock_t *lock,
- const char *func, uint32_t line)
- {
- wakeup_source_trash(&(lock->lock));
- qdf_wake_lock_dbg_untrack(lock, func, line);
- }
- #else
- void __qdf_wake_lock_destroy(qdf_wake_lock_t *lock,
- const char *func, uint32_t line)
- {
- }
- #endif
- qdf_export_symbol(__qdf_wake_lock_destroy);
- /**
- * qdf_pm_system_wakeup() - wakeup system
- *
- * Return: None
- */
- void qdf_pm_system_wakeup(void)
- {
- pm_system_wakeup();
- }
- qdf_export_symbol(qdf_pm_system_wakeup);
- #ifdef FEATURE_RUNTIME_PM
- /**
- * qdf_to_hif_convert_trpm_id() - Convert QDF Runtime PM ID to HIF RTPM ID
- * @id: Client id
- *
- * Return: HIF Runtime pm ID of client
- */
- static uint32_t qdf_to_hif_convert_rtpm_id(uint32_t id)
- {
- switch (id) {
- case QDF_RTPM_ID_RESERVED:
- return HIF_RTPM_ID_RESERVED;
- case QDF_RTPM_ID_PM_QOS_NOTIFY:
- return HIF_RTPM_ID_PM_QOS_NOTIFY;
- case QDF_RTPM_ID_WIPHY_SUSPEND:
- return HIF_RTPM_ID_WIPHY_SUSPEND;
- default:
- return HIF_RTPM_ID_MAX;
- }
- }
- /**
- * qdf_to_hif_convert_rtpm_type() - Convert QDF Runtime PM call type to HIF
- * call type
- * @type: call type
- *
- * Return: HIF runtime PM call type
- */
- static uint8_t qdf_to_hif_convert_rtpm_type(uint8_t type)
- {
- switch (type) {
- case QDF_RTPM_GET:
- return HIF_RTPM_GET_ASYNC;
- case QDF_RTPM_GET_FORCE:
- return HIF_RTPM_GET_FORCE;
- case QDF_RTPM_GET_SYNC:
- return HIF_RTPM_GET_SYNC;
- case QDF_RTPM_GET_NORESUME:
- return HIF_RTPM_GET_NORESUME;
- case QDF_RTPM_PUT:
- return HIF_RTPM_PUT_ASYNC;
- case QDF_RTPM_PUT_SYNC_SUSPEND:
- return HIF_RTPM_PUT_SYNC_SUSPEND;
- case QDF_RTPM_PUT_NOIDLE:
- return HIF_RTPM_PUT_NOIDLE;
- default:
- return QDF_STATUS_E_NOSUPPORT;
- }
- }
- QDF_STATUS qdf_rtpm_register(uint32_t id, void (*hif_rpm_cbk)(void))
- {
- return hif_rtpm_register(qdf_to_hif_convert_rtpm_id(id), hif_rpm_cbk);
- }
- qdf_export_symbol(qdf_rtpm_register);
- QDF_STATUS qdf_rtpm_deregister(uint32_t id)
- {
- return hif_rtpm_deregister(qdf_to_hif_convert_rtpm_id(id));
- }
- qdf_export_symbol(qdf_rtpm_deregister);
- QDF_STATUS __qdf_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name)
- {
- return hif_runtime_lock_init(lock, name);
- }
- qdf_export_symbol(__qdf_runtime_lock_init);
- void qdf_runtime_lock_deinit(qdf_runtime_lock_t *lock)
- {
- hif_runtime_lock_deinit(lock->lock);
- }
- qdf_export_symbol(qdf_runtime_lock_deinit);
- QDF_STATUS qdf_rtpm_get(uint8_t type, uint32_t id)
- {
- return hif_rtpm_get(qdf_to_hif_convert_rtpm_type(type),
- qdf_to_hif_convert_rtpm_id(id));
- }
- qdf_export_symbol(qdf_rtpm_get);
- QDF_STATUS qdf_rtpm_put(uint8_t type, uint32_t id)
- {
- return hif_rtpm_put(qdf_to_hif_convert_rtpm_type(type),
- qdf_to_hif_convert_rtpm_id(id));
- }
- qdf_export_symbol(qdf_rtpm_put);
- QDF_STATUS qdf_runtime_pm_prevent_suspend(qdf_runtime_lock_t *lock)
- {
- return hif_pm_runtime_prevent_suspend(lock->lock);
- }
- qdf_export_symbol(qdf_runtime_pm_prevent_suspend);
- QDF_STATUS qdf_runtime_pm_allow_suspend(qdf_runtime_lock_t *lock)
- {
- return hif_pm_runtime_allow_suspend(lock->lock);
- }
- qdf_export_symbol(qdf_runtime_pm_allow_suspend);
- QDF_STATUS qdf_rtpm_sync_resume(void)
- {
- return hif_rtpm_sync_resume();
- }
- #endif
- /**
- * qdf_spinlock_acquire() - acquires a spin lock
- * @lock: Spin lock to acquire
- *
- * Return:
- * QDF status success: if wake lock is acquired
- */
- QDF_STATUS qdf_spinlock_acquire(qdf_spinlock_t *lock)
- {
- spin_lock(&lock->lock.spinlock);
- return QDF_STATUS_SUCCESS;
- }
- qdf_export_symbol(qdf_spinlock_acquire);
- /**
- * qdf_spinlock_release() - release a spin lock
- * @lock: Spin lock to release
- *
- * Return:
- * QDF status success : if wake lock is acquired
- */
- QDF_STATUS qdf_spinlock_release(qdf_spinlock_t *lock)
- {
- spin_unlock(&lock->lock.spinlock);
- return QDF_STATUS_SUCCESS;
- }
- qdf_export_symbol(qdf_spinlock_release);
- /**
- * qdf_mutex_destroy() - destroy a QDF lock
- * @lock: Pointer to the opaque lock object to be destroyed
- *
- * function shall destroy the lock object referenced by lock. After a
- * successful return from qdf_mutex_destroy()
- * the lock object becomes, in effect, uninitialized.
- *
- * A destroyed lock object can be reinitialized using qdf_mutex_create();
- * the results of otherwise referencing the object after it has been destroyed
- * are undefined. Calls to QDF lock functions to manipulate the lock such
- * as qdf_mutex_acquire() will fail if the lock is destroyed. Therefore,
- * don't use the lock after it has been destroyed until it has
- * been re-initialized.
- *
- * Return:
- * QDF_STATUS_SUCCESS: lock was successfully initialized
- * QDF failure reason codes: lock is not initialized and can't be used
- */
- QDF_STATUS qdf_mutex_destroy(qdf_mutex_t *lock)
- {
- /* check for invalid pointer */
- if (!lock) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: NULL pointer passed in", __func__);
- return QDF_STATUS_E_FAULT;
- }
- if (LINUX_LOCK_COOKIE != lock->cookie) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: uninitialized lock", __func__);
- return QDF_STATUS_E_INVAL;
- }
- if (in_interrupt()) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s cannot be called from interrupt context!!!",
- __func__);
- return QDF_STATUS_E_FAULT;
- }
- /* check if lock is released */
- if (!mutex_trylock(&lock->m_lock)) {
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
- "%s: lock is not released", __func__);
- return QDF_STATUS_E_BUSY;
- }
- lock->cookie = 0;
- lock->state = LOCK_DESTROYED;
- lock->process_id = 0;
- lock->refcount = 0;
- qdf_lock_stats_destroy(&lock->stats);
- mutex_unlock(&lock->m_lock);
- return QDF_STATUS_SUCCESS;
- }
- qdf_export_symbol(qdf_mutex_destroy);
- #if QDF_LOCK_STATS_LIST
- struct qdf_lock_cookie {
- union {
- struct {
- struct lock_stats *stats;
- const char *func;
- int line;
- } cookie;
- struct {
- struct qdf_lock_cookie *next;
- } empty_node;
- } u;
- };
- #ifndef QDF_LOCK_STATS_LIST_SIZE
- #define QDF_LOCK_STATS_LIST_SIZE 256
- #endif
- static qdf_spinlock_t qdf_lock_list_spinlock;
- static struct qdf_lock_cookie lock_cookies[QDF_LOCK_STATS_LIST_SIZE];
- static struct qdf_lock_cookie *lock_cookie_freelist;
- static qdf_atomic_t lock_cookie_get_failures;
- static qdf_atomic_t lock_cookie_untracked_num;
- /* dummy value */
- #define DUMMY_LOCK_COOKIE 0xc00c1e
- /**
- * qdf_is_lock_cookie - check if memory is a valid lock cookie
- *
- * return true if the memory is within the range of the lock cookie
- * memory.
- */
- static bool qdf_is_lock_cookie(struct qdf_lock_cookie *lock_cookie)
- {
- return lock_cookie >= &lock_cookies[0] &&
- lock_cookie <= &lock_cookies[QDF_LOCK_STATS_LIST_SIZE-1];
- }
- /**
- * qdf_is_lock_cookie_free() - check if the lock cookie is on the freelist
- * @lock_cookie: lock cookie to check
- *
- * Check that the next field of the lock cookie points to a lock cookie.
- * currently this is only true if the cookie is on the freelist.
- *
- * Checking for the function and line being NULL and 0 should also have worked.
- */
- static bool qdf_is_lock_cookie_free(struct qdf_lock_cookie *lock_cookie)
- {
- struct qdf_lock_cookie *tmp = lock_cookie->u.empty_node.next;
- return qdf_is_lock_cookie(tmp) || (!tmp);
- }
- static struct qdf_lock_cookie *qdf_get_lock_cookie(void)
- {
- struct qdf_lock_cookie *lock_cookie;
- qdf_spin_lock_bh(&qdf_lock_list_spinlock);
- lock_cookie = lock_cookie_freelist;
- if (lock_cookie_freelist)
- lock_cookie_freelist = lock_cookie_freelist->u.empty_node.next;
- qdf_spin_unlock_bh(&qdf_lock_list_spinlock);
- return lock_cookie;
- }
- static void __qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie)
- {
- if (!qdf_is_lock_cookie(lock_cookie))
- QDF_BUG(0);
- lock_cookie->u.empty_node.next = lock_cookie_freelist;
- lock_cookie_freelist = lock_cookie;
- }
- static void qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie)
- {
- qdf_spin_lock_bh(&qdf_lock_list_spinlock);
- __qdf_put_lock_cookie(lock_cookie);
- qdf_spin_unlock_bh(&qdf_lock_list_spinlock);
- }
- void qdf_lock_stats_init(void)
- {
- int i;
- for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++)
- __qdf_put_lock_cookie(&lock_cookies[i]);
- /* stats must be allocated for the spinlock before the cookie,
- * otherwise this qdf_lock_list_spinlock wouldnt get initialized
- * properly
- */
- qdf_spinlock_create(&qdf_lock_list_spinlock);
- qdf_atomic_init(&lock_cookie_get_failures);
- qdf_atomic_init(&lock_cookie_untracked_num);
- }
- void qdf_lock_stats_deinit(void)
- {
- int i;
- qdf_spinlock_destroy(&qdf_lock_list_spinlock);
- for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++) {
- if (!qdf_is_lock_cookie_free(&lock_cookies[i]))
- QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
- "%s: lock_not_destroyed, fun: %s, line %d",
- __func__, lock_cookies[i].u.cookie.func,
- lock_cookies[i].u.cookie.line);
- }
- lock_cookie_freelist = NULL;
- }
- /* allocated separate memory in case the lock memory is freed without
- * running the deinitialization code. The cookie list will not be
- * corrupted.
- */
- void qdf_lock_stats_cookie_create(struct lock_stats *stats,
- const char *func, int line)
- {
- struct qdf_lock_cookie *cookie = qdf_get_lock_cookie();
- if (!cookie) {
- int count;
- qdf_atomic_inc(&lock_cookie_get_failures);
- count = qdf_atomic_inc_return(&lock_cookie_untracked_num);
- stats->cookie = (void *) DUMMY_LOCK_COOKIE;
- return;
- }
- stats->cookie = cookie;
- stats->cookie->u.cookie.stats = stats;
- stats->cookie->u.cookie.func = func;
- stats->cookie->u.cookie.line = line;
- }
- qdf_export_symbol(qdf_lock_stats_cookie_create);
- void qdf_lock_stats_cookie_destroy(struct lock_stats *stats)
- {
- struct qdf_lock_cookie *cookie = stats->cookie;
- if (!cookie) {
- QDF_DEBUG_PANIC("Lock destroyed twice or never created");
- return;
- }
- stats->cookie = NULL;
- if (cookie == (void *)DUMMY_LOCK_COOKIE) {
- qdf_atomic_dec(&lock_cookie_untracked_num);
- return;
- }
- cookie->u.cookie.stats = NULL;
- cookie->u.cookie.func = NULL;
- cookie->u.cookie.line = 0;
- qdf_put_lock_cookie(cookie);
- }
- qdf_export_symbol(qdf_lock_stats_cookie_destroy);
- #endif
|