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: contains core ocb function definitions
22  */
23 
24 #include <qdf_status.h>
25 #include "scheduler_api.h"
26 #include "wlan_objmgr_cmn.h"
27 #include "wlan_objmgr_global_obj.h"
28 #include "wlan_objmgr_psoc_obj.h"
29 #include "wlan_objmgr_pdev_obj.h"
30 #include "wlan_objmgr_vdev_obj.h"
31 #include <cdp_txrx_handle.h>
32 #include <cdp_txrx_cmn.h>
33 #include <cdp_txrx_ocb.h>
34 #include "wlan_ocb_main.h"
35 #include "wlan_ocb_tgt_api.h"
36 #include "target_if_ocb.h"
37 
38 /**
39  * ocb_get_evt_type_str() - parse event to string
40  * @evt_type: ocb event type
41  *
42  * This function parse ocb event to string.
43  *
44  * Return: command string
45  */
ocb_get_evt_type_str(enum ocb_southbound_event evt_type)46 static const char *ocb_get_evt_type_str(enum ocb_southbound_event evt_type)
47 {
48 	switch (evt_type) {
49 	case OCB_CHANNEL_CONFIG_STATUS:
50 		return "OCB channel config status";
51 	case OCB_TSF_TIMER:
52 		return "OCB TSF timer";
53 	case OCB_DCC_STATS_RESPONSE:
54 		return "OCB DCC get stats response";
55 	case OCB_NDL_RESPONSE:
56 		return "OCB NDL indication";
57 	case OCB_DCC_INDICATION:
58 		return "OCB DCC stats indication";
59 	default:
60 		return "Invalid OCB command";
61 	}
62 }
63 
64 /**
65  * ocb_set_chan_info() - Set channel info to dp
66  * @dp_soc: data path soc handle
67  * @dp_pdev: data path pdev handle
68  * @vdev_id: OCB vdev_id
69  * @config: channel config parameters
70  *
71  * Return: QDF_STATUS_SUCCESS on success
72  */
ocb_set_chan_info(void * dp_soc,void * dp_pdev,uint32_t vdev_id,struct ocb_config * config)73 static QDF_STATUS ocb_set_chan_info(void *dp_soc,
74 				    void *dp_pdev,
75 				    uint32_t vdev_id,
76 				    struct ocb_config *config)
77 {
78 	struct ol_txrx_ocb_set_chan ocb_set_chan;
79 	struct ol_txrx_ocb_chan_info *ocb_channel_info;
80 
81 	if (!dp_soc || !dp_pdev) {
82 		ocb_err("DP global handle is null");
83 		return QDF_STATUS_E_INVAL;
84 	}
85 
86 	ocb_set_chan.ocb_channel_count = config->channel_count;
87 
88 	/* release old settings */
89 	ocb_channel_info = cdp_get_ocb_chan_info(dp_soc, vdev_id);
90 	if (ocb_channel_info)
91 		qdf_mem_free(ocb_channel_info);
92 
93 	if (config->channel_count) {
94 		int i, buf_size;
95 
96 		buf_size = sizeof(*ocb_channel_info) * config->channel_count;
97 		ocb_set_chan.ocb_channel_info = qdf_mem_malloc(buf_size);
98 		if (!ocb_set_chan.ocb_channel_info)
99 			return QDF_STATUS_E_NOMEM;
100 
101 		ocb_channel_info = ocb_set_chan.ocb_channel_info;
102 		for (i = 0; i < config->channel_count; i++) {
103 			ocb_channel_info[i].chan_freq =
104 				config->channels[i].chan_freq;
105 			if (config->channels[i].flags &
106 				OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR)
107 				ocb_channel_info[i].disable_rx_stats_hdr = 1;
108 		}
109 	} else {
110 		ocb_debug("No channel config to dp");
111 		ocb_set_chan.ocb_channel_info = NULL;
112 	}
113 	ocb_debug("Sync channel config to dp");
114 	cdp_set_ocb_chan_info(dp_soc, vdev_id, ocb_set_chan);
115 
116 	return QDF_STATUS_SUCCESS;
117 }
118 
119 /**
120  * ocb_channel_config_status() - Process set channel config response
121  * @evt: response event
122  *
123  * Return: QDF_STATUS_SUCCESS on success
124  */
ocb_channel_config_status(struct ocb_rx_event * evt)125 static QDF_STATUS ocb_channel_config_status(struct ocb_rx_event *evt)
126 {
127 	QDF_STATUS status;
128 	uint32_t vdev_id;
129 	struct ocb_rx_event *event;
130 	struct wlan_objmgr_psoc *psoc;
131 	struct wlan_objmgr_pdev *pdev;
132 	struct ocb_pdev_obj *ocb_obj;
133 	struct ocb_callbacks *cbs;
134 	struct ocb_set_config_response config_rsp;
135 
136 	if (!evt) {
137 		ocb_err("Event buffer is NULL");
138 		return QDF_STATUS_E_FAILURE;
139 	}
140 	event = evt;
141 	psoc = event->psoc;
142 	pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_OCB_SB_ID);
143 	if (!pdev) {
144 		ocb_alert("Pdev is NULL");
145 		return QDF_STATUS_E_FAILURE;
146 	}
147 
148 	ocb_obj = wlan_get_pdev_ocb_obj(pdev);
149 	if (!ocb_obj) {
150 		ocb_err("Pdev object is NULL");
151 		status = QDF_STATUS_E_INVAL;
152 		goto exit;
153 	}
154 
155 	cbs = &ocb_obj->ocb_cbs;
156 	if (ocb_obj->channel_config) {
157 		vdev_id = ocb_obj->channel_config->vdev_id;
158 		config_rsp = event->rsp.channel_cfg_rsp;
159 
160 		/* Sync channel status to data path */
161 		if (config_rsp.status == OCB_CHANNEL_CONFIG_SUCCESS)
162 			ocb_set_chan_info(ocb_obj->dp_soc,
163 					  ocb_obj->pdev,
164 					  vdev_id,
165 					  ocb_obj->channel_config);
166 		qdf_mem_free(ocb_obj->channel_config);
167 		ocb_obj->channel_config = NULL;
168 	} else {
169 		ocb_err("Failed to sync channel info to DP");
170 		config_rsp.status = OCB_CHANNEL_CONFIG_FAIL;
171 	}
172 
173 	if (cbs->ocb_set_config_callback) {
174 		cbs->ocb_set_config_callback(cbs->ocb_set_config_context,
175 					     &config_rsp);
176 		status = QDF_STATUS_SUCCESS;
177 	} else {
178 		ocb_err("ocb_set_config_resp_cb is NULL");
179 		status = QDF_STATUS_E_INVAL;
180 	}
181 exit:
182 	wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID);
183 
184 	return status;
185 }
186 
187 /**
188  * ocb_tsf_timer() - Process get TSF timer response
189  * @evt: response event
190  *
191  * Return: QDF_STATUS_SUCCESS on success
192  */
ocb_tsf_timer(struct ocb_rx_event * evt)193 static QDF_STATUS ocb_tsf_timer(struct ocb_rx_event *evt)
194 {
195 	QDF_STATUS status;
196 	struct ocb_rx_event *event;
197 	struct wlan_objmgr_vdev *vdev;
198 	struct wlan_objmgr_pdev *pdev;
199 	struct ocb_callbacks *cbs;
200 	struct ocb_get_tsf_timer_response *tsf_timer;
201 
202 	if (!evt) {
203 		ocb_err("Event buffer is NULL");
204 		return QDF_STATUS_E_FAILURE;
205 	}
206 	event = evt;
207 	vdev = event->vdev;
208 	pdev = wlan_vdev_get_pdev(vdev);
209 	cbs = wlan_ocb_get_callbacks(pdev);
210 	tsf_timer = &event->rsp.tsf_timer;
211 	ocb_debug("TSF timer low=%d, high=%d",
212 		  tsf_timer->timer_low, tsf_timer->timer_high);
213 	if (cbs && cbs->ocb_get_tsf_timer_callback) {
214 		ocb_debug("send TSF timer");
215 		cbs->ocb_get_tsf_timer_callback(cbs->ocb_get_tsf_timer_context,
216 						tsf_timer);
217 		status = QDF_STATUS_SUCCESS;
218 	} else {
219 		ocb_err("ocb_get_tsf_timer_cb is NULL");
220 		status = QDF_STATUS_E_FAILURE;
221 	}
222 
223 	return status;
224 }
225 
226 /**
227  * ocb_dcc_stats_response() - Process get DCC stats response
228  * @evt: response event
229  *
230  * Return: QDF_STATUS_SUCCESS on success
231  */
ocb_dcc_stats_response(struct ocb_rx_event * evt)232 static QDF_STATUS ocb_dcc_stats_response(struct ocb_rx_event *evt)
233 {
234 	QDF_STATUS status;
235 	struct ocb_rx_event *event;
236 	struct wlan_objmgr_vdev *vdev;
237 	struct wlan_objmgr_pdev *pdev;
238 	struct ocb_callbacks *cbs;
239 	struct ocb_dcc_get_stats_response *dcc_stats;
240 
241 	if (!evt) {
242 		ocb_err("Event buffer is NULL");
243 		return QDF_STATUS_E_FAILURE;
244 	}
245 
246 	event = evt;
247 	vdev = event->vdev;
248 	pdev = wlan_vdev_get_pdev(vdev);
249 	cbs = wlan_ocb_get_callbacks(pdev);
250 	dcc_stats = &event->rsp.dcc_stats;
251 	if (cbs && cbs->ocb_dcc_get_stats_callback) {
252 		ocb_debug("send DCC stats");
253 		cbs->ocb_dcc_get_stats_callback(cbs->ocb_dcc_get_stats_context,
254 						dcc_stats);
255 		status = QDF_STATUS_SUCCESS;
256 	} else {
257 		ocb_err("dcc_get_stats_cb is NULL");
258 		status = QDF_STATUS_E_FAILURE;
259 	}
260 
261 	return status;
262 }
263 
264 /**
265  * ocb_ndl_response() - Process NDL update response
266  * @evt: response event
267  *
268  * Return: QDF_STATUS_SUCCESS on success
269  */
ocb_ndl_response(struct ocb_rx_event * evt)270 static QDF_STATUS ocb_ndl_response(struct ocb_rx_event *evt)
271 {
272 	QDF_STATUS status;
273 	struct ocb_rx_event *event;
274 	struct wlan_objmgr_vdev *vdev;
275 	struct wlan_objmgr_pdev *pdev;
276 	struct ocb_callbacks *cbs;
277 	struct ocb_dcc_update_ndl_response *ndl;
278 
279 	if (!evt) {
280 		ocb_err("Event buffer is NULL");
281 		return QDF_STATUS_E_FAILURE;
282 	}
283 	event = evt;
284 	vdev = event->vdev;
285 	pdev = wlan_vdev_get_pdev(vdev);
286 	cbs = wlan_ocb_get_callbacks(pdev);
287 	ndl = &event->rsp.ndl;
288 	if (cbs && cbs->ocb_dcc_update_ndl_callback) {
289 		ocb_debug("NDL update response");
290 		cbs->ocb_dcc_update_ndl_callback(
291 				cbs->ocb_dcc_update_ndl_context, ndl);
292 		status = QDF_STATUS_SUCCESS;
293 	} else {
294 		ocb_err("dcc_update_ndl is NULL");
295 		status = QDF_STATUS_E_FAILURE;
296 	}
297 
298 	return status;
299 }
300 
301 /**
302  * ocb_dcc_indication() - Process DCC stats indication
303  * @evt: response event
304  *
305  * Return: QDF_STATUS_SUCCESS on success
306  */
ocb_dcc_indication(struct ocb_rx_event * evt)307 static QDF_STATUS ocb_dcc_indication(struct ocb_rx_event *evt)
308 {
309 	QDF_STATUS status;
310 	struct ocb_rx_event *event;
311 	struct wlan_objmgr_vdev *vdev;
312 	struct ocb_callbacks *cbs;
313 	struct wlan_objmgr_pdev *pdev;
314 	struct ocb_dcc_get_stats_response *dcc_stats;
315 
316 	if (!evt) {
317 		ocb_err("Event buffer is NULL");
318 		return QDF_STATUS_E_FAILURE;
319 	}
320 
321 	event = evt;
322 	vdev = event->vdev;
323 	pdev = wlan_vdev_get_pdev(vdev);
324 	cbs = wlan_ocb_get_callbacks(pdev);
325 	dcc_stats = &event->rsp.dcc_stats;
326 	if (cbs && cbs->ocb_dcc_stats_event_callback) {
327 		ocb_debug("DCC stats indication");
328 		cbs->ocb_dcc_stats_event_callback(
329 				cbs->ocb_dcc_stats_event_context, dcc_stats);
330 		status = QDF_STATUS_SUCCESS;
331 	} else {
332 		ocb_err("dcc_get_stats_cb is NULL");
333 		status = QDF_STATUS_E_FAILURE;
334 	}
335 
336 	return status;
337 }
338 
339 /**
340  * ocb_flush_start_msg() - Flush ocb start message
341  * @msg: OCB start vdev message
342  *
343  * Return: QDF_STATUS_SUCCESS on success.
344  */
ocb_flush_start_msg(struct scheduler_msg * msg)345 static QDF_STATUS ocb_flush_start_msg(struct scheduler_msg *msg)
346 {
347 	struct ocb_pdev_obj *ocb_obj;
348 
349 	if (!msg) {
350 		ocb_err("Null point for OCB message");
351 		return QDF_STATUS_E_INVAL;
352 	}
353 
354 	ocb_obj = msg->bodyptr;
355 	if (ocb_obj && ocb_obj->channel_config) {
356 		ocb_info("release the backed config parameters");
357 		qdf_mem_free(ocb_obj->channel_config);
358 		ocb_obj->channel_config = NULL;
359 	}
360 
361 	return QDF_STATUS_SUCCESS;
362 }
363 
364 /**
365  * ocb_process_start_vdev_msg() - Handler for OCB vdev start message
366  * @msg: OCB start vdev message
367  *
368  * Return: QDF_STATUS_SUCCESS on success.
369  */
ocb_process_start_vdev_msg(struct scheduler_msg * msg)370 static QDF_STATUS ocb_process_start_vdev_msg(struct scheduler_msg *msg)
371 {
372 	QDF_STATUS status;
373 	struct ocb_config *config;
374 	struct ocb_pdev_obj *ocb_obj;
375 	struct ocb_callbacks *ocb_cbs;
376 	struct wlan_objmgr_vdev *vdev;
377 
378 	if (!msg || !msg->bodyptr) {
379 		ocb_err("invalid message");
380 		return QDF_STATUS_E_INVAL;
381 	}
382 
383 	ocb_obj = msg->bodyptr;
384 	ocb_cbs = &ocb_obj->ocb_cbs;
385 	if (!ocb_cbs->start_ocb_vdev) {
386 		ocb_err("No callback to start ocb vdev");
387 		return QDF_STATUS_E_FAILURE;
388 	}
389 
390 	config = ocb_obj->channel_config;
391 	if (!config) {
392 		ocb_err("NULL config parameters");
393 		return QDF_STATUS_E_INVAL;
394 	}
395 
396 	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(ocb_obj->pdev,
397 						    config->vdev_id,
398 						    WLAN_OCB_SB_ID);
399 	if (!vdev) {
400 		ocb_err("Cannot get vdev");
401 		return QDF_STATUS_E_FAILURE;
402 	}
403 
404 	ocb_debug("Start to send OCB vdev start cmd");
405 	status = ocb_cbs->start_ocb_vdev(config);
406 	wlan_objmgr_vdev_release_ref(vdev, WLAN_OCB_SB_ID);
407 	if (QDF_IS_STATUS_ERROR(status)) {
408 		ocb_err("Failed to start OCB vdev");
409 		return QDF_STATUS_E_FAILURE;
410 	}
411 
412 	return QDF_STATUS_SUCCESS;
413 }
414 
ocb_vdev_start(struct ocb_pdev_obj * ocb_obj)415 QDF_STATUS ocb_vdev_start(struct ocb_pdev_obj *ocb_obj)
416 {
417 	QDF_STATUS status;
418 	struct scheduler_msg msg = {0};
419 
420 	msg.bodyptr = ocb_obj;
421 	msg.callback = ocb_process_start_vdev_msg;
422 	msg.flush_callback = ocb_flush_start_msg;
423 	status = scheduler_post_message(QDF_MODULE_ID_OCB,
424 					QDF_MODULE_ID_OCB,
425 					QDF_MODULE_ID_TARGET_IF, &msg);
426 
427 	return status;
428 }
429 
ocb_process_evt(struct scheduler_msg * msg)430 QDF_STATUS ocb_process_evt(struct scheduler_msg *msg)
431 {
432 	QDF_STATUS status;
433 	struct ocb_rx_event *event;
434 
435 	ocb_debug("msg type %d, %s", msg->type,
436 		  ocb_get_evt_type_str(msg->type));
437 
438 	if (!(msg->bodyptr)) {
439 		ocb_err("Invalid message body");
440 		return QDF_STATUS_E_INVAL;
441 	}
442 	event = msg->bodyptr;
443 	switch (msg->type) {
444 	case OCB_CHANNEL_CONFIG_STATUS:
445 		status = ocb_channel_config_status(event);
446 		break;
447 	case OCB_TSF_TIMER:
448 		status = ocb_tsf_timer(event);
449 		break;
450 	case OCB_DCC_STATS_RESPONSE:
451 		status = ocb_dcc_stats_response(event);
452 		break;
453 	case OCB_NDL_RESPONSE:
454 		status = ocb_ndl_response(event);
455 		break;
456 	case OCB_DCC_INDICATION:
457 		status = ocb_dcc_indication(event);
458 		break;
459 	default:
460 		status = QDF_STATUS_E_INVAL;
461 		break;
462 	}
463 
464 	wlan_ocb_release_rx_event(event);
465 	msg->bodyptr = NULL;
466 
467 	return status;
468 }
469 
ocb_copy_config(struct ocb_config * src)470 struct ocb_config *ocb_copy_config(struct ocb_config *src)
471 {
472 	struct ocb_config *dst;
473 	uint32_t length;
474 	uint8_t *cursor;
475 
476 	length = sizeof(*src) +
477 		src->channel_count * sizeof(*src->channels) +
478 		src->schedule_size * sizeof(*src->schedule) +
479 		src->dcc_ndl_chan_list_len +
480 		src->dcc_ndl_active_state_list_len;
481 
482 	dst = qdf_mem_malloc(length);
483 	if (!dst)
484 		return NULL;
485 
486 	*dst = *src;
487 
488 	cursor = (uint8_t *)dst;
489 	cursor += sizeof(*dst);
490 	dst->channels = (struct ocb_config_chan *)cursor;
491 	cursor += src->channel_count * sizeof(*dst->channels);
492 	qdf_mem_copy(dst->channels, src->channels,
493 		     src->channel_count * sizeof(*dst->channels));
494 	dst->schedule = (struct ocb_config_schdl *)cursor;
495 	cursor += src->schedule_size * sizeof(*dst->schedule);
496 	qdf_mem_copy(dst->schedule, src->schedule,
497 		     src->schedule_size * sizeof(*dst->schedule));
498 	dst->dcc_ndl_chan_list = cursor;
499 	cursor += src->dcc_ndl_chan_list_len;
500 	qdf_mem_copy(dst->dcc_ndl_chan_list, src->dcc_ndl_chan_list,
501 		     src->dcc_ndl_chan_list_len);
502 	dst->dcc_ndl_active_state_list = cursor;
503 	cursor += src->dcc_ndl_active_state_list_len;
504 	qdf_mem_copy(dst->dcc_ndl_active_state_list,
505 		     src->dcc_ndl_active_state_list,
506 		     src->dcc_ndl_active_state_list_len);
507 
508 	return dst;
509 }
510 
ocb_pdev_obj_create_notification(struct wlan_objmgr_pdev * pdev,void * arg_list)511 QDF_STATUS ocb_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev,
512 					    void *arg_list)
513 {
514 	QDF_STATUS status;
515 	struct ocb_pdev_obj *ocb_obj;
516 
517 	ocb_notice("ocb pdev created");
518 	ocb_obj = qdf_mem_malloc(sizeof(*ocb_obj));
519 	if (!ocb_obj)
520 		return QDF_STATUS_E_FAILURE;
521 
522 	status = wlan_objmgr_pdev_component_obj_attach(pdev,
523 						       WLAN_UMAC_COMP_OCB,
524 						       (void *)ocb_obj,
525 						       QDF_STATUS_SUCCESS);
526 	if (QDF_IS_STATUS_ERROR(status)) {
527 		ocb_err("Failed to attach pdev ocb component");
528 		qdf_mem_free(ocb_obj);
529 		return status;
530 	}
531 	ocb_obj->pdev = pdev;
532 
533 	/* register OCB tx/rx ops */
534 	tgt_ocb_register_rx_ops(&ocb_obj->ocb_rxops);
535 	target_if_ocb_register_tx_ops(&ocb_obj->ocb_txops);
536 	ocb_notice("ocb pdev attached");
537 
538 	return status;
539 }
540 
ocb_pdev_obj_destroy_notification(struct wlan_objmgr_pdev * pdev,void * arg_list)541 QDF_STATUS ocb_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev,
542 					     void *arg_list)
543 {
544 	QDF_STATUS status;
545 	struct ocb_pdev_obj *ocb_obj;
546 
547 	ocb_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
548 							WLAN_UMAC_COMP_OCB);
549 	if (!ocb_obj) {
550 		ocb_err("Failed to get ocb pdev object");
551 		return QDF_STATUS_E_FAILURE;
552 	}
553 
554 	status = wlan_objmgr_pdev_component_obj_detach(pdev,
555 						       WLAN_UMAC_COMP_OCB,
556 						       ocb_obj);
557 	if (QDF_IS_STATUS_ERROR(status))
558 		ocb_err("Failed to detach ocb pdev object");
559 
560 	qdf_mem_free(ocb_obj);
561 
562 	return QDF_STATUS_SUCCESS;
563 }
564