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