xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_threads.c (revision 2848159cbf2fd6863dcd893e613ae04648250714)
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 /**
20  * DOC: qdf_threads
21  * QCA driver framework (QDF) thread APIs
22  */
23 
24 /* Include Files */
25 #include <qdf_threads.h>
26 #include <qdf_types.h>
27 #include <qdf_trace.h>
28 #include <linux/jiffies.h>
29 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
30 #include <linux/sched.h>
31 #else
32 #include <linux/sched/signal.h>
33 #endif /* KERNEL_VERSION(4, 11, 0) */
34 #include <linux/delay.h>
35 #include <linux/interrupt.h>
36 #include <linux/kthread.h>
37 #include <linux/stacktrace.h>
38 #include <qdf_defer.h>
39 #include <qdf_module.h>
40 
41 /* Function declarations and documenation */
42 
43 typedef int (*qdf_thread_os_func)(void *data);
44 
45 /**
46  *  qdf_sleep() - sleep
47  *  @ms_interval : Number of milliseconds to suspend the current thread.
48  *  A value of 0 may or may not cause the current thread to yield.
49  *
50  *  This function suspends the execution of the current thread
51  *  until the specified time out interval elapses.
52  *
53  *  Return: none
54  */
55 void qdf_sleep(uint32_t ms_interval)
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;
62 	}
63 	msleep_interruptible(ms_interval);
64 }
65 qdf_export_symbol(qdf_sleep);
66 
67 /**
68  *  qdf_sleep_us() - sleep
69  *  @us_interval : Number of microseconds to suspend the current thread.
70  *  A value of 0 may or may not cause the current thread to yield.
71  *
72  *  This function suspends the execution of the current thread
73  *  until the specified time out interval elapses.
74  *
75  *  Return : none
76  */
77 void qdf_sleep_us(uint32_t us_interval)
78 {
79 	unsigned long timeout = usecs_to_jiffies(us_interval) + 1;
80 
81 	if (in_interrupt()) {
82 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
83 			  "%s cannot be called from interrupt context!!!",
84 			  __func__);
85 		return;
86 	}
87 
88 	while (timeout && !signal_pending(current))
89 		timeout = schedule_timeout_interruptible(timeout);
90 }
91 qdf_export_symbol(qdf_sleep_us);
92 
93 /**
94  *  qdf_busy_wait() - busy wait
95  *  @us_interval : Number of microseconds to busy wait.
96  *
97  *  This function places the current thread in busy wait until the specified
98  *  time out interval elapses. If the interval is greater than 50us on WM, the
99  *  behaviour is undefined.
100  *
101  *  Return : none
102  */
103 void qdf_busy_wait(uint32_t us_interval)
104 {
105 	udelay(us_interval);
106 }
107 qdf_export_symbol(qdf_busy_wait);
108 
109 #ifdef PF_WAKE_UP_IDLE
110 void qdf_set_wake_up_idle(bool idle)
111 {
112 	set_wake_up_idle(idle);
113 }
114 #else
115 void qdf_set_wake_up_idle(bool idle)
116 {
117 }
118 #endif /* PF_WAKE_UP_IDLE */
119 
120 qdf_export_symbol(qdf_set_wake_up_idle);
121 
122 void qdf_set_user_nice(qdf_thread_t *thread, long nice)
123 {
124 	set_user_nice(thread, nice);
125 }
126 qdf_export_symbol(qdf_set_user_nice);
127 
128 qdf_thread_t *qdf_create_thread(int (*thread_handler)(void *data), void *data,
129 				const char thread_name[])
130 {
131 	struct task_struct *task;
132 
133 	task = kthread_create(thread_handler, data, thread_name);
134 
135 	if (IS_ERR(task))
136 		return NULL;
137 
138 	return task;
139 }
140 qdf_export_symbol(qdf_create_thread);
141 
142 static uint16_t qdf_thread_id;
143 
144 qdf_thread_t *qdf_thread_run(qdf_thread_func callback, void *context)
145 {
146 	struct task_struct *thread;
147 
148 	thread = kthread_create((qdf_thread_os_func)callback, context,
149 				"qdf %u", qdf_thread_id++);
150 	if (IS_ERR(thread))
151 		return NULL;
152 
153 	get_task_struct(thread);
154 	wake_up_process(thread);
155 
156 	return thread;
157 }
158 qdf_export_symbol(qdf_thread_run);
159 
160 QDF_STATUS qdf_thread_join(qdf_thread_t *thread)
161 {
162 	QDF_STATUS status;
163 
164 	QDF_BUG(thread);
165 
166 	status = (QDF_STATUS)kthread_stop(thread);
167 	put_task_struct(thread);
168 
169 	return status;
170 }
171 qdf_export_symbol(qdf_thread_join);
172 
173 bool qdf_thread_should_stop(void)
174 {
175 	return kthread_should_stop();
176 }
177 qdf_export_symbol(qdf_thread_should_stop);
178 
179 int qdf_wake_up_process(qdf_thread_t *thread)
180 {
181 	return wake_up_process(thread);
182 }
183 qdf_export_symbol(qdf_wake_up_process);
184 
185 /* save_stack_trace_tsk() is exported for:
186  * 1) non-arm architectures
187  * 2) arm architectures in kernel versions >=4.14
188  * 3) backported kernels defining BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM
189  */
190 #if ((defined(WLAN_HOST_ARCH_ARM) && !WLAN_HOST_ARCH_ARM) || \
191 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \
192 	defined(BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM)) && \
193 	defined(CONFIG_STACKTRACE) && !defined(CONFIG_ARCH_STACKWALK)
194 #define QDF_PRINT_TRACE_COUNT 32
195 
196 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
197 void qdf_print_thread_trace(qdf_thread_t *thread)
198 {
199 	const int spaces = 4;
200 	struct task_struct *task = thread;
201 	unsigned long entries[QDF_PRINT_TRACE_COUNT] = {0};
202 	struct stack_trace trace = {
203 		.nr_entries = 0,
204 		.skip = 0,
205 		.entries = &entries[0],
206 		.max_entries = QDF_PRINT_TRACE_COUNT,
207 	};
208 
209 	save_stack_trace_tsk(task, &trace);
210 	stack_trace_print(entries, trace.nr_entries, spaces);
211 }
212 #else
213 void qdf_print_thread_trace(qdf_thread_t *thread)
214 {
215 	const int spaces = 4;
216 	struct task_struct *task = thread;
217 	unsigned long entries[QDF_PRINT_TRACE_COUNT] = {0};
218 	struct stack_trace trace = {
219 		.nr_entries = 0,
220 		.skip = 0,
221 		.entries = &entries[0],
222 		.max_entries = QDF_PRINT_TRACE_COUNT,
223 	};
224 
225 	save_stack_trace_tsk(task, &trace);
226 	print_stack_trace(&trace, spaces);
227 }
228 #endif
229 
230 #else
231 void qdf_print_thread_trace(qdf_thread_t *thread) { }
232 #endif /* KERNEL_VERSION(4, 14, 0) */
233 qdf_export_symbol(qdf_print_thread_trace);
234 
235 qdf_thread_t *qdf_get_current_task(void)
236 {
237 	return current;
238 }
239 qdf_export_symbol(qdf_get_current_task);
240 
241 int qdf_get_current_pid(void)
242 {
243 	return current->pid;
244 }
245 qdf_export_symbol(qdf_get_current_pid);
246 
247 const char *qdf_get_current_comm(void)
248 {
249 	return current->comm;
250 }
251 qdf_export_symbol(qdf_get_current_comm);
252 
253 void
254 qdf_thread_set_cpus_allowed_mask(qdf_thread_t *thread, qdf_cpu_mask *new_mask)
255 {
256 	set_cpus_allowed_ptr(thread, new_mask);
257 }
258 
259 qdf_export_symbol(qdf_thread_set_cpus_allowed_mask);
260 
261 void qdf_cpumask_clear(qdf_cpu_mask *dstp)
262 {
263 	cpumask_clear(dstp);
264 }
265 
266 qdf_export_symbol(qdf_cpumask_clear);
267 
268 void qdf_cpumask_set_cpu(unsigned int cpu, qdf_cpu_mask *dstp)
269 {
270 	cpumask_set_cpu(cpu, dstp);
271 }
272 
273 qdf_export_symbol(qdf_cpumask_set_cpu);
274 
275 void qdf_cpumask_setall(qdf_cpu_mask *dstp)
276 {
277 	cpumask_setall(dstp);
278 }
279 
280 qdf_export_symbol(qdf_cpumask_setall);
281 
282 bool qdf_cpumask_empty(const qdf_cpu_mask *srcp)
283 {
284 	return cpumask_empty(srcp);
285 }
286 
287 qdf_export_symbol(qdf_cpumask_empty);
288 
289 void qdf_cpumask_copy(qdf_cpu_mask *dstp,
290 		      const qdf_cpu_mask *srcp)
291 {
292 	return cpumask_copy(dstp, srcp);
293 }
294 
295 qdf_export_symbol(qdf_cpumask_copy);
296