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