__wlan_dsc.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /*
  2. * Copyright (c) 2018 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. #include "qdf_list.h"
  19. #include "qdf_mem.h"
  20. #include "qdf_status.h"
  21. #include "qdf_str.h"
  22. #include "qdf_threads.h"
  23. #include "qdf_timer.h"
  24. #include "__wlan_dsc.h"
  25. #ifdef WLAN_DSC_DEBUG
  26. static void __dsc_dbg_op_timeout(void *opaque_op)
  27. {
  28. struct dsc_op *op = opaque_op;
  29. qdf_print_thread_trace(op->thread);
  30. QDF_DEBUG_PANIC("Operation '%s' exceeded %ums",
  31. op->func, DSC_OP_TIMEOUT_MS);
  32. }
  33. /**
  34. * __dsc_dbg_ops_init() - initialize debug ops data structures
  35. * @ops: the ops container to initialize
  36. *
  37. * Return: None
  38. */
  39. static inline void __dsc_dbg_ops_init(struct dsc_ops *ops)
  40. {
  41. qdf_list_create(&ops->list, 0);
  42. }
  43. /**
  44. * __dsc_dbg_ops_deinit() - de-initialize debug ops data structures
  45. * @ops: the ops container to de-initialize
  46. *
  47. * Return: None
  48. */
  49. static inline void __dsc_dbg_ops_deinit(struct dsc_ops *ops)
  50. {
  51. qdf_list_destroy(&ops->list);
  52. }
  53. /**
  54. * __dsc_dbg_ops_insert() - insert @func into the debug information in @ops
  55. * @ops: the ops container to insert into
  56. * @func: the debug information to insert
  57. *
  58. * Return: QDF_STATUS
  59. */
  60. static QDF_STATUS __dsc_dbg_ops_insert(struct dsc_ops *ops, const char *func)
  61. {
  62. QDF_STATUS status;
  63. struct dsc_op *op;
  64. op = qdf_mem_malloc(sizeof(*op));
  65. if (!op)
  66. return QDF_STATUS_E_NOMEM;
  67. op->thread = qdf_get_current_task();
  68. status = qdf_timer_init(NULL, &op->timeout_timer, __dsc_dbg_op_timeout,
  69. op, QDF_TIMER_TYPE_SW);
  70. if (QDF_IS_STATUS_ERROR(status))
  71. goto free_op;
  72. op->func = func;
  73. qdf_timer_start(&op->timeout_timer, DSC_OP_TIMEOUT_MS);
  74. qdf_list_insert_back(&ops->list, &op->node);
  75. return QDF_STATUS_SUCCESS;
  76. free_op:
  77. qdf_mem_free(op);
  78. return status;
  79. }
  80. /**
  81. * __dsc_dbg_ops_remove() - remove @func from the debug information in @ops
  82. * @ops: the ops container to remove from
  83. * @func: the debug information to remove
  84. *
  85. * Return: None
  86. */
  87. static void __dsc_dbg_ops_remove(struct dsc_ops *ops, const char *func)
  88. {
  89. struct dsc_op *op;
  90. /* Global pending op depth is usually <=3. Use linear search for now */
  91. qdf_list_for_each(&ops->list, op, node) {
  92. if (!qdf_str_eq(op->func, func))
  93. continue;
  94. /* this is safe because we cease iteration */
  95. qdf_list_remove_node(&ops->list, &op->node);
  96. qdf_timer_stop(&op->timeout_timer);
  97. qdf_timer_free(&op->timeout_timer);
  98. qdf_mem_free(op);
  99. return;
  100. }
  101. QDF_DEBUG_PANIC("Driver op '%s' is not pending", func);
  102. }
  103. #else
  104. static inline void __dsc_dbg_ops_init(struct dsc_ops *ops) { }
  105. static inline void __dsc_dbg_ops_deinit(struct dsc_ops *ops) { }
  106. static inline QDF_STATUS
  107. __dsc_dbg_ops_insert(struct dsc_ops *ops, const char *func)
  108. {
  109. return QDF_STATUS_SUCCESS;
  110. }
  111. static inline void
  112. __dsc_dbg_ops_remove(struct dsc_ops *ops, const char *func) { }
  113. #endif /* WLAN_DSC_DEBUG */
  114. void __dsc_ops_init(struct dsc_ops *ops)
  115. {
  116. ops->count = 0;
  117. qdf_event_create(&ops->event);
  118. __dsc_dbg_ops_init(ops);
  119. }
  120. void __dsc_ops_deinit(struct dsc_ops *ops)
  121. {
  122. /* assert no ops in flight */
  123. dsc_assert(!ops->count);
  124. __dsc_dbg_ops_deinit(ops);
  125. qdf_event_destroy(&ops->event);
  126. }
  127. QDF_STATUS __dsc_ops_insert(struct dsc_ops *ops, const char *func)
  128. {
  129. QDF_STATUS status;
  130. status = __dsc_dbg_ops_insert(ops, func);
  131. if (QDF_IS_STATUS_ERROR(status))
  132. return status;
  133. ops->count++;
  134. return QDF_STATUS_SUCCESS;
  135. }
  136. bool __dsc_ops_remove(struct dsc_ops *ops, const char *func)
  137. {
  138. dsc_assert(ops->count);
  139. ops->count--;
  140. __dsc_dbg_ops_remove(ops, func);
  141. return ops->count == 0;
  142. }
  143. #ifdef WLAN_DSC_DEBUG
  144. static void __dsc_dbg_trans_timeout(void *opaque_trans)
  145. {
  146. struct dsc_trans *trans = opaque_trans;
  147. qdf_print_thread_trace(trans->thread);
  148. QDF_DEBUG_PANIC("Transition '%s' exceeded %ums",
  149. trans->active_desc, DSC_TRANS_TIMEOUT_MS);
  150. }
  151. /**
  152. * __dsc_dbg_trans_timeout_start() - start a timeout timer for @trans
  153. * @trans: the active transition to start a timeout timer for
  154. *
  155. * Return: QDF_STATUS
  156. */
  157. static QDF_STATUS __dsc_dbg_trans_timeout_start(struct dsc_trans *trans)
  158. {
  159. QDF_STATUS status;
  160. trans->thread = qdf_get_current_task();
  161. status = qdf_timer_init(NULL, &trans->timeout_timer,
  162. __dsc_dbg_trans_timeout, trans,
  163. QDF_TIMER_TYPE_SW);
  164. if (QDF_IS_STATUS_ERROR(status))
  165. return status;
  166. qdf_timer_start(&trans->timeout_timer, DSC_TRANS_TIMEOUT_MS);
  167. return QDF_STATUS_SUCCESS;
  168. }
  169. /**
  170. * __dsc_dbg_trans_timeout_stop() - stop the timeout timer for @trans
  171. * @trans: the active transition to stop the timeout timer for
  172. *
  173. * Return: None
  174. */
  175. static void __dsc_dbg_trans_timeout_stop(struct dsc_trans *trans)
  176. {
  177. qdf_timer_stop(&trans->timeout_timer);
  178. qdf_timer_free(&trans->timeout_timer);
  179. }
  180. static void __dsc_dbg_tran_wait_timeout(void *opaque_tran)
  181. {
  182. struct dsc_tran *tran = opaque_tran;
  183. qdf_print_thread_trace(tran->thread);
  184. QDF_DEBUG_PANIC("Transition '%s' waited more than %ums",
  185. tran->desc, DSC_TRANS_WAIT_TIMEOUT_MS);
  186. }
  187. /**
  188. * __dsc_dbg_tran_wait_timeout_start() - start a timeout timer for @tran
  189. * @tran: the pending transition to start a timeout timer for
  190. *
  191. * Return: QDF_STATUS
  192. */
  193. static QDF_STATUS __dsc_dbg_tran_wait_timeout_start(struct dsc_tran *tran)
  194. {
  195. QDF_STATUS status;
  196. tran->thread = qdf_get_current_task();
  197. status = qdf_timer_init(NULL, &tran->timeout_timer,
  198. __dsc_dbg_tran_wait_timeout, tran,
  199. QDF_TIMER_TYPE_SW);
  200. if (QDF_IS_STATUS_ERROR(status))
  201. return status;
  202. qdf_timer_start(&tran->timeout_timer, DSC_TRANS_WAIT_TIMEOUT_MS);
  203. return QDF_STATUS_SUCCESS;
  204. }
  205. /**
  206. * __dsc_dbg_tran_wait_timeout_stop() - stop the timeout timer for @tran
  207. * @tran: the pending transition to stop the timeout timer for
  208. *
  209. * Return: None
  210. */
  211. static void __dsc_dbg_tran_wait_timeout_stop(struct dsc_tran *tran)
  212. {
  213. qdf_timer_stop(&tran->timeout_timer);
  214. qdf_timer_free(&tran->timeout_timer);
  215. }
  216. #else
  217. static inline QDF_STATUS __dsc_dbg_trans_timeout_start(struct dsc_trans *trans)
  218. {
  219. return QDF_STATUS_SUCCESS;
  220. }
  221. static inline void __dsc_dbg_trans_timeout_stop(struct dsc_trans *trans) { }
  222. static inline QDF_STATUS
  223. __dsc_dbg_tran_wait_timeout_start(struct dsc_tran *tran)
  224. {
  225. return QDF_STATUS_SUCCESS;
  226. }
  227. static inline void __dsc_dbg_tran_wait_timeout_stop(struct dsc_tran *tran) { }
  228. #endif /* WLAN_DSC_DEBUG */
  229. void __dsc_trans_init(struct dsc_trans *trans)
  230. {
  231. trans->active_desc = NULL;
  232. qdf_list_create(&trans->queue, 0);
  233. }
  234. void __dsc_trans_deinit(struct dsc_trans *trans)
  235. {
  236. qdf_list_destroy(&trans->queue);
  237. trans->active_desc = NULL;
  238. }
  239. QDF_STATUS __dsc_trans_start(struct dsc_trans *trans, const char *desc)
  240. {
  241. QDF_STATUS status;
  242. status = __dsc_dbg_trans_timeout_start(trans);
  243. if (QDF_IS_STATUS_ERROR(status))
  244. return status;
  245. dsc_assert(!trans->active_desc);
  246. trans->active_desc = desc;
  247. return QDF_STATUS_SUCCESS;
  248. }
  249. void __dsc_trans_stop(struct dsc_trans *trans)
  250. {
  251. dsc_assert(trans->active_desc);
  252. trans->active_desc = NULL;
  253. __dsc_dbg_trans_timeout_stop(trans);
  254. }
  255. QDF_STATUS __dsc_trans_queue(struct dsc_trans *trans, struct dsc_tran *tran,
  256. const char *desc)
  257. {
  258. QDF_STATUS status;
  259. tran->abort = false;
  260. tran->desc = desc;
  261. qdf_event_create(&tran->event);
  262. status = __dsc_dbg_tran_wait_timeout_start(tran);
  263. if (QDF_IS_STATUS_ERROR(status))
  264. goto event_destroy;
  265. qdf_list_insert_back(&trans->queue, &tran->node);
  266. return QDF_STATUS_SUCCESS;
  267. event_destroy:
  268. qdf_event_destroy(&tran->event);
  269. return status;
  270. }
  271. /**
  272. * __dsc_trans_dequeue() - dequeue the next queued transition from @trans
  273. * @trans: the transactions container to dequeue from
  274. *
  275. * Return: the dequeued transition, or NULL if @trans is empty
  276. */
  277. static struct dsc_tran *__dsc_trans_dequeue(struct dsc_trans *trans)
  278. {
  279. QDF_STATUS status;
  280. qdf_list_node_t *node;
  281. struct dsc_tran *tran;
  282. status = qdf_list_remove_front(&trans->queue, &node);
  283. if (QDF_IS_STATUS_ERROR(status))
  284. return NULL;
  285. tran = qdf_container_of(node, struct dsc_tran, node);
  286. __dsc_dbg_tran_wait_timeout_stop(tran);
  287. return tran;
  288. }
  289. bool __dsc_trans_abort(struct dsc_trans *trans)
  290. {
  291. struct dsc_tran *tran;
  292. tran = __dsc_trans_dequeue(trans);
  293. if (!tran)
  294. return false;
  295. tran->abort = true;
  296. qdf_event_set(&tran->event);
  297. return true;
  298. }
  299. bool __dsc_trans_trigger(struct dsc_trans *trans)
  300. {
  301. struct dsc_tran *tran;
  302. tran = __dsc_trans_dequeue(trans);
  303. if (!tran)
  304. return false;
  305. __dsc_trans_start(trans, tran->desc);
  306. qdf_event_set(&tran->event);
  307. return true;
  308. }
  309. bool __dsc_trans_active(struct dsc_trans *trans)
  310. {
  311. return !!trans->active_desc;
  312. }
  313. bool __dsc_trans_queued(struct dsc_trans *trans)
  314. {
  315. return !qdf_list_empty(&trans->queue);
  316. }
  317. bool __dsc_trans_active_or_queued(struct dsc_trans *trans)
  318. {
  319. return __dsc_trans_active(trans) || __dsc_trans_queued(trans);
  320. }
  321. QDF_STATUS __dsc_tran_wait(struct dsc_tran *tran)
  322. {
  323. QDF_STATUS status;
  324. status = qdf_wait_single_event(&tran->event, 0);
  325. qdf_event_destroy(&tran->event);
  326. if (QDF_IS_STATUS_ERROR(status))
  327. return status;
  328. if (tran->abort)
  329. return QDF_STATUS_E_ABORTED;
  330. return QDF_STATUS_SUCCESS;
  331. }