wlan_dsc_psoc.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /*
  2. * Copyright (c) 2018-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. #include "qdf_list.h"
  19. #include "qdf_status.h"
  20. #include "qdf_talloc.h"
  21. #include "qdf_types.h"
  22. #include "__wlan_dsc.h"
  23. #include "wlan_dsc.h"
  24. #define __dsc_driver_lock(psoc) __dsc_lock((psoc)->driver)
  25. #define __dsc_driver_unlock(psoc) __dsc_unlock((psoc)->driver)
  26. static QDF_STATUS
  27. __dsc_psoc_create(struct dsc_driver *driver, struct dsc_psoc **out_psoc)
  28. {
  29. struct dsc_psoc *psoc;
  30. if (!dsc_assert(driver))
  31. return QDF_STATUS_E_INVAL;
  32. if (!dsc_assert(out_psoc))
  33. return QDF_STATUS_E_INVAL;
  34. *out_psoc = NULL;
  35. psoc = qdf_talloc_type(driver, psoc);
  36. if (!psoc)
  37. return QDF_STATUS_E_NOMEM;
  38. /* init */
  39. psoc->driver = driver;
  40. qdf_list_create(&psoc->vdevs, 0);
  41. __dsc_trans_init(&psoc->trans);
  42. __dsc_ops_init(&psoc->ops);
  43. /* attach */
  44. __dsc_driver_lock(psoc);
  45. qdf_list_insert_back(&driver->psocs, &psoc->node);
  46. __dsc_driver_unlock(psoc);
  47. *out_psoc = psoc;
  48. return QDF_STATUS_SUCCESS;
  49. }
  50. QDF_STATUS
  51. dsc_psoc_create(struct dsc_driver *driver, struct dsc_psoc **out_psoc)
  52. {
  53. QDF_STATUS status;
  54. dsc_enter();
  55. status = __dsc_psoc_create(driver, out_psoc);
  56. dsc_exit();
  57. return status;
  58. }
  59. static void __dsc_psoc_destroy(struct dsc_psoc **out_psoc)
  60. {
  61. struct dsc_psoc *psoc;
  62. if (!dsc_assert(out_psoc))
  63. return;
  64. psoc = *out_psoc;
  65. if (!dsc_assert(psoc))
  66. return;
  67. *out_psoc = NULL;
  68. /* assert no children */
  69. dsc_assert(qdf_list_empty(&psoc->vdevs));
  70. /* flush pending transitions */
  71. while (__dsc_trans_abort(&psoc->trans))
  72. ;
  73. /* detach */
  74. __dsc_driver_lock(psoc);
  75. qdf_list_remove_node(&psoc->driver->psocs, &psoc->node);
  76. __dsc_driver_unlock(psoc);
  77. /* de-init */
  78. __dsc_ops_deinit(&psoc->ops);
  79. __dsc_trans_deinit(&psoc->trans);
  80. qdf_list_destroy(&psoc->vdevs);
  81. psoc->driver = NULL;
  82. qdf_tfree(psoc);
  83. }
  84. void dsc_psoc_destroy(struct dsc_psoc **out_psoc)
  85. {
  86. dsc_enter();
  87. __dsc_psoc_destroy(out_psoc);
  88. dsc_exit();
  89. }
  90. static bool __dsc_psoc_trans_active_down_tree(struct dsc_psoc *psoc)
  91. {
  92. struct dsc_vdev *vdev;
  93. dsc_for_each_psoc_vdev(psoc, vdev) {
  94. if (__dsc_trans_active(&vdev->trans))
  95. return true;
  96. }
  97. return false;
  98. }
  99. #define __dsc_psoc_can_op(psoc) __dsc_psoc_can_trans(psoc)
  100. /*
  101. * __dsc_psoc_can_trans() - Returns if the psoc transition can occur or not
  102. * @psoc: The DSC psoc
  103. *
  104. * This function checks if the psoc transition can occur or not by checking if
  105. * any other down the tree/up the tree transition/operation is taking place.
  106. *
  107. * If there are any driver transition taking place, then the psoc trans/ops
  108. * should be rejected and not queued in the DSC queue. Return QDF_STATUS_E_INVAL
  109. * in this case.
  110. *
  111. * If there any psoc or vdev trans/ops is taking place, then the psoc trans/ops
  112. * should be rejected and queued in the DSC queue so that it may be resumed
  113. * after the current trans/ops is completed. Return QDF_STATUS_E_AGAIN in this
  114. * case.
  115. *
  116. * Return: QDF_STATUS_SUCCESS if transition is allowed, error code if not.
  117. */
  118. static QDF_STATUS __dsc_psoc_can_trans(struct dsc_psoc *psoc)
  119. {
  120. if (__dsc_trans_active_or_queued(&psoc->driver->trans))
  121. return QDF_STATUS_E_INVAL;
  122. if (__dsc_trans_active_or_queued(&psoc->trans) ||
  123. __dsc_psoc_trans_active_down_tree(psoc))
  124. return QDF_STATUS_E_AGAIN;
  125. return QDF_STATUS_SUCCESS;
  126. }
  127. static bool __dsc_psoc_can_trigger(struct dsc_psoc *psoc)
  128. {
  129. return !__dsc_trans_active_or_queued(&psoc->driver->trans) &&
  130. !__dsc_trans_active(&psoc->trans) &&
  131. !__dsc_psoc_trans_active_down_tree(psoc);
  132. }
  133. static QDF_STATUS
  134. __dsc_psoc_trans_start_nolock(struct dsc_psoc *psoc, const char *desc)
  135. {
  136. QDF_STATUS status;
  137. status = __dsc_psoc_can_trans(psoc);
  138. if (QDF_IS_STATUS_ERROR(status))
  139. return status;
  140. return __dsc_trans_start(&psoc->trans, desc);
  141. }
  142. static QDF_STATUS
  143. __dsc_psoc_trans_start(struct dsc_psoc *psoc, const char *desc)
  144. {
  145. QDF_STATUS status;
  146. if (!dsc_assert(psoc))
  147. return QDF_STATUS_E_INVAL;
  148. if (!dsc_assert(desc))
  149. return QDF_STATUS_E_INVAL;
  150. __dsc_driver_lock(psoc);
  151. status = __dsc_psoc_trans_start_nolock(psoc, desc);
  152. __dsc_driver_unlock(psoc);
  153. return status;
  154. }
  155. QDF_STATUS dsc_psoc_trans_start(struct dsc_psoc *psoc, const char *desc)
  156. {
  157. QDF_STATUS status;
  158. dsc_enter_str(desc);
  159. status = __dsc_psoc_trans_start(psoc, desc);
  160. dsc_exit_status(status);
  161. return status;
  162. }
  163. static QDF_STATUS
  164. __dsc_psoc_trans_start_wait(struct dsc_psoc *psoc, const char *desc)
  165. {
  166. QDF_STATUS status;
  167. struct dsc_tran tran = { 0 };
  168. if (!dsc_assert(psoc))
  169. return QDF_STATUS_E_INVAL;
  170. if (!dsc_assert(desc))
  171. return QDF_STATUS_E_INVAL;
  172. __dsc_driver_lock(psoc);
  173. /* try to start without waiting */
  174. status = __dsc_psoc_trans_start_nolock(psoc, desc);
  175. if (QDF_IS_STATUS_SUCCESS(status) || status == QDF_STATUS_E_INVAL)
  176. goto unlock;
  177. status = __dsc_trans_queue(&psoc->trans, &tran, desc);
  178. if (QDF_IS_STATUS_ERROR(status))
  179. goto unlock;
  180. __dsc_driver_unlock(psoc);
  181. return __dsc_tran_wait(&tran);
  182. unlock:
  183. __dsc_driver_unlock(psoc);
  184. return status;
  185. }
  186. QDF_STATUS dsc_psoc_trans_start_wait(struct dsc_psoc *psoc, const char *desc)
  187. {
  188. QDF_STATUS status;
  189. dsc_enter_str(desc);
  190. status = __dsc_psoc_trans_start_wait(psoc, desc);
  191. dsc_exit_status(status);
  192. return status;
  193. }
  194. static void __dsc_psoc_trigger_trans(struct dsc_psoc *psoc)
  195. {
  196. struct dsc_vdev *vdev;
  197. if (__dsc_driver_trans_trigger_checked(psoc->driver))
  198. return;
  199. if (__dsc_trans_trigger(&psoc->trans))
  200. return;
  201. dsc_for_each_psoc_vdev(psoc, vdev)
  202. __dsc_trans_trigger(&vdev->trans);
  203. }
  204. static void __dsc_psoc_trans_stop(struct dsc_psoc *psoc)
  205. {
  206. if (!dsc_assert(psoc))
  207. return;
  208. __dsc_driver_lock(psoc);
  209. __dsc_trans_stop(&psoc->trans);
  210. __dsc_psoc_trigger_trans(psoc);
  211. __dsc_driver_unlock(psoc);
  212. }
  213. void dsc_psoc_trans_stop(struct dsc_psoc *psoc)
  214. {
  215. dsc_enter();
  216. __dsc_psoc_trans_stop(psoc);
  217. dsc_exit();
  218. }
  219. static void __dsc_psoc_assert_trans_protected(struct dsc_psoc *psoc)
  220. {
  221. if (!dsc_assert(psoc))
  222. return;
  223. __dsc_driver_lock(psoc);
  224. dsc_assert(__dsc_trans_active(&psoc->trans) ||
  225. __dsc_trans_active(&psoc->driver->trans));
  226. __dsc_driver_unlock(psoc);
  227. }
  228. void dsc_psoc_assert_trans_protected(struct dsc_psoc *psoc)
  229. {
  230. dsc_enter();
  231. __dsc_psoc_assert_trans_protected(psoc);
  232. dsc_exit();
  233. }
  234. bool __dsc_psoc_trans_trigger_checked(struct dsc_psoc *psoc)
  235. {
  236. if (qdf_list_empty(&psoc->trans.queue))
  237. return false;
  238. /* handled, but don't trigger; we need to wait for more children */
  239. if (!__dsc_psoc_can_trigger(psoc))
  240. return true;
  241. return __dsc_trans_trigger(&psoc->trans);
  242. }
  243. static QDF_STATUS __dsc_psoc_op_start(struct dsc_psoc *psoc, const char *func)
  244. {
  245. QDF_STATUS status;
  246. if (!dsc_assert(psoc))
  247. return QDF_STATUS_E_INVAL;
  248. if (!dsc_assert(func))
  249. return QDF_STATUS_E_INVAL;
  250. __dsc_driver_lock(psoc);
  251. status = __dsc_psoc_can_op(psoc);
  252. if (QDF_IS_STATUS_ERROR(status))
  253. goto unlock;
  254. status = __dsc_ops_insert(&psoc->ops, func);
  255. unlock:
  256. __dsc_driver_unlock(psoc);
  257. return status;
  258. }
  259. QDF_STATUS _dsc_psoc_op_start(struct dsc_psoc *psoc, const char *func)
  260. {
  261. QDF_STATUS status;
  262. status = __dsc_psoc_op_start(psoc, func);
  263. return status;
  264. }
  265. static void __dsc_psoc_op_stop(struct dsc_psoc *psoc, const char *func)
  266. {
  267. if (!dsc_assert(psoc))
  268. return;
  269. if (!dsc_assert(func))
  270. return;
  271. __dsc_driver_lock(psoc);
  272. if (__dsc_ops_remove(&psoc->ops, func))
  273. qdf_event_set(&psoc->ops.event);
  274. __dsc_driver_unlock(psoc);
  275. }
  276. void _dsc_psoc_op_stop(struct dsc_psoc *psoc, const char *func)
  277. {
  278. __dsc_psoc_op_stop(psoc, func);
  279. }
  280. static void __dsc_psoc_wait_for_ops(struct dsc_psoc *psoc)
  281. {
  282. struct dsc_vdev *vdev;
  283. bool wait;
  284. if (!dsc_assert(psoc))
  285. return;
  286. __dsc_driver_lock(psoc);
  287. wait = psoc->ops.count > 0;
  288. if (wait)
  289. qdf_event_reset(&psoc->ops.event);
  290. __dsc_driver_unlock(psoc);
  291. if (wait)
  292. qdf_wait_single_event(&psoc->ops.event, 0);
  293. /* wait for down-tree ops to complete as well */
  294. dsc_for_each_psoc_vdev(psoc, vdev)
  295. dsc_vdev_wait_for_ops(vdev);
  296. }
  297. void dsc_psoc_wait_for_ops(struct dsc_psoc *psoc)
  298. {
  299. dsc_enter();
  300. __dsc_psoc_wait_for_ops(psoc);
  301. dsc_exit();
  302. }