xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_lock.c (revision bea437e2293c3d4fb1b5704fcf633aedac996962)
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 FEATURE_RUNTIME_PM
27 #include <cds_api.h>
28 #include <hif.h>
29 #endif
30 #include <i_qdf_lock.h>
31 #include <linux/suspend.h>
32 
33 /**
34  * qdf_mutex_create() - Initialize a mutex
35  * @m: mutex to initialize
36  *
37  * Returns: QDF_STATUS
38  * =0 success
39  * else fail status
40  */
41 #undef qdf_mutex_create
42 QDF_STATUS qdf_mutex_create(qdf_mutex_t *lock, const char *func, int line)
43 {
44 	/* check for invalid pointer */
45 	if (!lock) {
46 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
47 			  "%s: NULL pointer passed in", __func__);
48 		return QDF_STATUS_E_FAULT;
49 	}
50 	/* check for 'already initialized' lock */
51 	if (LINUX_LOCK_COOKIE == lock->cookie) {
52 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
53 			  "%s: already initialized lock", __func__);
54 		return QDF_STATUS_E_BUSY;
55 	}
56 
57 	if (in_interrupt()) {
58 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
59 			  "%s cannot be called from interrupt context!!!",
60 			  __func__);
61 		return QDF_STATUS_E_FAULT;
62 	}
63 
64 	qdf_lock_stats_create(&lock->stats, func, line);
65 
66 	/* initialize new lock */
67 	mutex_init(&lock->m_lock);
68 	lock->cookie = LINUX_LOCK_COOKIE;
69 	lock->state = LOCK_RELEASED;
70 	lock->process_id = 0;
71 	lock->refcount = 0;
72 
73 	return QDF_STATUS_SUCCESS;
74 }
75 qdf_export_symbol(qdf_mutex_create);
76 
77 /**
78  * qdf_mutex_acquire() - acquire a QDF lock
79  * @lock: Pointer to the opaque lock object to acquire
80  *
81  * A lock object is acquired by calling qdf_mutex_acquire().  If the lock
82  * is already locked, the calling thread shall block until the lock becomes
83  * available. This operation shall return with the lock object referenced by
84  * lock in the locked state with the calling thread as its owner.
85  *
86  * Return:
87  * QDF_STATUS_SUCCESS: lock was successfully initialized
88  * QDF failure reason codes: lock is not initialized and can't be used
89  */
90 QDF_STATUS qdf_mutex_acquire(qdf_mutex_t *lock)
91 {
92 	int rc;
93 	/* check for invalid pointer */
94 	if (!lock) {
95 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
96 			  "%s: NULL pointer passed in", __func__);
97 		QDF_ASSERT(0);
98 		return QDF_STATUS_E_FAULT;
99 	}
100 	/* check if lock refers to an initialized object */
101 	if (LINUX_LOCK_COOKIE != lock->cookie) {
102 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
103 			  "%s: uninitialized lock", __func__);
104 		QDF_ASSERT(0);
105 		return QDF_STATUS_E_INVAL;
106 	}
107 
108 	if (in_interrupt()) {
109 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
110 			  "%s cannot be called from interrupt context!!!",
111 			  __func__);
112 		QDF_ASSERT(0);
113 		return QDF_STATUS_E_FAULT;
114 	}
115 	if ((lock->process_id == current->pid) &&
116 		(lock->state == LOCK_ACQUIRED)) {
117 		lock->refcount++;
118 #ifdef QDF_NESTED_LOCK_DEBUG
119 			pe_err("%s: %x %d %d", __func__, lock, current->pid,
120 			  lock->refcount);
121 #endif
122 		return QDF_STATUS_SUCCESS;
123 	}
124 
125 	BEFORE_LOCK(lock, mutex_is_locked(&lock->m_lock));
126 	/* acquire a Lock */
127 	mutex_lock(&lock->m_lock);
128 	AFTER_LOCK(lock, __func__);
129 	rc = mutex_is_locked(&lock->m_lock);
130 	if (rc == 0) {
131 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
132 			  "%s: unable to lock mutex (rc = %d)", __func__, rc);
133 		QDF_ASSERT(0);
134 		return QDF_STATUS_E_FAILURE;
135 	}
136 #ifdef QDF_NESTED_LOCK_DEBUG
137 		pe_err("%s: %x %d", __func__, lock, current->pid);
138 #endif
139 	if (LOCK_DESTROYED != lock->state) {
140 		lock->process_id = current->pid;
141 		lock->refcount++;
142 		lock->state = LOCK_ACQUIRED;
143 		return QDF_STATUS_SUCCESS;
144 	}
145 
146 	/* lock is already destroyed */
147 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
148 		  "%s: Lock is already destroyed", __func__);
149 	mutex_unlock(&lock->m_lock);
150 	QDF_ASSERT(0);
151 	return QDF_STATUS_E_FAILURE;
152 }
153 qdf_export_symbol(qdf_mutex_acquire);
154 
155 /**
156  * qdf_mutex_release() - release a QDF lock
157  * @lock: Pointer to the opaque lock object to be released
158  *
159  * qdf_mutex_release() function shall release the lock object
160  * referenced by 'lock'.
161  *
162  * If a thread attempts to release a lock that it unlocked or is not
163  * initialized, an error is returned.
164  *
165  * Return:
166  * QDF_STATUS_SUCCESS: lock was successfully initialized
167  * QDF failure reason codes: lock is not initialized and can't be used
168  */
169 QDF_STATUS qdf_mutex_release(qdf_mutex_t *lock)
170 {
171 	/* check for invalid pointer */
172 	if (!lock) {
173 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
174 			  "%s: NULL pointer passed in", __func__);
175 		QDF_ASSERT(0);
176 		return QDF_STATUS_E_FAULT;
177 	}
178 
179 	/* check if lock refers to an uninitialized object */
180 	if (LINUX_LOCK_COOKIE != lock->cookie) {
181 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
182 			  "%s: uninitialized lock", __func__);
183 		QDF_ASSERT(0);
184 		return QDF_STATUS_E_INVAL;
185 	}
186 
187 	if (in_interrupt()) {
188 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
189 			  "%s cannot be called from interrupt context!!!",
190 			  __func__);
191 		QDF_ASSERT(0);
192 		return QDF_STATUS_E_FAULT;
193 	}
194 
195 	/* current_thread = get_current_thread_id();
196 	 * Check thread ID of caller against thread ID
197 	 * of the thread which acquire the lock
198 	 */
199 	if (lock->process_id != current->pid) {
200 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
201 			  "%s: current task pid does not match original task pid!!",
202 			  __func__);
203 #ifdef QDF_NESTED_LOCK_DEBUG
204 		pe_err("%s: Lock held by=%d being released by=%d",
205 			  __func__, lock->process_id, current->pid);
206 #endif
207 		QDF_ASSERT(0);
208 		return QDF_STATUS_E_PERM;
209 	}
210 	if ((lock->process_id == current->pid) &&
211 		(lock->state == LOCK_ACQUIRED)) {
212 		if (lock->refcount > 0)
213 			lock->refcount--;
214 	}
215 #ifdef QDF_NESTED_LOCK_DEBUG
216 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: %x %d %d", __func__, lock, lock->process_id,
217 		  lock->refcount);
218 #endif
219 	if (lock->refcount)
220 		return QDF_STATUS_SUCCESS;
221 
222 	lock->process_id = 0;
223 	lock->refcount = 0;
224 	lock->state = LOCK_RELEASED;
225 	/* release a Lock */
226 	BEFORE_UNLOCK(lock, 0);
227 	mutex_unlock(&lock->m_lock);
228 #ifdef QDF_NESTED_LOCK_DEBUG
229 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: Freeing lock %x %d %d", lock, lock->process_id,
230 		  lock->refcount);
231 #endif
232 	return QDF_STATUS_SUCCESS;
233 }
234 qdf_export_symbol(qdf_mutex_release);
235 
236 /**
237  * qdf_wake_lock_name() - This function returns the name of the wakelock
238  * @lock: Pointer to the wakelock
239  *
240  * This function returns the name of the wakelock
241  *
242  * Return: Pointer to the name if it is valid or a default string
243  */
244 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
245 const char *qdf_wake_lock_name(qdf_wake_lock_t *lock)
246 {
247 	if (lock->name)
248 		return lock->name;
249 	return "UNNAMED_WAKELOCK";
250 }
251 #else
252 const char *qdf_wake_lock_name(qdf_wake_lock_t *lock)
253 {
254 	return "NO_WAKELOCK_SUPPORT";
255 }
256 #endif
257 qdf_export_symbol(qdf_wake_lock_name);
258 
259 /**
260  * qdf_wake_lock_create() - initializes a wake lock
261  * @lock: The wake lock to initialize
262  * @name: Name of wake lock
263  *
264  * Return:
265  * QDF status success: if wake lock is initialized
266  * QDF status failure: if wake lock was not initialized
267  */
268 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
269 QDF_STATUS qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name)
270 {
271 	wakeup_source_register(lock->dev, name);
272 	return QDF_STATUS_SUCCESS;
273 }
274 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
275 QDF_STATUS qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name)
276 {
277 	wakeup_source_init(lock, name);
278 	return QDF_STATUS_SUCCESS;
279 }
280 #else
281 QDF_STATUS qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name)
282 {
283 	return QDF_STATUS_SUCCESS;
284 }
285 #endif
286 qdf_export_symbol(qdf_wake_lock_create);
287 
288 /**
289  * qdf_wake_lock_acquire() - acquires a wake lock
290  * @lock: The wake lock to acquire
291  * @reason: Reason for wakelock
292  *
293  * Return:
294  * QDF status success: if wake lock is acquired
295  * QDF status failure: if wake lock was not acquired
296  */
297 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
298 QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason)
299 {
300 	host_diag_log_wlock(reason, qdf_wake_lock_name(lock),
301 			    WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT,
302 			    WIFI_POWER_EVENT_WAKELOCK_TAKEN);
303 	__pm_stay_awake(lock);
304 
305 	return QDF_STATUS_SUCCESS;
306 }
307 #else
308 QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason)
309 {
310 	return QDF_STATUS_SUCCESS;
311 }
312 #endif
313 qdf_export_symbol(qdf_wake_lock_acquire);
314 
315 /**
316  * qdf_wake_lock_timeout_acquire() - acquires a wake lock with a timeout
317  * @lock: The wake lock to acquire
318  * @reason: Reason for wakelock
319  *
320  * Return:
321  * QDF status success: if wake lock is acquired
322  * QDF status failure: if wake lock was not acquired
323  */
324 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
325 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
326 {
327 	pm_wakeup_ws_event(lock, msec, true);
328 	return QDF_STATUS_SUCCESS;
329 }
330 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
331 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
332 {
333 	/* Wakelock for Rx is frequent.
334 	 * It is reported only during active debug
335 	 */
336 	__pm_wakeup_event(lock, msec);
337 	return QDF_STATUS_SUCCESS;
338 }
339 #else /* LINUX_VERSION_CODE */
340 QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec)
341 {
342 	return QDF_STATUS_SUCCESS;
343 }
344 #endif /* LINUX_VERSION_CODE */
345 qdf_export_symbol(qdf_wake_lock_timeout_acquire);
346 
347 /**
348  * qdf_wake_lock_release() - releases a wake lock
349  * @lock: the wake lock to release
350  * @reason: Reason for wakelock
351  *
352  * Return:
353  * QDF status success: if wake lock is acquired
354  * QDF status failure: if wake lock was not acquired
355  */
356 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
357 QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason)
358 {
359 	host_diag_log_wlock(reason, qdf_wake_lock_name(lock),
360 			    WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT,
361 			    WIFI_POWER_EVENT_WAKELOCK_RELEASED);
362 	__pm_relax(lock);
363 
364 	return QDF_STATUS_SUCCESS;
365 }
366 #else
367 QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason)
368 {
369 	return QDF_STATUS_SUCCESS;
370 }
371 #endif
372 qdf_export_symbol(qdf_wake_lock_release);
373 
374 /**
375  * qdf_wake_lock_destroy() - destroys a wake lock
376  * @lock: The wake lock to destroy
377  *
378  * Return:
379  * QDF status success: if wake lock is acquired
380  * QDF status failure: if wake lock was not acquired
381  */
382 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0))
383 QDF_STATUS qdf_wake_lock_destroy(qdf_wake_lock_t *lock)
384 {
385 	wakeup_source_unregister(lock);
386 	return QDF_STATUS_SUCCESS;
387 }
388 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
389 QDF_STATUS qdf_wake_lock_destroy(qdf_wake_lock_t *lock)
390 {
391 	wakeup_source_trash(lock);
392 	return QDF_STATUS_SUCCESS;
393 }
394 #else
395 QDF_STATUS qdf_wake_lock_destroy(qdf_wake_lock_t *lock)
396 {
397 	return QDF_STATUS_SUCCESS;
398 }
399 #endif
400 qdf_export_symbol(qdf_wake_lock_destroy);
401 
402 /**
403  * qdf_pm_system_wakeup() - wakeup system
404  *
405  * Return: None
406  */
407 void qdf_pm_system_wakeup(void)
408 {
409 	pm_system_wakeup();
410 }
411 
412 qdf_export_symbol(qdf_pm_system_wakeup);
413 
414 #ifdef FEATURE_RUNTIME_PM
415 /**
416  * qdf_runtime_pm_get() - do a get opperation on the device
417  *
418  * A get opperation will prevent a runtime suspend until a
419  * corresponding put is done.  This api should be used when sending
420  * data.
421  *
422  * CONTRARY TO THE REGULAR RUNTIME PM, WHEN THE BUS IS SUSPENDED,
423  * THIS API WILL ONLY REQUEST THE RESUME AND NOT TO A GET!!!
424  *
425  * return: success if the bus is up and a get has been issued
426  *   otherwise an error code.
427  */
428 QDF_STATUS qdf_runtime_pm_get(void)
429 {
430 	void *ol_sc;
431 	int ret;
432 
433 	ol_sc = cds_get_context(QDF_MODULE_ID_HIF);
434 
435 	if (!ol_sc) {
436 		QDF_ASSERT(0);
437 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
438 			  "%s: HIF context is null!", __func__);
439 		return QDF_STATUS_E_INVAL;
440 	}
441 
442 	ret = hif_pm_runtime_get(ol_sc);
443 
444 	if (ret)
445 		return QDF_STATUS_E_FAILURE;
446 	return QDF_STATUS_SUCCESS;
447 }
448 qdf_export_symbol(qdf_runtime_pm_get);
449 
450 /**
451  * qdf_runtime_pm_put() - do a put opperation on the device
452  *
453  * A put opperation will allow a runtime suspend after a corresponding
454  * get was done.  This api should be used when sending data.
455  *
456  * This api will return a failure if the hif module hasn't been
457  * initialized
458  *
459  * return: QDF_STATUS_SUCCESS if the put is performed
460  */
461 QDF_STATUS qdf_runtime_pm_put(void)
462 {
463 	void *ol_sc;
464 	int ret;
465 
466 	ol_sc = cds_get_context(QDF_MODULE_ID_HIF);
467 
468 	if (!ol_sc) {
469 		QDF_ASSERT(0);
470 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
471 			  "%s: HIF context is null!", __func__);
472 		return QDF_STATUS_E_INVAL;
473 	}
474 
475 	ret = hif_pm_runtime_put(ol_sc);
476 
477 	if (ret)
478 		return QDF_STATUS_E_FAILURE;
479 	return QDF_STATUS_SUCCESS;
480 }
481 qdf_export_symbol(qdf_runtime_pm_put);
482 
483 /**
484  * qdf_runtime_pm_prevent_suspend() - prevent a runtime bus suspend
485  * @lock: an opaque context for tracking
486  *
487  * The lock can only be acquired once per lock context and is tracked.
488  *
489  * return: QDF_STATUS_SUCCESS or failure code.
490  */
491 QDF_STATUS qdf_runtime_pm_prevent_suspend(qdf_runtime_lock_t *lock)
492 {
493 	void *ol_sc;
494 	int ret;
495 
496 	ol_sc = cds_get_context(QDF_MODULE_ID_HIF);
497 
498 	if (!ol_sc) {
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_prevent_suspend(ol_sc, lock->lock);
506 
507 	if (ret)
508 		return QDF_STATUS_E_FAILURE;
509 	return QDF_STATUS_SUCCESS;
510 }
511 qdf_export_symbol(qdf_runtime_pm_prevent_suspend);
512 
513 /**
514  * qdf_runtime_pm_allow_suspend() - prevent a runtime bus suspend
515  * @lock: an opaque context for tracking
516  *
517  * The lock can only be acquired once per lock context and is tracked.
518  *
519  * return: QDF_STATUS_SUCCESS or failure code.
520  */
521 QDF_STATUS qdf_runtime_pm_allow_suspend(qdf_runtime_lock_t *lock)
522 {
523 	void *ol_sc;
524 	int ret;
525 
526 	ol_sc = cds_get_context(QDF_MODULE_ID_HIF);
527 	if (!ol_sc) {
528 		QDF_ASSERT(0);
529 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
530 		"%s: HIF context is null!", __func__);
531 		return QDF_STATUS_E_INVAL;
532 	}
533 
534 	ret = hif_pm_runtime_allow_suspend(ol_sc, lock->lock);
535 	if (ret)
536 		return QDF_STATUS_E_FAILURE;
537 
538 	return QDF_STATUS_SUCCESS;
539 }
540 qdf_export_symbol(qdf_runtime_pm_allow_suspend);
541 
542 /**
543  * qdf_runtime_lock_init() - initialize runtime lock
544  * @name: name of the runtime lock
545  *
546  * Initialize a runtime pm lock.  This lock can be used
547  * to prevent the runtime pm system from putting the bus
548  * to sleep.
549  *
550  * Return: runtime_pm_lock_t
551  */
552 QDF_STATUS __qdf_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name)
553 {
554 	int ret = hif_runtime_lock_init(lock, name);
555 
556 	if (ret)
557 		return QDF_STATUS_E_NOMEM;
558 
559 	return QDF_STATUS_SUCCESS;
560 }
561 qdf_export_symbol(__qdf_runtime_lock_init);
562 
563 /**
564  * qdf_runtime_lock_deinit() - deinitialize runtime pm lock
565  * @lock: the lock to deinitialize
566  *
567  * Ensures the lock is released. Frees the runtime lock.
568  *
569  * Return: void
570  */
571 void qdf_runtime_lock_deinit(qdf_runtime_lock_t *lock)
572 {
573 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
574 	hif_runtime_lock_deinit(hif_ctx, lock->lock);
575 }
576 qdf_export_symbol(qdf_runtime_lock_deinit);
577 
578 #else
579 
580 QDF_STATUS qdf_runtime_pm_get(void)
581 {
582 	return QDF_STATUS_SUCCESS;
583 }
584 qdf_export_symbol(qdf_runtime_pm_get);
585 
586 QDF_STATUS qdf_runtime_pm_put(void)
587 {
588 	return QDF_STATUS_SUCCESS;
589 }
590 qdf_export_symbol(qdf_runtime_pm_put);
591 
592 QDF_STATUS qdf_runtime_pm_prevent_suspend(qdf_runtime_lock_t *lock)
593 {
594 	return QDF_STATUS_SUCCESS;
595 }
596 qdf_export_symbol(qdf_runtime_pm_prevent_suspend);
597 
598 QDF_STATUS qdf_runtime_pm_allow_suspend(qdf_runtime_lock_t *lock)
599 {
600 	return QDF_STATUS_SUCCESS;
601 }
602 qdf_export_symbol(qdf_runtime_pm_allow_suspend);
603 
604 QDF_STATUS __qdf_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name)
605 {
606 	return QDF_STATUS_SUCCESS;
607 }
608 qdf_export_symbol(__qdf_runtime_lock_init);
609 
610 void qdf_runtime_lock_deinit(qdf_runtime_lock_t *lock)
611 {
612 }
613 qdf_export_symbol(qdf_runtime_lock_deinit);
614 
615 #endif /* FEATURE_RUNTIME_PM */
616 
617 /**
618  * qdf_spinlock_acquire() - acquires a spin lock
619  * @lock: Spin lock to acquire
620  *
621  * Return:
622  * QDF status success: if wake lock is acquired
623  */
624 QDF_STATUS qdf_spinlock_acquire(qdf_spinlock_t *lock)
625 {
626 	spin_lock(&lock->lock.spinlock);
627 	return QDF_STATUS_SUCCESS;
628 }
629 qdf_export_symbol(qdf_spinlock_acquire);
630 
631 
632 /**
633  * qdf_spinlock_release() - release a spin lock
634  * @lock: Spin lock to release
635  *
636  * Return:
637  * QDF status success : if wake lock is acquired
638  */
639 QDF_STATUS qdf_spinlock_release(qdf_spinlock_t *lock)
640 {
641 	spin_unlock(&lock->lock.spinlock);
642 	return QDF_STATUS_SUCCESS;
643 }
644 qdf_export_symbol(qdf_spinlock_release);
645 
646 /**
647  * qdf_mutex_destroy() - destroy a QDF lock
648  * @lock: Pointer to the opaque lock object to be destroyed
649  *
650  * function shall destroy the lock object referenced by lock. After a
651  * successful return from qdf_mutex_destroy()
652  * the lock object becomes, in effect, uninitialized.
653  *
654  * A destroyed lock object can be reinitialized using qdf_mutex_create();
655  * the results of otherwise referencing the object after it has been destroyed
656  * are undefined.  Calls to QDF lock functions to manipulate the lock such
657  * as qdf_mutex_acquire() will fail if the lock is destroyed.  Therefore,
658  * don't use the lock after it has been destroyed until it has
659  * been re-initialized.
660  *
661  * Return:
662  * QDF_STATUS_SUCCESS: lock was successfully initialized
663  * QDF failure reason codes: lock is not initialized and can't be used
664  */
665 QDF_STATUS qdf_mutex_destroy(qdf_mutex_t *lock)
666 {
667 	/* check for invalid pointer */
668 	if (!lock) {
669 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
670 			  "%s: NULL pointer passed in", __func__);
671 		return QDF_STATUS_E_FAULT;
672 	}
673 
674 	if (LINUX_LOCK_COOKIE != lock->cookie) {
675 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
676 			  "%s: uninitialized lock", __func__);
677 		return QDF_STATUS_E_INVAL;
678 	}
679 
680 	if (in_interrupt()) {
681 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
682 			  "%s cannot be called from interrupt context!!!",
683 			  __func__);
684 		return QDF_STATUS_E_FAULT;
685 	}
686 
687 	/* check if lock is released */
688 	if (!mutex_trylock(&lock->m_lock)) {
689 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
690 			  "%s: lock is not released", __func__);
691 		return QDF_STATUS_E_BUSY;
692 	}
693 	lock->cookie = 0;
694 	lock->state = LOCK_DESTROYED;
695 	lock->process_id = 0;
696 	lock->refcount = 0;
697 
698 	qdf_lock_stats_destroy(&lock->stats);
699 	mutex_unlock(&lock->m_lock);
700 
701 	return QDF_STATUS_SUCCESS;
702 }
703 qdf_export_symbol(qdf_mutex_destroy);
704 
705 #if QDF_LOCK_STATS_LIST
706 struct qdf_lock_cookie {
707 	union {
708 		struct {
709 			struct lock_stats *stats;
710 			const char *func;
711 			int line;
712 		} cookie;
713 		struct {
714 			struct qdf_lock_cookie *next;
715 		} empty_node;
716 	} u;
717 };
718 
719 #ifndef QDF_LOCK_STATS_LIST_SIZE
720 #define QDF_LOCK_STATS_LIST_SIZE 256
721 #endif
722 
723 static qdf_spinlock_t qdf_lock_list_spinlock;
724 static struct qdf_lock_cookie lock_cookies[QDF_LOCK_STATS_LIST_SIZE];
725 static struct qdf_lock_cookie *lock_cookie_freelist;
726 static qdf_atomic_t lock_cookie_get_failures;
727 static qdf_atomic_t lock_cookie_untracked_num;
728 /* dummy value */
729 #define DUMMY_LOCK_COOKIE 0xc00c1e
730 
731 /**
732  * qdf_is_lock_cookie - check if memory is a valid lock cookie
733  *
734  * return true if the memory is within the range of the lock cookie
735  * memory.
736  */
737 static bool qdf_is_lock_cookie(struct qdf_lock_cookie *lock_cookie)
738 {
739 	return lock_cookie >= &lock_cookies[0] &&
740 		lock_cookie <= &lock_cookies[QDF_LOCK_STATS_LIST_SIZE-1];
741 }
742 
743 /**
744  * qdf_is_lock_cookie_free() -  check if the lock cookie is on the freelist
745  * @lock_cookie: lock cookie to check
746  *
747  * Check that the next field of the lock cookie points to a lock cookie.
748  * currently this is only true if the cookie is on the freelist.
749  *
750  * Checking for the function and line being NULL and 0 should also have worked.
751  */
752 static bool qdf_is_lock_cookie_free(struct qdf_lock_cookie *lock_cookie)
753 {
754 	struct qdf_lock_cookie *tmp = lock_cookie->u.empty_node.next;
755 
756 	return qdf_is_lock_cookie(tmp) || (!tmp);
757 }
758 
759 static struct qdf_lock_cookie *qdf_get_lock_cookie(void)
760 {
761 	struct qdf_lock_cookie *lock_cookie;
762 
763 	qdf_spin_lock_bh(&qdf_lock_list_spinlock);
764 	lock_cookie = lock_cookie_freelist;
765 	if (lock_cookie_freelist)
766 		lock_cookie_freelist = lock_cookie_freelist->u.empty_node.next;
767 	qdf_spin_unlock_bh(&qdf_lock_list_spinlock);
768 	return lock_cookie;
769 }
770 
771 static void __qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie)
772 {
773 	if (!qdf_is_lock_cookie(lock_cookie))
774 		QDF_BUG(0);
775 
776 	lock_cookie->u.empty_node.next = lock_cookie_freelist;
777 	lock_cookie_freelist = lock_cookie;
778 }
779 
780 static void qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie)
781 {
782 	qdf_spin_lock_bh(&qdf_lock_list_spinlock);
783 	__qdf_put_lock_cookie(lock_cookie);
784 	qdf_spin_unlock_bh(&qdf_lock_list_spinlock);
785 }
786 
787 void qdf_lock_stats_init(void)
788 {
789 	int i;
790 
791 	for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++)
792 		__qdf_put_lock_cookie(&lock_cookies[i]);
793 
794 	/* stats must be allocated for the spinlock before the cookie,
795 	 * otherwise this qdf_lock_list_spinlock wouldnt get initialized
796 	 * properly
797 	 */
798 	qdf_spinlock_create(&qdf_lock_list_spinlock);
799 	qdf_atomic_init(&lock_cookie_get_failures);
800 	qdf_atomic_init(&lock_cookie_untracked_num);
801 }
802 
803 void qdf_lock_stats_deinit(void)
804 {
805 	int i;
806 
807 	qdf_spinlock_destroy(&qdf_lock_list_spinlock);
808 	for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++) {
809 		if (!qdf_is_lock_cookie_free(&lock_cookies[i]))
810 			QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
811 				  "%s: lock_not_destroyed, fun: %s, line %d",
812 				  __func__, lock_cookies[i].u.cookie.func,
813 				  lock_cookies[i].u.cookie.line);
814 	}
815 }
816 
817 /* allocated separate memory in case the lock memory is freed without
818  * running the deinitialization code.  The cookie list will not be
819  * corrupted.
820  */
821 void qdf_lock_stats_cookie_create(struct lock_stats *stats,
822 				  const char *func, int line)
823 {
824 	struct qdf_lock_cookie *cookie = qdf_get_lock_cookie();
825 
826 	if (!cookie) {
827 		int count;
828 
829 		qdf_atomic_inc(&lock_cookie_get_failures);
830 		count = qdf_atomic_inc_return(&lock_cookie_untracked_num);
831 		stats->cookie = (void *) DUMMY_LOCK_COOKIE;
832 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
833 			  "%s: cookie allocation failure, using dummy (%s:%d) count %d",
834 			  __func__, func, line, count);
835 		return;
836 	}
837 
838 	stats->cookie = cookie;
839 	stats->cookie->u.cookie.stats = stats;
840 	stats->cookie->u.cookie.func = func;
841 	stats->cookie->u.cookie.line = line;
842 }
843 
844 void qdf_lock_stats_cookie_destroy(struct lock_stats *stats)
845 {
846 	struct qdf_lock_cookie *cookie = stats->cookie;
847 
848 	if (!cookie) {
849 		QDF_DEBUG_PANIC("Lock destroyed twice or never created");
850 		return;
851 	}
852 
853 	stats->cookie = NULL;
854 	if (cookie == (void *)DUMMY_LOCK_COOKIE) {
855 		qdf_atomic_dec(&lock_cookie_untracked_num);
856 		return;
857 	}
858 
859 	cookie->u.cookie.stats = NULL;
860 	cookie->u.cookie.func = NULL;
861 	cookie->u.cookie.line = 0;
862 
863 	qdf_put_lock_cookie(cookie);
864 }
865 #endif
866