xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_event.c (revision 9b24afb720cd7079342f34d267eef718e719ce65)
1 /*
2  * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
3  *
4  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5  *
6  *
7  * Permission to use, copy, modify, and/or distribute this software for
8  * any purpose with or without fee is hereby granted, provided that the
9  * above copyright notice and this permission notice appear in all
10  * copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19  * PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 /*
23  * This file was originally distributed by Qualcomm Atheros, Inc.
24  * under proprietary terms before Copyright ownership was assigned
25  * to the Linux Foundation.
26  */
27 
28 /**
29  * DOC: qdf_event.c
30  *
31  * This source file contains linux specific definitions for QDF event APIs
32  * The APIs mentioned in this file are used for initializing, setting,
33  * resetting, destroying an event and waiting on an occurance of an event
34  * among multiple events.
35  */
36 
37 /* Include Files */
38 #include "qdf_event.h"
39 #include "qdf_mc_timer.h"
40 #include <linux/export.h>
41 
42 #ifdef CONFIG_MCL
43 static qdf_self_recovery_callback self_recovery_cb;
44 #endif
45 
46 /* Function Definitions and Documentation */
47 
48 /**
49  * qdf_event_create() - initializes a QDF event
50  * @event: Pointer to the opaque event object to initialize
51  *
52  * The qdf_event_create() function initializes the specified event. Upon
53  * successful initialization, the state of the event becomes initialized
54  * and not signalled.
55  *
56  * An event must be initialized before it may be used in any other event
57  * functions.
58  * Attempting to initialize an already initialized event results in
59  * a failure.
60  *
61  * Return: QDF status
62  */
63 QDF_STATUS qdf_event_create(qdf_event_t *event)
64 {
65 	/* check for null pointer */
66 	if (NULL == event) {
67 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
68 			  "NULL event passed into %s", __func__);
69 		QDF_ASSERT(0);
70 		return QDF_STATUS_E_FAULT;
71 	}
72 
73 	/* check for 'already initialized' event */
74 	if (LINUX_EVENT_COOKIE == event->cookie) {
75 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
76 			  "Initialized event passed into %s", __func__);
77 		QDF_ASSERT(0);
78 		return QDF_STATUS_E_BUSY;
79 	}
80 
81 	/* initialize new event */
82 	init_completion(&event->complete);
83 	event->cookie = LINUX_EVENT_COOKIE;
84 
85 	return QDF_STATUS_SUCCESS;
86 }
87 EXPORT_SYMBOL(qdf_event_create);
88 
89 /**
90  * qdf_event_set() - sets a QDF event
91  * @event: The event to set to the signalled state
92  *
93  * The state of the specified event is set to signalled by calling
94  * qdf_event_set().
95  *
96  * Any threads waiting on the event as a result of a qdf_event_wait() will
97  * be unblocked and available to be scheduled for execution when the event
98  * is signaled by a call to qdf_event_set().
99  *
100  * Return: QDF status
101  */
102 QDF_STATUS qdf_event_set(qdf_event_t *event)
103 {
104 	/* check for null pointer */
105 	if (NULL == event) {
106 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
107 			  "NULL event passed into %s", __func__);
108 		QDF_ASSERT(0);
109 		return QDF_STATUS_E_FAULT;
110 	}
111 
112 	/* check if event refers to an initialized object */
113 	if (LINUX_EVENT_COOKIE != event->cookie) {
114 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
115 			  "Uninitialized event passed into %s", __func__);
116 		QDF_ASSERT(0);
117 		return QDF_STATUS_E_INVAL;
118 	}
119 
120 	complete(&event->complete);
121 
122 	return QDF_STATUS_SUCCESS;
123 }
124 EXPORT_SYMBOL(qdf_event_set);
125 
126 /**
127  * qdf_event_reset() - resets a QDF event
128  * @event: The event to set to the NOT signalled state
129  *
130  * This function isn't required for Linux. Therefore, it doesn't do much.
131  *
132  * The state of the specified event is set to 'NOT signalled' by calling
133  * qdf_event_reset().  The state of the event remains NOT signalled until an
134  * explicit call to qdf_event_set().
135  *
136  * This function sets the event to a NOT signalled state even if the event was
137  * signalled multiple times before being signaled.
138  *
139  * Return: QDF status
140  */
141 QDF_STATUS qdf_event_reset(qdf_event_t *event)
142 {
143 	/* check for null pointer */
144 	if (NULL == event) {
145 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
146 			  "NULL event passed into %s", __func__);
147 		QDF_ASSERT(0);
148 		return QDF_STATUS_E_FAULT;
149 	}
150 
151 	/* check to make sure it is an 'already initialized' event */
152 	if (LINUX_EVENT_COOKIE != event->cookie) {
153 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
154 			  "Uninitialized event passed into %s", __func__);
155 		QDF_ASSERT(0);
156 		return QDF_STATUS_E_INVAL;
157 	}
158 
159 	/* (re)initialize event */
160 	INIT_COMPLETION(event->complete);
161 	return QDF_STATUS_SUCCESS;
162 }
163 EXPORT_SYMBOL(qdf_event_reset);
164 
165 /**
166  * qdf_event_destroy() - Destroys a QDF event
167  * @event: The event object to be destroyed.
168  *
169  * This function doesn't do much in Linux. There is no need for the caller
170  * to explicitly destroy an event after use.
171  *
172  * The os_event_destroy() function shall destroy the event object
173  * referenced by event.  After a successful return from qdf_event_destroy()
174  * the event object becomes, in effect, uninitialized.
175  *
176  * A destroyed event object can be reinitialized using qdf_event_create();
177  * the results of otherwise referencing the object after it has been destroyed
178  * are undefined.  Calls to QDF event functions to manipulate the lock such
179  * as qdf_event_set() will fail if the event is destroyed.  Therefore,
180  * don't use the event after it has been destroyed until it has
181  * been re-initialized.
182  *
183  * Return: QDF status
184  */
185 QDF_STATUS qdf_event_destroy(qdf_event_t *event)
186 {
187 	/* check for null pointer */
188 	if (NULL == event) {
189 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
190 			  "NULL event passed into %s", __func__);
191 		QDF_ASSERT(0);
192 		return QDF_STATUS_E_FAULT;
193 	}
194 
195 	/* check to make sure it is an 'already initialized' event */
196 	if (LINUX_EVENT_COOKIE != event->cookie) {
197 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
198 			  "Uninitialized event passed into %s", __func__);
199 		QDF_ASSERT(0);
200 		return QDF_STATUS_E_INVAL;
201 	}
202 
203 	/* make sure nobody is waiting on the event */
204 	complete_all(&event->complete);
205 
206 	/* destroy the event */
207 	memset(event, 0, sizeof(qdf_event_t));
208 
209 	return QDF_STATUS_SUCCESS;
210 }
211 EXPORT_SYMBOL(qdf_event_destroy);
212 
213 /**
214  * qdf_wait_single_event() - Waits for a single event to be set.
215  * This API waits for the event to be set.
216  *
217  * @event: Pointer to an event to wait on.
218  * @timeout: Timeout value (in milliseconds).  This function returns
219  * if this interval elapses, regardless if any of the events have
220  * been set.  An input value of 0 for this timeout parameter means
221  * to wait infinitely, meaning a timeout will never occur.
222  *
223  * Return: QDF status
224  */
225 QDF_STATUS qdf_wait_single_event(qdf_event_t *event, uint32_t timeout)
226 {
227 	if (in_interrupt()) {
228 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
229 			  "%s cannot be called from interrupt context!!!",
230 			  __func__);
231 		QDF_ASSERT(0);
232 		return QDF_STATUS_E_FAULT;
233 	}
234 
235 	/* check for null pointer */
236 	if (NULL == event) {
237 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
238 			  "NULL event passed into %s", __func__);
239 		QDF_ASSERT(0);
240 		return QDF_STATUS_E_FAULT;
241 	}
242 
243 	/* check if cookie is same as that of initialized event */
244 	if (LINUX_EVENT_COOKIE != event->cookie) {
245 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
246 			  "Uninitialized event passed into %s", __func__);
247 		QDF_ASSERT(0);
248 		return QDF_STATUS_E_INVAL;
249 	}
250 
251 	/* update the timeout if its on a emaulation platform */
252 	timeout *= qdf_timer_get_multiplier();
253 	if (timeout) {
254 		long ret;
255 
256 		ret = wait_for_completion_timeout(&event->complete,
257 						  msecs_to_jiffies(timeout));
258 		if (0 >= ret)
259 			return QDF_STATUS_E_TIMEOUT;
260 	} else {
261 		wait_for_completion(&event->complete);
262 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
263 			  "Signaled for completion %s", __func__);
264 		return QDF_STATUS_SUCCESS;
265 	}
266 	return QDF_STATUS_SUCCESS;
267 }
268 EXPORT_SYMBOL(qdf_wait_single_event);
269 
270 QDF_STATUS qdf_exit_thread(QDF_STATUS status)
271 {
272 	if (status == QDF_STATUS_SUCCESS)
273 		do_exit(0);
274 	else
275 		do_exit(SIGKILL);
276 
277 	return QDF_STATUS_SUCCESS;
278 }
279 EXPORT_SYMBOL(qdf_exit_thread);
280 
281 #ifdef CONFIG_MCL
282 void qdf_register_self_recovery_callback(qdf_self_recovery_callback callback)
283 {
284 	self_recovery_cb = callback;
285 }
286 
287 void qdf_trigger_self_recovery(void)
288 {
289 	if (!self_recovery_cb) {
290 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
291 			  "No self recovery callback registered %s", __func__);
292 		return;
293 	}
294 	self_recovery_cb();
295 }
296 #endif
297