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