1  /*
2   * Copyright (c) 2014-2018, 2020 The Linux Foundation. All rights reserved.
3   * Copyright (c) 2022-2023 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  /**
21   * DOC: i_qdf_lock.h
22   * Linux-specific definitions for QDF Lock API's
23   */
24  
25  #if !defined(__I_QDF_LOCK_H)
26  #define __I_QDF_LOCK_H
27  
28  /* Include Files */
29  #include <qdf_types.h>
30  #include <qdf_status.h>
31  #include <linux/mutex.h>
32  #include <linux/spinlock.h>
33  #include <linux/sched.h>
34  #include <linux/device.h>
35  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
36  #include <asm/semaphore.h>
37  #else
38  #include <linux/semaphore.h>
39  #endif
40  #include <linux/interrupt.h>
41  #include <linux/pm_wakeup.h>
42  
43  /* define for flag */
44  #define QDF_LINUX_UNLOCK_BH  1
45  
46  #ifdef __cplusplus
47  extern "C" {
48  #endif /* __cplusplus */
49  
50  enum {
51  	LOCK_RELEASED = 0x11223344,
52  	LOCK_ACQUIRED,
53  	LOCK_DESTROYED
54  };
55  
56  /**
57   * struct qdf_lock_s - mutex abstraction
58   * @m_lock: Mutex lock
59   * @cookie: Lock cookie
60   * @process_id: Process ID to track lock
61   * @state: Lock status
62   * @refcount: Reference count for recursive lock
63   * @stats: a structure that contains usage statistics
64   */
65  struct qdf_lock_s {
66  	struct mutex m_lock;
67  	uint32_t cookie;
68  	int process_id;
69  	uint32_t state;
70  	uint8_t refcount;
71  	struct lock_stats stats;
72  };
73  
74  /**
75   * typedef __qdf_mutex_t - Mutex abstraction
76   */
77  typedef struct qdf_lock_s __qdf_mutex_t;
78  
79  /**
80   * typedef __qdf_spinlock_t - spinlock abstraction
81   * @spinlock: Spin lock
82   * @flags: Lock flag
83   */
84  typedef struct __qdf_spinlock {
85  	spinlock_t spinlock;
86  	unsigned long flags;
87  } __qdf_spinlock_t;
88  
89  /**
90   * typedef __qdf_semaphore_t - semaphore abstraction
91   */
92  typedef struct semaphore __qdf_semaphore_t;
93  
94  /**
95   * typedef qdf_wake_lock_t - wakelock abstraction
96   * @lock: this lock needs to be used in kernel version < 5.4
97   * @priv: this lock pointer needs to be used in kernel version >= 5.4
98   */
99  typedef struct qdf_wake_lock {
100  	struct wakeup_source lock;
101  	struct wakeup_source *priv;
102  } qdf_wake_lock_t;
103  
104  struct hif_pm_runtime_lock;
105  typedef struct qdf_runtime_lock {
106  	struct hif_pm_runtime_lock *lock;
107  } qdf_runtime_lock_t;
108  
109  #define LINUX_LOCK_COOKIE 0x12345678
110  
111  /* Function declarations and documentation */
112  
113  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
114  /**
115   * __qdf_semaphore_init() - initialize the semaphore
116   * @m: Semaphore object
117   *
118   * Return: QDF_STATUS_SUCCESS
119   */
__qdf_semaphore_init(struct semaphore * m)120  static inline QDF_STATUS __qdf_semaphore_init(struct semaphore *m)
121  {
122  	init_MUTEX(m);
123  	return QDF_STATUS_SUCCESS;
124  }
125  #else
__qdf_semaphore_init(struct semaphore * m)126  static inline QDF_STATUS __qdf_semaphore_init(struct semaphore *m)
127  {
128  	sema_init(m, 1);
129  	return QDF_STATUS_SUCCESS;
130  }
131  #endif
132  
133  /**
134   * __qdf_semaphore_acquire() - acquire semaphore
135   * @m: Semaphore object
136   *
137   * Return: 0
138   */
__qdf_semaphore_acquire(struct semaphore * m)139  static inline int __qdf_semaphore_acquire(struct semaphore *m)
140  {
141  	down(m);
142  	return 0;
143  }
144  
145  /**
146   * __qdf_semaphore_acquire_intr() - Take the semaphore, interruptible
147   * @m: Semaphore object
148   *
149   * This function allows a user-space process that is waiting on a
150   * semaphore to be interrupted by the user.  If the operation is
151   * interrupted, the function returns a nonzero value, and the caller
152   * does not hold the semaphore.  Always check the return value and
153   * responding accordingly.
154   *
155   * Return: 0 if the semaphore was acquired, non-zero if not acquired
156   */
__qdf_semaphore_acquire_intr(struct semaphore * m)157  static inline int __qdf_semaphore_acquire_intr(struct semaphore *m)
158  {
159  	return down_interruptible(m);
160  }
161  
162  /**
163   * __qdf_semaphore_release() - release semaphore
164   * @m: Semaphore object
165   *
166   * Return: result of UP operation in integer
167   */
__qdf_semaphore_release(struct semaphore * m)168  static inline void __qdf_semaphore_release(struct semaphore *m)
169  {
170  	up(m);
171  }
172  
173  /**
174   * __qdf_semaphore_acquire_timeout() - Take the semaphore before timeout
175   * @m: semaphore to take
176   * @timeout: maximum time to try to take the semaphore
177   *
178   * Return: int
179   */
__qdf_semaphore_acquire_timeout(struct semaphore * m,unsigned long timeout)180  static inline int __qdf_semaphore_acquire_timeout(struct semaphore *m,
181  						  unsigned long timeout)
182  {
183  	unsigned long jiffie_val = msecs_to_jiffies(timeout);
184  
185  	return down_timeout(m, jiffie_val);
186  }
187  
188  /**
189   * __qdf_spinlock_create() - initialize spin lock
190   * @lock: Spin lock object
191   *
192   * Return: QDF_STATUS_SUCCESS
193   */
__qdf_spinlock_create(__qdf_spinlock_t * lock)194  static inline QDF_STATUS __qdf_spinlock_create(__qdf_spinlock_t *lock)
195  {
196  	spin_lock_init(&lock->spinlock);
197  	lock->flags = 0;
198  	return QDF_STATUS_SUCCESS;
199  }
200  
201  #define __qdf_spinlock_destroy(lock)
202  
203  /**
204   * __qdf_spin_lock() - Acquire a Spinlock(SMP) & disable Preemption (Preemptive)
205   * @lock: Lock object
206   *
207   * Return: none
208   */
__qdf_spin_lock(__qdf_spinlock_t * lock)209  static inline void __qdf_spin_lock(__qdf_spinlock_t *lock)
210  {
211  	spin_lock(&lock->spinlock);
212  }
213  
214  /**
215   * __qdf_spin_unlock() - Unlock the spinlock and enables the Preemption
216   * @lock: Lock object
217   *
218   * Return: none
219   */
__qdf_spin_unlock(__qdf_spinlock_t * lock)220  static inline void __qdf_spin_unlock(__qdf_spinlock_t *lock)
221  {
222  	spin_unlock(&lock->spinlock);
223  }
224  
225  /**
226   * __qdf_spin_lock_irqsave() - Acquire a Spinlock (SMP) & disable Preemption
227   * (Preemptive) and disable IRQs
228   * @lock: Lock object
229   *
230   * Return: none
231   */
__qdf_spin_lock_irqsave(__qdf_spinlock_t * lock)232  static inline void __qdf_spin_lock_irqsave(__qdf_spinlock_t *lock)
233  {
234  	spin_lock_irqsave(&lock->spinlock, lock->flags);
235  }
236  
237  /**
238   * __qdf_spin_unlock_irqrestore() - Unlock the spinlock and enables the
239   * Preemption and enable IRQ
240   * @lock: Lock object
241   *
242   * Return: none
243   */
__qdf_spin_unlock_irqrestore(__qdf_spinlock_t * lock)244  static inline void __qdf_spin_unlock_irqrestore(__qdf_spinlock_t *lock)
245  {
246  	spin_unlock_irqrestore(&lock->spinlock, lock->flags);
247  }
248  
249  /*
250   * Synchronous versions - only for OS' that have interrupt disable
251   */
252  #define __qdf_spin_lock_irq(_p_lock, _flags) spin_lock_irqsave(_p_lock, _flags)
253  #define __qdf_spin_unlock_irq(_p_lock, _flags) \
254  	spin_unlock_irqrestore(_p_lock, _flags)
255  
256  /**
257   * __qdf_spin_is_locked() - Test if spinlock is locked
258   * @lock: spinlock object
259   *
260   * Return: nonzero if lock is held.
261   */
__qdf_spin_is_locked(__qdf_spinlock_t * lock)262  static inline int __qdf_spin_is_locked(__qdf_spinlock_t *lock)
263  {
264  	return spin_is_locked(&lock->spinlock);
265  }
266  
267  /**
268   * __qdf_spin_trylock_bh() - spin trylock bottomhalf
269   * @lock: spinlock object
270   *
271   * Return: nonzero if lock is acquired
272   */
__qdf_spin_trylock_bh(__qdf_spinlock_t * lock)273  static inline int __qdf_spin_trylock_bh(__qdf_spinlock_t *lock)
274  {
275  	if (likely(irqs_disabled() || in_irq() || in_softirq()))
276  		return spin_trylock(&lock->spinlock);
277  
278  	if (spin_trylock_bh(&lock->spinlock)) {
279  		lock->flags |= QDF_LINUX_UNLOCK_BH;
280  		return 1;
281  	}
282  
283  	return 0;
284  }
285  
286  /**
287   * __qdf_spin_trylock() - spin trylock
288   * @lock: spinlock object
289   *
290   * Return: int
291   */
__qdf_spin_trylock(__qdf_spinlock_t * lock)292  static inline int __qdf_spin_trylock(__qdf_spinlock_t *lock)
293  {
294  	return spin_trylock(&lock->spinlock);
295  }
296  
297  /**
298   * __qdf_spin_lock_bh() - Acquire the spinlock and disable bottom halves
299   * @lock: Lock object
300   *
301   * Return: none
302   */
__qdf_spin_lock_bh(__qdf_spinlock_t * lock)303  static inline void __qdf_spin_lock_bh(__qdf_spinlock_t *lock)
304  {
305  	if (likely(irqs_disabled() || in_irq() || in_softirq())) {
306  		spin_lock(&lock->spinlock);
307  	} else {
308  		spin_lock_bh(&lock->spinlock);
309  		lock->flags |= QDF_LINUX_UNLOCK_BH;
310  	}
311  }
312  
313  /**
314   * __qdf_spin_unlock_bh() - Release the spinlock and enable bottom halves
315   * @lock: Lock object
316   *
317   * Return: none
318   */
__qdf_spin_unlock_bh(__qdf_spinlock_t * lock)319  static inline void __qdf_spin_unlock_bh(__qdf_spinlock_t *lock)
320  {
321  	if (unlikely(lock->flags & QDF_LINUX_UNLOCK_BH)) {
322  		lock->flags &= (unsigned long)~QDF_LINUX_UNLOCK_BH;
323  		spin_unlock_bh(&lock->spinlock);
324  	} else
325  		spin_unlock(&lock->spinlock);
326  }
327  
328  /**
329   * __qdf_spinlock_irq_exec() - Execute the input function with
330   *                             spinlock held and interrupt disabled.
331   * @hdl: OS handle
332   * @lock: spinlock to be held for the critical region
333   * @func: critical region function that to be executed
334   * @arg: context of the critical region function
335   *
336   * Return: Boolean status returned by the critical region function
337   */
__qdf_spinlock_irq_exec(qdf_handle_t hdl,__qdf_spinlock_t * lock,qdf_irqlocked_func_t func,void * arg)338  static inline bool __qdf_spinlock_irq_exec(qdf_handle_t hdl,
339  			__qdf_spinlock_t *lock,
340  			qdf_irqlocked_func_t func,
341  			void *arg)
342  {
343  	unsigned long flags;
344  	bool ret;
345  
346  	spin_lock_irqsave(&lock->spinlock, flags);
347  	ret = func(arg);
348  	spin_unlock_irqrestore(&lock->spinlock, flags);
349  
350  	return ret;
351  }
352  
353  /**
354   * __qdf_in_softirq() - in soft irq context
355   *
356   * Return: true if in softirs context else false
357   */
__qdf_in_softirq(void)358  static inline bool __qdf_in_softirq(void)
359  {
360  	return in_softirq();
361  }
362  
363  #ifdef __cplusplus
364  }
365  #endif /* __cplusplus */
366  
367  #endif /* __I_QDF_LOCK_H */
368