1 /* 2 * Copyright (c) 2014-2017 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/export.h> 46 #include <linux/kthread.h> 47 #include <linux/stacktrace.h> 48 49 /* Function declarations and documenation */ 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 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 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 EXPORT_SYMBOL(qdf_busy_wait); 114 115 void qdf_set_user_nice(qdf_thread_t *thread, long nice) 116 { 117 set_user_nice(thread, nice); 118 } 119 EXPORT_SYMBOL(qdf_set_user_nice); 120 121 qdf_thread_t *qdf_create_thread(int (*thread_handler)(void *data), void *data, 122 const char thread_name[]) 123 { 124 return kthread_create(thread_handler, data, thread_name); 125 } 126 EXPORT_SYMBOL(qdf_create_thread); 127 128 int qdf_wake_up_process(qdf_thread_t *thread) 129 { 130 return wake_up_process(thread); 131 } 132 EXPORT_SYMBOL(qdf_wake_up_process); 133 134 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \ 135 defined(BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM) 136 #define QDF_PRINT_TRACE_COUNT 32 137 void qdf_print_thread_trace(qdf_thread_t *thread) 138 { 139 const int spaces = 4; 140 struct task_struct *task = thread; 141 unsigned long entries[QDF_PRINT_TRACE_COUNT] = {0}; 142 struct stack_trace trace = { 143 .nr_entries = 0, 144 .skip = 0, 145 .entries = &entries[0], 146 .max_entries = QDF_PRINT_TRACE_COUNT, 147 }; 148 149 save_stack_trace_tsk(task, &trace); 150 print_stack_trace(&trace, spaces); 151 } 152 #else 153 void qdf_print_thread_trace(qdf_thread_t *thread) { } 154 #endif /* KERNEL_VERSION(4, 14, 0) */ 155 EXPORT_SYMBOL(qdf_print_thread_trace); 156 157