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