xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_lock.c (revision 10fe6982eb7194813d8d8335da336bbcd531b22e)
1 /*
2  * Copyright (c) 2014-2021 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 #include <linux/module.h>
21 #include <qdf_lock.h>
22 #include <qdf_trace.h>
23 #include <qdf_module.h>
24 
25 #include <qdf_types.h>
26 #include <i_host_diag_core_event.h>
27 #ifdef FEATURE_RUNTIME_PM
28 #include <cds_api.h>
29 #include <hif.h>
30 #endif
31 #include <i_qdf_lock.h>
32 #include <linux/suspend.h>
33 
34 #undef qdf_mutex_create
35 QDF_STATUS qdf_mutex_create(qdf_mutex_t *lock, const char *func, int line)
36 {
37 	/* check for invalid pointer */
38 	if (!lock) {
39 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
40 			  "%s: NULL pointer passed in", __func__);
41 		return QDF_STATUS_E_FAULT;
42 	}
43 	/* check for 'already initialized' lock */
44 	if (LINUX_LOCK_COOKIE == lock->cookie) {
45 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
46 			  "%s: already initialized lock", __func__);
47 		return QDF_STATUS_E_BUSY;
48 	}
49 
50 	if (in_interrupt()) {
51 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
52 			  "%s cannot be called from interrupt context!!!",
53 			  __func__);
54 		return QDF_STATUS_E_FAULT;
55 	}
56 
57 	qdf_lock_stats_create(&lock->stats, func, line);
58 
59 	/* initialize new lock */
60 	mutex_init(&lock->m_lock);
61 	lock->cookie = LINUX_LOCK_COOKIE;
62 	lock->state = LOCK_RELEASED;
63 	lock->process_id = 0;
64 	lock->refcount = 0;
65 
66 	return QDF_STATUS_SUCCESS;
67 }
68 qdf_export_symbol(qdf_mutex_create);
69 
70 QDF_STATUS qdf_mutex_acquire(qdf_mutex_t *lock)
71 {
72 	int rc;
73 	/* check for invalid pointer */
74 	if (!lock) {
75 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
76 			  "%s: NULL pointer passed in", __func__);
77 		QDF_ASSERT(0);
78 		return QDF_STATUS_E_FAULT;
79 	}
80 	/* check if lock refers to an initialized object */
81 	if (LINUX_LOCK_COOKIE != lock->cookie) {
82 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
83 			  "%s: uninitialized lock", __func__);
84 		QDF_ASSERT(0);
85 		return QDF_STATUS_E_INVAL;
86 	}
87 
88 	if (in_interrupt()) {
89 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
90 			  "%s cannot be called from interrupt context!!!",
91 			  __func__);
92 		QDF_ASSERT(0);
93 		return QDF_STATUS_E_FAULT;
94 	}
95 	if ((lock->process_id == current->pid) &&
96 		(lock->state == LOCK_ACQUIRED)) {
97 		lock->refcount++;
98 #ifdef QDF_NESTED_LOCK_DEBUG
99 			pe_err("%s: %x %d %d", __func__, lock, current->pid,
100 			  lock->refcount);
101 #endif
102 		return QDF_STATUS_SUCCESS;
103 	}
104 
105 	BEFORE_LOCK(lock, mutex_is_locked(&lock->m_lock));
106 	/* acquire a Lock */
107 	mutex_lock(&lock->m_lock);
108 	AFTER_LOCK(lock, __func__);
109 	rc = mutex_is_locked(&lock->m_lock);
110 	if (rc == 0) {
111 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
112 			  "%s: unable to lock mutex (rc = %d)", __func__, rc);
113 		QDF_ASSERT(0);
114 		return QDF_STATUS_E_FAILURE;
115 	}
116 #ifdef QDF_NESTED_LOCK_DEBUG
117 		pe_err("%s: %x %d", __func__, lock, current->pid);
118 #endif
119 	if (LOCK_DESTROYED != lock->state) {
120 		lock->process_id = current->pid;
121 		lock->refcount++;
122 		lock->state = LOCK_ACQUIRED;
123 		return QDF_STATUS_SUCCESS;
124 	}
125 
126 	/* lock is already destroyed */
127 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
128 		  "%s: Lock is already destroyed", __func__);
129 	mutex_unlock(&lock->m_lock);
130 	QDF_ASSERT(0);
131 	return QDF_STATUS_E_FAILURE;
132 }
133 qdf_export_symbol(qdf_mutex_acquire);
134 
135 QDF_STATUS qdf_mutex_release(qdf_mutex_t *lock)
136 {
137 	/* check for invalid pointer */
138 	if (!lock) {
139 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
140 			  "%s: NULL pointer passed in", __func__);
141 		QDF_ASSERT(0);
142 		return QDF_STATUS_E_FAULT;
143 	}
144 
145 	/* check if lock refers to an uninitialized object */
146 	if (LINUX_LOCK_COOKIE != lock->cookie) {
147 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
148 			  "%s: uninitialized lock", __func__);
149 		QDF_ASSERT(0);
150 		return QDF_STATUS_E_INVAL;
151 	}
152 
153 	if (in_interrupt()) {
154 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
155 			  "%s cannot be called from interrupt context!!!",
156 			  __func__);
157 		QDF_ASSERT(0);
158 		return QDF_STATUS_E_FAULT;
159 	}
160 
161 	/* current_thread = get_current_thread_id();
162 	 * Check thread ID of caller against thread ID
163 	 * of the thread which acquire the lock
164 	 */
165 	if (lock->process_id != current->pid) {
166 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
167 			  "%s: current task pid does not match original task pid!!",
168 			  __func__);
169 #ifdef QDF_NESTED_LOCK_DEBUG
170 		pe_err("%s: Lock held by=%d being released by=%d",
171 			  __func__, lock->process_id, current->pid);
172 #endif
173 		QDF_ASSERT(0);
174 		return QDF_STATUS_E_PERM;
175 	}
176 	if ((lock->process_id == current->pid) &&
177 		(lock->state == LOCK_ACQUIRED)) {
178 		if (lock->refcount > 0)
179 			lock->refcount--;
180 	}
181 #ifdef QDF_NESTED_LOCK_DEBUG
182 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: %x %d %d", __func__, lock, lock->process_id,
183 		  lock->refcount);
184 #endif
185 	if (lock->refcount)
186 		return QDF_STATUS_SUCCESS;
187 
188 	lock->process_id = 0;
189 	lock->refcount = 0;
190 	lock->state = LOCK_RELEASED;
191 	/* release a Lock */
192 	BEFORE_UNLOCK(lock, 0);
193 	mutex_unlock(&lock->m_lock);
194 #ifdef QDF_NESTED_LOCK_DEBUG
195 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: Freeing lock %x %d %d", lock, lock->process_id,
196 		  lock->refcount);
197 #endif
198 	return QDF_STATUS_SUCCESS;
199 }
200 qdf_export_symbol(qdf_mutex_release);
201 
202 #ifdef WLAN_WAKE_LOCK_DEBUG
203 #include "qdf_tracker.h"
204 
205 #define qdf_wake_lock_tracker_bits 2 /* 4 buckets */
206 static qdf_tracker_declare(qdf_wake_lock_tracker, qdf_wake_lock_tracker_bits,
207 			   "wake lock leaks", "wake lock create",
208 			   "wake lock destroy");
209 
210 void qdf_wake_lock_feature_init(void)
211 {
212 	qdf_tracker_init(&qdf_wake_lock_tracker);
213 }
214 
215 void qdf_wake_lock_feature_deinit(void)
216 {
217 	qdf_tracker_deinit(&qdf_wake_lock_tracker);
218 }
219 
220 void qdf_wake_lock_check_for_leaks(void)
221 {
222 	qdf_tracker_check_for_leaks(&qdf_wake_lock_tracker);
223 }
224 
225 static inline QDF_STATUS qdf_wake_lock_dbg_track(qdf_wake_lock_t *lock,
226 						 const char *func,
227 						 uint32_t line)
228 {
229 	return qdf_tracker_track(&qdf_wake_lock_tracker, lock, func, line);
230 }
231 
232 static inline void qdf_wake_lock_dbg_untrack(qdf_wake_lock_t *lock,
233 					     const char *func, uint32_t line)
234 {
235 	qdf_tracker_untrack(&qdf_wake_lock_tracker, lock, func, line);
236 }
237 #else
238 static inline QDF_STATUS qdf_wake_lock_dbg_track(qdf_wake_lock_t *lock,
239 						 const char *func,
240 						 uint32_t line)
241 {
242 	return QDF_STATUS_SUCCESS;
243 }
244 
245 static inline void qdf_wake_lock_dbg_untrack(qdf_wake_lock_t *lock,
246 					     const char *func, uint32_t line)
247 { }
248 #endif /* WLAN_WAKE_LOCK_DEBUG */
249 
250 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
251 const char *qdf_wake_lock_name(qdf_wake_lock_t *lock)
252 {
253 	if (lock)
254 		return lock->lock.name;
255 	return "UNNAMED_WAKELOCK";
256 }
257 #else
258 const char *qdf_wake_lock_name(qdf_wake_lock_t *lock)
259 {
260 	return "NO_WAKELOCK_SUPPORT";
261 }
262 #endif
263 qdf_export_symbol(qdf_wake_lock_name);
264 
265 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 110)) || \
266 	defined(WAKEUP_SOURCE_DEV)
267 QDF_STATUS __qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name,
268 				  const char *func, uint32_t line)
269 {
270 	QDF_STATUS status;
271 
272 	status = qdf_wake_lock_dbg_track(lock, func, line);
273 	if (QDF_IS_STATUS_ERROR(status))
274 		return status;
275 
276 	qdf_mem_zero(lock, sizeof(*lock));
277 	lock->priv = wakeup_source_register(lock->lock.dev, name);
278 	if (!(lock->priv)) {
279 		QDF_BUG(0);
280 		return QDF_STATUS_E_FAILURE;
281 	}
282 
283 	lock->lock = *(lock->priv);
284 
285 	return QDF_STATUS_SUCCESS;
286 }
287 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
288 QDF_STATUS __qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name,
289 				  const char *func, uint32_t line)
290 {
291 	QDF_STATUS status;
292 
293 	status = qdf_wake_lock_dbg_track(lock, func, line);
294 	if (QDF_IS_STATUS_ERROR(status))
295 		return status;
296 
297 	wakeup_source_init(&(lock->lock), name);
298 	lock->priv = &(lock->lock);
299 
300 	return QDF_STATUS_SUCCESS;
301 }
302 #else
303 QDF_STATUS __qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name,
304 				  const char *func, uint32_t line)
305 {
306 	return QDF_STATUS_SUCCESS;
307 }
308 #endif
309 qdf_export_symbol(__qdf_wake_lock_create);
310 
311 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
312 QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason)
313 {
314 	host_diag_log_wlock(reason, qdf_wake_lock_name(lock),
315 			    WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT,
316 			    WIFI_POWER_EVENT_WAKELOCK_TAKEN);
317 	__pm_stay_awake(lock->priv);
318 
319 	return QDF_STATUS_SUCCESS;
320 }
321 #else
322 QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason)
323 {
324 	return QDF_STATUS_SUCCESS;
325 }
326 #endif
327 qdf_export_symbol(qdf_wake_lock_acquire);
328 
329 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
330 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
331 {
332 	pm_wakeup_ws_event(lock->priv, msec, true);
333 	return QDF_STATUS_SUCCESS;
334 }
335 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
336 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
337 {
338 	/* Wakelock for Rx is frequent.
339 	 * It is reported only during active debug
340 	 */
341 	__pm_wakeup_event(&(lock->lock), msec);
342 	return QDF_STATUS_SUCCESS;
343 }
344 #else /* LINUX_VERSION_CODE */
345 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
346 {
347 	return QDF_STATUS_SUCCESS;
348 }
349 #endif /* LINUX_VERSION_CODE */
350 qdf_export_symbol(qdf_wake_lock_timeout_acquire);
351 
352 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
353 QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason)
354 {
355 	host_diag_log_wlock(reason, qdf_wake_lock_name(lock),
356 			    WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT,
357 			    WIFI_POWER_EVENT_WAKELOCK_RELEASED);
358 	__pm_relax(lock->priv);
359 
360 	return QDF_STATUS_SUCCESS;
361 }
362 #else
363 QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason)
364 {
365 	return QDF_STATUS_SUCCESS;
366 }
367 #endif
368 qdf_export_symbol(qdf_wake_lock_release);
369 
370 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 110)) || \
371 	defined(WAKEUP_SOURCE_DEV)
372 void __qdf_wake_lock_destroy(qdf_wake_lock_t *lock,
373 			     const char *func, uint32_t line)
374 {
375 	wakeup_source_unregister(lock->priv);
376 	qdf_wake_lock_dbg_untrack(lock, func, line);
377 }
378 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
379 void __qdf_wake_lock_destroy(qdf_wake_lock_t *lock,
380 			     const char *func, uint32_t line)
381 {
382 	wakeup_source_trash(&(lock->lock));
383 	qdf_wake_lock_dbg_untrack(lock, func, line);
384 }
385 #else
386 void __qdf_wake_lock_destroy(qdf_wake_lock_t *lock,
387 			     const char *func, uint32_t line)
388 {
389 }
390 #endif
391 qdf_export_symbol(__qdf_wake_lock_destroy);
392 
393 void qdf_pm_system_wakeup(void)
394 {
395 	pm_system_wakeup();
396 }
397 
398 qdf_export_symbol(qdf_pm_system_wakeup);
399 
400 #ifdef FEATURE_RUNTIME_PM
401 /**
402  * qdf_to_hif_convert_rtpm_id() - Convert QDF Runtime PM ID to HIF RTPM ID
403  * @id: Client id
404  *
405  * Return: HIF Runtime pm ID of client
406  */
407 static uint32_t qdf_to_hif_convert_rtpm_id(uint32_t id)
408 {
409 	switch (id) {
410 	case QDF_RTPM_ID_RESERVED:
411 		return HIF_RTPM_ID_RESERVED;
412 	case QDF_RTPM_ID_PM_QOS_NOTIFY:
413 		return HIF_RTPM_ID_PM_QOS_NOTIFY;
414 	case QDF_RTPM_ID_WIPHY_SUSPEND:
415 		return HIF_RTPM_ID_WIPHY_SUSPEND;
416 	default:
417 		return HIF_RTPM_ID_MAX;
418 	}
419 }
420 
421 /**
422  * qdf_to_hif_convert_rtpm_type() - Convert QDF Runtime PM call type to HIF
423  *                                 call type
424  * @type: call type
425  *
426  * Return: HIF runtime PM call type
427  */
428 static uint8_t qdf_to_hif_convert_rtpm_type(uint8_t type)
429 {
430 	switch (type) {
431 	case QDF_RTPM_GET:
432 		return HIF_RTPM_GET_ASYNC;
433 	case QDF_RTPM_GET_FORCE:
434 		return HIF_RTPM_GET_FORCE;
435 	case QDF_RTPM_GET_SYNC:
436 		return HIF_RTPM_GET_SYNC;
437 	case QDF_RTPM_GET_NORESUME:
438 		return HIF_RTPM_GET_NORESUME;
439 	case QDF_RTPM_PUT:
440 		return HIF_RTPM_PUT_ASYNC;
441 	case QDF_RTPM_PUT_SYNC_SUSPEND:
442 		return HIF_RTPM_PUT_SYNC_SUSPEND;
443 	case QDF_RTPM_PUT_NOIDLE:
444 		return HIF_RTPM_PUT_NOIDLE;
445 	default:
446 		return QDF_STATUS_E_NOSUPPORT;
447 	}
448 }
449 
450 QDF_STATUS qdf_rtpm_register(uint32_t id, void (*hif_rpm_cbk)(void))
451 {
452 	return hif_rtpm_register(qdf_to_hif_convert_rtpm_id(id), hif_rpm_cbk);
453 }
454 
455 qdf_export_symbol(qdf_rtpm_register);
456 
457 QDF_STATUS qdf_rtpm_deregister(uint32_t id)
458 {
459 	return hif_rtpm_deregister(qdf_to_hif_convert_rtpm_id(id));
460 }
461 
462 qdf_export_symbol(qdf_rtpm_deregister);
463 
464 QDF_STATUS __qdf_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name)
465 {
466 	return hif_runtime_lock_init(lock, name);
467 }
468 
469 qdf_export_symbol(__qdf_runtime_lock_init);
470 
471 void qdf_runtime_lock_deinit(qdf_runtime_lock_t *lock)
472 {
473 	hif_runtime_lock_deinit(lock->lock);
474 }
475 qdf_export_symbol(qdf_runtime_lock_deinit);
476 
477 QDF_STATUS qdf_rtpm_get(uint8_t type, uint32_t id)
478 {
479 	return hif_rtpm_get(qdf_to_hif_convert_rtpm_type(type),
480 			    qdf_to_hif_convert_rtpm_id(id));
481 }
482 
483 qdf_export_symbol(qdf_rtpm_get);
484 
485 QDF_STATUS qdf_rtpm_put(uint8_t type, uint32_t id)
486 {
487 	return hif_rtpm_put(qdf_to_hif_convert_rtpm_type(type),
488 			    qdf_to_hif_convert_rtpm_id(id));
489 }
490 
491 qdf_export_symbol(qdf_rtpm_put);
492 
493 QDF_STATUS qdf_runtime_pm_prevent_suspend(qdf_runtime_lock_t *lock)
494 {
495 	return hif_pm_runtime_prevent_suspend(lock->lock);
496 }
497 
498 qdf_export_symbol(qdf_runtime_pm_prevent_suspend);
499 
500 QDF_STATUS qdf_runtime_pm_prevent_suspend_sync(qdf_runtime_lock_t *lock)
501 {
502 	return hif_pm_runtime_prevent_suspend_sync(lock->lock);
503 }
504 
505 qdf_export_symbol(qdf_runtime_pm_prevent_suspend_sync);
506 
507 QDF_STATUS qdf_runtime_pm_allow_suspend(qdf_runtime_lock_t *lock)
508 {
509 	return hif_pm_runtime_allow_suspend(lock->lock);
510 }
511 
512 qdf_export_symbol(qdf_runtime_pm_allow_suspend);
513 
514 QDF_STATUS qdf_rtpm_sync_resume(void)
515 {
516 	return hif_rtpm_sync_resume();
517 }
518 #endif
519 QDF_STATUS qdf_spinlock_acquire(qdf_spinlock_t *lock)
520 {
521 	spin_lock(&lock->lock.spinlock);
522 	return QDF_STATUS_SUCCESS;
523 }
524 qdf_export_symbol(qdf_spinlock_acquire);
525 
526 
527 QDF_STATUS qdf_spinlock_release(qdf_spinlock_t *lock)
528 {
529 	spin_unlock(&lock->lock.spinlock);
530 	return QDF_STATUS_SUCCESS;
531 }
532 qdf_export_symbol(qdf_spinlock_release);
533 
534 QDF_STATUS qdf_mutex_destroy(qdf_mutex_t *lock)
535 {
536 	/* check for invalid pointer */
537 	if (!lock) {
538 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
539 			  "%s: NULL pointer passed in", __func__);
540 		return QDF_STATUS_E_FAULT;
541 	}
542 
543 	if (LINUX_LOCK_COOKIE != lock->cookie) {
544 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
545 			  "%s: uninitialized lock", __func__);
546 		return QDF_STATUS_E_INVAL;
547 	}
548 
549 	if (in_interrupt()) {
550 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
551 			  "%s cannot be called from interrupt context!!!",
552 			  __func__);
553 		return QDF_STATUS_E_FAULT;
554 	}
555 
556 	/* check if lock is released */
557 	if (!mutex_trylock(&lock->m_lock)) {
558 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
559 			  "%s: lock is not released", __func__);
560 		return QDF_STATUS_E_BUSY;
561 	}
562 	lock->cookie = 0;
563 	lock->state = LOCK_DESTROYED;
564 	lock->process_id = 0;
565 	lock->refcount = 0;
566 
567 	qdf_lock_stats_destroy(&lock->stats);
568 	mutex_unlock(&lock->m_lock);
569 
570 	return QDF_STATUS_SUCCESS;
571 }
572 qdf_export_symbol(qdf_mutex_destroy);
573 
574 #if QDF_LOCK_STATS_LIST
575 struct qdf_lock_cookie {
576 	union {
577 		struct {
578 			struct lock_stats *stats;
579 			const char *func;
580 			int line;
581 		} cookie;
582 		struct {
583 			struct qdf_lock_cookie *next;
584 		} empty_node;
585 	} u;
586 };
587 
588 #ifndef QDF_LOCK_STATS_LIST_SIZE
589 #define QDF_LOCK_STATS_LIST_SIZE 256
590 #endif
591 
592 static qdf_spinlock_t qdf_lock_list_spinlock;
593 static struct qdf_lock_cookie lock_cookies[QDF_LOCK_STATS_LIST_SIZE];
594 static struct qdf_lock_cookie *lock_cookie_freelist;
595 static qdf_atomic_t lock_cookie_get_failures;
596 static qdf_atomic_t lock_cookie_untracked_num;
597 /* dummy value */
598 #define DUMMY_LOCK_COOKIE 0xc00c1e
599 
600 /**
601  * qdf_is_lock_cookie - check if memory is a valid lock cookie
602  * @lock_cookie: lock cookie to check
603  *
604  * Return: true if the memory is within the range of the lock cookie
605  *         memory.
606  */
607 static bool qdf_is_lock_cookie(struct qdf_lock_cookie *lock_cookie)
608 {
609 	return lock_cookie >= &lock_cookies[0] &&
610 		lock_cookie <= &lock_cookies[QDF_LOCK_STATS_LIST_SIZE-1];
611 }
612 
613 /**
614  * qdf_is_lock_cookie_free() -  check if the lock cookie is on the freelist
615  * @lock_cookie: lock cookie to check
616  *
617  * Check that the next field of the lock cookie points to a lock cookie.
618  * currently this is only true if the cookie is on the freelist.
619  *
620  * Checking for the function and line being NULL and 0 should also have worked.
621  *
622  * Return: true if the cookie is free
623  */
624 static bool qdf_is_lock_cookie_free(struct qdf_lock_cookie *lock_cookie)
625 {
626 	struct qdf_lock_cookie *tmp = lock_cookie->u.empty_node.next;
627 
628 	return qdf_is_lock_cookie(tmp) || (!tmp);
629 }
630 
631 static struct qdf_lock_cookie *qdf_get_lock_cookie(void)
632 {
633 	struct qdf_lock_cookie *lock_cookie;
634 
635 	qdf_spin_lock_bh(&qdf_lock_list_spinlock);
636 	lock_cookie = lock_cookie_freelist;
637 	if (lock_cookie_freelist)
638 		lock_cookie_freelist = lock_cookie_freelist->u.empty_node.next;
639 	qdf_spin_unlock_bh(&qdf_lock_list_spinlock);
640 	return lock_cookie;
641 }
642 
643 static void __qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie)
644 {
645 	if (!qdf_is_lock_cookie(lock_cookie))
646 		QDF_BUG(0);
647 
648 	lock_cookie->u.empty_node.next = lock_cookie_freelist;
649 	lock_cookie_freelist = lock_cookie;
650 }
651 
652 static void qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie)
653 {
654 	qdf_spin_lock_bh(&qdf_lock_list_spinlock);
655 	__qdf_put_lock_cookie(lock_cookie);
656 	qdf_spin_unlock_bh(&qdf_lock_list_spinlock);
657 }
658 
659 void qdf_lock_stats_init(void)
660 {
661 	int i;
662 
663 	for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++)
664 		__qdf_put_lock_cookie(&lock_cookies[i]);
665 
666 	/* stats must be allocated for the spinlock before the cookie,
667 	 * otherwise this qdf_lock_list_spinlock wouldn't get initialized
668 	 * properly
669 	 */
670 	qdf_spinlock_create(&qdf_lock_list_spinlock);
671 	qdf_atomic_init(&lock_cookie_get_failures);
672 	qdf_atomic_init(&lock_cookie_untracked_num);
673 }
674 
675 void qdf_lock_stats_deinit(void)
676 {
677 	int i;
678 
679 	qdf_spinlock_destroy(&qdf_lock_list_spinlock);
680 	for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++) {
681 		if (!qdf_is_lock_cookie_free(&lock_cookies[i]))
682 			QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
683 				  "%s: lock_not_destroyed, fun: %s, line %d",
684 				  __func__, lock_cookies[i].u.cookie.func,
685 				  lock_cookies[i].u.cookie.line);
686 	}
687 	lock_cookie_freelist = NULL;
688 }
689 
690 /* allocated separate memory in case the lock memory is freed without
691  * running the deinitialization code.  The cookie list will not be
692  * corrupted.
693  */
694 void qdf_lock_stats_cookie_create(struct lock_stats *stats,
695 				  const char *func, int line)
696 {
697 	struct qdf_lock_cookie *cookie = qdf_get_lock_cookie();
698 
699 	if (!cookie) {
700 		int count;
701 
702 		qdf_atomic_inc(&lock_cookie_get_failures);
703 		count = qdf_atomic_inc_return(&lock_cookie_untracked_num);
704 		stats->cookie = (void *) DUMMY_LOCK_COOKIE;
705 		return;
706 	}
707 
708 	stats->cookie = cookie;
709 	stats->cookie->u.cookie.stats = stats;
710 	stats->cookie->u.cookie.func = func;
711 	stats->cookie->u.cookie.line = line;
712 }
713 
714 qdf_export_symbol(qdf_lock_stats_cookie_create);
715 
716 void qdf_lock_stats_cookie_destroy(struct lock_stats *stats)
717 {
718 	struct qdf_lock_cookie *cookie = stats->cookie;
719 
720 	if (!cookie) {
721 		QDF_DEBUG_PANIC("Lock destroyed twice or never created");
722 		return;
723 	}
724 
725 	stats->cookie = NULL;
726 	if (cookie == (void *)DUMMY_LOCK_COOKIE) {
727 		qdf_atomic_dec(&lock_cookie_untracked_num);
728 		return;
729 	}
730 
731 	cookie->u.cookie.stats = NULL;
732 	cookie->u.cookie.func = NULL;
733 	cookie->u.cookie.line = 0;
734 
735 	qdf_put_lock_cookie(cookie);
736 }
737 
738 qdf_export_symbol(qdf_lock_stats_cookie_destroy);
739 #endif
740