1 /* 2 * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 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