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