blob: ce39b48546360e0341ec68dfaf9dee27fd071a7b [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2014-2015 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: cdf_event.c
30 *
31 * This source file contains linux specific definitions for CDF 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 "cdf_event.h"
39#include "cdf_trace.h"
40
41/* Preprocessor Definitions and Constants */
42
43/* Type Declarations */
44
45/* Global Data Definitions */
46
47/* Static Variable Definitions */
48
49/* Function Definitions and Documentation */
50
51/**
52 * cdf_event_init() - initializes a CDF event
53 * @event: Pointer to the opaque event object to initialize
54 *
55 * The cdf_event_init() function initializes the specified event. Upon
56 * successful initialization, the state of the event becomes initialized
57 * and not signaled.
58 *
59 * An event must be initialized before it may be used in any other event
60 * functions.
61 *
62 * Attempting to initialize an already initialized event results in
63 * a failure.
64 *
65 * Return: CDF status
66 */
67CDF_STATUS cdf_event_init(cdf_event_t *event)
68{
69 /* check for null pointer */
70 if (NULL == event) {
71 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
72 "NULL event passed into %s", __func__);
73 CDF_ASSERT(0);
74 return CDF_STATUS_E_FAULT;
75 }
76
77 /* check for 'already initialized' event */
78 if (LINUX_EVENT_COOKIE == event->cookie) {
79 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
80 "Initialized event passed into %s", __func__);
81 CDF_ASSERT(0);
82 return CDF_STATUS_E_BUSY;
83 }
84
85 /* initialize new event */
86 init_completion(&event->complete);
87 event->cookie = LINUX_EVENT_COOKIE;
88
89 return CDF_STATUS_SUCCESS;
90}
91
92/**
93 * cdf_event_set() - sets a CDF event
94 * @event: The event to set to the signalled state
95 *
96 * The state of the specified event is set to signalled by calling
97 * cdf_event_set().
98 *
99 * Any threads waiting on the event as a result of a cdf_event_wait() will
100 * be unblocked and available to be scheduled for execution when the event
101 * is signaled by a call to cdf_event_set().
102 *
103 *
104 * Return: CDF status
105 */
106
107CDF_STATUS cdf_event_set(cdf_event_t *event)
108{
109 /* check for null pointer */
110 if (NULL == event) {
111 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
112 "NULL event passed into %s", __func__);
113 CDF_ASSERT(0);
114 return CDF_STATUS_E_FAULT;
115 }
116
117 /* check if event refers to an initialized object */
118 if (LINUX_EVENT_COOKIE != event->cookie) {
119 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
120 "Uninitialized event passed into %s", __func__);
121 CDF_ASSERT(0);
122 return CDF_STATUS_E_INVAL;
123 }
124
125 complete(&event->complete);
126
127 return CDF_STATUS_SUCCESS;
128}
129
130/**
131 * cdf_event_reset() - resets a CDF event
132 * @event: The event to set to the NOT signalled state
133 *
134 * This function isn't required for Linux. Therefore, it doesn't do much.
135 *
136 * The state of the specified event is set to 'NOT signalled' by calling
137 * cdf_event_reset(). The state of the event remains NOT signalled until an
138 * explicit call to cdf_event_set().
139 *
140 * This function sets the event to a NOT signalled state even if the event was
141 * signalled multiple times before being signaled.
142 *
143 *
144 * Return: CDF status
145 */
146CDF_STATUS cdf_event_reset(cdf_event_t *event)
147{
148 /* check for null pointer */
149 if (NULL == event) {
150 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
151 "NULL event passed into %s", __func__);
152 CDF_ASSERT(0);
153 return CDF_STATUS_E_FAULT;
154 }
155
156 /* check to make sure it is an 'already initialized' event */
157 if (LINUX_EVENT_COOKIE != event->cookie) {
158 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
159 "Uninitialized event passed into %s", __func__);
160 CDF_ASSERT(0);
161 return CDF_STATUS_E_INVAL;
162 }
163
164 /* (re)initialize event */
165 INIT_COMPLETION(event->complete);
166 return CDF_STATUS_SUCCESS;
167}
168
169/**
170 * cdf_event_destroy() - Destroys a CDF event
171 * @event: The event object to be destroyed.
172 *
173 * This function doesn't do much in Linux. There is no need for the caller
174 * to explicitly destroy an event after use.
175 *
176 * The os_event_destroy() function shall destroy the event object
177 * referenced by event. After a successful return from cdf_event_destroy()
178 * the event object becomes, in effect, uninitialized.
179 *
180 * A destroyed event object can be reinitialized using cdf_event_init();
181 * the results of otherwise referencing the object after it has been destroyed
182 * are undefined. Calls to CDF event functions to manipulate the lock such
183 * as cdf_event_set() will fail if the event is destroyed. Therefore,
184 * don't use the event after it has been destroyed until it has
185 * been re-initialized.
186 *
187 * Return: CDF status
188 */
189
190CDF_STATUS cdf_event_destroy(cdf_event_t *event)
191{
192 /* check for null pointer */
193 if (NULL == event) {
194 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
195 "NULL event passed into %s", __func__);
196 CDF_ASSERT(0);
197 return CDF_STATUS_E_FAULT;
198 }
199
200 /* check to make sure it is an 'already initialized' event */
201 if (LINUX_EVENT_COOKIE != event->cookie) {
202 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
203 "Uninitialized event passed into %s", __func__);
204 CDF_ASSERT(0);
205 return CDF_STATUS_E_INVAL;
206 }
207
208 /* make sure nobody is waiting on the event */
209 complete_all(&event->complete);
210
211 /* destroy the event */
212 memset(event, 0, sizeof(cdf_event_t));
213
214 return CDF_STATUS_SUCCESS;
215}
216
217/**
218 * cdf_wait_single_event() - Waits for a single event to be set.
219 *
220 * This API waits for the event to be set.
221 *
222 * @pEvent: Pointer to an event to wait on.
223 * @timeout: Timeout value (in milliseconds). This function returns
224 * if this interval elapses, regardless if any of the events have
225 * been set. An input value of 0 for this timeout parameter means
226 * to wait infinitely, meaning a timeout will never occur.
227 *
228 * Return: CDF status
229 */
230CDF_STATUS cdf_wait_single_event(cdf_event_t *event, uint32_t timeout)
231{
232 if (in_interrupt()) {
233 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
234 "%s cannot be called from interrupt context!!!",
235 __func__);
236 CDF_ASSERT(0);
237 return CDF_STATUS_E_FAULT;
238 }
239
240 /* check for null pointer */
241 if (NULL == event) {
242 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
243 "NULL event passed into %s", __func__);
244 CDF_ASSERT(0);
245 return CDF_STATUS_E_FAULT;
246 }
247
248 /* check if cookie is same as that of initialized event */
249 if (LINUX_EVENT_COOKIE != event->cookie) {
250 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
251 "Uninitialized event passed into %s", __func__);
252 CDF_ASSERT(0);
253 return CDF_STATUS_E_INVAL;
254 }
255
256 if (timeout) {
257 long ret;
258 ret = wait_for_completion_timeout(&event->complete,
259 msecs_to_jiffies(timeout));
260 if (0 >= ret)
261 return CDF_STATUS_E_TIMEOUT;
262 } else {
263 CDF_ASSERT(0);
264 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL,
265 "Zero timeout value passed into %s", __func__);
266 return CDF_STATUS_E_FAULT;
267 }
268
269 return CDF_STATUS_SUCCESS;
270}