qdf_threads.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * Copyright (c) 2014-2019 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. * DOC: qdf_threads
  20. * QCA driver framework (QDF) thread APIs
  21. */
  22. /* Include Files */
  23. #include <qdf_threads.h>
  24. #include <qdf_types.h>
  25. #include <qdf_trace.h>
  26. #include <linux/jiffies.h>
  27. #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
  28. #include <linux/sched.h>
  29. #else
  30. #include <linux/sched/signal.h>
  31. #endif /* KERNEL_VERSION(4, 11, 0) */
  32. #include <linux/delay.h>
  33. #include <linux/interrupt.h>
  34. #include <linux/kthread.h>
  35. #include <linux/stacktrace.h>
  36. #include <qdf_defer.h>
  37. #include <qdf_module.h>
  38. /* Function declarations and documenation */
  39. typedef int (*qdf_thread_os_func)(void *data);
  40. /**
  41. * qdf_sleep() - sleep
  42. * @ms_interval : Number of milliseconds to suspend the current thread.
  43. * A value of 0 may or may not cause the current thread to yield.
  44. *
  45. * This function suspends the execution of the current thread
  46. * until the specified time out interval elapses.
  47. *
  48. * Return: none
  49. */
  50. void qdf_sleep(uint32_t ms_interval)
  51. {
  52. if (in_interrupt()) {
  53. QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
  54. "%s cannot be called from interrupt context!!!",
  55. __func__);
  56. return;
  57. }
  58. msleep_interruptible(ms_interval);
  59. }
  60. qdf_export_symbol(qdf_sleep);
  61. /**
  62. * qdf_sleep_us() - sleep
  63. * @us_interval : Number of microseconds to suspend the current thread.
  64. * A value of 0 may or may not cause the current thread to yield.
  65. *
  66. * This function suspends the execution of the current thread
  67. * until the specified time out interval elapses.
  68. *
  69. * Return : none
  70. */
  71. void qdf_sleep_us(uint32_t us_interval)
  72. {
  73. unsigned long timeout = usecs_to_jiffies(us_interval) + 1;
  74. if (in_interrupt()) {
  75. QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
  76. "%s cannot be called from interrupt context!!!",
  77. __func__);
  78. return;
  79. }
  80. while (timeout && !signal_pending(current))
  81. timeout = schedule_timeout_interruptible(timeout);
  82. }
  83. qdf_export_symbol(qdf_sleep_us);
  84. /**
  85. * qdf_busy_wait() - busy wait
  86. * @us_interval : Number of microseconds to busy wait.
  87. *
  88. * This function places the current thread in busy wait until the specified
  89. * time out interval elapses. If the interval is greater than 50us on WM, the
  90. * behaviour is undefined.
  91. *
  92. * Return : none
  93. */
  94. void qdf_busy_wait(uint32_t us_interval)
  95. {
  96. udelay(us_interval);
  97. }
  98. qdf_export_symbol(qdf_busy_wait);
  99. #ifdef PF_WAKE_UP_IDLE
  100. void qdf_set_wake_up_idle(bool idle)
  101. {
  102. set_wake_up_idle(idle);
  103. }
  104. #else
  105. void qdf_set_wake_up_idle(bool idle)
  106. {
  107. }
  108. #endif /* PF_WAKE_UP_IDLE */
  109. qdf_export_symbol(qdf_set_wake_up_idle);
  110. void qdf_set_user_nice(qdf_thread_t *thread, long nice)
  111. {
  112. set_user_nice(thread, nice);
  113. }
  114. qdf_export_symbol(qdf_set_user_nice);
  115. qdf_thread_t *qdf_create_thread(int (*thread_handler)(void *data), void *data,
  116. const char thread_name[])
  117. {
  118. struct task_struct *task;
  119. task = kthread_create(thread_handler, data, thread_name);
  120. if (IS_ERR(task))
  121. return NULL;
  122. return task;
  123. }
  124. qdf_export_symbol(qdf_create_thread);
  125. static uint16_t qdf_thread_id;
  126. qdf_thread_t *qdf_thread_run(qdf_thread_func callback, void *context)
  127. {
  128. struct task_struct *thread;
  129. thread = kthread_create((qdf_thread_os_func)callback, context,
  130. "qdf %u", qdf_thread_id++);
  131. if (IS_ERR(thread))
  132. return NULL;
  133. get_task_struct(thread);
  134. wake_up_process(thread);
  135. return thread;
  136. }
  137. qdf_export_symbol(qdf_thread_run);
  138. QDF_STATUS qdf_thread_join(qdf_thread_t *thread)
  139. {
  140. QDF_STATUS status;
  141. QDF_BUG(thread);
  142. status = (QDF_STATUS)kthread_stop(thread);
  143. put_task_struct(thread);
  144. return status;
  145. }
  146. qdf_export_symbol(qdf_thread_join);
  147. bool qdf_thread_should_stop(void)
  148. {
  149. return kthread_should_stop();
  150. }
  151. qdf_export_symbol(qdf_thread_should_stop);
  152. int qdf_wake_up_process(qdf_thread_t *thread)
  153. {
  154. return wake_up_process(thread);
  155. }
  156. qdf_export_symbol(qdf_wake_up_process);
  157. /* save_stack_trace_tsk() is exported for:
  158. * 1) non-arm architectures
  159. * 2) arm architectures in kernel versions >=4.14
  160. * 3) backported kernels defining BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM
  161. */
  162. #if ((defined(WLAN_HOST_ARCH_ARM) && !WLAN_HOST_ARCH_ARM) || \
  163. LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) || \
  164. defined(BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM)) && \
  165. defined(CONFIG_STACKTRACE) && !defined(CONFIG_ARCH_STACKWALK)
  166. #define QDF_PRINT_TRACE_COUNT 32
  167. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
  168. void qdf_print_thread_trace(qdf_thread_t *thread)
  169. {
  170. const int spaces = 4;
  171. struct task_struct *task = thread;
  172. unsigned long entries[QDF_PRINT_TRACE_COUNT] = {0};
  173. struct stack_trace trace = {
  174. .nr_entries = 0,
  175. .skip = 0,
  176. .entries = &entries[0],
  177. .max_entries = QDF_PRINT_TRACE_COUNT,
  178. };
  179. save_stack_trace_tsk(task, &trace);
  180. stack_trace_print(entries, trace.nr_entries, spaces);
  181. }
  182. #else
  183. void qdf_print_thread_trace(qdf_thread_t *thread)
  184. {
  185. const int spaces = 4;
  186. struct task_struct *task = thread;
  187. unsigned long entries[QDF_PRINT_TRACE_COUNT] = {0};
  188. struct stack_trace trace = {
  189. .nr_entries = 0,
  190. .skip = 0,
  191. .entries = &entries[0],
  192. .max_entries = QDF_PRINT_TRACE_COUNT,
  193. };
  194. save_stack_trace_tsk(task, &trace);
  195. print_stack_trace(&trace, spaces);
  196. }
  197. #endif
  198. #else
  199. void qdf_print_thread_trace(qdf_thread_t *thread) { }
  200. #endif /* KERNEL_VERSION(4, 14, 0) */
  201. qdf_export_symbol(qdf_print_thread_trace);
  202. qdf_thread_t *qdf_get_current_task(void)
  203. {
  204. return current;
  205. }
  206. qdf_export_symbol(qdf_get_current_task);
  207. int qdf_get_current_pid(void)
  208. {
  209. return current->pid;
  210. }
  211. qdf_export_symbol(qdf_get_current_pid);
  212. const char *qdf_get_current_comm(void)
  213. {
  214. return current->comm;
  215. }
  216. qdf_export_symbol(qdf_get_current_comm);
  217. void
  218. qdf_thread_set_cpus_allowed_mask(qdf_thread_t *thread, qdf_cpu_mask *new_mask)
  219. {
  220. set_cpus_allowed_ptr(thread, new_mask);
  221. }
  222. qdf_export_symbol(qdf_thread_set_cpus_allowed_mask);
  223. void qdf_cpumask_clear(qdf_cpu_mask *dstp)
  224. {
  225. cpumask_clear(dstp);
  226. }
  227. qdf_export_symbol(qdf_cpumask_clear);
  228. void qdf_cpumask_set_cpu(unsigned int cpu, qdf_cpu_mask *dstp)
  229. {
  230. cpumask_set_cpu(cpu, dstp);
  231. }
  232. qdf_export_symbol(qdf_cpumask_set_cpu);
  233. void qdf_cpumask_setall(qdf_cpu_mask *dstp)
  234. {
  235. cpumask_setall(dstp);
  236. }
  237. qdf_export_symbol(qdf_cpumask_setall);