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