1  /*
2   * Copyright (c) 2018, 2020 The Linux Foundation. All rights reserved.
3   * Copyright (c) 2022 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  /**
21   * DOC: This file contains ocb south bound interface definitions
22   */
23  
24  #include <scheduler_api.h>
25  #include <wlan_objmgr_psoc_obj.h>
26  #include <wlan_objmgr_global_obj.h>
27  #include <wlan_objmgr_pdev_obj.h>
28  #include <wlan_objmgr_vdev_obj.h>
29  #include "wlan_ocb_public_structs.h"
30  #include "wlan_ocb_ucfg_api.h"
31  #include "wlan_ocb_tgt_api.h"
32  #include "wlan_ocb_main.h"
33  
34  /**
35   * wlan_ocb_flush_callback() - OCB message flash callback
36   * @msg: OCB message
37   *
38   * Return: QDF_STATUS_SUCCESS on success.
39   */
wlan_ocb_flush_callback(struct scheduler_msg * msg)40  static QDF_STATUS wlan_ocb_flush_callback(struct scheduler_msg *msg)
41  {
42  	struct ocb_rx_event *event;
43  
44  	if (!msg) {
45  		ocb_err("Null point for OCB message");
46  		return QDF_STATUS_E_INVAL;
47  	}
48  
49  	event = msg->bodyptr;
50  	wlan_ocb_release_rx_event(event);
51  
52  	return QDF_STATUS_SUCCESS;
53  }
54  
55  /**
56   * tgt_ocb_channel_config_status() - handler for channel config response
57   * @psoc: psoc handle
58   * @status: status for last channel config
59   *
60   * Return: QDF_STATUS_SUCCESS on success
61   */
62  static QDF_STATUS
tgt_ocb_channel_config_status(struct wlan_objmgr_psoc * psoc,uint32_t status)63  tgt_ocb_channel_config_status(struct wlan_objmgr_psoc *psoc,
64  			      uint32_t status)
65  {
66  	QDF_STATUS qdf_status;
67  	struct scheduler_msg msg = {0};
68  	struct ocb_rx_event *event;
69  
70  	event = qdf_mem_malloc(sizeof(*event));
71  	if (!event)
72  		return QDF_STATUS_E_NOMEM;
73  
74  	qdf_status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID);
75  	if (QDF_IS_STATUS_ERROR(qdf_status)) {
76  		ocb_err("Failed to get psoc ref");
77  		wlan_ocb_release_rx_event(event);
78  		return qdf_status;
79  	}
80  	event->psoc = psoc;
81  	event->rsp.channel_cfg_rsp.status = status;
82  	event->evt_id = OCB_CHANNEL_CONFIG_STATUS;
83  	msg.type = OCB_CHANNEL_CONFIG_STATUS;
84  	msg.bodyptr = event;
85  	msg.callback = ocb_process_evt;
86  	msg.flush_callback = wlan_ocb_flush_callback;
87  	qdf_status = scheduler_post_message(QDF_MODULE_ID_OCB,
88  					    QDF_MODULE_ID_OCB,
89  					    QDF_MODULE_ID_TARGET_IF, &msg);
90  
91  	if (QDF_IS_STATUS_SUCCESS(qdf_status))
92  		return QDF_STATUS_SUCCESS;
93  
94  	ocb_err("failed to send OCB_CHANNEL_CONFIG_STATUS msg");
95  	wlan_ocb_release_rx_event(event);
96  
97  	return qdf_status;
98  }
99  
100  /**
101   * tgt_ocb_get_tsf_timer() - handle for TSF timer response
102   * @psoc: psoc handle
103   * @response: TSF timer response
104   *
105   * Return: QDF_STATUS_SUCCESS on success
106   */
107  static QDF_STATUS
tgt_ocb_get_tsf_timer(struct wlan_objmgr_psoc * psoc,struct ocb_get_tsf_timer_response * response)108  tgt_ocb_get_tsf_timer(struct wlan_objmgr_psoc *psoc,
109  		      struct ocb_get_tsf_timer_response *response)
110  {
111  	QDF_STATUS status;
112  	struct scheduler_msg msg = {0};
113  	struct ocb_rx_event *event;
114  
115  	event = qdf_mem_malloc(sizeof(*event));
116  	if (!event)
117  		return QDF_STATUS_E_NOMEM;
118  
119  	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID);
120  	if (QDF_IS_STATUS_ERROR(status)) {
121  		ocb_err("Failed to get psoc ref");
122  		goto flush_ref;
123  	}
124  	event->psoc = psoc;
125  	event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
126  							   response->vdev_id,
127  							   WLAN_OCB_SB_ID);
128  	if (!event->vdev) {
129  		ocb_err("Cannot get vdev handle");
130  		status = QDF_STATUS_E_FAILURE;
131  		goto flush_ref;
132  	}
133  
134  	event->evt_id = OCB_TSF_TIMER;
135  	event->rsp.tsf_timer.vdev_id = response->vdev_id;
136  	event->rsp.tsf_timer.timer_high = response->timer_high;
137  	event->rsp.tsf_timer.timer_low = response->timer_low;
138  	msg.type = OCB_TSF_TIMER;
139  	msg.bodyptr = event;
140  	msg.callback = ocb_process_evt;
141  	msg.flush_callback = wlan_ocb_flush_callback;
142  
143  	status = scheduler_post_message(QDF_MODULE_ID_OCB,
144  					QDF_MODULE_ID_OCB,
145  					QDF_MODULE_ID_TARGET_IF, &msg);
146  	if (QDF_IS_STATUS_SUCCESS(status))
147  		return QDF_STATUS_SUCCESS;
148  
149  	ocb_err("failed to send OCB_TSF_TIMER msg");
150  flush_ref:
151  	wlan_ocb_release_rx_event(event);
152  
153  	return status;
154  }
155  
156  /**
157   * tgt_ocb_dcc_ndl_update() - handler for NDL update response
158   * @psoc: psoc handle
159   * @resp: NDL update response
160   *
161   * Return: QDF_STATUS_SUCCESS on success
162   */
163  static QDF_STATUS
tgt_ocb_dcc_ndl_update(struct wlan_objmgr_psoc * psoc,struct ocb_dcc_update_ndl_response * resp)164  tgt_ocb_dcc_ndl_update(struct wlan_objmgr_psoc *psoc,
165  		       struct ocb_dcc_update_ndl_response *resp)
166  {
167  	QDF_STATUS status;
168  	struct scheduler_msg msg = {0};
169  	struct ocb_rx_event *event;
170  
171  	event = qdf_mem_malloc(sizeof(*event));
172  	if (!event)
173  		return QDF_STATUS_E_NOMEM;
174  
175  	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID);
176  	if (QDF_IS_STATUS_ERROR(status)) {
177  		ocb_err("Failed to get psoc ref");
178  		goto flush_ref;
179  	}
180  	event->psoc = psoc;
181  	event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
182  							   resp->vdev_id,
183  							   WLAN_OCB_SB_ID);
184  	if (!event->vdev) {
185  		ocb_err("Cannot get vdev handle");
186  		status = QDF_STATUS_E_FAILURE;
187  		goto flush_ref;
188  	}
189  
190  	event->evt_id = OCB_NDL_RESPONSE;
191  	qdf_mem_copy(&event->rsp.ndl, resp, sizeof(*resp));
192  	msg.type = OCB_NDL_RESPONSE;
193  	msg.bodyptr = event;
194  	msg.callback = ocb_process_evt;
195  	msg.flush_callback = wlan_ocb_flush_callback;
196  
197  	status = scheduler_post_message(QDF_MODULE_ID_OCB,
198  					QDF_MODULE_ID_OCB,
199  					QDF_MODULE_ID_TARGET_IF, &msg);
200  	if (QDF_IS_STATUS_SUCCESS(status))
201  		return QDF_STATUS_SUCCESS;
202  
203  	ocb_err("failed to send OCB_NDL_RESPONSE msg");
204  flush_ref:
205  	wlan_ocb_release_rx_event(event);
206  
207  	return status;
208  }
209  
210  /**
211   * tgt_ocb_dcc_stats_indicate() - handler for DCC stats indication
212   * @psoc: psoc handle
213   * @response: DCC stats
214   * @active: true for active query, false for passive indicate
215   *
216   * Return: QDF_STATUS_SUCCESS on success
217   */
218  static QDF_STATUS
tgt_ocb_dcc_stats_indicate(struct wlan_objmgr_psoc * psoc,struct ocb_dcc_get_stats_response * response,bool active)219  tgt_ocb_dcc_stats_indicate(struct wlan_objmgr_psoc *psoc,
220  			   struct ocb_dcc_get_stats_response *response,
221  			   bool active)
222  {
223  	QDF_STATUS status;
224  	uint8_t *buf;
225  	uint32_t size;
226  	struct scheduler_msg msg = {0};
227  	struct ocb_rx_event *event;
228  
229  	size = sizeof(*event) +
230  		response->channel_stats_array_len;
231  	buf = qdf_mem_malloc(size);
232  	if (!buf)
233  		return QDF_STATUS_E_NOMEM;
234  
235  	event = (struct ocb_rx_event *)buf;
236  	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID);
237  	if (QDF_IS_STATUS_ERROR(status)) {
238  		ocb_err("Failed to get psoc ref");
239  		goto flush_ref;
240  	}
241  	event->psoc = psoc;
242  	event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
243  							   response->vdev_id,
244  							   WLAN_OCB_SB_ID);
245  	if (!event->vdev) {
246  		ocb_err("Cannot get vdev handle");
247  		status = QDF_STATUS_E_FAILURE;
248  		goto flush_ref;
249  	}
250  
251  	event->rsp.dcc_stats.channel_stats_array =
252  		(uint8_t *)&event->rsp.dcc_stats +
253  		sizeof(struct ocb_dcc_get_stats_response);
254  	event->rsp.dcc_stats.vdev_id = response->vdev_id;
255  	event->rsp.dcc_stats.num_channels = response->num_channels;
256  	event->rsp.dcc_stats.channel_stats_array_len =
257  		response->channel_stats_array_len;
258  	qdf_mem_copy(event->rsp.dcc_stats.channel_stats_array,
259  		     response->channel_stats_array,
260  		     response->channel_stats_array_len);
261  	ocb_debug("Message type is %s",
262  		  active ? "Get stats response" : "DCC stats indication");
263  	if (active)
264  		msg.type = OCB_DCC_STATS_RESPONSE;
265  	else
266  		msg.type = OCB_DCC_INDICATION;
267  	event->evt_id = msg.type;
268  	msg.bodyptr = event;
269  	msg.callback = ocb_process_evt;
270  	msg.flush_callback = wlan_ocb_flush_callback;
271  
272  	status = scheduler_post_message(QDF_MODULE_ID_OCB,
273  					QDF_MODULE_ID_OCB,
274  					QDF_MODULE_ID_TARGET_IF, &msg);
275  	if (QDF_IS_STATUS_SUCCESS(status))
276  		return QDF_STATUS_SUCCESS;
277  
278  	ocb_err("failed to send DCC stats msg(%d)", msg.type);
279  flush_ref:
280  	wlan_ocb_release_rx_event(event);
281  
282  	return status;
283  }
284  
tgt_ocb_register_ev_handler(struct wlan_objmgr_pdev * pdev)285  QDF_STATUS tgt_ocb_register_ev_handler(struct wlan_objmgr_pdev *pdev)
286  {
287  	struct wlan_objmgr_psoc *psoc;
288  	struct wlan_ocb_tx_ops *ocb_ops;
289  	QDF_STATUS status = QDF_STATUS_E_FAILURE;
290  
291  	psoc = wlan_pdev_get_psoc(pdev);
292  	if (!psoc) {
293  		ocb_err("Null soc handle");
294  		return QDF_STATUS_E_INVAL;
295  	}
296  	ocb_ops = wlan_pdev_get_ocb_tx_ops(pdev);
297  	if (ocb_ops && ocb_ops->ocb_reg_ev_handler) {
298  		status = ocb_ops->ocb_reg_ev_handler(psoc, NULL);
299  		ocb_debug("register ocb event, status:%d", status);
300  	} else {
301  		ocb_alert("No ocb objects or ocb_reg_ev_handler");
302  	}
303  
304  	return status;
305  }
306  
tgt_ocb_unregister_ev_handler(struct wlan_objmgr_pdev * pdev)307  QDF_STATUS tgt_ocb_unregister_ev_handler(struct wlan_objmgr_pdev *pdev)
308  {
309  	struct wlan_objmgr_psoc *psoc;
310  	struct wlan_ocb_tx_ops *ocb_ops;
311  	QDF_STATUS status;
312  
313  	psoc = wlan_pdev_get_psoc(pdev);
314  	if (!psoc) {
315  		ocb_err("Null soc handle");
316  		return QDF_STATUS_E_INVAL;
317  	}
318  	ocb_ops = wlan_pdev_get_ocb_tx_ops(pdev);
319  	if (ocb_ops && ocb_ops->ocb_unreg_ev_handler) {
320  		status = ocb_ops->ocb_unreg_ev_handler(psoc, NULL);
321  		ocb_debug("unregister ocb event, status:%d", status);
322  	} else {
323  		ocb_alert("No ocb objects or ocb_unreg_ev_handler");
324  		status = QDF_STATUS_E_FAILURE;
325  	}
326  
327  	return status;
328  }
329  
tgt_ocb_register_rx_ops(struct wlan_ocb_rx_ops * ocb_rxops)330  QDF_STATUS tgt_ocb_register_rx_ops(struct wlan_ocb_rx_ops *ocb_rxops)
331  {
332  	ocb_rxops->ocb_set_config_status = tgt_ocb_channel_config_status;
333  	ocb_rxops->ocb_tsf_timer = tgt_ocb_get_tsf_timer;
334  	ocb_rxops->ocb_dcc_ndl_update = tgt_ocb_dcc_ndl_update;
335  	ocb_rxops->ocb_dcc_stats_indicate = tgt_ocb_dcc_stats_indicate;
336  
337  	return QDF_STATUS_SUCCESS;
338  }
339