/* * Copyright (c) 2014-2018, 2020 The Linux Foundation. All rights reserved. * Copyright (c) 2022-2023 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. */ /** * DOC: i_qdf_lock.h * Linux-specific definitions for QDF Lock API's */ #if !defined(__I_QDF_LOCK_H) #define __I_QDF_LOCK_H /* Include Files */ #include #include #include #include #include #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) #include #else #include #endif #include #include /* define for flag */ #define QDF_LINUX_UNLOCK_BH 1 #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ enum { LOCK_RELEASED = 0x11223344, LOCK_ACQUIRED, LOCK_DESTROYED }; /** * struct qdf_lock_s - mutex abstraction * @m_lock: Mutex lock * @cookie: Lock cookie * @process_id: Process ID to track lock * @state: Lock status * @refcount: Reference count for recursive lock * @stats: a structure that contains usage statistics */ struct qdf_lock_s { struct mutex m_lock; uint32_t cookie; int process_id; uint32_t state; uint8_t refcount; struct lock_stats stats; }; /** * typedef __qdf_mutex_t - Mutex abstraction */ typedef struct qdf_lock_s __qdf_mutex_t; /** * typedef __qdf_spinlock_t - spinlock abstraction * @spinlock: Spin lock * @flags: Lock flag */ typedef struct __qdf_spinlock { spinlock_t spinlock; unsigned long flags; } __qdf_spinlock_t; /** * typedef __qdf_semaphore_t - semaphore abstraction */ typedef struct semaphore __qdf_semaphore_t; /** * typedef qdf_wake_lock_t - wakelock abstraction * @lock: this lock needs to be used in kernel version < 5.4 * @priv: this lock pointer needs to be used in kernel version >= 5.4 */ typedef struct qdf_wake_lock { struct wakeup_source lock; struct wakeup_source *priv; } qdf_wake_lock_t; struct hif_pm_runtime_lock; typedef struct qdf_runtime_lock { struct hif_pm_runtime_lock *lock; } qdf_runtime_lock_t; #define LINUX_LOCK_COOKIE 0x12345678 /* Function declarations and documentation */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) /** * __qdf_semaphore_init() - initialize the semaphore * @m: Semaphore object * * Return: QDF_STATUS_SUCCESS */ static inline QDF_STATUS __qdf_semaphore_init(struct semaphore *m) { init_MUTEX(m); return QDF_STATUS_SUCCESS; } #else static inline QDF_STATUS __qdf_semaphore_init(struct semaphore *m) { sema_init(m, 1); return QDF_STATUS_SUCCESS; } #endif /** * __qdf_semaphore_acquire() - acquire semaphore * @m: Semaphore object * * Return: 0 */ static inline int __qdf_semaphore_acquire(struct semaphore *m) { down(m); return 0; } /** * __qdf_semaphore_acquire_intr() - Take the semaphore, interruptible * @m: Semaphore object * * This function allows a user-space process that is waiting on a * semaphore to be interrupted by the user. If the operation is * interrupted, the function returns a nonzero value, and the caller * does not hold the semaphore. Always check the return value and * responding accordingly. * * Return: 0 if the semaphore was acquired, non-zero if not acquired */ static inline int __qdf_semaphore_acquire_intr(struct semaphore *m) { return down_interruptible(m); } /** * __qdf_semaphore_release() - release semaphore * @m: Semaphore object * * Return: result of UP operation in integer */ static inline void __qdf_semaphore_release(struct semaphore *m) { up(m); } /** * __qdf_semaphore_acquire_timeout() - Take the semaphore before timeout * @m: semaphore to take * @timeout: maximum time to try to take the semaphore * * Return: int */ static inline int __qdf_semaphore_acquire_timeout(struct semaphore *m, unsigned long timeout) { unsigned long jiffie_val = msecs_to_jiffies(timeout); return down_timeout(m, jiffie_val); } /** * __qdf_spinlock_create() - initialize spin lock * @lock: Spin lock object * * Return: QDF_STATUS_SUCCESS */ static inline QDF_STATUS __qdf_spinlock_create(__qdf_spinlock_t *lock) { spin_lock_init(&lock->spinlock); lock->flags = 0; return QDF_STATUS_SUCCESS; } #define __qdf_spinlock_destroy(lock) /** * __qdf_spin_lock() - Acquire a Spinlock(SMP) & disable Preemption (Preemptive) * @lock: Lock object * * Return: none */ static inline void __qdf_spin_lock(__qdf_spinlock_t *lock) { spin_lock(&lock->spinlock); } /** * __qdf_spin_unlock() - Unlock the spinlock and enables the Preemption * @lock: Lock object * * Return: none */ static inline void __qdf_spin_unlock(__qdf_spinlock_t *lock) { spin_unlock(&lock->spinlock); } /** * __qdf_spin_lock_irqsave() - Acquire a Spinlock (SMP) & disable Preemption * (Preemptive) and disable IRQs * @lock: Lock object * * Return: none */ static inline void __qdf_spin_lock_irqsave(__qdf_spinlock_t *lock) { spin_lock_irqsave(&lock->spinlock, lock->flags); } /** * __qdf_spin_unlock_irqrestore() - Unlock the spinlock and enables the * Preemption and enable IRQ * @lock: Lock object * * Return: none */ static inline void __qdf_spin_unlock_irqrestore(__qdf_spinlock_t *lock) { spin_unlock_irqrestore(&lock->spinlock, lock->flags); } /* * Synchronous versions - only for OS' that have interrupt disable */ #define __qdf_spin_lock_irq(_p_lock, _flags) spin_lock_irqsave(_p_lock, _flags) #define __qdf_spin_unlock_irq(_p_lock, _flags) \ spin_unlock_irqrestore(_p_lock, _flags) /** * __qdf_spin_is_locked() - Test if spinlock is locked * @lock: spinlock object * * Return: nonzero if lock is held. */ static inline int __qdf_spin_is_locked(__qdf_spinlock_t *lock) { return spin_is_locked(&lock->spinlock); } /** * __qdf_spin_trylock_bh() - spin trylock bottomhalf * @lock: spinlock object * * Return: nonzero if lock is acquired */ static inline int __qdf_spin_trylock_bh(__qdf_spinlock_t *lock) { if (likely(irqs_disabled() || in_irq() || in_softirq())) return spin_trylock(&lock->spinlock); if (spin_trylock_bh(&lock->spinlock)) { lock->flags |= QDF_LINUX_UNLOCK_BH; return 1; } return 0; } /** * __qdf_spin_trylock() - spin trylock * @lock: spinlock object * * Return: int */ static inline int __qdf_spin_trylock(__qdf_spinlock_t *lock) { return spin_trylock(&lock->spinlock); } /** * __qdf_spin_lock_bh() - Acquire the spinlock and disable bottom halves * @lock: Lock object * * Return: none */ static inline void __qdf_spin_lock_bh(__qdf_spinlock_t *lock) { if (likely(irqs_disabled() || in_irq() || in_softirq())) { spin_lock(&lock->spinlock); } else { spin_lock_bh(&lock->spinlock); lock->flags |= QDF_LINUX_UNLOCK_BH; } } /** * __qdf_spin_unlock_bh() - Release the spinlock and enable bottom halves * @lock: Lock object * * Return: none */ static inline void __qdf_spin_unlock_bh(__qdf_spinlock_t *lock) { if (unlikely(lock->flags & QDF_LINUX_UNLOCK_BH)) { lock->flags &= (unsigned long)~QDF_LINUX_UNLOCK_BH; spin_unlock_bh(&lock->spinlock); } else spin_unlock(&lock->spinlock); } /** * __qdf_spinlock_irq_exec() - Execute the input function with * spinlock held and interrupt disabled. * @hdl: OS handle * @lock: spinlock to be held for the critical region * @func: critical region function that to be executed * @arg: context of the critical region function * * Return: Boolean status returned by the critical region function */ static inline bool __qdf_spinlock_irq_exec(qdf_handle_t hdl, __qdf_spinlock_t *lock, qdf_irqlocked_func_t func, void *arg) { unsigned long flags; bool ret; spin_lock_irqsave(&lock->spinlock, flags); ret = func(arg); spin_unlock_irqrestore(&lock->spinlock, flags); return ret; } /** * __qdf_in_softirq() - in soft irq context * * Return: true if in softirs context else false */ static inline bool __qdf_in_softirq(void) { return in_softirq(); } #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __I_QDF_LOCK_H */