xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_threads.c (revision 6ecd284e5a94a1c96e26d571dd47419ac305990d)
1 /*
2  * Copyright (c) 2014-2018 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/kthread.h>
46 #include <linux/stacktrace.h>
47 #include <qdf_defer.h>
48 #include <qdf_module.h>
49 
50 /* Function declarations and documenation */
51 
52 /**
53  *  qdf_sleep() - sleep
54  *  @ms_interval : Number of milliseconds to suspend the current thread.
55  *  A value of 0 may or may not cause the current thread to yield.
56  *
57  *  This function suspends the execution of the current thread
58  *  until the specified time out interval elapses.
59  *
60  *  Return: none
61  */
62 void qdf_sleep(uint32_t ms_interval)
63 {
64 	if (in_interrupt()) {
65 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
66 			  "%s cannot be called from interrupt context!!!",
67 			  __func__);
68 		return;
69 	}
70 	msleep_interruptible(ms_interval);
71 }
72 qdf_export_symbol(qdf_sleep);
73 
74 /**
75  *  qdf_sleep_us() - sleep
76  *  @us_interval : Number of microseconds to suspend the current thread.
77  *  A value of 0 may or may not cause the current thread to yield.
78  *
79  *  This function suspends the execution of the current thread
80  *  until the specified time out interval elapses.
81  *
82  *  Return : none
83  */
84 void qdf_sleep_us(uint32_t us_interval)
85 {
86 	unsigned long timeout = usecs_to_jiffies(us_interval) + 1;
87 
88 	if (in_interrupt()) {
89 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
90 			  "%s cannot be called from interrupt context!!!",
91 			  __func__);
92 		return;
93 	}
94 
95 	while (timeout && !signal_pending(current))
96 		timeout = schedule_timeout_interruptible(timeout);
97 }
98 qdf_export_symbol(qdf_sleep_us);
99 
100 /**
101  *  qdf_busy_wait() - busy wait
102  *  @us_interval : Number of microseconds to busy wait.
103  *
104  *  This function places the current thread in busy wait until the specified
105  *  time out interval elapses. If the interval is greater than 50us on WM, the
106  *  behaviour is undefined.
107  *
108  *  Return : none
109  */
110 void qdf_busy_wait(uint32_t us_interval)
111 {
112 	udelay(us_interval);
113 }
114 qdf_export_symbol(qdf_busy_wait);
115 
116 void qdf_set_user_nice(qdf_thread_t *thread, long nice)
117 {
118 	set_user_nice(thread, nice);
119 }
120 qdf_export_symbol(qdf_set_user_nice);
121 
122 qdf_thread_t *qdf_create_thread(int (*thread_handler)(void *data), void *data,
123 				const char thread_name[])
124 {
125 	return kthread_create(thread_handler, data, thread_name);
126 }
127 qdf_export_symbol(qdf_create_thread);
128 
129 int qdf_wake_up_process(qdf_thread_t *thread)
130 {
131 	return wake_up_process(thread);
132 }
133 qdf_export_symbol(qdf_wake_up_process);
134 
135 /* save_stack_trace_tsk() is exported for:
136  * 1) non-arm architectures
137  * 2) arm architectures in kernel versions >=4.14
138  * 3) backported kernels defining BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM
139  */
140 #if (defined(WLAN_HOST_ARCH_ARM) && !WLAN_HOST_ARCH_ARM) || \
141 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \
142 	defined(BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM)
143 #define QDF_PRINT_TRACE_COUNT 32
144 void qdf_print_thread_trace(qdf_thread_t *thread)
145 {
146 	const int spaces = 4;
147 	struct task_struct *task = thread;
148 	unsigned long entries[QDF_PRINT_TRACE_COUNT] = {0};
149 	struct stack_trace trace = {
150 		.nr_entries = 0,
151 		.skip = 0,
152 		.entries = &entries[0],
153 		.max_entries = QDF_PRINT_TRACE_COUNT,
154 	};
155 
156 	save_stack_trace_tsk(task, &trace);
157 	print_stack_trace(&trace, spaces);
158 }
159 #else
160 void qdf_print_thread_trace(qdf_thread_t *thread) { }
161 #endif /* KERNEL_VERSION(4, 14, 0) */
162 qdf_export_symbol(qdf_print_thread_trace);
163 
164 qdf_thread_t *qdf_get_current_task(void)
165 {
166 	return current;
167 }
168 qdf_export_symbol(qdf_get_current_task);
169