xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_threads.c (revision ef615e7655641c631b491672197920d85ac046d8)
1 /*
2  * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
3  *
4  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5  *
6  *
7  * Permission to use, copy, modify, and/or distribute this software for
8  * any purpose with or without fee is hereby granted, provided that the
9  * above copyright notice and this permission notice appear in all
10  * copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19  * PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 /*
23  * This file was originally distributed by Qualcomm Atheros, Inc.
24  * under proprietary terms before Copyright ownership was assigned
25  * to the Linux Foundation.
26  */
27 
28 /**
29  * DOC: qdf_threads
30  * QCA driver framework (QDF) thread APIs
31  */
32 
33 /* Include Files */
34 #include <qdf_threads.h>
35 #include <qdf_types.h>
36 #include <qdf_trace.h>
37 #include <linux/jiffies.h>
38 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
39 #include <linux/sched.h>
40 #else
41 #include <linux/sched/signal.h>
42 #endif /* KERNEL_VERSION(4, 11, 0) */
43 #include <linux/delay.h>
44 #include <linux/interrupt.h>
45 #include <linux/export.h>
46 #include <linux/kthread.h>
47 #include <linux/stacktrace.h>
48 
49 /* Function declarations and documenation */
50 
51 /**
52  *  qdf_sleep() - sleep
53  *  @ms_interval : Number of milliseconds to suspend the current thread.
54  *  A value of 0 may or may not cause the current thread to yield.
55  *
56  *  This function suspends the execution of the current thread
57  *  until the specified time out interval elapses.
58  *
59  *  Return: none
60  */
61 void qdf_sleep(uint32_t ms_interval)
62 {
63 	if (in_interrupt()) {
64 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
65 			  "%s cannot be called from interrupt context!!!",
66 			  __func__);
67 		return;
68 	}
69 	msleep_interruptible(ms_interval);
70 }
71 EXPORT_SYMBOL(qdf_sleep);
72 
73 /**
74  *  qdf_sleep_us() - sleep
75  *  @us_interval : Number of microseconds to suspend the current thread.
76  *  A value of 0 may or may not cause the current thread to yield.
77  *
78  *  This function suspends the execution of the current thread
79  *  until the specified time out interval elapses.
80  *
81  *  Return : none
82  */
83 void qdf_sleep_us(uint32_t us_interval)
84 {
85 	unsigned long timeout = usecs_to_jiffies(us_interval) + 1;
86 
87 	if (in_interrupt()) {
88 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
89 			  "%s cannot be called from interrupt context!!!",
90 			  __func__);
91 		return;
92 	}
93 
94 	while (timeout && !signal_pending(current))
95 		timeout = schedule_timeout_interruptible(timeout);
96 }
97 EXPORT_SYMBOL(qdf_sleep_us);
98 
99 /**
100  *  qdf_busy_wait() - busy wait
101  *  @us_interval : Number of microseconds to busy wait.
102  *
103  *  This function places the current thread in busy wait until the specified
104  *  time out interval elapses. If the interval is greater than 50us on WM, the
105  *  behaviour is undefined.
106  *
107  *  Return : none
108  */
109 void qdf_busy_wait(uint32_t us_interval)
110 {
111 	udelay(us_interval);
112 }
113 EXPORT_SYMBOL(qdf_busy_wait);
114 
115 void qdf_set_user_nice(qdf_thread_t *thread, long nice)
116 {
117 	set_user_nice(thread, nice);
118 }
119 EXPORT_SYMBOL(qdf_set_user_nice);
120 
121 qdf_thread_t *qdf_create_thread(int (*thread_handler)(void *data), void *data,
122 				const char thread_name[])
123 {
124 	return kthread_create(thread_handler, data, thread_name);
125 }
126 EXPORT_SYMBOL(qdf_create_thread);
127 
128 int qdf_wake_up_process(qdf_thread_t *thread)
129 {
130 	return wake_up_process(thread);
131 }
132 EXPORT_SYMBOL(qdf_wake_up_process);
133 
134 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \
135 	defined(BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM)
136 #define QDF_PRINT_TRACE_COUNT 32
137 void qdf_print_thread_trace(qdf_thread_t *thread)
138 {
139 	const int spaces = 4;
140 	struct task_struct *task = thread;
141 	unsigned long entries[QDF_PRINT_TRACE_COUNT] = {0};
142 	struct stack_trace trace = {
143 		.nr_entries = 0,
144 		.skip = 0,
145 		.entries = &entries[0],
146 		.max_entries = QDF_PRINT_TRACE_COUNT,
147 	};
148 
149 	save_stack_trace_tsk(task, &trace);
150 	print_stack_trace(&trace, spaces);
151 }
152 #else
153 void qdf_print_thread_trace(qdf_thread_t *thread) { }
154 #endif /* KERNEL_VERSION(4, 14, 0) */
155 EXPORT_SYMBOL(qdf_print_thread_trace);
156 
157