1 /*
2 * Copyright (c) 2018-2019, 2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 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 "linux/netdevice.h"
22 #include "__osif_psoc_sync.h"
23 #include "__osif_vdev_sync.h"
24 #include "osif_vdev_sync.h"
25 #include "qdf_lock.h"
26 #include "qdf_status.h"
27 #include "qdf_types.h"
28 #include <qdf_trace.h>
29 #include <wlan_cfg80211.h>
30
31 static struct osif_vdev_sync __osif_vdev_sync_arr[WLAN_MAX_VDEVS +
32 WLAN_MAX_ML_VDEVS];
33 static qdf_spinlock_t __osif_vdev_sync_lock;
34
35 #define osif_vdev_sync_lock_create() qdf_spinlock_create(&__osif_vdev_sync_lock)
36 #define osif_vdev_sync_lock_destroy() \
37 qdf_spinlock_destroy(&__osif_vdev_sync_lock)
38 #define osif_vdev_sync_lock() qdf_spin_lock_bh(&__osif_vdev_sync_lock)
39 #define osif_vdev_sync_unlock() qdf_spin_unlock_bh(&__osif_vdev_sync_lock)
40
osif_vdev_sync_lookup(struct net_device * net_dev)41 static struct osif_vdev_sync *osif_vdev_sync_lookup(struct net_device *net_dev)
42 {
43 int i;
44
45 for (i = 0; i < QDF_ARRAY_SIZE(__osif_vdev_sync_arr); i++) {
46 struct osif_vdev_sync *vdev_sync = __osif_vdev_sync_arr + i;
47
48 if (!vdev_sync->in_use)
49 continue;
50
51 if (vdev_sync->net_dev == net_dev)
52 return vdev_sync;
53 }
54
55 return NULL;
56 }
57
osif_get_vdev_sync_arr(void)58 struct osif_vdev_sync *osif_get_vdev_sync_arr(void)
59 {
60 return __osif_vdev_sync_arr;
61 }
62
osif_vdev_sync_get(void)63 static struct osif_vdev_sync *osif_vdev_sync_get(void)
64 {
65 int i;
66
67 for (i = 0; i < QDF_ARRAY_SIZE(__osif_vdev_sync_arr); i++) {
68 struct osif_vdev_sync *vdev_sync = __osif_vdev_sync_arr + i;
69
70 if (!vdev_sync->in_use) {
71 vdev_sync->in_use = true;
72 return vdev_sync;
73 }
74 }
75
76 return NULL;
77 }
78
osif_vdev_sync_put(struct osif_vdev_sync * vdev_sync)79 static void osif_vdev_sync_put(struct osif_vdev_sync *vdev_sync)
80 {
81 qdf_mem_zero(vdev_sync, sizeof(*vdev_sync));
82 }
83
osif_vdev_sync_create(struct device * dev,struct osif_vdev_sync ** out_vdev_sync)84 int osif_vdev_sync_create(struct device *dev,
85 struct osif_vdev_sync **out_vdev_sync)
86 {
87 struct osif_vdev_sync *vdev_sync;
88 QDF_STATUS status;
89
90 QDF_BUG(dev);
91 if (!dev)
92 return -EINVAL;
93
94 QDF_BUG(out_vdev_sync);
95 if (!out_vdev_sync)
96 return -EINVAL;
97
98 osif_vdev_sync_lock();
99 vdev_sync = osif_vdev_sync_get();
100 osif_vdev_sync_unlock();
101 if (!vdev_sync)
102 return -ENOMEM;
103
104 status = osif_psoc_sync_dsc_vdev_create(dev, &vdev_sync->dsc_vdev);
105 if (QDF_IS_STATUS_ERROR(status))
106 goto sync_put;
107
108 *out_vdev_sync = vdev_sync;
109
110 return 0;
111
112 sync_put:
113 osif_vdev_sync_lock();
114 osif_vdev_sync_put(vdev_sync);
115 osif_vdev_sync_unlock();
116
117 return qdf_status_to_os_return(status);
118 }
119
__osif_vdev_sync_create_and_trans(struct device * dev,struct osif_vdev_sync ** out_vdev_sync,const char * desc)120 int __osif_vdev_sync_create_and_trans(struct device *dev,
121 struct osif_vdev_sync **out_vdev_sync,
122 const char *desc)
123 {
124 struct osif_vdev_sync *vdev_sync;
125 QDF_STATUS status;
126 int errno;
127
128 errno = osif_vdev_sync_create(dev, &vdev_sync);
129 if (errno)
130 return errno;
131
132 status = dsc_vdev_trans_start(vdev_sync->dsc_vdev, desc);
133 if (QDF_IS_STATUS_ERROR(status))
134 goto sync_destroy;
135
136 *out_vdev_sync = vdev_sync;
137
138 return 0;
139
140 sync_destroy:
141 osif_vdev_sync_destroy(vdev_sync);
142
143 return qdf_status_to_os_return(status);
144 }
145
osif_vdev_sync_destroy(struct osif_vdev_sync * vdev_sync)146 void osif_vdev_sync_destroy(struct osif_vdev_sync *vdev_sync)
147 {
148 QDF_BUG(vdev_sync);
149 if (!vdev_sync)
150 return;
151
152 dsc_vdev_destroy(&vdev_sync->dsc_vdev);
153
154 osif_vdev_sync_lock();
155 osif_vdev_sync_put(vdev_sync);
156 osif_vdev_sync_unlock();
157 }
158
osif_vdev_sync_register(struct net_device * net_dev,struct osif_vdev_sync * vdev_sync)159 void osif_vdev_sync_register(struct net_device *net_dev,
160 struct osif_vdev_sync *vdev_sync)
161 {
162 QDF_BUG(net_dev);
163 QDF_BUG(vdev_sync);
164 if (!vdev_sync)
165 return;
166
167 osif_vdev_sync_lock();
168 vdev_sync->net_dev = net_dev;
169 osif_vdev_sync_unlock();
170 }
171
osif_vdev_sync_unregister(struct net_device * net_dev)172 struct osif_vdev_sync *osif_vdev_sync_unregister(struct net_device *net_dev)
173 {
174 struct osif_vdev_sync *vdev_sync;
175
176 QDF_BUG(net_dev);
177 if (!net_dev)
178 return NULL;
179
180 osif_vdev_sync_lock();
181 vdev_sync = osif_vdev_sync_lookup(net_dev);
182 if (vdev_sync)
183 vdev_sync->net_dev = NULL;
184 osif_vdev_sync_unlock();
185
186 return vdev_sync;
187 }
188
189 typedef QDF_STATUS (*vdev_start_func)(struct dsc_vdev *, const char *);
190
191 static int
__osif_vdev_sync_start_callback(struct net_device * net_dev,struct osif_vdev_sync ** out_vdev_sync,const char * desc,vdev_start_func vdev_start_cb)192 __osif_vdev_sync_start_callback(struct net_device *net_dev,
193 struct osif_vdev_sync **out_vdev_sync,
194 const char *desc,
195 vdev_start_func vdev_start_cb)
196 {
197 QDF_STATUS status;
198 struct osif_vdev_sync *vdev_sync;
199
200 *out_vdev_sync = NULL;
201
202 vdev_sync = osif_vdev_sync_lookup(net_dev);
203 if (!vdev_sync)
204 return -EAGAIN;
205
206 *out_vdev_sync = vdev_sync;
207
208 status = vdev_start_cb(vdev_sync->dsc_vdev, desc);
209 if (QDF_IS_STATUS_ERROR(status))
210 return qdf_status_to_os_return(status);
211
212 return 0;
213 }
214
215 static int
__osif_vdev_sync_start_wait_callback(struct net_device * net_dev,struct osif_vdev_sync ** out_vdev_sync,const char * desc,vdev_start_func vdev_start_cb)216 __osif_vdev_sync_start_wait_callback(struct net_device *net_dev,
217 struct osif_vdev_sync **out_vdev_sync,
218 const char *desc,
219 vdev_start_func vdev_start_cb)
220 {
221 QDF_STATUS status;
222 struct osif_vdev_sync *vdev_sync;
223
224 *out_vdev_sync = NULL;
225
226 osif_vdev_sync_lock();
227 vdev_sync = osif_vdev_sync_lookup(net_dev);
228 osif_vdev_sync_unlock();
229 if (!vdev_sync)
230 return -EAGAIN;
231
232 status = vdev_start_cb(vdev_sync->dsc_vdev, desc);
233 if (QDF_IS_STATUS_ERROR(status))
234 return qdf_status_to_os_return(status);
235
236 *out_vdev_sync = vdev_sync;
237
238 return 0;
239 }
240
241 /**
242 * osif_vdev_sync_wait_for_uptree_ops - Wait for psoc/driver operations
243 * @vdev_sync: vdev sync pointer
244 *
245 * If there are any psoc/driver operations are taking place, then vdev
246 * trans/ops should wait for these operations to be completed to avoid
247 * memory domain mismatch issues. For example, if modules are closed
248 * because of idle shutdown, memory domain will be init domain and at
249 * that time if some psoc ops starts, memory allocated as part of this
250 * ops will be allocated in init domain and if at the same time if vdev
251 * up starts which will trigger the vdev trans and will start the
252 * modules and change the memory domain to active domain, now when the
253 * memory allocated as part of psoc operation is release on psoc ops
254 * completion will be released in the active domain which leads the
255 * memory domain mismatch.
256 *
257 * Return: None.
258 */
osif_vdev_sync_wait_for_uptree_ops(struct osif_vdev_sync * vdev_sync)259 static void osif_vdev_sync_wait_for_uptree_ops(struct osif_vdev_sync *vdev_sync)
260 {
261 dsc_vdev_wait_for_uptree_ops(vdev_sync->dsc_vdev);
262 }
263
__osif_vdev_sync_trans_start(struct net_device * net_dev,struct osif_vdev_sync ** out_vdev_sync,const char * desc)264 int __osif_vdev_sync_trans_start(struct net_device *net_dev,
265 struct osif_vdev_sync **out_vdev_sync,
266 const char *desc)
267 {
268 int errno;
269
270 osif_vdev_sync_lock();
271 errno = __osif_vdev_sync_start_callback(net_dev, out_vdev_sync, desc,
272 dsc_vdev_trans_start);
273 osif_vdev_sync_unlock();
274
275 if (!errno) {
276 osif_vdev_sync_wait_for_ops(*out_vdev_sync);
277 osif_vdev_sync_wait_for_uptree_ops(*out_vdev_sync);
278 }
279
280 return errno;
281 }
282
__osif_vdev_sync_trans_start_wait(struct net_device * net_dev,struct osif_vdev_sync ** out_vdev_sync,const char * desc)283 int __osif_vdev_sync_trans_start_wait(struct net_device *net_dev,
284 struct osif_vdev_sync **out_vdev_sync,
285 const char *desc)
286 {
287 int errno;
288
289 /* since dsc_vdev_trans_start_wait may sleep do not take lock here */
290 errno = __osif_vdev_sync_start_wait_callback(net_dev,
291 out_vdev_sync, desc,
292 dsc_vdev_trans_start_wait);
293
294 if (!errno) {
295 osif_vdev_sync_wait_for_ops(*out_vdev_sync);
296 osif_vdev_sync_wait_for_uptree_ops(*out_vdev_sync);
297 }
298
299 return errno;
300 }
301
osif_vdev_sync_trans_stop(struct osif_vdev_sync * vdev_sync)302 void osif_vdev_sync_trans_stop(struct osif_vdev_sync *vdev_sync)
303 {
304 dsc_vdev_trans_stop(vdev_sync->dsc_vdev);
305 }
306
osif_vdev_sync_assert_trans_protected(struct net_device * net_dev)307 void osif_vdev_sync_assert_trans_protected(struct net_device *net_dev)
308 {
309 struct osif_vdev_sync *vdev_sync;
310
311 osif_vdev_sync_lock();
312
313 vdev_sync = osif_vdev_sync_lookup(net_dev);
314 QDF_BUG(vdev_sync);
315 if (vdev_sync)
316 dsc_vdev_assert_trans_protected(vdev_sync->dsc_vdev);
317
318 osif_vdev_sync_unlock();
319 }
320
__osif_vdev_sync_op_start(struct net_device * net_dev,struct osif_vdev_sync ** out_vdev_sync,const char * func)321 int __osif_vdev_sync_op_start(struct net_device *net_dev,
322 struct osif_vdev_sync **out_vdev_sync,
323 const char *func)
324 {
325 int errno;
326
327 osif_vdev_sync_lock();
328 errno = __osif_vdev_sync_start_callback(net_dev, out_vdev_sync, func,
329 _dsc_vdev_op_start);
330 osif_vdev_sync_unlock();
331
332 return errno;
333 }
334
__osif_vdev_sync_op_stop(struct osif_vdev_sync * vdev_sync,const char * func)335 void __osif_vdev_sync_op_stop(struct osif_vdev_sync *vdev_sync,
336 const char *func)
337 {
338 _dsc_vdev_op_stop(vdev_sync->dsc_vdev, func);
339 }
340
osif_vdev_sync_wait_for_ops(struct osif_vdev_sync * vdev_sync)341 void osif_vdev_sync_wait_for_ops(struct osif_vdev_sync *vdev_sync)
342 {
343 dsc_vdev_wait_for_ops(vdev_sync->dsc_vdev);
344 }
345
osif_vdev_sync_init(void)346 void osif_vdev_sync_init(void)
347 {
348 osif_vdev_sync_lock_create();
349 }
350
osif_vdev_sync_deinit(void)351 void osif_vdev_sync_deinit(void)
352 {
353 osif_vdev_sync_lock_destroy();
354 }
355
osif_vdev_get_cached_cmd(struct osif_vdev_sync * vdev_sync)356 uint8_t osif_vdev_get_cached_cmd(struct osif_vdev_sync *vdev_sync)
357 {
358 return dsc_vdev_get_cached_cmd(vdev_sync->dsc_vdev);
359 }
360
osif_vdev_cache_command(struct osif_vdev_sync * vdev_sync,uint8_t cmd_id)361 void osif_vdev_cache_command(struct osif_vdev_sync *vdev_sync, uint8_t cmd_id)
362 {
363 dsc_vdev_cache_command(vdev_sync->dsc_vdev, cmd_id);
364 osif_debug("Set cache cmd to %d", cmd_id);
365 }
366
367