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