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