__wlan_dsc.c 9.6 KB

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