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