1 /*
2 * Copyright (c) 2019, 2021 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
19 #include "__osif_driver_sync.h"
20 #include "osif_driver_sync.h"
21 #include "qdf_lock.h"
22 #include "qdf_status.h"
23 #include "qdf_types.h"
24 #include "wlan_dsc_driver.h"
25 #include "wlan_dsc_psoc.h"
26
27 /**
28 * struct osif_driver_sync - a driver synchronization context
29 * @dsc_driver: the dsc_driver used for synchronization
30 * @in_use: indicates if the context is being used
31 * @is_registered: indicates if the context is registered for
32 * transitions/operations
33 */
34 struct osif_driver_sync {
35 struct dsc_driver *dsc_driver;
36 bool in_use;
37 bool is_registered;
38 };
39
40 static struct osif_driver_sync __osif_driver_sync;
41 static qdf_spinlock_t __osif_driver_sync_lock;
42
43 #define osif_driver_sync_lock_create() \
44 qdf_spinlock_create(&__osif_driver_sync_lock)
45 #define osif_driver_sync_lock_destroy() \
46 qdf_spinlock_destroy(&__osif_driver_sync_lock)
47 #define osif_driver_sync_lock() qdf_spin_lock_bh(&__osif_driver_sync_lock)
48 #define osif_driver_sync_unlock() qdf_spin_unlock_bh(&__osif_driver_sync_lock)
49
osif_driver_sync_lookup(void)50 static struct osif_driver_sync *osif_driver_sync_lookup(void)
51 {
52 if (!__osif_driver_sync.is_registered)
53 return NULL;
54
55 return &__osif_driver_sync;
56 }
57
osif_driver_sync_get(void)58 static struct osif_driver_sync *osif_driver_sync_get(void)
59 {
60 if (__osif_driver_sync.in_use)
61 return NULL;
62
63 __osif_driver_sync.in_use = true;
64
65 return &__osif_driver_sync;
66 }
67
osif_driver_sync_put(struct osif_driver_sync * driver_sync)68 static void osif_driver_sync_put(struct osif_driver_sync *driver_sync)
69 {
70 qdf_mem_zero(driver_sync, sizeof(*driver_sync));
71 }
72
osif_driver_sync_create(struct osif_driver_sync ** out_driver_sync)73 int osif_driver_sync_create(struct osif_driver_sync **out_driver_sync)
74 {
75 QDF_STATUS status;
76 struct osif_driver_sync *driver_sync;
77
78 QDF_BUG(out_driver_sync);
79 if (!out_driver_sync)
80 return -EINVAL;
81
82 osif_driver_sync_lock();
83 driver_sync = osif_driver_sync_get();
84 osif_driver_sync_unlock();
85 if (!driver_sync)
86 return -ENOMEM;
87
88 status = dsc_driver_create(&driver_sync->dsc_driver);
89 if (QDF_IS_STATUS_ERROR(status))
90 goto sync_put;
91
92 *out_driver_sync = driver_sync;
93
94 return 0;
95
96 sync_put:
97 osif_driver_sync_lock();
98 osif_driver_sync_put(driver_sync);
99 osif_driver_sync_unlock();
100
101 return qdf_status_to_os_return(status);
102 }
103
104 int
__osif_driver_sync_create_and_trans(struct osif_driver_sync ** out_driver_sync,const char * desc)105 __osif_driver_sync_create_and_trans(struct osif_driver_sync **out_driver_sync,
106 const char *desc)
107 {
108 struct osif_driver_sync *driver_sync;
109 QDF_STATUS status;
110 int errno;
111
112 errno = osif_driver_sync_create(&driver_sync);
113 if (errno)
114 return errno;
115
116 status = dsc_driver_trans_start(driver_sync->dsc_driver, desc);
117 if (QDF_IS_STATUS_ERROR(status))
118 goto sync_destroy;
119
120 *out_driver_sync = driver_sync;
121
122 return 0;
123
124 sync_destroy:
125 osif_driver_sync_destroy(driver_sync);
126
127 return qdf_status_to_os_return(status);
128 }
129
osif_driver_sync_destroy(struct osif_driver_sync * driver_sync)130 void osif_driver_sync_destroy(struct osif_driver_sync *driver_sync)
131 {
132 QDF_BUG(driver_sync);
133 if (!driver_sync)
134 return;
135
136 dsc_driver_destroy(&driver_sync->dsc_driver);
137
138 osif_driver_sync_lock();
139 osif_driver_sync_put(driver_sync);
140 osif_driver_sync_unlock();
141 }
142
osif_driver_sync_register(struct osif_driver_sync * driver_sync)143 void osif_driver_sync_register(struct osif_driver_sync *driver_sync)
144 {
145 QDF_BUG(driver_sync);
146 if (!driver_sync)
147 return;
148
149 osif_driver_sync_lock();
150 driver_sync->is_registered = true;
151 osif_driver_sync_unlock();
152 }
153
osif_driver_sync_unregister(void)154 struct osif_driver_sync *osif_driver_sync_unregister(void)
155 {
156 struct osif_driver_sync *driver_sync;
157
158 osif_driver_sync_lock();
159 driver_sync = osif_driver_sync_lookup();
160 if (driver_sync)
161 driver_sync->is_registered = false;
162 osif_driver_sync_unlock();
163
164 return driver_sync;
165 }
166
167 typedef QDF_STATUS (*driver_start_func)(struct dsc_driver *, const char *);
168
169 static int
__osif_driver_sync_start_callback(struct osif_driver_sync ** out_driver_sync,const char * desc,driver_start_func driver_start_cb)170 __osif_driver_sync_start_callback(struct osif_driver_sync **out_driver_sync,
171 const char *desc,
172 driver_start_func driver_start_cb)
173 {
174 QDF_STATUS status;
175 struct osif_driver_sync *driver_sync;
176
177 *out_driver_sync = NULL;
178
179 driver_sync = osif_driver_sync_lookup();
180 if (!driver_sync)
181 return -EAGAIN;
182
183 status = driver_start_cb(driver_sync->dsc_driver, desc);
184 if (QDF_IS_STATUS_ERROR(status))
185 return qdf_status_to_os_return(status);
186
187 *out_driver_sync = driver_sync;
188
189 return 0;
190 }
191
192 static int
__osif_driver_sync_start_wait_callback(struct osif_driver_sync ** out_driver_sync,const char * desc,driver_start_func driver_start_cb)193 __osif_driver_sync_start_wait_callback(
194 struct osif_driver_sync **out_driver_sync,
195 const char *desc,
196 driver_start_func driver_start_cb)
197 {
198 QDF_STATUS status;
199 struct osif_driver_sync *driver_sync;
200
201 *out_driver_sync = NULL;
202
203 osif_driver_sync_lock();
204 driver_sync = osif_driver_sync_lookup();
205 osif_driver_sync_unlock();
206 if (!driver_sync)
207 return -EAGAIN;
208
209 status = driver_start_cb(driver_sync->dsc_driver, desc);
210 if (QDF_IS_STATUS_ERROR(status))
211 return qdf_status_to_os_return(status);
212
213 *out_driver_sync = driver_sync;
214
215 return 0;
216 }
__osif_driver_sync_trans_start(struct osif_driver_sync ** out_driver_sync,const char * desc)217 int __osif_driver_sync_trans_start(struct osif_driver_sync **out_driver_sync,
218 const char *desc)
219 {
220 int errno;
221
222 osif_driver_sync_lock();
223 errno = __osif_driver_sync_start_callback(out_driver_sync, desc,
224 dsc_driver_trans_start);
225 osif_driver_sync_unlock();
226
227 return errno;
228 }
229
230 int
__osif_driver_sync_trans_start_wait(struct osif_driver_sync ** out_driver_sync,const char * desc)231 __osif_driver_sync_trans_start_wait(struct osif_driver_sync **out_driver_sync,
232 const char *desc)
233 {
234 int errno;
235
236 /* since dsc_driver_trans_start_wait may sleep do not take lock here */
237 errno = __osif_driver_sync_start_wait_callback(out_driver_sync, desc,
238 dsc_driver_trans_start_wait);
239
240 return errno;
241 }
242
osif_driver_sync_trans_stop(struct osif_driver_sync * driver_sync)243 void osif_driver_sync_trans_stop(struct osif_driver_sync *driver_sync)
244 {
245 dsc_driver_trans_stop(driver_sync->dsc_driver);
246 }
247
osif_driver_sync_assert_trans_protected(void)248 void osif_driver_sync_assert_trans_protected(void)
249 {
250 struct osif_driver_sync *driver_sync;
251
252 osif_driver_sync_lock();
253
254 driver_sync = osif_driver_sync_lookup();
255 QDF_BUG(driver_sync);
256 if (driver_sync)
257 dsc_driver_assert_trans_protected(driver_sync->dsc_driver);
258
259 osif_driver_sync_unlock();
260 }
261
__osif_driver_sync_op_start(struct osif_driver_sync ** out_driver_sync,const char * func)262 int __osif_driver_sync_op_start(struct osif_driver_sync **out_driver_sync,
263 const char *func)
264 {
265 int errno;
266
267 osif_driver_sync_lock();
268 errno = __osif_driver_sync_start_callback(out_driver_sync, func,
269 _dsc_driver_op_start);
270 osif_driver_sync_unlock();
271
272 return errno;
273 }
274
__osif_driver_sync_op_stop(struct osif_driver_sync * driver_sync,const char * func)275 void __osif_driver_sync_op_stop(struct osif_driver_sync *driver_sync,
276 const char *func)
277 {
278 _dsc_driver_op_stop(driver_sync->dsc_driver, func);
279 }
280
osif_driver_sync_wait_for_ops(struct osif_driver_sync * driver_sync)281 void osif_driver_sync_wait_for_ops(struct osif_driver_sync *driver_sync)
282 {
283 dsc_driver_wait_for_ops(driver_sync->dsc_driver);
284 }
285
osif_driver_sync_init(void)286 void osif_driver_sync_init(void)
287 {
288 osif_driver_sync_lock_create();
289 }
290
osif_driver_sync_deinit(void)291 void osif_driver_sync_deinit(void)
292 {
293 osif_driver_sync_lock_destroy();
294 }
295
296 static QDF_STATUS
__osif_driver_sync_dsc_psoc_create(struct dsc_psoc ** out_dsc_psoc)297 __osif_driver_sync_dsc_psoc_create(struct dsc_psoc **out_dsc_psoc)
298 {
299 struct osif_driver_sync *driver_sync;
300
301 driver_sync = osif_driver_sync_lookup();
302 if (!driver_sync)
303 return QDF_STATUS_E_INVAL;
304
305 return dsc_psoc_create(driver_sync->dsc_driver, out_dsc_psoc);
306 }
307
osif_driver_sync_dsc_psoc_create(struct dsc_psoc ** out_dsc_psoc)308 QDF_STATUS osif_driver_sync_dsc_psoc_create(struct dsc_psoc **out_dsc_psoc)
309 {
310 QDF_STATUS status;
311
312 osif_driver_sync_lock();
313 status = __osif_driver_sync_dsc_psoc_create(out_dsc_psoc);
314 osif_driver_sync_unlock();
315
316 return status;
317 }
318
319