wlan_dsc_vdev.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /*
  2. * Copyright (c) 2018-2020 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. #include "qdf_platform.h"
  25. #define __dsc_driver_lock(vdev) __dsc_lock((vdev)->psoc->driver)
  26. #define __dsc_driver_unlock(vdev) __dsc_unlock((vdev)->psoc->driver)
  27. static QDF_STATUS
  28. __dsc_vdev_create(struct dsc_psoc *psoc, struct dsc_vdev **out_vdev)
  29. {
  30. struct dsc_vdev *vdev;
  31. if (!dsc_assert(psoc))
  32. return QDF_STATUS_E_INVAL;
  33. if (!dsc_assert(out_vdev))
  34. return QDF_STATUS_E_INVAL;
  35. *out_vdev = NULL;
  36. vdev = qdf_talloc_type(psoc, vdev);
  37. if (!vdev)
  38. return QDF_STATUS_E_NOMEM;
  39. /* init */
  40. vdev->psoc = psoc;
  41. __dsc_trans_init(&vdev->trans);
  42. __dsc_ops_init(&vdev->ops);
  43. /* attach */
  44. __dsc_driver_lock(vdev);
  45. qdf_list_insert_back(&psoc->vdevs, &vdev->node);
  46. __dsc_driver_unlock(vdev);
  47. *out_vdev = vdev;
  48. return QDF_STATUS_SUCCESS;
  49. }
  50. QDF_STATUS dsc_vdev_create(struct dsc_psoc *psoc, struct dsc_vdev **out_vdev)
  51. {
  52. QDF_STATUS status;
  53. status = __dsc_vdev_create(psoc, out_vdev);
  54. return status;
  55. }
  56. static void __dsc_vdev_destroy(struct dsc_vdev **out_vdev)
  57. {
  58. struct dsc_vdev *vdev;
  59. if (!dsc_assert(out_vdev))
  60. return;
  61. vdev = *out_vdev;
  62. if (!dsc_assert(vdev))
  63. return;
  64. *out_vdev = NULL;
  65. /* flush pending transitions */
  66. while (__dsc_trans_abort(&vdev->trans))
  67. ;
  68. /* detach */
  69. __dsc_driver_lock(vdev);
  70. qdf_list_remove_node(&vdev->psoc->vdevs, &vdev->node);
  71. __dsc_driver_unlock(vdev);
  72. /* de-init */
  73. __dsc_ops_deinit(&vdev->ops);
  74. __dsc_trans_deinit(&vdev->trans);
  75. vdev->psoc = NULL;
  76. qdf_tfree(vdev);
  77. }
  78. void dsc_vdev_destroy(struct dsc_vdev **out_vdev)
  79. {
  80. __dsc_vdev_destroy(out_vdev);
  81. }
  82. #define __dsc_vdev_can_op(vdev) __dsc_vdev_can_trans(vdev)
  83. /*
  84. * __dsc_vdev_can_trans() - Returns if the vdev transition can occur or not
  85. * @vdev: The DSC vdev
  86. *
  87. * This function checks if the vdev transition can occur or not by checking if
  88. * any other down the tree/up the tree transition/operation is taking place.
  89. *
  90. * If there are any driver transition taking place, then the vdev trans/ops
  91. * should be rejected and not queued in the DSC queue. Return QDF_STATUS_E_INVAL
  92. * in this case.
  93. *
  94. * If there are any psoc transition taking place because of SSR, then vdev
  95. * trans/op should be rejected and queued in the DSC queue so that it may be
  96. * resumed after the current trans/op is completed. return QDF_STATUS_E_AGAIN
  97. * in this case.
  98. *
  99. * If there is a psoc transition taking place becasue of psoc idle shutdown,
  100. * then the vdev trans/ops should be rejected and queued in the DSC queue so
  101. * that it may be resumed after the current trans/ops is completed. Return
  102. * QDF_STATUS_E_AGAIN in this case.
  103. *
  104. * If there are any vdev trans/ops taking place, then the vdev trans/ops
  105. * should be rejected and queued in the DSC queue so that it may be resumed
  106. * after the current trans/ops is completed. Return QDF_STATUS_E_AGAIN in this
  107. * case.
  108. *
  109. * Return: QDF_STATUS_SUCCESS if transition is allowed, error code if not.
  110. */
  111. static QDF_STATUS __dsc_vdev_can_trans(struct dsc_vdev *vdev)
  112. {
  113. if (__dsc_trans_active_or_queued(&vdev->psoc->driver->trans))
  114. return QDF_STATUS_E_INVAL;
  115. if (qdf_is_recovering())
  116. return QDF_STATUS_E_AGAIN;
  117. if (__dsc_trans_active_or_queued(&vdev->psoc->trans)) {
  118. /* psoc idle shutdown(wifi off) needs to be added in DSC queue
  119. * to avoid wifi on failure while previous psoc idle shutdown
  120. * is in progress and wifi is turned on. And Wifi On also needs
  121. * to be added to the queue so that it waits for SSR to
  122. * complete.
  123. */
  124. if (qdf_is_driver_unloading())
  125. return QDF_STATUS_E_INVAL;
  126. else
  127. return QDF_STATUS_E_AGAIN;
  128. }
  129. if (__dsc_trans_active_or_queued(&vdev->trans))
  130. return QDF_STATUS_E_AGAIN;
  131. return QDF_STATUS_SUCCESS;
  132. }
  133. static QDF_STATUS
  134. __dsc_vdev_trans_start_nolock(struct dsc_vdev *vdev, const char *desc)
  135. {
  136. QDF_STATUS status = QDF_STATUS_SUCCESS;
  137. status = __dsc_vdev_can_trans(vdev);
  138. if (QDF_IS_STATUS_ERROR(status))
  139. return status;
  140. return __dsc_trans_start(&vdev->trans, desc);
  141. }
  142. static QDF_STATUS
  143. __dsc_vdev_trans_start(struct dsc_vdev *vdev, const char *desc)
  144. {
  145. QDF_STATUS status;
  146. if (!dsc_assert(vdev))
  147. return QDF_STATUS_E_INVAL;
  148. if (!dsc_assert(desc))
  149. return QDF_STATUS_E_INVAL;
  150. __dsc_driver_lock(vdev);
  151. status = __dsc_vdev_trans_start_nolock(vdev, desc);
  152. __dsc_driver_unlock(vdev);
  153. return status;
  154. }
  155. QDF_STATUS dsc_vdev_trans_start(struct dsc_vdev *vdev, const char *desc)
  156. {
  157. QDF_STATUS status;
  158. dsc_enter_str(desc);
  159. status = __dsc_vdev_trans_start(vdev, desc);
  160. if (QDF_IS_STATUS_ERROR(status))
  161. dsc_exit_status(status);
  162. return status;
  163. }
  164. static QDF_STATUS
  165. __dsc_vdev_trans_start_wait(struct dsc_vdev *vdev, const char *desc)
  166. {
  167. QDF_STATUS status;
  168. struct dsc_tran tran = { 0 };
  169. if (!dsc_assert(vdev))
  170. return QDF_STATUS_E_INVAL;
  171. if (!dsc_assert(desc))
  172. return QDF_STATUS_E_INVAL;
  173. __dsc_driver_lock(vdev);
  174. /* try to start without waiting */
  175. status = __dsc_vdev_trans_start_nolock(vdev, desc);
  176. if (QDF_IS_STATUS_SUCCESS(status) || status == QDF_STATUS_E_INVAL)
  177. goto unlock;
  178. status = __dsc_trans_queue(&vdev->trans, &tran, desc);
  179. if (QDF_IS_STATUS_ERROR(status))
  180. goto unlock;
  181. __dsc_driver_unlock(vdev);
  182. return __dsc_tran_wait(&tran);
  183. unlock:
  184. __dsc_driver_unlock(vdev);
  185. return status;
  186. }
  187. QDF_STATUS dsc_vdev_trans_start_wait(struct dsc_vdev *vdev, const char *desc)
  188. {
  189. QDF_STATUS status;
  190. dsc_enter_str(desc);
  191. status = __dsc_vdev_trans_start_wait(vdev, desc);
  192. if (QDF_IS_STATUS_ERROR(status))
  193. dsc_exit_status(status);
  194. return status;
  195. }
  196. static void __dsc_vdev_trigger_trans(struct dsc_vdev *vdev)
  197. {
  198. if (__dsc_driver_trans_trigger_checked(vdev->psoc->driver))
  199. return;
  200. if (__dsc_psoc_trans_trigger_checked(vdev->psoc))
  201. return;
  202. __dsc_trans_trigger(&vdev->trans);
  203. }
  204. static void __dsc_vdev_trans_stop(struct dsc_vdev *vdev)
  205. {
  206. if (!dsc_assert(vdev))
  207. return;
  208. __dsc_driver_lock(vdev);
  209. __dsc_trans_stop(&vdev->trans);
  210. __dsc_vdev_trigger_trans(vdev);
  211. __dsc_driver_unlock(vdev);
  212. }
  213. void dsc_vdev_trans_stop(struct dsc_vdev *vdev)
  214. {
  215. __dsc_vdev_trans_stop(vdev);
  216. }
  217. static void __dsc_vdev_assert_trans_protected(struct dsc_vdev *vdev)
  218. {
  219. if (!dsc_assert(vdev))
  220. return;
  221. __dsc_driver_lock(vdev);
  222. dsc_assert(__dsc_trans_active(&vdev->trans) ||
  223. __dsc_trans_active(&vdev->psoc->trans) ||
  224. __dsc_trans_active(&vdev->psoc->driver->trans));
  225. __dsc_driver_unlock(vdev);
  226. }
  227. void dsc_vdev_assert_trans_protected(struct dsc_vdev *vdev)
  228. {
  229. __dsc_vdev_assert_trans_protected(vdev);
  230. }
  231. static QDF_STATUS __dsc_vdev_op_start(struct dsc_vdev *vdev, const char *func)
  232. {
  233. QDF_STATUS status;
  234. if (!dsc_assert(vdev))
  235. return QDF_STATUS_E_INVAL;
  236. if (!dsc_assert(func))
  237. return QDF_STATUS_E_INVAL;
  238. __dsc_driver_lock(vdev);
  239. status = __dsc_vdev_can_op(vdev);
  240. if (QDF_IS_STATUS_ERROR(status))
  241. goto unlock;
  242. status = __dsc_ops_insert(&vdev->ops, func);
  243. unlock:
  244. __dsc_driver_unlock(vdev);
  245. return status;
  246. }
  247. QDF_STATUS _dsc_vdev_op_start(struct dsc_vdev *vdev, const char *func)
  248. {
  249. QDF_STATUS status;
  250. /* do not log from here because it can flood log message because vdev
  251. * op protect is per vdev operation
  252. */
  253. status = __dsc_vdev_op_start(vdev, func);
  254. return status;
  255. }
  256. static void __dsc_vdev_op_stop(struct dsc_vdev *vdev, const char *func)
  257. {
  258. if (!dsc_assert(vdev))
  259. return;
  260. if (!dsc_assert(func))
  261. return;
  262. __dsc_driver_lock(vdev);
  263. if (__dsc_ops_remove(&vdev->ops, func))
  264. qdf_event_set(&vdev->ops.event);
  265. __dsc_driver_unlock(vdev);
  266. }
  267. void _dsc_vdev_op_stop(struct dsc_vdev *vdev, const char *func)
  268. {
  269. /* do not log from here because it can flood log message because vdev
  270. * op protect is per vdev operation
  271. */
  272. __dsc_vdev_op_stop(vdev, func);
  273. }
  274. static void __dsc_vdev_wait_for_ops(struct dsc_vdev *vdev)
  275. {
  276. bool wait;
  277. if (!dsc_assert(vdev))
  278. return;
  279. __dsc_driver_lock(vdev);
  280. wait = vdev->ops.count > 0;
  281. if (wait)
  282. qdf_event_reset(&vdev->ops.event);
  283. __dsc_driver_unlock(vdev);
  284. if (wait)
  285. qdf_wait_single_event(&vdev->ops.event, 0);
  286. }
  287. void dsc_vdev_wait_for_ops(struct dsc_vdev *vdev)
  288. {
  289. __dsc_vdev_wait_for_ops(vdev);
  290. }