xref: /wlan-dirver/qcacld-3.0/core/wma/src/wma_ocb.c (revision bb8e47c200751dd274982fa7d00566e04456aa23)
1 /*
2  * Copyright (c) 2013-2018 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: wma_ocb.c
21  *
22  * WLAN Host Device Driver 802.11p OCB implementation
23  */
24 
25 #include "wma_ocb.h"
26 #include "wmi_unified_api.h"
27 #include "cds_utils.h"
28 #include "cds_api.h"
29 #include <cdp_txrx_ocb.h>
30 #include <cdp_txrx_handle.h>
31 #include "wlan_ocb_ucfg_api.h"
32 
33 /**
34  * wma_ocb_resp() - send the OCB set config response via callback
35  * @wma_handle: pointer to the WMA handle
36  * @status: status of the set config command
37  */
38 int wma_ocb_set_config_resp(tp_wma_handle wma_handle, uint8_t status)
39 {
40 	QDF_STATUS qdf_status;
41 	struct sir_ocb_set_config_response *resp;
42 	struct scheduler_msg msg = {0};
43 	struct sir_ocb_config *req = wma_handle->ocb_config_req;
44 	void *vdev = (req ?
45 		wma_handle->interfaces[req->session_id].handle : NULL);
46 	struct ol_txrx_ocb_set_chan ocb_set_chan;
47 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
48 
49 	/*
50 	 * If the command was successful, save the channel information in the
51 	 * vdev.
52 	 */
53 	if (status == QDF_STATUS_SUCCESS && vdev && req) {
54 		ocb_set_chan.ocb_channel_info = cdp_get_ocb_chan_info(soc,
55 						(struct cdp_vdev *)vdev);
56 		if (ocb_set_chan.ocb_channel_info)
57 			qdf_mem_free(ocb_set_chan.ocb_channel_info);
58 		ocb_set_chan.ocb_channel_count =
59 			req->channel_count;
60 		if (req->channel_count) {
61 			int i;
62 			int buf_size = sizeof(*ocb_set_chan.ocb_channel_info) *
63 			    req->channel_count;
64 			ocb_set_chan.ocb_channel_info =
65 				qdf_mem_malloc(buf_size);
66 			if (!ocb_set_chan.ocb_channel_info)
67 				return -ENOMEM;
68 			qdf_mem_zero(ocb_set_chan.ocb_channel_info, buf_size);
69 			for (i = 0; i < req->channel_count; i++) {
70 				ocb_set_chan.ocb_channel_info[i].chan_freq =
71 					req->channels[i].chan_freq;
72 				if (req->channels[i].flags &
73 					OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR)
74 					ocb_set_chan.ocb_channel_info[i].
75 					disable_rx_stats_hdr = 1;
76 			}
77 		} else {
78 			ocb_set_chan.ocb_channel_info = 0;
79 			ocb_set_chan.ocb_channel_count = 0;
80 		}
81 		cdp_set_ocb_chan_info(soc,
82 			(struct cdp_vdev *)vdev,
83 			ocb_set_chan);
84 	}
85 
86 	/* Free the configuration that was saved in wma_ocb_set_config. */
87 	qdf_mem_free(wma_handle->ocb_config_req);
88 	wma_handle->ocb_config_req = NULL;
89 
90 	resp = qdf_mem_malloc(sizeof(*resp));
91 	if (!resp)
92 		return -ENOMEM;
93 
94 	resp->status = status;
95 
96 	msg.type = eWNI_SME_OCB_SET_CONFIG_RSP;
97 	msg.bodyptr = resp;
98 
99 	qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &msg);
100 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
101 		WMA_LOGE(FL("Fail to post msg to SME"));
102 		qdf_mem_free(resp);
103 		return -EINVAL;
104 	}
105 
106 	return 0;
107 }
108 
109 /**
110  * copy_sir_ocb_config() - deep copy of an OCB config struct
111  * @src: pointer to the source struct
112  *
113  * Return: pointer to the copied struct
114  */
115 static struct sir_ocb_config *copy_sir_ocb_config(struct sir_ocb_config *src)
116 {
117 	struct sir_ocb_config *dst;
118 	uint32_t length;
119 	void *cursor;
120 
121 	length = sizeof(*src) +
122 		src->channel_count * sizeof(*src->channels) +
123 		src->schedule_size * sizeof(*src->schedule) +
124 		src->dcc_ndl_chan_list_len +
125 		src->dcc_ndl_active_state_list_len;
126 
127 	dst = qdf_mem_malloc(length);
128 	if (!dst)
129 		return NULL;
130 
131 	*dst = *src;
132 
133 	cursor = dst;
134 	cursor += sizeof(*dst);
135 	dst->channels = cursor;
136 	cursor += src->channel_count * sizeof(*dst->channels);
137 	qdf_mem_copy(dst->channels, src->channels,
138 		     src->channel_count * sizeof(*dst->channels));
139 	dst->schedule = cursor;
140 	cursor += src->schedule_size * sizeof(*dst->schedule);
141 	qdf_mem_copy(dst->schedule, src->schedule,
142 		     src->schedule_size * sizeof(*dst->schedule));
143 	dst->dcc_ndl_chan_list = cursor;
144 	cursor += src->dcc_ndl_chan_list_len;
145 	qdf_mem_copy(dst->dcc_ndl_chan_list, src->dcc_ndl_chan_list,
146 		     src->dcc_ndl_chan_list_len);
147 	dst->dcc_ndl_active_state_list = cursor;
148 	cursor += src->dcc_ndl_active_state_list_len;
149 	qdf_mem_copy(dst->dcc_ndl_active_state_list,
150 		     src->dcc_ndl_active_state_list,
151 		     src->dcc_ndl_active_state_list_len);
152 	return dst;
153 }
154 
155 /**
156  * wma_ocb_set_config_req() - send the OCB config request
157  * @wma_handle: pointer to the WMA handle
158  * @config_req: the configuration to be set.
159  */
160 int wma_ocb_set_config_req(tp_wma_handle wma_handle,
161 			   struct sir_ocb_config *config_req)
162 {
163 	struct wma_target_req *msg;
164 	struct wma_vdev_start_req req;
165 	QDF_STATUS status = QDF_STATUS_SUCCESS;
166 
167 	/* if vdev is not yet up, send vdev start request and wait for response.
168 	 * OCB set_config request should be sent on receiving
169 	 * vdev start response message
170 	 */
171 	if (!wma_is_vdev_up(config_req->session_id)) {
172 		qdf_mem_zero(&req, sizeof(req));
173 		/* Enqueue OCB Set Schedule request message */
174 		msg = wma_fill_vdev_req(wma_handle, config_req->session_id,
175 					WMA_OCB_SET_CONFIG_CMD,
176 					WMA_TARGET_REQ_TYPE_VDEV_START,
177 					(void *)config_req, 1000);
178 		if (!msg) {
179 			WMA_LOGE(FL("Failed to fill vdev req %d"), req.vdev_id);
180 			status = QDF_STATUS_E_NOMEM;
181 			return status;
182 		}
183 		req.chan = cds_freq_to_chan(config_req->channels[0].chan_freq);
184 		req.vdev_id = msg->vdev_id;
185 		if (cds_chan_to_band(req.chan) == CDS_BAND_2GHZ)
186 			req.dot11_mode = WNI_CFG_DOT11_MODE_11G;
187 		else
188 			req.dot11_mode = WNI_CFG_DOT11_MODE_11A;
189 
190 		if (wma_handle->ocb_config_req)
191 			qdf_mem_free(wma_handle->ocb_config_req);
192 		wma_handle->ocb_config_req = copy_sir_ocb_config(config_req);
193 		req.preferred_rx_streams = 2;
194 		req.preferred_tx_streams = 2;
195 
196 		status = wma_vdev_start(wma_handle, &req, false);
197 		if (status != QDF_STATUS_SUCCESS) {
198 			wma_remove_vdev_req(wma_handle, req.vdev_id,
199 					    WMA_TARGET_REQ_TYPE_VDEV_START);
200 			WMA_LOGE(FL("vdev_start failed, status = %d"), status);
201 		}
202 		return 0;
203 	} else {
204 		return wma_ocb_set_config(wma_handle, config_req);
205 	}
206 }
207 
208 int wma_ocb_start_resp_ind_cont(tp_wma_handle wma_handle)
209 {
210 	QDF_STATUS qdf_status = 0;
211 
212 	if (!wma_handle->ocb_config_req) {
213 		WMA_LOGE(FL("The request could not be found"));
214 		return QDF_STATUS_E_EMPTY;
215 	}
216 
217 	qdf_status = wma_ocb_set_config(wma_handle, wma_handle->ocb_config_req);
218 	return qdf_status;
219 }
220 
221 static WLAN_PHY_MODE wma_ocb_freq_to_mode(uint32_t freq)
222 {
223 	if (cds_chan_to_band(cds_freq_to_chan(freq)) == CDS_BAND_2GHZ)
224 		return MODE_11G;
225 	else
226 		return MODE_11A;
227 }
228 
229 /**
230  * wma_send_ocb_set_config() - send the OCB config to the FW
231  * @wma_handle: pointer to the WMA handle
232  * @config: the OCB configuration
233  *
234  * Return: 0 on success
235  */
236 int wma_ocb_set_config(tp_wma_handle wma_handle, struct sir_ocb_config *config)
237 {
238 	int32_t ret, i;
239 	uint32_t *ch_mhz;
240 	struct ocb_config tconfig = {0};
241 
242 	tconfig.vdev_id = config->session_id;
243 	tconfig.channel_count = config->channel_count;
244 	tconfig.schedule_size = config->schedule_size;
245 	tconfig.flags = config->flags;
246 	tconfig.channels = (struct ocb_config_chan *)config->channels;
247 	tconfig.schedule = (struct ocb_config_schdl *)config->schedule;
248 	tconfig.dcc_ndl_chan_list_len = config->dcc_ndl_chan_list_len;
249 	tconfig.dcc_ndl_chan_list = config->dcc_ndl_chan_list;
250 	tconfig.dcc_ndl_active_state_list_len =
251 				config->dcc_ndl_active_state_list_len;
252 	tconfig.dcc_ndl_active_state_list = config->dcc_ndl_active_state_list;
253 	ch_mhz = qdf_mem_malloc(sizeof(uint32_t)*config->channel_count);
254 	if (ch_mhz == NULL) {
255 		WMA_LOGE(FL("Memory allocation failed"));
256 		return -ENOMEM;
257 	}
258 
259 	for (i = 0; i < config->channel_count; i++)
260 		ch_mhz[i] = wma_ocb_freq_to_mode(config->channels[i].chan_freq);
261 
262 	/*
263 	 * Save the configuration so that it can be used in
264 	 * wma_ocb_set_config_event_handler.
265 	 */
266 	if (wma_handle->ocb_config_req != config) {
267 		if (wma_handle->ocb_config_req)
268 			qdf_mem_free(wma_handle->ocb_config_req);
269 		wma_handle->ocb_config_req = copy_sir_ocb_config(config);
270 	}
271 
272 	ret = wmi_unified_ocb_set_config(wma_handle->wmi_handle, &tconfig);
273 	if (ret != EOK) {
274 		if (wma_handle->ocb_config_req) {
275 			qdf_mem_free(wma_handle->ocb_config_req);
276 			wma_handle->ocb_config_req = NULL;
277 		}
278 		qdf_mem_free(ch_mhz);
279 		WMA_LOGE("Failed to set OCB config");
280 		return -EIO;
281 	}
282 	qdf_mem_free(ch_mhz);
283 
284 	return 0;
285 }
286 
287 /**
288  * wma_ocb_set_config_event_handler() - Response event for the set config cmd
289  * @handle: the WMA handle
290  * @event_buf: buffer with the event parameters
291  * @len: length of the buffer
292  *
293  * Return: 0 on success
294  */
295 int wma_ocb_set_config_event_handler(void *handle, uint8_t *event_buf,
296 				     uint32_t len)
297 {
298 	WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *param_tlvs;
299 	wmi_ocb_set_config_resp_event_fixed_param *fix_param;
300 
301 	param_tlvs = (WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *)event_buf;
302 	fix_param = param_tlvs->fixed_param;
303 	return wma_ocb_set_config_resp(handle, fix_param->status);
304 };
305 
306 /**
307  * wma_ocb_set_utc_time() - send the UTC time to the firmware
308  * @wma_handle: pointer to the WMA handle
309  * @utc: pointer to the UTC time struct
310  *
311  * Return: 0 on succes
312  */
313 int wma_ocb_set_utc_time(tp_wma_handle wma_handle, struct sir_ocb_utc *utc)
314 {
315 	int32_t ret;
316 	struct ocb_utc_param cmd = {0};
317 
318 	cmd.vdev_id = utc->vdev_id;
319 	qdf_mem_copy(&cmd.utc_time, &utc->utc_time, WMI_SIZE_UTC_TIME);
320 	qdf_mem_copy(&cmd.time_error, &utc->time_error,
321 				 WMI_SIZE_UTC_TIME_ERROR);
322 	ret = wmi_unified_ocb_set_utc_time_cmd(wma_handle->wmi_handle, &cmd);
323 	if (ret != EOK) {
324 		WMA_LOGE(FL("Failed to set OCB UTC time"));
325 		return -EIO;
326 	}
327 
328 	return 0;
329 }
330 
331 /**
332  * wma_ocb_start_timing_advert() - start sending the timing advertisement
333  *				   frames on a channel
334  * @wma_handle: pointer to the WMA handle
335  * @timing_advert: pointer to the timing advertisement struct
336  *
337  * Return: 0 on succes
338  */
339 int wma_ocb_start_timing_advert(tp_wma_handle wma_handle,
340 	struct sir_ocb_timing_advert *timing_advert)
341 {
342 	int32_t ret;
343 	struct ocb_timing_advert_param cmd = {0};
344 
345 	cmd.vdev_id = timing_advert->vdev_id;
346 	cmd.repeat_rate = timing_advert->repeat_rate;
347 	cmd.chan_freq = timing_advert->chan_freq;
348 	cmd.timestamp_offset = timing_advert->timestamp_offset;
349 	cmd.time_value_offset = timing_advert->time_value_offset;
350 	cmd.template_length = timing_advert->template_length;
351 	cmd.template_value = (uint8_t *)timing_advert->template_value;
352 
353 	ret = wmi_unified_ocb_start_timing_advert(wma_handle->wmi_handle,
354 				   &cmd);
355 	if (ret != EOK) {
356 		WMA_LOGE(FL("Failed to start OCB timing advert"));
357 		return -EIO;
358 	}
359 
360 	return 0;
361 }
362 
363 /**
364  * wma_ocb_stop_timing_advert() - stop sending the timing advertisement frames
365  *				  on a channel
366  * @wma_handle: pointer to the WMA handle
367  * @timing_advert: pointer to the timing advertisement struct
368  *
369  * Return: 0 on succes
370  */
371 int wma_ocb_stop_timing_advert(tp_wma_handle wma_handle,
372 	struct sir_ocb_timing_advert *timing_advert)
373 {
374 	int32_t ret;
375 	struct ocb_timing_advert_param cmd = {0};
376 
377 	cmd.vdev_id = timing_advert->vdev_id;
378 	cmd.chan_freq = timing_advert->chan_freq;
379 	ret = wmi_unified_ocb_stop_timing_advert(wma_handle->wmi_handle,
380 				   &cmd);
381 	if (ret != EOK) {
382 		WMA_LOGE(FL("Failed to stop OCB timing advert"));
383 		return -EIO;
384 	}
385 
386 	return 0;
387 }
388 
389 /**
390  * wma_ocb_get_tsf_timer() - stop sending the timing advertisement frames on a
391  *			     channel
392  * @wma_handle: pointer to the WMA handle
393  * @request: pointer to the request
394  *
395  * Return: 0 on succes
396  */
397 int wma_ocb_get_tsf_timer(tp_wma_handle wma_handle,
398 			  struct sir_ocb_get_tsf_timer *request)
399 {
400 	QDF_STATUS ret;
401 
402 	/* Send the WMI command */
403 	ret = wmi_unified_ocb_get_tsf_timer(wma_handle->wmi_handle,
404 			(struct ocb_get_tsf_timer_param *)request);
405 	/* If there is an error, set the completion event */
406 	if (ret != EOK) {
407 		WMA_LOGE(FL("Failed to send WMI message: %d"), ret);
408 		return -EIO;
409 	}
410 	return 0;
411 }
412 
413 /**
414  * wma_ocb_get_tsf_timer_resp_event_handler() - Event for the get TSF timer cmd
415  * @handle: the WMA handle
416  * @event_buf: buffer with the event parameters
417  * @len: length of the buffer
418  *
419  * Return: 0 on success
420  */
421 static int wma_ocb_get_tsf_timer_resp_event_handler(void *handle,
422 						    uint8_t *event_buf,
423 						    uint32_t len)
424 {
425 	QDF_STATUS qdf_status;
426 	struct sir_ocb_get_tsf_timer_response *response;
427 	WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *param_tlvs;
428 	wmi_ocb_get_tsf_timer_resp_event_fixed_param *fix_param;
429 	struct scheduler_msg msg = {0};
430 
431 	param_tlvs = (WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *)event_buf;
432 	fix_param = param_tlvs->fixed_param;
433 
434 	/* Allocate and populate the response */
435 	response = qdf_mem_malloc(sizeof(*response));
436 	if (response == NULL)
437 		return -ENOMEM;
438 	response->vdev_id = fix_param->vdev_id;
439 	response->timer_high = fix_param->tsf_timer_high;
440 	response->timer_low = fix_param->tsf_timer_low;
441 
442 	msg.type = eWNI_SME_OCB_GET_TSF_TIMER_RSP;
443 	msg.bodyptr = response;
444 
445 	qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &msg);
446 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
447 		WMA_LOGE(FL("Failed to post msg to SME"));
448 		qdf_mem_free(response);
449 		return -EINVAL;
450 	}
451 
452 	return 0;
453 }
454 
455 /**
456  * wma_dcc_get_stats() - get the DCC channel stats
457  * @wma_handle: pointer to the WMA handle
458  * @get_stats_param: pointer to the dcc stats
459  *
460  * Return: 0 on succes
461  */
462 int wma_dcc_get_stats(tp_wma_handle wma_handle,
463 		      struct sir_dcc_get_stats *get_stats_param)
464 {
465 	int32_t ret;
466 	struct ocb_dcc_get_stats_param cmd = {0};
467 
468 	cmd.vdev_id = get_stats_param->vdev_id;
469 	cmd.channel_count = get_stats_param->channel_count;
470 	cmd.request_array_len = get_stats_param->request_array_len;
471 	cmd.request_array = get_stats_param->request_array;
472 
473 	/* Send the WMI command */
474 	ret = wmi_unified_dcc_get_stats_cmd(wma_handle->wmi_handle, &cmd);
475 
476 	if (ret != EOK) {
477 		WMA_LOGE(FL("Failed to send WMI message: %d"), ret);
478 		return -EIO;
479 	}
480 
481 	return 0;
482 }
483 
484 /**
485  * wma_dcc_get_stats_resp_event_handler() - Response event for the get stats cmd
486  * @handle: the WMA handle
487  * @event_buf: buffer with the event parameters
488  * @len: length of the buffer
489  *
490  * Return: 0 on success
491  */
492 static int wma_dcc_get_stats_resp_event_handler(void *handle,
493 						uint8_t *event_buf,
494 						uint32_t len)
495 {
496 	QDF_STATUS qdf_status;
497 	struct sir_dcc_get_stats_response *response;
498 	WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *param_tlvs;
499 	wmi_dcc_get_stats_resp_event_fixed_param *fix_param;
500 	struct scheduler_msg msg = {0};
501 
502 	param_tlvs = (WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *)event_buf;
503 	fix_param = param_tlvs->fixed_param;
504 
505 	/* Allocate and populate the response */
506 	if (fix_param->num_channels > ((WMI_SVC_MSG_MAX_SIZE -
507 	    sizeof(*fix_param)) / sizeof(wmi_dcc_ndl_stats_per_channel)) ||
508 	    fix_param->num_channels > param_tlvs->num_stats_per_channel_list) {
509 		WMA_LOGE("%s: too many channels:%d, param_tlvs->num_stats_per_channel_list:%d",
510 			__func__, fix_param->num_channels,
511 			param_tlvs->num_stats_per_channel_list);
512 		return -EINVAL;
513 	}
514 	response = qdf_mem_malloc(sizeof(*response) + fix_param->num_channels *
515 		sizeof(wmi_dcc_ndl_stats_per_channel));
516 	if (response == NULL)
517 		return -ENOMEM;
518 
519 	response->vdev_id = fix_param->vdev_id;
520 	response->num_channels = fix_param->num_channels;
521 	response->channel_stats_array_len =
522 		fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel);
523 	response->channel_stats_array = ((void *)response) + sizeof(*response);
524 	qdf_mem_copy(response->channel_stats_array,
525 		     param_tlvs->stats_per_channel_list,
526 		     response->channel_stats_array_len);
527 
528 	msg.type = eWNI_SME_DCC_GET_STATS_RSP;
529 	msg.bodyptr = response;
530 
531 	qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &msg);
532 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
533 		WMA_LOGE(FL("Failed to post msg to SME"));
534 		qdf_mem_free(response);
535 		return -EINVAL;
536 	}
537 
538 	return 0;
539 }
540 
541 /**
542  * wma_dcc_clear_stats() - command to clear the DCC stats
543  * @wma_handle: pointer to the WMA handle
544  * @clear_stats_param: parameters to the command
545  *
546  * Return: 0 on succes
547  */
548 int wma_dcc_clear_stats(tp_wma_handle wma_handle,
549 			struct sir_dcc_clear_stats *clear_stats_param)
550 {
551 	int32_t ret;
552 
553 	/* Send the WMI command */
554 	ret = wmi_unified_dcc_clear_stats(wma_handle->wmi_handle,
555 		(struct ocb_dcc_clear_stats_param *)clear_stats_param);
556 	if (ret != EOK) {
557 		WMA_LOGE(FL("Failed to send the WMI command"));
558 		return -EIO;
559 	}
560 
561 	return 0;
562 }
563 
564 /**
565  * wma_dcc_update_ndl() - command to update the NDL data
566  * @wma_handle: pointer to the WMA handle
567  * @update_ndl_param: pointer to the request parameters
568  *
569  * Return: 0 on success
570  */
571 int wma_dcc_update_ndl(tp_wma_handle wma_handle,
572 		       struct sir_dcc_update_ndl *update_ndl_param)
573 {
574 	QDF_STATUS qdf_status;
575 	struct ocb_dcc_update_ndl_param *cmd;
576 
577 	cmd = (struct ocb_dcc_update_ndl_param *) update_ndl_param;
578 	/* Send the WMI command */
579 	qdf_status = wmi_unified_dcc_update_ndl(wma_handle->wmi_handle,
580 				   cmd);
581 	/* If there is an error, set the completion event */
582 	if (qdf_status) {
583 		WMA_LOGE(FL("Failed to send WMI message: %d"), qdf_status);
584 		return -EIO;
585 	}
586 
587 	return 0;
588 }
589 
590 /**
591  * wma_dcc_update_ndl_resp_event_handler() - Response event for the update NDL
592  * command
593  * @handle: the WMA handle
594  * @event_buf: buffer with the event parameters
595  * @len: length of the buffer
596  *
597  * Return: 0 on success
598  */
599 static int wma_dcc_update_ndl_resp_event_handler(void *handle,
600 						 uint8_t *event_buf,
601 						 uint32_t len)
602 {
603 	QDF_STATUS qdf_status;
604 	struct sir_dcc_update_ndl_response *resp;
605 	WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *param_tlvs;
606 	wmi_dcc_update_ndl_resp_event_fixed_param *fix_param;
607 	struct scheduler_msg msg = {0};
608 
609 	param_tlvs = (WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *)event_buf;
610 	fix_param = param_tlvs->fixed_param;
611 	/* Allocate and populate the response */
612 	resp = qdf_mem_malloc(sizeof(*resp));
613 	if (!resp) {
614 		WMA_LOGE(FL("Error allocating memory for the response."));
615 		return -ENOMEM;
616 	}
617 	resp->vdev_id = fix_param->vdev_id;
618 	resp->status = fix_param->status;
619 
620 	msg.type = eWNI_SME_DCC_UPDATE_NDL_RSP;
621 	msg.bodyptr = resp;
622 
623 	qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &msg);
624 	if (!QDF_IS_STATUS_SUCCESS(qdf_status))	{
625 		WMA_LOGE(FL("Failed to post msg to SME"));
626 		qdf_mem_free(resp);
627 		return -EINVAL;
628 	}
629 
630 	return 0;
631 }
632 
633 /**
634  * wma_dcc_stats_event_handler() - Response event for the get stats cmd
635  * @handle: the WMA handle
636  * @event_buf: buffer with the event parameters
637  * @len: length of the buffer
638  *
639  * Return: 0 on success
640  */
641 static int wma_dcc_stats_event_handler(void *handle, uint8_t *event_buf,
642 				       uint32_t len)
643 {
644 	QDF_STATUS qdf_status;
645 	struct sir_dcc_get_stats_response *response;
646 	WMI_DCC_STATS_EVENTID_param_tlvs *param_tlvs;
647 	wmi_dcc_stats_event_fixed_param *fix_param;
648 	struct scheduler_msg msg = {0};
649 
650 	param_tlvs = (WMI_DCC_STATS_EVENTID_param_tlvs *)event_buf;
651 	fix_param = param_tlvs->fixed_param;
652 	/* Allocate and populate the response */
653 	if (fix_param->num_channels > ((WMI_SVC_MSG_MAX_SIZE -
654 	    sizeof(*fix_param)) / sizeof(wmi_dcc_ndl_stats_per_channel))) {
655 		WMA_LOGE("%s: too many channels:%d", __func__,
656 			fix_param->num_channels);
657 		QDF_ASSERT(0);
658 		return -EINVAL;
659 	}
660 	response = qdf_mem_malloc(sizeof(*response) +
661 	    fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel));
662 	if (response == NULL)
663 		return -ENOMEM;
664 	response->vdev_id = fix_param->vdev_id;
665 	response->num_channels = fix_param->num_channels;
666 	response->channel_stats_array_len =
667 		fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel);
668 
669 	if (fix_param->num_channels > param_tlvs->num_stats_per_channel_list) {
670 		WMA_LOGE("FW message num_chan %d more than TLV hdr %d",
671 			 fix_param->num_channels,
672 			 param_tlvs->num_stats_per_channel_list);
673 		return -EINVAL;
674 	}
675 
676 	response->channel_stats_array = ((void *)response) + sizeof(*response);
677 	qdf_mem_copy(response->channel_stats_array,
678 		     param_tlvs->stats_per_channel_list,
679 		     response->channel_stats_array_len);
680 
681 	msg.type = eWNI_SME_DCC_STATS_EVENT;
682 	msg.bodyptr = response;
683 
684 	qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &msg);
685 	if (!QDF_IS_STATUS_SUCCESS(qdf_status))	{
686 		WMA_LOGE(FL("Failed to post msg to SME"));
687 		qdf_mem_free(response);
688 		return -EINVAL;
689 	}
690 
691 	return 0;
692 }
693 
694 /**
695  * wma_ocb_register_event_handlers() - register handlers for the OCB WMI
696  * events
697  * @wma_handle: pointer to the WMA handle
698  *
699  * Return: 0 on success, non-zero on failure
700  */
701 int wma_ocb_register_event_handlers(tp_wma_handle wma_handle)
702 {
703 	int status;
704 
705 	if (!wma_handle) {
706 		WMA_LOGE(FL("wma_handle is NULL"));
707 		return -EINVAL;
708 	}
709 
710 	/* Initialize the members in WMA used by wma_ocb */
711 	status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
712 			wmi_ocb_set_config_resp_event_id,
713 			wma_ocb_set_config_event_handler,
714 			WMA_RX_SERIALIZER_CTX);
715 	if (status)
716 		return status;
717 
718 	status = wmi_unified_register_event_handler(
719 			wma_handle->wmi_handle,
720 			wmi_ocb_get_tsf_timer_resp_event_id,
721 			wma_ocb_get_tsf_timer_resp_event_handler,
722 			WMA_RX_SERIALIZER_CTX);
723 	if (status)
724 		return status;
725 
726 	status = wmi_unified_register_event_handler(
727 			wma_handle->wmi_handle,
728 			wmi_dcc_get_stats_resp_event_id,
729 			wma_dcc_get_stats_resp_event_handler,
730 			WMA_RX_SERIALIZER_CTX);
731 	if (status)
732 		return status;
733 
734 	status = wmi_unified_register_event_handler(
735 			wma_handle->wmi_handle,
736 			wmi_dcc_update_ndl_resp_event_id,
737 			wma_dcc_update_ndl_resp_event_handler,
738 			WMA_RX_SERIALIZER_CTX);
739 	if (status)
740 		return status;
741 
742 	status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
743 			wmi_dcc_stats_event_id,
744 			wma_dcc_stats_event_handler,
745 			WMA_RX_SERIALIZER_CTX);
746 	if (status)
747 		return status;
748 
749 	return QDF_STATUS_SUCCESS;
750 }
751 
752 /**
753  * wma_start_ocb_vdev() - start OCB vdev
754  * @config: ocb channel config
755  *
756  * Return: QDF_STATUS_SUCCESS on success
757  */
758 static QDF_STATUS wma_start_ocb_vdev(struct ocb_config *config)
759 {
760 	struct wma_target_req *msg;
761 	struct wma_vdev_start_req req;
762 	QDF_STATUS status;
763 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
764 
765 	qdf_mem_zero(&req, sizeof(req));
766 	msg = wma_fill_vdev_req(wma, config->vdev_id,
767 				WMA_OCB_SET_CONFIG_CMD,
768 				WMA_TARGET_REQ_TYPE_VDEV_START,
769 				(void *)config, 1000);
770 	if (!msg) {
771 		WMA_LOGE(FL("Failed to fill vdev req %d"), config->vdev_id);
772 
773 		return QDF_STATUS_E_NOMEM;
774 	}
775 	req.chan = cds_freq_to_chan(config->channels[0].chan_freq);
776 	req.vdev_id = msg->vdev_id;
777 	if (cds_chan_to_band(req.chan) == CDS_BAND_2GHZ)
778 		req.dot11_mode = WNI_CFG_DOT11_MODE_11G;
779 	else
780 		req.dot11_mode = WNI_CFG_DOT11_MODE_11A;
781 
782 	req.preferred_rx_streams = 2;
783 	req.preferred_tx_streams = 2;
784 
785 	status = wma_vdev_start(wma, &req, false);
786 	if (status != QDF_STATUS_SUCCESS) {
787 		wma_remove_vdev_req(wma, req.vdev_id,
788 				    WMA_TARGET_REQ_TYPE_VDEV_START);
789 		WMA_LOGE(FL("vdev_start failed, status = %d"), status);
790 	}
791 
792 	return status;
793 }
794 
795 QDF_STATUS wma_ocb_register_callbacks(tp_wma_handle wma_handle)
796 {
797 	ucfg_ocb_register_vdev_start(wma_handle->pdev, wma_start_ocb_vdev);
798 
799 	return QDF_STATUS_SUCCESS;
800 }
801