xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_threads.c (revision 9b27c6e104d726e99b1515faf0f55e5a36178530)
1 /*
2  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 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 /**
21  * DOC: qdf_threads
22  * QCA driver framework (QDF) thread APIs
23  */
24 
25 /* Include Files */
26 #include <qdf_threads.h>
27 #include <qdf_types.h>
28 #include <qdf_trace.h>
29 #include <linux/jiffies.h>
30 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
31 #include <linux/sched.h>
32 #else
33 #include <linux/sched/signal.h>
34 #endif /* KERNEL_VERSION(4, 11, 0) */
35 /* Test against msm kernel version */
36 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) && \
37 	IS_ENABLED(CONFIG_SCHED_WALT)
38 #include <linux/sched/walt.h>
39 #endif
40 #include <linux/delay.h>
41 #include <linux/interrupt.h>
42 #include <linux/kthread.h>
43 #include <linux/stacktrace.h>
44 #include <qdf_defer.h>
45 #include <qdf_module.h>
46 #include <linux/cpumask.h>
47 /* Function declarations and documentation */
48 
49 typedef int (*qdf_thread_os_func)(void *data);
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 qdf_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 qdf_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 qdf_export_symbol(qdf_busy_wait);
114 
115 #if defined(PF_WAKE_UP_IDLE) || IS_ENABLED(CONFIG_SCHED_WALT)
116 void qdf_set_wake_up_idle(bool idle)
117 {
118 	set_wake_up_idle(idle);
119 }
120 #else
121 void qdf_set_wake_up_idle(bool idle)
122 {
123 }
124 #endif /* PF_WAKE_UP_IDLE */
125 
126 qdf_export_symbol(qdf_set_wake_up_idle);
127 
128 void qdf_set_user_nice(qdf_thread_t *thread, long nice)
129 {
130 	set_user_nice(thread, nice);
131 }
132 qdf_export_symbol(qdf_set_user_nice);
133 
134 qdf_thread_t *qdf_create_thread(int (*thread_handler)(void *data), void *data,
135 				const char thread_name[])
136 {
137 	struct task_struct *task;
138 
139 	task = kthread_create(thread_handler, data, thread_name);
140 
141 	if (IS_ERR(task))
142 		return NULL;
143 
144 	return task;
145 }
146 qdf_export_symbol(qdf_create_thread);
147 
148 static uint16_t qdf_thread_id;
149 
150 qdf_thread_t *qdf_thread_run(qdf_thread_func callback, void *context)
151 {
152 	struct task_struct *thread;
153 
154 	thread = kthread_create((qdf_thread_os_func)callback, context,
155 				"qdf %u", qdf_thread_id++);
156 	if (IS_ERR(thread))
157 		return NULL;
158 
159 	get_task_struct(thread);
160 	wake_up_process(thread);
161 
162 	return thread;
163 }
164 qdf_export_symbol(qdf_thread_run);
165 
166 QDF_STATUS qdf_thread_join(qdf_thread_t *thread)
167 {
168 	QDF_STATUS status;
169 
170 	QDF_BUG(thread);
171 
172 	status = (QDF_STATUS)kthread_stop(thread);
173 	put_task_struct(thread);
174 
175 	return status;
176 }
177 qdf_export_symbol(qdf_thread_join);
178 
179 bool qdf_thread_should_stop(void)
180 {
181 	return kthread_should_stop();
182 }
183 qdf_export_symbol(qdf_thread_should_stop);
184 
185 int qdf_wake_up_process(qdf_thread_t *thread)
186 {
187 	return wake_up_process(thread);
188 }
189 qdf_export_symbol(qdf_wake_up_process);
190 
191 /* save_stack_trace_tsk() is exported for:
192  * 1) non-arm architectures
193  * 2) arm architectures in kernel versions >=4.14
194  * 3) backported kernels defining BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM
195  */
196 #if ((defined(WLAN_HOST_ARCH_ARM) && !WLAN_HOST_ARCH_ARM) || \
197 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \
198 	defined(BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM)) && \
199 	defined(CONFIG_STACKTRACE) && !defined(CONFIG_ARCH_STACKWALK)
200 #define QDF_PRINT_TRACE_COUNT 32
201 
202 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
203 void qdf_print_thread_trace(qdf_thread_t *thread)
204 {
205 	const int spaces = 4;
206 	struct task_struct *task = thread;
207 	unsigned long entries[QDF_PRINT_TRACE_COUNT] = {0};
208 	struct stack_trace trace = {
209 		.nr_entries = 0,
210 		.skip = 0,
211 		.entries = &entries[0],
212 		.max_entries = QDF_PRINT_TRACE_COUNT,
213 	};
214 
215 	save_stack_trace_tsk(task, &trace);
216 	stack_trace_print(entries, trace.nr_entries, spaces);
217 }
218 #else
219 void qdf_print_thread_trace(qdf_thread_t *thread)
220 {
221 	const int spaces = 4;
222 	struct task_struct *task = thread;
223 	unsigned long entries[QDF_PRINT_TRACE_COUNT] = {0};
224 	struct stack_trace trace = {
225 		.nr_entries = 0,
226 		.skip = 0,
227 		.entries = &entries[0],
228 		.max_entries = QDF_PRINT_TRACE_COUNT,
229 	};
230 
231 	save_stack_trace_tsk(task, &trace);
232 	print_stack_trace(&trace, spaces);
233 }
234 #endif
235 
236 #else
237 void qdf_print_thread_trace(qdf_thread_t *thread) { }
238 #endif /* KERNEL_VERSION(4, 14, 0) */
239 qdf_export_symbol(qdf_print_thread_trace);
240 
241 qdf_thread_t *qdf_get_current_task(void)
242 {
243 	return current;
244 }
245 qdf_export_symbol(qdf_get_current_task);
246 
247 int qdf_get_current_pid(void)
248 {
249 	return current->pid;
250 }
251 qdf_export_symbol(qdf_get_current_pid);
252 
253 const char *qdf_get_current_comm(void)
254 {
255 	return current->comm;
256 }
257 qdf_export_symbol(qdf_get_current_comm);
258 
259 void
260 qdf_thread_set_cpus_allowed_mask(qdf_thread_t *thread, qdf_cpu_mask *new_mask)
261 {
262 	set_cpus_allowed_ptr(thread, new_mask);
263 }
264 
265 qdf_export_symbol(qdf_thread_set_cpus_allowed_mask);
266 
267 void qdf_cpumask_clear(qdf_cpu_mask *dstp)
268 {
269 	cpumask_clear(dstp);
270 }
271 
272 qdf_export_symbol(qdf_cpumask_clear);
273 
274 void qdf_cpumask_set_cpu(unsigned int cpu, qdf_cpu_mask *dstp)
275 {
276 	cpumask_set_cpu(cpu, dstp);
277 }
278 qdf_export_symbol(qdf_cpumask_set_cpu);
279 
280 void qdf_cpumask_clear_cpu(unsigned int cpu, qdf_cpu_mask *dstp)
281 {
282 	cpumask_clear_cpu(cpu, dstp);
283 }
284 
285 qdf_export_symbol(qdf_cpumask_clear_cpu);
286 
287 void qdf_cpumask_setall(qdf_cpu_mask *dstp)
288 {
289 	cpumask_setall(dstp);
290 }
291 
292 qdf_export_symbol(qdf_cpumask_setall);
293 
294 bool qdf_cpumask_empty(const qdf_cpu_mask *srcp)
295 {
296 	return cpumask_empty(srcp);
297 }
298 
299 qdf_export_symbol(qdf_cpumask_empty);
300 
301 void qdf_cpumask_copy(qdf_cpu_mask *dstp,
302 		      const qdf_cpu_mask *srcp)
303 {
304 	return cpumask_copy(dstp, srcp);
305 }
306 
307 qdf_export_symbol(qdf_cpumask_copy);
308 
309 void qdf_cpumask_or(qdf_cpu_mask *dstp, qdf_cpu_mask *src1p,
310 		    qdf_cpu_mask *src2p)
311 {
312 	cpumask_or(dstp, src1p, src2p);
313 }
314 
315 qdf_export_symbol(qdf_cpumask_or);
316 
317 void
318 qdf_thread_cpumap_print_to_pagebuf(bool list, char *new_mask_str,
319 				   qdf_cpu_mask *new_mask)
320 {
321 	cpumap_print_to_pagebuf(list, new_mask_str, new_mask);
322 }
323 
324 qdf_export_symbol(qdf_thread_cpumap_print_to_pagebuf);
325 
326 bool
327 qdf_cpumask_and(qdf_cpu_mask *dstp, const qdf_cpu_mask *src1p,
328 		const qdf_cpu_mask *src2p)
329 {
330 	return cpumask_and(dstp, src1p, src2p);
331 }
332 
333 qdf_export_symbol(qdf_cpumask_and);
334 
335 bool
336 qdf_cpumask_andnot(qdf_cpu_mask *dstp, const qdf_cpu_mask *src1p,
337 		   const qdf_cpu_mask *src2p)
338 {
339 	return cpumask_andnot(dstp, src1p, src2p);
340 }
341 
342 qdf_export_symbol(qdf_cpumask_andnot);
343 
344 bool
345 qdf_cpumask_equal(const qdf_cpu_mask *src1p, const qdf_cpu_mask *src2p)
346 {
347 	return cpumask_equal(src1p, src2p);
348 }
349 
350 qdf_export_symbol(qdf_cpumask_equal);
351 
352 void
353 qdf_cpumask_complement(qdf_cpu_mask *dstp, const qdf_cpu_mask *srcp)
354 {
355 	cpumask_complement(dstp, srcp);
356 }
357 
358 qdf_export_symbol(qdf_cpumask_complement);
359 
360 #ifdef WALT_GET_CPU_TAKEN_SUPPORT
361 qdf_cpu_mask qdf_walt_get_cpus_taken(void)
362 {
363 	return walt_get_cpus_taken();
364 }
365 
366 qdf_export_symbol(qdf_walt_get_cpus_taken);
367 #endif
368