1 /*
2 * Copyright (c) 2019, 2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2024 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 #include "linux/device.h"
21 #include "__osif_driver_sync.h"
22 #include "__osif_psoc_sync.h"
23 #include "osif_psoc_sync.h"
24 #include "qdf_lock.h"
25 #include "qdf_status.h"
26 #include "qdf_types.h"
27 #include "wlan_dsc_psoc.h"
28 #include "wlan_dsc_vdev.h"
29 #include "__wlan_dsc.h"
30
31 /**
32 * struct osif_psoc_sync - a psoc synchronization context
33 * @dev: the device used as a lookup key
34 * @dsc_psoc: the dsc_psoc used for synchronization
35 * @in_use: indicates if the context is being used
36 */
37 struct osif_psoc_sync {
38 struct device *dev;
39 struct dsc_psoc *dsc_psoc;
40 bool in_use;
41 };
42
43 static struct osif_psoc_sync __osif_psoc_sync_arr[WLAN_MAX_PSOCS];
44 static qdf_spinlock_t __osif_psoc_sync_lock;
45
46 #define osif_psoc_sync_lock_create() qdf_spinlock_create(&__osif_psoc_sync_lock)
47 #define osif_psoc_sync_lock_destroy() \
48 qdf_spinlock_destroy(&__osif_psoc_sync_lock)
49 #define osif_psoc_sync_lock() qdf_spin_lock_bh(&__osif_psoc_sync_lock)
50 #define osif_psoc_sync_unlock() qdf_spin_unlock_bh(&__osif_psoc_sync_lock)
51
osif_psoc_sync_lookup(struct device * dev)52 static struct osif_psoc_sync *osif_psoc_sync_lookup(struct device *dev)
53 {
54 int i;
55
56 for (i = 0; i < QDF_ARRAY_SIZE(__osif_psoc_sync_arr); i++) {
57 struct osif_psoc_sync *psoc_sync = __osif_psoc_sync_arr + i;
58
59 if (!psoc_sync->in_use)
60 continue;
61
62 if (psoc_sync->dev == dev)
63 return psoc_sync;
64 }
65
66 return NULL;
67 }
68
osif_psoc_sync_get(void)69 static struct osif_psoc_sync *osif_psoc_sync_get(void)
70 {
71 int i;
72
73 for (i = 0; i < QDF_ARRAY_SIZE(__osif_psoc_sync_arr); i++) {
74 struct osif_psoc_sync *psoc_sync = __osif_psoc_sync_arr + i;
75
76 if (!psoc_sync->in_use) {
77 psoc_sync->in_use = true;
78 return psoc_sync;
79 }
80 }
81
82 return NULL;
83 }
84
osif_psoc_sync_put(struct osif_psoc_sync * psoc_sync)85 static void osif_psoc_sync_put(struct osif_psoc_sync *psoc_sync)
86 {
87 qdf_mem_zero(psoc_sync, sizeof(*psoc_sync));
88 }
89
osif_psoc_sync_create(struct osif_psoc_sync ** out_psoc_sync)90 int osif_psoc_sync_create(struct osif_psoc_sync **out_psoc_sync)
91 {
92 QDF_STATUS status;
93 struct osif_psoc_sync *psoc_sync;
94
95 QDF_BUG(out_psoc_sync);
96 if (!out_psoc_sync)
97 return -EINVAL;
98
99 osif_psoc_sync_lock();
100 psoc_sync = osif_psoc_sync_get();
101 osif_psoc_sync_unlock();
102 if (!psoc_sync)
103 return -ENOMEM;
104
105 status = osif_driver_sync_dsc_psoc_create(&psoc_sync->dsc_psoc);
106 if (QDF_IS_STATUS_ERROR(status))
107 goto sync_put;
108
109 *out_psoc_sync = psoc_sync;
110
111 return 0;
112
113 sync_put:
114 osif_psoc_sync_lock();
115 osif_psoc_sync_put(psoc_sync);
116 osif_psoc_sync_unlock();
117
118 return qdf_status_to_os_return(status);
119 }
120
__osif_psoc_sync_create_and_trans(struct osif_psoc_sync ** out_psoc_sync,const char * desc)121 int __osif_psoc_sync_create_and_trans(struct osif_psoc_sync **out_psoc_sync,
122 const char *desc)
123 {
124 struct osif_psoc_sync *psoc_sync;
125 QDF_STATUS status;
126 int errno;
127
128 errno = osif_psoc_sync_create(&psoc_sync);
129 if (errno)
130 return errno;
131
132 status = dsc_psoc_trans_start(psoc_sync->dsc_psoc, desc);
133 if (QDF_IS_STATUS_ERROR(status))
134 goto sync_destroy;
135
136 *out_psoc_sync = psoc_sync;
137
138 return 0;
139
140 sync_destroy:
141 osif_psoc_sync_destroy(psoc_sync);
142
143 return qdf_status_to_os_return(status);
144 }
145
osif_psoc_sync_destroy(struct osif_psoc_sync * psoc_sync)146 void osif_psoc_sync_destroy(struct osif_psoc_sync *psoc_sync)
147 {
148 QDF_BUG(psoc_sync);
149 if (!psoc_sync)
150 return;
151
152 dsc_psoc_destroy(&psoc_sync->dsc_psoc);
153
154 osif_psoc_sync_lock();
155 osif_psoc_sync_put(psoc_sync);
156 osif_psoc_sync_unlock();
157 }
158
osif_psoc_sync_register(struct device * dev,struct osif_psoc_sync * psoc_sync)159 void osif_psoc_sync_register(struct device *dev,
160 struct osif_psoc_sync *psoc_sync)
161 {
162 QDF_BUG(dev);
163 QDF_BUG(psoc_sync);
164 if (!psoc_sync)
165 return;
166
167 osif_psoc_sync_lock();
168 psoc_sync->dev = dev;
169 osif_psoc_sync_unlock();
170 }
171
osif_psoc_sync_unregister(struct device * dev)172 struct osif_psoc_sync *osif_psoc_sync_unregister(struct device *dev)
173 {
174 struct osif_psoc_sync *psoc_sync;
175
176 QDF_BUG(dev);
177 if (!dev)
178 return NULL;
179
180 osif_psoc_sync_lock();
181 psoc_sync = osif_psoc_sync_lookup(dev);
182 if (psoc_sync)
183 psoc_sync->dev = NULL;
184 osif_psoc_sync_unlock();
185
186 return psoc_sync;
187 }
188
189 typedef QDF_STATUS (*psoc_start_func)(struct dsc_psoc *, const char *);
190
191 static int
__osif_psoc_sync_start_callback(struct device * dev,struct osif_psoc_sync ** out_psoc_sync,const char * desc,psoc_start_func psoc_start_cb)192 __osif_psoc_sync_start_callback(struct device *dev,
193 struct osif_psoc_sync **out_psoc_sync,
194 const char *desc,
195 psoc_start_func psoc_start_cb)
196 {
197 QDF_STATUS status;
198 struct osif_psoc_sync *psoc_sync;
199
200 *out_psoc_sync = NULL;
201
202 psoc_sync = osif_psoc_sync_lookup(dev);
203 if (!psoc_sync)
204 return -EAGAIN;
205
206 status = psoc_start_cb(psoc_sync->dsc_psoc, desc);
207 if (QDF_IS_STATUS_ERROR(status))
208 return qdf_status_to_os_return(status);
209
210 *out_psoc_sync = psoc_sync;
211
212 return 0;
213 }
214
215 static int
__osif_psoc_sync_start_wait_callback(struct device * dev,struct osif_psoc_sync ** out_psoc_sync,const char * desc,psoc_start_func psoc_start_cb)216 __osif_psoc_sync_start_wait_callback(struct device *dev,
217 struct osif_psoc_sync **out_psoc_sync,
218 const char *desc,
219 psoc_start_func psoc_start_cb)
220 {
221 QDF_STATUS status;
222 struct osif_psoc_sync *psoc_sync;
223
224 *out_psoc_sync = NULL;
225
226 osif_psoc_sync_lock();
227 psoc_sync = osif_psoc_sync_lookup(dev);
228 osif_psoc_sync_unlock();
229 if (!psoc_sync)
230 return -EAGAIN;
231
232 status = psoc_start_cb(psoc_sync->dsc_psoc, desc);
233 if (QDF_IS_STATUS_ERROR(status))
234 return qdf_status_to_os_return(status);
235
236 *out_psoc_sync = psoc_sync;
237
238 return 0;
239 }
240
__osif_psoc_sync_trans_start(struct device * dev,struct osif_psoc_sync ** out_psoc_sync,const char * desc)241 int __osif_psoc_sync_trans_start(struct device *dev,
242 struct osif_psoc_sync **out_psoc_sync,
243 const char *desc)
244 {
245 int errno;
246
247 osif_psoc_sync_lock();
248 errno = __osif_psoc_sync_start_callback(dev, out_psoc_sync, desc,
249 dsc_psoc_trans_start);
250 osif_psoc_sync_unlock();
251
252 return errno;
253 }
254
__osif_psoc_sync_trans_start_wait(struct device * dev,struct osif_psoc_sync ** out_psoc_sync,const char * desc)255 int __osif_psoc_sync_trans_start_wait(struct device *dev,
256 struct osif_psoc_sync **out_psoc_sync,
257 const char *desc)
258 {
259 int errno;
260
261 /* since dsc_psoc_trans_start_wait may sleep do not take lock here */
262 errno = __osif_psoc_sync_start_wait_callback(dev, out_psoc_sync, desc,
263 dsc_psoc_trans_start_wait);
264
265 return errno;
266 }
267
__assert_trans_cb(struct dsc_psoc * dsc_psoc,const char * desc)268 static QDF_STATUS __assert_trans_cb(struct dsc_psoc *dsc_psoc, const char *desc)
269 {
270 dsc_psoc_assert_trans_protected(dsc_psoc);
271
272 return QDF_STATUS_SUCCESS;
273 }
274
osif_psoc_sync_trans_resume(struct device * dev,struct osif_psoc_sync ** out_psoc_sync)275 int osif_psoc_sync_trans_resume(struct device *dev,
276 struct osif_psoc_sync **out_psoc_sync)
277 {
278 int errno;
279
280 osif_psoc_sync_lock();
281 errno = __osif_psoc_sync_start_callback(dev, out_psoc_sync, NULL,
282 __assert_trans_cb);
283 osif_psoc_sync_unlock();
284
285 return errno;
286 }
287
osif_psoc_sync_trans_stop(struct osif_psoc_sync * psoc_sync)288 void osif_psoc_sync_trans_stop(struct osif_psoc_sync *psoc_sync)
289 {
290 dsc_psoc_trans_stop(psoc_sync->dsc_psoc);
291 }
292
osif_psoc_sync_assert_trans_protected(struct device * dev)293 void osif_psoc_sync_assert_trans_protected(struct device *dev)
294 {
295 struct osif_psoc_sync *psoc_sync;
296
297 osif_psoc_sync_lock();
298
299 psoc_sync = osif_psoc_sync_lookup(dev);
300 QDF_BUG(psoc_sync);
301 if (psoc_sync)
302 dsc_psoc_assert_trans_protected(psoc_sync->dsc_psoc);
303
304 osif_psoc_sync_unlock();
305 }
306
__osif_psoc_sync_op_start(struct device * dev,struct osif_psoc_sync ** out_psoc_sync,const char * func)307 int __osif_psoc_sync_op_start(struct device *dev,
308 struct osif_psoc_sync **out_psoc_sync,
309 const char *func)
310 {
311 int errno;
312
313 osif_psoc_sync_lock();
314 errno = __osif_psoc_sync_start_callback(dev, out_psoc_sync, func,
315 _dsc_psoc_op_start);
316 osif_psoc_sync_unlock();
317 if (errno)
318 dsc_exit_status(errno);
319
320 return errno;
321 }
322
__osif_psoc_sync_op_stop(struct osif_psoc_sync * psoc_sync,const char * func)323 void __osif_psoc_sync_op_stop(struct osif_psoc_sync *psoc_sync,
324 const char *func)
325 {
326 _dsc_psoc_op_stop(psoc_sync->dsc_psoc, func);
327 }
328
osif_psoc_sync_wait_for_ops(struct osif_psoc_sync * psoc_sync)329 void osif_psoc_sync_wait_for_ops(struct osif_psoc_sync *psoc_sync)
330 {
331 dsc_psoc_wait_for_ops(psoc_sync->dsc_psoc);
332 }
333
osif_psoc_sync_init(void)334 void osif_psoc_sync_init(void)
335 {
336 osif_psoc_sync_lock_create();
337 }
338
osif_psoc_sync_deinit(void)339 void osif_psoc_sync_deinit(void)
340 {
341 osif_psoc_sync_lock_destroy();
342 }
343
344 static QDF_STATUS
__osif_psoc_sync_dsc_vdev_create(struct device * dev,struct dsc_vdev ** out_dsc_vdev)345 __osif_psoc_sync_dsc_vdev_create(struct device *dev,
346 struct dsc_vdev **out_dsc_vdev)
347 {
348 struct osif_psoc_sync *psoc_sync;
349
350 psoc_sync = osif_psoc_sync_lookup(dev);
351 if (!psoc_sync)
352 return QDF_STATUS_E_INVAL;
353
354 return dsc_vdev_create(psoc_sync->dsc_psoc, out_dsc_vdev);
355 }
356
osif_psoc_sync_dsc_vdev_create(struct device * dev,struct dsc_vdev ** out_dsc_vdev)357 QDF_STATUS osif_psoc_sync_dsc_vdev_create(struct device *dev,
358 struct dsc_vdev **out_dsc_vdev)
359 {
360 QDF_STATUS status;
361
362 osif_psoc_sync_lock();
363 status = __osif_psoc_sync_dsc_vdev_create(dev, out_dsc_vdev);
364 osif_psoc_sync_unlock();
365
366 return status;
367 }
368
369