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