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