qdf_event.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
  3. * Copyright (c) 2022 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. /**
  20. * DOC: qdf_event.c
  21. *
  22. * This source file contains linux specific definitions for QDF event APIs
  23. * The APIs mentioned in this file are used for initializing, setting,
  24. * resetting, destroying an event and waiting on an occurrence of an event
  25. * among multiple events.
  26. */
  27. /* Include Files */
  28. #include "qdf_event.h"
  29. #include "qdf_mc_timer.h"
  30. #include "qdf_timer.h"
  31. #include <qdf_module.h>
  32. struct qdf_evt_node {
  33. qdf_list_node_t node;
  34. qdf_event_t *pevent;
  35. };
  36. #define MAX_WAIT_EVENTS 10
  37. static qdf_list_t qdf_wait_event_list;
  38. static qdf_spinlock_t qdf_wait_event_lock;
  39. /* Function Definitions and Documentation */
  40. /**
  41. * qdf_event_create() - initializes a QDF event
  42. * @event: Pointer to the opaque event object to initialize
  43. *
  44. * The qdf_event_create() function initializes the specified event. Upon
  45. * successful initialization, the state of the event becomes initialized
  46. * and not signalled.
  47. *
  48. * An event must be initialized before it may be used in any other event
  49. * functions.
  50. * Attempting to initialize an already initialized event results in
  51. * a failure.
  52. *
  53. * Return: QDF status
  54. */
  55. QDF_STATUS qdf_event_create(qdf_event_t *event)
  56. {
  57. QDF_BUG(event);
  58. if (!event)
  59. return QDF_STATUS_E_FAULT;
  60. /* check for 'already initialized' event */
  61. QDF_BUG(event->cookie != LINUX_EVENT_COOKIE);
  62. if (event->cookie == LINUX_EVENT_COOKIE)
  63. return QDF_STATUS_E_BUSY;
  64. /* initialize new event */
  65. init_completion(&event->complete);
  66. event->cookie = LINUX_EVENT_COOKIE;
  67. return QDF_STATUS_SUCCESS;
  68. }
  69. qdf_export_symbol(qdf_event_create);
  70. QDF_STATUS qdf_event_set(qdf_event_t *event)
  71. {
  72. QDF_BUG(event);
  73. if (!event)
  74. return QDF_STATUS_E_FAULT;
  75. /* ensure event is initialized */
  76. QDF_BUG(event->cookie == LINUX_EVENT_COOKIE);
  77. if (event->cookie != LINUX_EVENT_COOKIE)
  78. return QDF_STATUS_E_INVAL;
  79. event->done = true;
  80. complete(&event->complete);
  81. return QDF_STATUS_SUCCESS;
  82. }
  83. qdf_export_symbol(qdf_event_set);
  84. QDF_STATUS qdf_event_set_all(qdf_event_t *event)
  85. {
  86. QDF_BUG(event);
  87. if (!event)
  88. return QDF_STATUS_E_FAULT;
  89. /* ensure event is initialized */
  90. QDF_BUG(event->cookie == LINUX_EVENT_COOKIE);
  91. if (event->cookie != LINUX_EVENT_COOKIE)
  92. return QDF_STATUS_E_INVAL;
  93. event->done = true;
  94. complete_all(&event->complete);
  95. return QDF_STATUS_SUCCESS;
  96. }
  97. qdf_export_symbol(qdf_event_set_all);
  98. /**
  99. * qdf_event_reset() - resets a QDF event
  100. * @event: The event to set to the NOT signalled state
  101. *
  102. * This function isn't required for Linux. Therefore, it doesn't do much.
  103. *
  104. * The state of the specified event is set to 'NOT signalled' by calling
  105. * qdf_event_reset(). The state of the event remains NOT signalled until an
  106. * explicit call to qdf_event_set().
  107. *
  108. * This function sets the event to a NOT signalled state even if the event was
  109. * signalled multiple times before being signaled.
  110. *
  111. * Return: QDF status
  112. */
  113. QDF_STATUS qdf_event_reset(qdf_event_t *event)
  114. {
  115. QDF_BUG(event);
  116. if (!event)
  117. return QDF_STATUS_E_FAULT;
  118. /* ensure event is initialized */
  119. QDF_BUG(event->cookie == LINUX_EVENT_COOKIE);
  120. if (event->cookie != LINUX_EVENT_COOKIE)
  121. return QDF_STATUS_E_INVAL;
  122. /* (re)initialize event */
  123. event->done = false;
  124. event->force_set = false;
  125. INIT_COMPLETION(event->complete);
  126. return QDF_STATUS_SUCCESS;
  127. }
  128. qdf_export_symbol(qdf_event_reset);
  129. /**
  130. * qdf_event_destroy() - Destroys a QDF event
  131. * @event: The event object to be destroyed.
  132. *
  133. * This function doesn't do much in Linux. There is no need for the caller
  134. * to explicitly destroy an event after use.
  135. *
  136. * The os_event_destroy() function shall destroy the event object
  137. * referenced by event. After a successful return from qdf_event_destroy()
  138. * the event object becomes, in effect, uninitialized.
  139. *
  140. * A destroyed event object can be reinitialized using qdf_event_create();
  141. * the results of otherwise referencing the object after it has been destroyed
  142. * are undefined. Calls to QDF event functions to manipulate the lock such
  143. * as qdf_event_set() will fail if the event is destroyed. Therefore,
  144. * don't use the event after it has been destroyed until it has
  145. * been re-initialized.
  146. *
  147. * Return: QDF status
  148. */
  149. QDF_STATUS qdf_event_destroy(qdf_event_t *event)
  150. {
  151. QDF_BUG(event);
  152. if (!event)
  153. return QDF_STATUS_E_FAULT;
  154. /* ensure event is initialized */
  155. QDF_BUG(event->cookie == LINUX_EVENT_COOKIE);
  156. if (event->cookie != LINUX_EVENT_COOKIE)
  157. return QDF_STATUS_E_INVAL;
  158. /* make sure nobody is waiting on the event */
  159. complete_all(&event->complete);
  160. /* destroy the event */
  161. memset(event, 0, sizeof(qdf_event_t));
  162. return QDF_STATUS_SUCCESS;
  163. }
  164. qdf_export_symbol(qdf_event_destroy);
  165. /**
  166. * qdf_wait_single_event() - Waits for a single event to be set.
  167. * This API waits for the event to be set.
  168. *
  169. * @event: Pointer to an event to wait on.
  170. * @timeout: Timeout value (in milliseconds). This function returns
  171. * if this interval elapses, regardless if any of the events have
  172. * been set. An input value of 0 for this timeout parameter means
  173. * to wait infinitely, meaning a timeout will never occur.
  174. *
  175. * Return: QDF status
  176. */
  177. QDF_STATUS qdf_wait_single_event(qdf_event_t *event, uint32_t timeout)
  178. {
  179. QDF_BUG(!in_interrupt());
  180. if (in_interrupt())
  181. return QDF_STATUS_E_FAULT;
  182. QDF_BUG(event);
  183. if (!event)
  184. return QDF_STATUS_E_FAULT;
  185. /* ensure event is initialized */
  186. QDF_BUG(event->cookie == LINUX_EVENT_COOKIE);
  187. if (event->cookie != LINUX_EVENT_COOKIE)
  188. return QDF_STATUS_E_INVAL;
  189. if (timeout) {
  190. long ret;
  191. ret = wait_for_completion_timeout(
  192. &event->complete,
  193. __qdf_scaled_msecs_to_jiffies(timeout));
  194. if (ret <= 0)
  195. return QDF_STATUS_E_TIMEOUT;
  196. } else {
  197. wait_for_completion(&event->complete);
  198. }
  199. return QDF_STATUS_SUCCESS;
  200. }
  201. qdf_export_symbol(qdf_wait_single_event);
  202. /**
  203. * qdf_complete_wait_events() - Sets all the events which are in the list.
  204. *
  205. * This function traverses the list of events and sets all of them. It
  206. * sets the flag force_set as TRUE to indicate that these events have
  207. * been forcefully set.
  208. *
  209. * Return: None
  210. */
  211. void qdf_complete_wait_events(void)
  212. {
  213. struct qdf_evt_node *event_node = NULL;
  214. qdf_list_node_t *list_node = NULL;
  215. QDF_STATUS status;
  216. if (qdf_list_empty(&qdf_wait_event_list))
  217. return;
  218. qdf_spin_lock(&qdf_wait_event_lock);
  219. qdf_list_peek_front(&qdf_wait_event_list,
  220. &list_node);
  221. while (list_node) {
  222. event_node = qdf_container_of(list_node,
  223. struct qdf_evt_node, node);
  224. if (!event_node->pevent->done) {
  225. event_node->pevent->force_set = true;
  226. qdf_event_set(event_node->pevent);
  227. }
  228. status = qdf_list_peek_next(&qdf_wait_event_list,
  229. &event_node->node, &list_node);
  230. if (!QDF_IS_STATUS_SUCCESS(status))
  231. break;
  232. }
  233. qdf_spin_unlock(&qdf_wait_event_lock);
  234. }
  235. qdf_export_symbol(qdf_complete_wait_events);
  236. /**
  237. * qdf_wait_for_event_completion() - Waits for an event to be set.
  238. *
  239. * @event: Pointer to an event to wait on.
  240. * @timeout: Timeout value (in milliseconds).
  241. *
  242. * This function adds the event in a list and waits on it until it
  243. * is set or the timeout duration elapses. The purpose of waiting
  244. * is considered complete only if the event is set and the flag
  245. * force_set is FALSE, it returns success in this case. In other
  246. * cases it returns appropriate error status.
  247. *
  248. * Return: QDF status
  249. */
  250. QDF_STATUS qdf_wait_for_event_completion(qdf_event_t *event, uint32_t timeout)
  251. {
  252. struct qdf_evt_node *event_node;
  253. QDF_STATUS status;
  254. QDF_BUG(!in_interrupt());
  255. if (in_interrupt())
  256. return QDF_STATUS_E_FAULT;
  257. QDF_BUG(event);
  258. if (!event)
  259. return QDF_STATUS_E_FAULT;
  260. /* ensure event is initialized */
  261. QDF_BUG(event->cookie == LINUX_EVENT_COOKIE);
  262. if (event->cookie != LINUX_EVENT_COOKIE)
  263. return QDF_STATUS_E_INVAL;
  264. event_node = qdf_mem_malloc(sizeof(*event_node));
  265. if (!event_node)
  266. return QDF_STATUS_E_NOMEM;
  267. event_node->pevent = event;
  268. qdf_spin_lock(&qdf_wait_event_lock);
  269. status = qdf_list_insert_back(&qdf_wait_event_list, &event_node->node);
  270. qdf_spin_unlock(&qdf_wait_event_lock);
  271. if (QDF_STATUS_SUCCESS != status) {
  272. qdf_err("Failed to insert event into tracking list");
  273. goto free_node;
  274. }
  275. if (timeout) {
  276. long ret;
  277. /* update the timeout if it's on an emulation platform */
  278. ret = wait_for_completion_timeout(&event->complete,
  279. __qdf_scaled_msecs_to_jiffies(timeout));
  280. if (ret <= 0) {
  281. status = QDF_STATUS_E_TIMEOUT;
  282. goto list_remove;
  283. }
  284. } else {
  285. wait_for_completion(&event->complete);
  286. }
  287. /* if event was forcefully completed, return failure */
  288. if (event->force_set)
  289. status = QDF_STATUS_E_FAULT;
  290. list_remove:
  291. qdf_spin_lock(&qdf_wait_event_lock);
  292. qdf_list_remove_node(&qdf_wait_event_list, &event_node->node);
  293. qdf_spin_unlock(&qdf_wait_event_lock);
  294. free_node:
  295. qdf_mem_free(event_node);
  296. return status;
  297. }
  298. qdf_export_symbol(qdf_wait_for_event_completion);
  299. /**
  300. * qdf_event_list_init() - Creates a list and spinlock for events.
  301. *
  302. * This function creates a list for maintaining events on which threads
  303. * wait for completion. A spinlock is also created to protect related
  304. * oprations.
  305. *
  306. * Return: None
  307. */
  308. void qdf_event_list_init(void)
  309. {
  310. qdf_list_create(&qdf_wait_event_list, MAX_WAIT_EVENTS);
  311. qdf_spinlock_create(&qdf_wait_event_lock);
  312. }
  313. qdf_export_symbol(qdf_event_list_init);
  314. /**
  315. * qdf_event_list_destroy() - Destroys list and spinlock created for events.
  316. *
  317. * This function destroys the list and spinlock created for events on which
  318. * threads wait for completion.
  319. *
  320. * Return: None
  321. */
  322. void qdf_event_list_destroy(void)
  323. {
  324. qdf_list_destroy(&qdf_wait_event_list);
  325. qdf_spinlock_destroy(&qdf_wait_event_lock);
  326. }
  327. qdf_export_symbol(qdf_event_list_destroy);