xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_lock.c (revision dd4dc88b837a295134aa9869114a2efee0f4894b)
1 /*
2  * Copyright (c) 2014-2019 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 CONFIG_MCL
27 #include <cds_api.h>
28 #include <hif.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) {
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) {
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) {
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 	host_diag_log_wlock(reason, qdf_wake_lock_name(lock),
294 			    WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT,
295 			    WIFI_POWER_EVENT_WAKELOCK_TAKEN);
296 	__pm_stay_awake(lock);
297 
298 	return QDF_STATUS_SUCCESS;
299 }
300 #else
301 QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason)
302 {
303 	return QDF_STATUS_SUCCESS;
304 }
305 #endif
306 qdf_export_symbol(qdf_wake_lock_acquire);
307 
308 /**
309  * qdf_wake_lock_timeout_acquire() - acquires a wake lock with a timeout
310  * @lock: The wake lock to acquire
311  * @reason: Reason for wakelock
312  *
313  * Return:
314  * QDF status success: if wake lock is acquired
315  * QDF status failure: if wake lock was not acquired
316  */
317 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
318 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
319 {
320 	pm_wakeup_ws_event(lock, msec, true);
321 	return QDF_STATUS_SUCCESS;
322 }
323 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
324 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
325 {
326 	/* Wakelock for Rx is frequent.
327 	 * It is reported only during active debug
328 	 */
329 	__pm_wakeup_event(lock, msec);
330 	return QDF_STATUS_SUCCESS;
331 }
332 #else /* LINUX_VERSION_CODE */
333 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
334 {
335 	return QDF_STATUS_SUCCESS;
336 }
337 #endif /* LINUX_VERSION_CODE */
338 qdf_export_symbol(qdf_wake_lock_timeout_acquire);
339 
340 /**
341  * qdf_wake_lock_release() - releases a wake lock
342  * @lock: the wake lock to release
343  * @reason: Reason for wakelock
344  *
345  * Return:
346  * QDF status success: if wake lock is acquired
347  * QDF status failure: if wake lock was not acquired
348  */
349 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
350 QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason)
351 {
352 	host_diag_log_wlock(reason, qdf_wake_lock_name(lock),
353 			    WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT,
354 			    WIFI_POWER_EVENT_WAKELOCK_RELEASED);
355 	__pm_relax(lock);
356 
357 	return QDF_STATUS_SUCCESS;
358 }
359 #else
360 QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason)
361 {
362 	return QDF_STATUS_SUCCESS;
363 }
364 #endif
365 qdf_export_symbol(qdf_wake_lock_release);
366 
367 /**
368  * qdf_wake_lock_destroy() - destroys a wake lock
369  * @lock: The wake lock to destroy
370  *
371  * Return:
372  * QDF status success: if wake lock is acquired
373  * QDF status failure: if wake lock was not acquired
374  */
375 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
376 QDF_STATUS qdf_wake_lock_destroy(qdf_wake_lock_t *lock)
377 {
378 	wakeup_source_trash(lock);
379 	return QDF_STATUS_SUCCESS;
380 }
381 #else
382 QDF_STATUS qdf_wake_lock_destroy(qdf_wake_lock_t *lock)
383 {
384 	return QDF_STATUS_SUCCESS;
385 }
386 #endif
387 qdf_export_symbol(qdf_wake_lock_destroy);
388 
389 #ifdef CONFIG_MCL
390 /**
391  * qdf_runtime_pm_get() - do a get opperation on the device
392  *
393  * A get opperation will prevent a runtime suspend until a
394  * corresponding put is done.  This api should be used when sending
395  * data.
396  *
397  * CONTRARY TO THE REGULAR RUNTIME PM, WHEN THE BUS IS SUSPENDED,
398  * THIS API WILL ONLY REQUEST THE RESUME AND NOT TO A GET!!!
399  *
400  * return: success if the bus is up and a get has been issued
401  *   otherwise an error code.
402  */
403 QDF_STATUS qdf_runtime_pm_get(void)
404 {
405 	void *ol_sc;
406 	int ret;
407 
408 	ol_sc = cds_get_context(QDF_MODULE_ID_HIF);
409 
410 	if (!ol_sc) {
411 		QDF_ASSERT(0);
412 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
413 			  "%s: HIF context is null!", __func__);
414 		return QDF_STATUS_E_INVAL;
415 	}
416 
417 	ret = hif_pm_runtime_get(ol_sc);
418 
419 	if (ret)
420 		return QDF_STATUS_E_FAILURE;
421 	return QDF_STATUS_SUCCESS;
422 }
423 qdf_export_symbol(qdf_runtime_pm_get);
424 
425 /**
426  * qdf_runtime_pm_put() - do a put opperation on the device
427  *
428  * A put opperation will allow a runtime suspend after a corresponding
429  * get was done.  This api should be used when sending data.
430  *
431  * This api will return a failure if the hif module hasn't been
432  * initialized
433  *
434  * return: QDF_STATUS_SUCCESS if the put is performed
435  */
436 QDF_STATUS qdf_runtime_pm_put(void)
437 {
438 	void *ol_sc;
439 	int ret;
440 
441 	ol_sc = cds_get_context(QDF_MODULE_ID_HIF);
442 
443 	if (!ol_sc) {
444 		QDF_ASSERT(0);
445 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
446 			  "%s: HIF context is null!", __func__);
447 		return QDF_STATUS_E_INVAL;
448 	}
449 
450 	ret = hif_pm_runtime_put(ol_sc);
451 
452 	if (ret)
453 		return QDF_STATUS_E_FAILURE;
454 	return QDF_STATUS_SUCCESS;
455 }
456 qdf_export_symbol(qdf_runtime_pm_put);
457 
458 /**
459  * qdf_runtime_pm_prevent_suspend() - prevent a runtime bus suspend
460  * @lock: an opaque context for tracking
461  *
462  * The lock can only be acquired once per lock context and is tracked.
463  *
464  * return: QDF_STATUS_SUCCESS or failure code.
465  */
466 QDF_STATUS qdf_runtime_pm_prevent_suspend(qdf_runtime_lock_t *lock)
467 {
468 	void *ol_sc;
469 	int ret;
470 
471 	ol_sc = cds_get_context(QDF_MODULE_ID_HIF);
472 
473 	if (!ol_sc) {
474 		QDF_ASSERT(0);
475 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
476 			  "%s: HIF context is null!", __func__);
477 		return QDF_STATUS_E_INVAL;
478 	}
479 
480 	ret = hif_pm_runtime_prevent_suspend(ol_sc, lock->lock);
481 
482 	if (ret)
483 		return QDF_STATUS_E_FAILURE;
484 	return QDF_STATUS_SUCCESS;
485 }
486 qdf_export_symbol(qdf_runtime_pm_prevent_suspend);
487 
488 /**
489  * qdf_runtime_pm_allow_suspend() - prevent a runtime bus suspend
490  * @lock: an opaque context for tracking
491  *
492  * The lock can only be acquired once per lock context and is tracked.
493  *
494  * return: QDF_STATUS_SUCCESS or failure code.
495  */
496 QDF_STATUS qdf_runtime_pm_allow_suspend(qdf_runtime_lock_t *lock)
497 {
498 	void *ol_sc;
499 	int ret;
500 
501 	ol_sc = cds_get_context(QDF_MODULE_ID_HIF);
502 	if (!ol_sc) {
503 		QDF_ASSERT(0);
504 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
505 		"%s: HIF context is null!", __func__);
506 		return QDF_STATUS_E_INVAL;
507 	}
508 
509 	ret = hif_pm_runtime_allow_suspend(ol_sc, lock->lock);
510 	if (ret)
511 		return QDF_STATUS_E_FAILURE;
512 
513 	return QDF_STATUS_SUCCESS;
514 }
515 qdf_export_symbol(qdf_runtime_pm_allow_suspend);
516 
517 /**
518  * qdf_runtime_lock_init() - initialize runtime lock
519  * @name: name of the runtime lock
520  *
521  * Initialize a runtime pm lock.  This lock can be used
522  * to prevent the runtime pm system from putting the bus
523  * to sleep.
524  *
525  * Return: runtime_pm_lock_t
526  */
527 QDF_STATUS __qdf_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name)
528 {
529 	int ret = hif_runtime_lock_init(lock, name);
530 
531 	if (ret)
532 		return QDF_STATUS_E_NOMEM;
533 
534 	return QDF_STATUS_SUCCESS;
535 }
536 qdf_export_symbol(__qdf_runtime_lock_init);
537 
538 /**
539  * qdf_runtime_lock_deinit() - deinitialize runtime pm lock
540  * @lock: the lock to deinitialize
541  *
542  * Ensures the lock is released. Frees the runtime lock.
543  *
544  * Return: void
545  */
546 void qdf_runtime_lock_deinit(qdf_runtime_lock_t *lock)
547 {
548 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
549 	hif_runtime_lock_deinit(hif_ctx, lock->lock);
550 }
551 qdf_export_symbol(qdf_runtime_lock_deinit);
552 
553 #else
554 
555 QDF_STATUS qdf_runtime_pm_get(void)
556 {
557 	return QDF_STATUS_SUCCESS;
558 }
559 qdf_export_symbol(qdf_runtime_pm_get);
560 
561 QDF_STATUS qdf_runtime_pm_put(void)
562 {
563 	return QDF_STATUS_SUCCESS;
564 }
565 qdf_export_symbol(qdf_runtime_pm_put);
566 
567 QDF_STATUS qdf_runtime_pm_prevent_suspend(qdf_runtime_lock_t *lock)
568 {
569 	return QDF_STATUS_SUCCESS;
570 }
571 qdf_export_symbol(qdf_runtime_pm_prevent_suspend);
572 
573 QDF_STATUS qdf_runtime_pm_allow_suspend(qdf_runtime_lock_t *lock)
574 {
575 	return QDF_STATUS_SUCCESS;
576 }
577 qdf_export_symbol(qdf_runtime_pm_allow_suspend);
578 
579 QDF_STATUS __qdf_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name)
580 {
581 	return QDF_STATUS_SUCCESS;
582 }
583 qdf_export_symbol(__qdf_runtime_lock_init);
584 
585 void qdf_runtime_lock_deinit(qdf_runtime_lock_t *lock)
586 {
587 }
588 qdf_export_symbol(qdf_runtime_lock_deinit);
589 
590 #endif /* CONFIG_MCL */
591 
592 /**
593  * qdf_spinlock_acquire() - acquires a spin lock
594  * @lock: Spin lock to acquire
595  *
596  * Return:
597  * QDF status success: if wake lock is acquired
598  */
599 QDF_STATUS qdf_spinlock_acquire(qdf_spinlock_t *lock)
600 {
601 	spin_lock(&lock->lock.spinlock);
602 	return QDF_STATUS_SUCCESS;
603 }
604 qdf_export_symbol(qdf_spinlock_acquire);
605 
606 
607 /**
608  * qdf_spinlock_release() - release a spin lock
609  * @lock: Spin lock to release
610  *
611  * Return:
612  * QDF status success : if wake lock is acquired
613  */
614 QDF_STATUS qdf_spinlock_release(qdf_spinlock_t *lock)
615 {
616 	spin_unlock(&lock->lock.spinlock);
617 	return QDF_STATUS_SUCCESS;
618 }
619 qdf_export_symbol(qdf_spinlock_release);
620 
621 /**
622  * qdf_mutex_destroy() - destroy a QDF lock
623  * @lock: Pointer to the opaque lock object to be destroyed
624  *
625  * function shall destroy the lock object referenced by lock. After a
626  * successful return from qdf_mutex_destroy()
627  * the lock object becomes, in effect, uninitialized.
628  *
629  * A destroyed lock object can be reinitialized using qdf_mutex_create();
630  * the results of otherwise referencing the object after it has been destroyed
631  * are undefined.  Calls to QDF lock functions to manipulate the lock such
632  * as qdf_mutex_acquire() will fail if the lock is destroyed.  Therefore,
633  * don't use the lock after it has been destroyed until it has
634  * been re-initialized.
635  *
636  * Return:
637  * QDF_STATUS_SUCCESS: lock was successfully initialized
638  * QDF failure reason codes: lock is not initialized and can't be used
639  */
640 QDF_STATUS qdf_mutex_destroy(qdf_mutex_t *lock)
641 {
642 	/* check for invalid pointer */
643 	if (!lock) {
644 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
645 			  "%s: NULL pointer passed in", __func__);
646 		return QDF_STATUS_E_FAULT;
647 	}
648 
649 	if (LINUX_LOCK_COOKIE != lock->cookie) {
650 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
651 			  "%s: uninitialized lock", __func__);
652 		return QDF_STATUS_E_INVAL;
653 	}
654 
655 	if (in_interrupt()) {
656 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
657 			  "%s cannot be called from interrupt context!!!",
658 			  __func__);
659 		return QDF_STATUS_E_FAULT;
660 	}
661 
662 	/* check if lock is released */
663 	if (!mutex_trylock(&lock->m_lock)) {
664 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
665 			  "%s: lock is not released", __func__);
666 		return QDF_STATUS_E_BUSY;
667 	}
668 	lock->cookie = 0;
669 	lock->state = LOCK_DESTROYED;
670 	lock->process_id = 0;
671 	lock->refcount = 0;
672 
673 	qdf_lock_stats_destroy(&lock->stats);
674 	mutex_unlock(&lock->m_lock);
675 
676 	return QDF_STATUS_SUCCESS;
677 }
678 qdf_export_symbol(qdf_mutex_destroy);
679 
680 #if QDF_LOCK_STATS_LIST
681 struct qdf_lock_cookie {
682 	union {
683 		struct {
684 			struct lock_stats *stats;
685 			const char *func;
686 			int line;
687 		} cookie;
688 		struct {
689 			struct qdf_lock_cookie *next;
690 		} empty_node;
691 	} u;
692 };
693 
694 #ifndef QDF_LOCK_STATS_LIST_SIZE
695 #define QDF_LOCK_STATS_LIST_SIZE 256
696 #endif
697 
698 static qdf_spinlock_t qdf_lock_list_spinlock;
699 static struct qdf_lock_cookie lock_cookies[QDF_LOCK_STATS_LIST_SIZE];
700 static struct qdf_lock_cookie *lock_cookie_freelist;
701 static qdf_atomic_t lock_cookie_get_failures;
702 static qdf_atomic_t lock_cookie_untracked_num;
703 /* dummy value */
704 #define DUMMY_LOCK_COOKIE 0xc00c1e
705 
706 /**
707  * qdf_is_lock_cookie - check if memory is a valid lock cookie
708  *
709  * return true if the memory is within the range of the lock cookie
710  * memory.
711  */
712 static bool qdf_is_lock_cookie(struct qdf_lock_cookie *lock_cookie)
713 {
714 	return lock_cookie >= &lock_cookies[0] &&
715 		lock_cookie <= &lock_cookies[QDF_LOCK_STATS_LIST_SIZE-1];
716 }
717 
718 /**
719  * qdf_is_lock_cookie_free() -  check if the lock cookie is on the freelist
720  * @lock_cookie: lock cookie to check
721  *
722  * Check that the next field of the lock cookie points to a lock cookie.
723  * currently this is only true if the cookie is on the freelist.
724  *
725  * Checking for the function and line being NULL and 0 should also have worked.
726  */
727 static bool qdf_is_lock_cookie_free(struct qdf_lock_cookie *lock_cookie)
728 {
729 	struct qdf_lock_cookie *tmp = lock_cookie->u.empty_node.next;
730 
731 	return qdf_is_lock_cookie(tmp) || (!tmp);
732 }
733 
734 static struct qdf_lock_cookie *qdf_get_lock_cookie(void)
735 {
736 	struct qdf_lock_cookie *lock_cookie;
737 
738 	qdf_spin_lock_bh(&qdf_lock_list_spinlock);
739 	lock_cookie = lock_cookie_freelist;
740 	if (lock_cookie_freelist)
741 		lock_cookie_freelist = lock_cookie_freelist->u.empty_node.next;
742 	qdf_spin_unlock_bh(&qdf_lock_list_spinlock);
743 	return lock_cookie;
744 }
745 
746 static void __qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie)
747 {
748 	if (!qdf_is_lock_cookie(lock_cookie))
749 		QDF_BUG(0);
750 
751 	lock_cookie->u.empty_node.next = lock_cookie_freelist;
752 	lock_cookie_freelist = lock_cookie;
753 }
754 
755 static void qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie)
756 {
757 	qdf_spin_lock_bh(&qdf_lock_list_spinlock);
758 	__qdf_put_lock_cookie(lock_cookie);
759 	qdf_spin_unlock_bh(&qdf_lock_list_spinlock);
760 }
761 
762 void qdf_lock_stats_init(void)
763 {
764 	int i;
765 
766 	for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++)
767 		__qdf_put_lock_cookie(&lock_cookies[i]);
768 
769 	/* stats must be allocated for the spinlock before the cookie,
770 	 * otherwise this qdf_lock_list_spinlock wouldnt get initialized
771 	 * properly
772 	 */
773 	qdf_spinlock_create(&qdf_lock_list_spinlock);
774 	qdf_atomic_init(&lock_cookie_get_failures);
775 	qdf_atomic_init(&lock_cookie_untracked_num);
776 }
777 
778 void qdf_lock_stats_deinit(void)
779 {
780 	int i;
781 
782 	qdf_spinlock_destroy(&qdf_lock_list_spinlock);
783 	for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++) {
784 		if (!qdf_is_lock_cookie_free(&lock_cookies[i]))
785 			QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
786 				  "%s: lock_not_destroyed, fun: %s, line %d",
787 				  __func__, lock_cookies[i].u.cookie.func,
788 				  lock_cookies[i].u.cookie.line);
789 	}
790 }
791 
792 /* allocated separate memory in case the lock memory is freed without
793  * running the deinitialization code.  The cookie list will not be
794  * corrupted.
795  */
796 void qdf_lock_stats_cookie_create(struct lock_stats *stats,
797 				  const char *func, int line)
798 {
799 	struct qdf_lock_cookie *cookie = qdf_get_lock_cookie();
800 
801 	if (!cookie) {
802 		int count;
803 
804 		qdf_atomic_inc(&lock_cookie_get_failures);
805 		count = qdf_atomic_inc_return(&lock_cookie_untracked_num);
806 		stats->cookie = (void *) DUMMY_LOCK_COOKIE;
807 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
808 			  "%s: cookie allocation failure, using dummy (%s:%d) count %d",
809 			  __func__, func, line, count);
810 		return;
811 	}
812 
813 	stats->cookie = cookie;
814 	stats->cookie->u.cookie.stats = stats;
815 	stats->cookie->u.cookie.func = func;
816 	stats->cookie->u.cookie.line = line;
817 }
818 
819 void qdf_lock_stats_cookie_destroy(struct lock_stats *stats)
820 {
821 	struct qdf_lock_cookie *cookie = stats->cookie;
822 
823 	if (!cookie) {
824 		QDF_DEBUG_PANIC("Lock destroyed twice or never created");
825 		return;
826 	}
827 
828 	stats->cookie = NULL;
829 	if (cookie == (void *)DUMMY_LOCK_COOKIE) {
830 		qdf_atomic_dec(&lock_cookie_untracked_num);
831 		return;
832 	}
833 
834 	cookie->u.cookie.stats = NULL;
835 	cookie->u.cookie.func = NULL;
836 	cookie->u.cookie.line = 0;
837 
838 	qdf_put_lock_cookie(cookie);
839 }
840 #endif
841