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