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