xref: /wlan-driver/qca-wifi-host-cmn/wmi/src/wmi_unified_ocb_tlv.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name #include <osdep.h>
21*5113495bSYour Name #include <wmi.h>
22*5113495bSYour Name #include <wmi_unified_priv.h>
23*5113495bSYour Name #include <wlan_ocb_public_structs.h>
24*5113495bSYour Name #include <wmi_unified_ocb_api.h>
25*5113495bSYour Name 
26*5113495bSYour Name /**
27*5113495bSYour Name  * send_ocb_set_utc_time_cmd_tlv() - send the UTC time to the firmware
28*5113495bSYour Name  * @wmi_handle: pointer to the wmi handle
29*5113495bSYour Name  * @utc: pointer to the UTC time struct
30*5113495bSYour Name  *
31*5113495bSYour Name  * Return: 0 on success
32*5113495bSYour Name  */
send_ocb_set_utc_time_cmd_tlv(wmi_unified_t wmi_handle,struct ocb_utc_param * utc)33*5113495bSYour Name static QDF_STATUS send_ocb_set_utc_time_cmd_tlv(wmi_unified_t wmi_handle,
34*5113495bSYour Name 						struct ocb_utc_param *utc)
35*5113495bSYour Name {
36*5113495bSYour Name 	QDF_STATUS ret;
37*5113495bSYour Name 	wmi_ocb_set_utc_time_cmd_fixed_param *cmd;
38*5113495bSYour Name 	uint8_t *buf_ptr;
39*5113495bSYour Name 	uint32_t len, i;
40*5113495bSYour Name 	wmi_buf_t buf;
41*5113495bSYour Name 
42*5113495bSYour Name 	len = sizeof(*cmd);
43*5113495bSYour Name 	buf = wmi_buf_alloc(wmi_handle, len);
44*5113495bSYour Name 	if (!buf) {
45*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
46*5113495bSYour Name 	}
47*5113495bSYour Name 
48*5113495bSYour Name 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
49*5113495bSYour Name 	cmd = (wmi_ocb_set_utc_time_cmd_fixed_param *)buf_ptr;
50*5113495bSYour Name 	WMITLV_SET_HDR(&cmd->tlv_header,
51*5113495bSYour Name 		WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param,
52*5113495bSYour Name 		WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_set_utc_time_cmd_fixed_param));
53*5113495bSYour Name 	cmd->vdev_id = utc->vdev_id;
54*5113495bSYour Name 
55*5113495bSYour Name 	for (i = 0; i < SIZE_UTC_TIME; i++)
56*5113495bSYour Name 		WMI_UTC_TIME_SET(cmd, i, utc->utc_time[i]);
57*5113495bSYour Name 
58*5113495bSYour Name 	for (i = 0; i < SIZE_UTC_TIME_ERROR; i++)
59*5113495bSYour Name 		WMI_TIME_ERROR_SET(cmd, i, utc->time_error[i]);
60*5113495bSYour Name 
61*5113495bSYour Name 	wmi_mtrace(WMI_OCB_SET_UTC_TIME_CMDID, cmd->vdev_id, 0);
62*5113495bSYour Name 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
63*5113495bSYour Name 				   WMI_OCB_SET_UTC_TIME_CMDID);
64*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(ret)) {
65*5113495bSYour Name 		wmi_err("Failed to set OCB UTC time");
66*5113495bSYour Name 		wmi_buf_free(buf);
67*5113495bSYour Name 	}
68*5113495bSYour Name 
69*5113495bSYour Name 	return ret;
70*5113495bSYour Name }
71*5113495bSYour Name 
72*5113495bSYour Name /**
73*5113495bSYour Name  * send_ocb_start_timing_advert_cmd_tlv() - start sending the timing advertisement
74*5113495bSYour Name  *				   frames on a channel
75*5113495bSYour Name  * @wmi_handle: pointer to the wmi handle
76*5113495bSYour Name  * @timing_advert: pointer to the timing advertisement struct
77*5113495bSYour Name  *
78*5113495bSYour Name  * Return: 0 on success
79*5113495bSYour Name  */
send_ocb_start_timing_advert_cmd_tlv(wmi_unified_t wmi_handle,struct ocb_timing_advert_param * timing_advert)80*5113495bSYour Name static QDF_STATUS send_ocb_start_timing_advert_cmd_tlv(wmi_unified_t wmi_handle,
81*5113495bSYour Name 				struct ocb_timing_advert_param *timing_advert)
82*5113495bSYour Name {
83*5113495bSYour Name 	QDF_STATUS ret;
84*5113495bSYour Name 	wmi_ocb_start_timing_advert_cmd_fixed_param *cmd;
85*5113495bSYour Name 	uint8_t *buf_ptr;
86*5113495bSYour Name 	uint32_t len, len_template;
87*5113495bSYour Name 	wmi_buf_t buf;
88*5113495bSYour Name 
89*5113495bSYour Name 	len = sizeof(*cmd) +
90*5113495bSYour Name 		     WMI_TLV_HDR_SIZE;
91*5113495bSYour Name 
92*5113495bSYour Name 	len_template = timing_advert->template_length;
93*5113495bSYour Name 	/* Add padding to the template if needed */
94*5113495bSYour Name 	if (len_template % 4 != 0)
95*5113495bSYour Name 		len_template += 4 - (len_template % 4);
96*5113495bSYour Name 	len += len_template;
97*5113495bSYour Name 
98*5113495bSYour Name 	buf = wmi_buf_alloc(wmi_handle, len);
99*5113495bSYour Name 	if (!buf) {
100*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
101*5113495bSYour Name 	}
102*5113495bSYour Name 
103*5113495bSYour Name 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
104*5113495bSYour Name 	cmd = (wmi_ocb_start_timing_advert_cmd_fixed_param *)buf_ptr;
105*5113495bSYour Name 	WMITLV_SET_HDR(&cmd->tlv_header,
106*5113495bSYour Name 		WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param,
107*5113495bSYour Name 		WMITLV_GET_STRUCT_TLVLEN(
108*5113495bSYour Name 			wmi_ocb_start_timing_advert_cmd_fixed_param));
109*5113495bSYour Name 	cmd->vdev_id = timing_advert->vdev_id;
110*5113495bSYour Name 	cmd->repeat_rate = timing_advert->repeat_rate;
111*5113495bSYour Name 	cmd->channel_freq = timing_advert->chan_freq;
112*5113495bSYour Name 	cmd->timestamp_offset = timing_advert->timestamp_offset;
113*5113495bSYour Name 	cmd->time_value_offset = timing_advert->time_value_offset;
114*5113495bSYour Name 	cmd->timing_advert_template_length = timing_advert->template_length;
115*5113495bSYour Name 	buf_ptr += sizeof(*cmd);
116*5113495bSYour Name 
117*5113495bSYour Name 	/* Add the timing advert template */
118*5113495bSYour Name 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
119*5113495bSYour Name 		       len_template);
120*5113495bSYour Name 	qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
121*5113495bSYour Name 		     (uint8_t *)timing_advert->template_value,
122*5113495bSYour Name 		     timing_advert->template_length);
123*5113495bSYour Name 
124*5113495bSYour Name 	wmi_mtrace(WMI_OCB_START_TIMING_ADVERT_CMDID, cmd->vdev_id, 0);
125*5113495bSYour Name 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
126*5113495bSYour Name 				   WMI_OCB_START_TIMING_ADVERT_CMDID);
127*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(ret)) {
128*5113495bSYour Name 		wmi_err("Failed to start OCB timing advert");
129*5113495bSYour Name 		wmi_buf_free(buf);
130*5113495bSYour Name 	}
131*5113495bSYour Name 
132*5113495bSYour Name 	return ret;
133*5113495bSYour Name }
134*5113495bSYour Name 
135*5113495bSYour Name /**
136*5113495bSYour Name  * send_ocb_stop_timing_advert_cmd_tlv() - stop sending the timing advertisement frames
137*5113495bSYour Name  *				  on a channel
138*5113495bSYour Name  * @wmi_handle: pointer to the wmi handle
139*5113495bSYour Name  * @timing_advert: pointer to the timing advertisement struct
140*5113495bSYour Name  *
141*5113495bSYour Name  * Return: 0 on success
142*5113495bSYour Name  */
send_ocb_stop_timing_advert_cmd_tlv(wmi_unified_t wmi_handle,struct ocb_timing_advert_param * timing_advert)143*5113495bSYour Name static QDF_STATUS send_ocb_stop_timing_advert_cmd_tlv(wmi_unified_t wmi_handle,
144*5113495bSYour Name 	struct ocb_timing_advert_param *timing_advert)
145*5113495bSYour Name {
146*5113495bSYour Name 	QDF_STATUS ret;
147*5113495bSYour Name 	wmi_ocb_stop_timing_advert_cmd_fixed_param *cmd;
148*5113495bSYour Name 	uint8_t *buf_ptr;
149*5113495bSYour Name 	uint32_t len;
150*5113495bSYour Name 	wmi_buf_t buf;
151*5113495bSYour Name 
152*5113495bSYour Name 	len = sizeof(*cmd);
153*5113495bSYour Name 	buf = wmi_buf_alloc(wmi_handle, len);
154*5113495bSYour Name 	if (!buf) {
155*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
156*5113495bSYour Name 	}
157*5113495bSYour Name 
158*5113495bSYour Name 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
159*5113495bSYour Name 	cmd = (wmi_ocb_stop_timing_advert_cmd_fixed_param *)buf_ptr;
160*5113495bSYour Name 	WMITLV_SET_HDR(&cmd->tlv_header,
161*5113495bSYour Name 		WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param,
162*5113495bSYour Name 		WMITLV_GET_STRUCT_TLVLEN(
163*5113495bSYour Name 			wmi_ocb_stop_timing_advert_cmd_fixed_param));
164*5113495bSYour Name 	cmd->vdev_id = timing_advert->vdev_id;
165*5113495bSYour Name 	cmd->channel_freq = timing_advert->chan_freq;
166*5113495bSYour Name 
167*5113495bSYour Name 	wmi_mtrace(WMI_OCB_STOP_TIMING_ADVERT_CMDID, cmd->vdev_id, 0);
168*5113495bSYour Name 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
169*5113495bSYour Name 				   WMI_OCB_STOP_TIMING_ADVERT_CMDID);
170*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(ret)) {
171*5113495bSYour Name 		wmi_err("Failed to stop OCB timing advert");
172*5113495bSYour Name 		wmi_buf_free(buf);
173*5113495bSYour Name 	}
174*5113495bSYour Name 
175*5113495bSYour Name 	return ret;
176*5113495bSYour Name }
177*5113495bSYour Name 
178*5113495bSYour Name /**
179*5113495bSYour Name  * send_ocb_get_tsf_timer_cmd_tlv() - get ocb tsf timer val
180*5113495bSYour Name  * @wmi_handle: pointer to the wmi handle
181*5113495bSYour Name  * @vdev_id: vdev identifier
182*5113495bSYour Name  *
183*5113495bSYour Name  * Return: 0 on success
184*5113495bSYour Name  */
send_ocb_get_tsf_timer_cmd_tlv(wmi_unified_t wmi_handle,uint8_t vdev_id)185*5113495bSYour Name static QDF_STATUS send_ocb_get_tsf_timer_cmd_tlv(wmi_unified_t wmi_handle,
186*5113495bSYour Name 			  uint8_t vdev_id)
187*5113495bSYour Name {
188*5113495bSYour Name 	QDF_STATUS ret;
189*5113495bSYour Name 	wmi_ocb_get_tsf_timer_cmd_fixed_param *cmd;
190*5113495bSYour Name 	uint8_t *buf_ptr;
191*5113495bSYour Name 	wmi_buf_t buf;
192*5113495bSYour Name 	int32_t len;
193*5113495bSYour Name 
194*5113495bSYour Name 	len = sizeof(*cmd);
195*5113495bSYour Name 	buf = wmi_buf_alloc(wmi_handle, len);
196*5113495bSYour Name 	if (!buf) {
197*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
198*5113495bSYour Name 	}
199*5113495bSYour Name 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
200*5113495bSYour Name 
201*5113495bSYour Name 	cmd = (wmi_ocb_get_tsf_timer_cmd_fixed_param *)buf_ptr;
202*5113495bSYour Name 	qdf_mem_zero(cmd, len);
203*5113495bSYour Name 	WMITLV_SET_HDR(&cmd->tlv_header,
204*5113495bSYour Name 		WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param,
205*5113495bSYour Name 		WMITLV_GET_STRUCT_TLVLEN(
206*5113495bSYour Name 			wmi_ocb_get_tsf_timer_cmd_fixed_param));
207*5113495bSYour Name 	cmd->vdev_id = vdev_id;
208*5113495bSYour Name 
209*5113495bSYour Name 	/* Send the WMI command */
210*5113495bSYour Name 	wmi_mtrace(WMI_OCB_GET_TSF_TIMER_CMDID, cmd->vdev_id, 0);
211*5113495bSYour Name 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
212*5113495bSYour Name 				   WMI_OCB_GET_TSF_TIMER_CMDID);
213*5113495bSYour Name 	/* If there is an error, set the completion event */
214*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(ret)) {
215*5113495bSYour Name 		wmi_err("Failed to send WMI message: %d", ret);
216*5113495bSYour Name 		wmi_buf_free(buf);
217*5113495bSYour Name 	}
218*5113495bSYour Name 
219*5113495bSYour Name 	return ret;
220*5113495bSYour Name }
221*5113495bSYour Name 
222*5113495bSYour Name /**
223*5113495bSYour Name  * send_dcc_get_stats_cmd_tlv() - get the DCC channel stats
224*5113495bSYour Name  * @wmi_handle: pointer to the wmi handle
225*5113495bSYour Name  * @get_stats_param: pointer to the dcc stats
226*5113495bSYour Name  *
227*5113495bSYour Name  * Return: 0 on success
228*5113495bSYour Name  */
send_dcc_get_stats_cmd_tlv(wmi_unified_t wmi_handle,struct ocb_dcc_get_stats_param * get_stats_param)229*5113495bSYour Name static QDF_STATUS send_dcc_get_stats_cmd_tlv(wmi_unified_t wmi_handle,
230*5113495bSYour Name 		     struct ocb_dcc_get_stats_param *get_stats_param)
231*5113495bSYour Name {
232*5113495bSYour Name 	QDF_STATUS ret;
233*5113495bSYour Name 	wmi_dcc_get_stats_cmd_fixed_param *cmd;
234*5113495bSYour Name 	wmi_dcc_channel_stats_request *channel_stats_array;
235*5113495bSYour Name 	wmi_buf_t buf;
236*5113495bSYour Name 	uint8_t *buf_ptr;
237*5113495bSYour Name 	uint32_t len;
238*5113495bSYour Name 	uint32_t i;
239*5113495bSYour Name 
240*5113495bSYour Name 	/* Validate the input */
241*5113495bSYour Name 	if (get_stats_param->request_array_len !=
242*5113495bSYour Name 	    get_stats_param->channel_count * sizeof(*channel_stats_array)) {
243*5113495bSYour Name 		wmi_err("Invalid parameter");
244*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
245*5113495bSYour Name 	}
246*5113495bSYour Name 
247*5113495bSYour Name 	/* Allocate memory for the WMI command */
248*5113495bSYour Name 	len = sizeof(*cmd) + WMI_TLV_HDR_SIZE +
249*5113495bSYour Name 		get_stats_param->request_array_len;
250*5113495bSYour Name 
251*5113495bSYour Name 	buf = wmi_buf_alloc(wmi_handle, len);
252*5113495bSYour Name 	if (!buf) {
253*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
254*5113495bSYour Name 	}
255*5113495bSYour Name 
256*5113495bSYour Name 	buf_ptr = wmi_buf_data(buf);
257*5113495bSYour Name 	qdf_mem_zero(buf_ptr, len);
258*5113495bSYour Name 
259*5113495bSYour Name 	/* Populate the WMI command */
260*5113495bSYour Name 	cmd = (wmi_dcc_get_stats_cmd_fixed_param *)buf_ptr;
261*5113495bSYour Name 	buf_ptr += sizeof(*cmd);
262*5113495bSYour Name 
263*5113495bSYour Name 	WMITLV_SET_HDR(&cmd->tlv_header,
264*5113495bSYour Name 		       WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param,
265*5113495bSYour Name 		       WMITLV_GET_STRUCT_TLVLEN(
266*5113495bSYour Name 			   wmi_dcc_get_stats_cmd_fixed_param));
267*5113495bSYour Name 	cmd->vdev_id = get_stats_param->vdev_id;
268*5113495bSYour Name 	cmd->num_channels = get_stats_param->channel_count;
269*5113495bSYour Name 
270*5113495bSYour Name 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
271*5113495bSYour Name 		       get_stats_param->request_array_len);
272*5113495bSYour Name 	buf_ptr += WMI_TLV_HDR_SIZE;
273*5113495bSYour Name 
274*5113495bSYour Name 	channel_stats_array = (wmi_dcc_channel_stats_request *)buf_ptr;
275*5113495bSYour Name 	qdf_mem_copy(channel_stats_array, get_stats_param->request_array,
276*5113495bSYour Name 		     get_stats_param->request_array_len);
277*5113495bSYour Name 	for (i = 0; i < cmd->num_channels; i++)
278*5113495bSYour Name 		WMITLV_SET_HDR(&channel_stats_array[i].tlv_header,
279*5113495bSYour Name 			       WMITLV_TAG_STRUC_wmi_dcc_channel_stats_request,
280*5113495bSYour Name 			       WMITLV_GET_STRUCT_TLVLEN(
281*5113495bSYour Name 					wmi_dcc_channel_stats_request));
282*5113495bSYour Name 
283*5113495bSYour Name 	/* Send the WMI command */
284*5113495bSYour Name 	wmi_mtrace(WMI_DCC_GET_STATS_CMDID, cmd->vdev_id, 0);
285*5113495bSYour Name 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
286*5113495bSYour Name 				   WMI_DCC_GET_STATS_CMDID);
287*5113495bSYour Name 
288*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(ret)) {
289*5113495bSYour Name 		wmi_err("Failed to send WMI message: %d", ret);
290*5113495bSYour Name 		wmi_buf_free(buf);
291*5113495bSYour Name 	}
292*5113495bSYour Name 
293*5113495bSYour Name 	return ret;
294*5113495bSYour Name }
295*5113495bSYour Name 
296*5113495bSYour Name /**
297*5113495bSYour Name  * send_dcc_clear_stats_cmd_tlv() - command to clear the DCC stats
298*5113495bSYour Name  * @wmi_handle: pointer to the wmi handle
299*5113495bSYour Name  * @vdev_id: vdev id
300*5113495bSYour Name  * @dcc_stats_bitmap: dcc status bitmap
301*5113495bSYour Name  *
302*5113495bSYour Name  * Return: 0 on success
303*5113495bSYour Name  */
send_dcc_clear_stats_cmd_tlv(wmi_unified_t wmi_handle,uint32_t vdev_id,uint32_t dcc_stats_bitmap)304*5113495bSYour Name static QDF_STATUS send_dcc_clear_stats_cmd_tlv(wmi_unified_t wmi_handle,
305*5113495bSYour Name 				uint32_t vdev_id, uint32_t dcc_stats_bitmap)
306*5113495bSYour Name {
307*5113495bSYour Name 	QDF_STATUS ret;
308*5113495bSYour Name 	wmi_dcc_clear_stats_cmd_fixed_param *cmd;
309*5113495bSYour Name 	wmi_buf_t buf;
310*5113495bSYour Name 	uint8_t *buf_ptr;
311*5113495bSYour Name 	uint32_t len;
312*5113495bSYour Name 
313*5113495bSYour Name 	/* Allocate memory for the WMI command */
314*5113495bSYour Name 	len = sizeof(*cmd);
315*5113495bSYour Name 
316*5113495bSYour Name 	buf = wmi_buf_alloc(wmi_handle, len);
317*5113495bSYour Name 	if (!buf) {
318*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
319*5113495bSYour Name 	}
320*5113495bSYour Name 
321*5113495bSYour Name 	buf_ptr = wmi_buf_data(buf);
322*5113495bSYour Name 	qdf_mem_zero(buf_ptr, len);
323*5113495bSYour Name 
324*5113495bSYour Name 	/* Populate the WMI command */
325*5113495bSYour Name 	cmd = (wmi_dcc_clear_stats_cmd_fixed_param *)buf_ptr;
326*5113495bSYour Name 
327*5113495bSYour Name 	WMITLV_SET_HDR(&cmd->tlv_header,
328*5113495bSYour Name 		       WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param,
329*5113495bSYour Name 		       WMITLV_GET_STRUCT_TLVLEN(
330*5113495bSYour Name 			   wmi_dcc_clear_stats_cmd_fixed_param));
331*5113495bSYour Name 	cmd->vdev_id = vdev_id;
332*5113495bSYour Name 	cmd->dcc_stats_bitmap = dcc_stats_bitmap;
333*5113495bSYour Name 
334*5113495bSYour Name 	/* Send the WMI command */
335*5113495bSYour Name 	wmi_mtrace(WMI_DCC_CLEAR_STATS_CMDID, cmd->vdev_id, 0);
336*5113495bSYour Name 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
337*5113495bSYour Name 				   WMI_DCC_CLEAR_STATS_CMDID);
338*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(ret)) {
339*5113495bSYour Name 		wmi_err("Failed to send the WMI command");
340*5113495bSYour Name 		wmi_buf_free(buf);
341*5113495bSYour Name 	}
342*5113495bSYour Name 
343*5113495bSYour Name 	return ret;
344*5113495bSYour Name }
345*5113495bSYour Name 
346*5113495bSYour Name /**
347*5113495bSYour Name  * send_dcc_update_ndl_cmd_tlv() - command to update the NDL data
348*5113495bSYour Name  * @wmi_handle: pointer to the wmi handle
349*5113495bSYour Name  * @update_ndl_param: pointer to the request parameters
350*5113495bSYour Name  *
351*5113495bSYour Name  * Return: 0 on success
352*5113495bSYour Name  */
send_dcc_update_ndl_cmd_tlv(wmi_unified_t wmi_handle,struct ocb_dcc_update_ndl_param * update_ndl_param)353*5113495bSYour Name static QDF_STATUS send_dcc_update_ndl_cmd_tlv(wmi_unified_t wmi_handle,
354*5113495bSYour Name 		       struct ocb_dcc_update_ndl_param *update_ndl_param)
355*5113495bSYour Name {
356*5113495bSYour Name 	QDF_STATUS qdf_status;
357*5113495bSYour Name 	wmi_dcc_update_ndl_cmd_fixed_param *cmd;
358*5113495bSYour Name 	wmi_dcc_ndl_chan *ndl_chan_array;
359*5113495bSYour Name 	wmi_dcc_ndl_active_state_config *ndl_active_state_array;
360*5113495bSYour Name 	uint32_t active_state_count;
361*5113495bSYour Name 	wmi_buf_t buf;
362*5113495bSYour Name 	uint8_t *buf_ptr;
363*5113495bSYour Name 	uint32_t len;
364*5113495bSYour Name 	uint32_t i;
365*5113495bSYour Name 
366*5113495bSYour Name 	/* validate the input */
367*5113495bSYour Name 	if (update_ndl_param->dcc_ndl_chan_list_len !=
368*5113495bSYour Name 	    update_ndl_param->channel_count * sizeof(*ndl_chan_array)) {
369*5113495bSYour Name 		wmi_err("Invalid parameter");
370*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
371*5113495bSYour Name 	}
372*5113495bSYour Name 	active_state_count = 0;
373*5113495bSYour Name 	ndl_chan_array = update_ndl_param->dcc_ndl_chan_list;
374*5113495bSYour Name 	for (i = 0; i < update_ndl_param->channel_count; i++)
375*5113495bSYour Name 		active_state_count +=
376*5113495bSYour Name 			WMI_NDL_NUM_ACTIVE_STATE_GET(&ndl_chan_array[i]);
377*5113495bSYour Name 	if (update_ndl_param->dcc_ndl_active_state_list_len !=
378*5113495bSYour Name 	    active_state_count * sizeof(*ndl_active_state_array)) {
379*5113495bSYour Name 		wmi_err("Invalid parameter");
380*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
381*5113495bSYour Name 	}
382*5113495bSYour Name 
383*5113495bSYour Name 	/* Allocate memory for the WMI command */
384*5113495bSYour Name 	len = sizeof(*cmd) +
385*5113495bSYour Name 		WMI_TLV_HDR_SIZE + update_ndl_param->dcc_ndl_chan_list_len +
386*5113495bSYour Name 		WMI_TLV_HDR_SIZE +
387*5113495bSYour Name 		update_ndl_param->dcc_ndl_active_state_list_len;
388*5113495bSYour Name 
389*5113495bSYour Name 	buf = wmi_buf_alloc(wmi_handle, len);
390*5113495bSYour Name 	if (!buf) {
391*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
392*5113495bSYour Name 	}
393*5113495bSYour Name 
394*5113495bSYour Name 	buf_ptr = wmi_buf_data(buf);
395*5113495bSYour Name 	qdf_mem_zero(buf_ptr, len);
396*5113495bSYour Name 
397*5113495bSYour Name 	/* Populate the WMI command */
398*5113495bSYour Name 	cmd = (wmi_dcc_update_ndl_cmd_fixed_param *)buf_ptr;
399*5113495bSYour Name 	buf_ptr += sizeof(*cmd);
400*5113495bSYour Name 
401*5113495bSYour Name 	WMITLV_SET_HDR(&cmd->tlv_header,
402*5113495bSYour Name 		       WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param,
403*5113495bSYour Name 		       WMITLV_GET_STRUCT_TLVLEN(
404*5113495bSYour Name 			   wmi_dcc_update_ndl_cmd_fixed_param));
405*5113495bSYour Name 	cmd->vdev_id = update_ndl_param->vdev_id;
406*5113495bSYour Name 	cmd->num_channel = update_ndl_param->channel_count;
407*5113495bSYour Name 
408*5113495bSYour Name 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
409*5113495bSYour Name 		       update_ndl_param->dcc_ndl_chan_list_len);
410*5113495bSYour Name 	buf_ptr += WMI_TLV_HDR_SIZE;
411*5113495bSYour Name 
412*5113495bSYour Name 	ndl_chan_array = (wmi_dcc_ndl_chan *)buf_ptr;
413*5113495bSYour Name 	qdf_mem_copy(ndl_chan_array, update_ndl_param->dcc_ndl_chan_list,
414*5113495bSYour Name 		     update_ndl_param->dcc_ndl_chan_list_len);
415*5113495bSYour Name 	for (i = 0; i < cmd->num_channel; i++)
416*5113495bSYour Name 		WMITLV_SET_HDR(&ndl_chan_array[i].tlv_header,
417*5113495bSYour Name 			       WMITLV_TAG_STRUC_wmi_dcc_ndl_chan,
418*5113495bSYour Name 			       WMITLV_GET_STRUCT_TLVLEN(
419*5113495bSYour Name 					wmi_dcc_ndl_chan));
420*5113495bSYour Name 	buf_ptr += update_ndl_param->dcc_ndl_chan_list_len;
421*5113495bSYour Name 
422*5113495bSYour Name 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
423*5113495bSYour Name 		       update_ndl_param->dcc_ndl_active_state_list_len);
424*5113495bSYour Name 	buf_ptr += WMI_TLV_HDR_SIZE;
425*5113495bSYour Name 
426*5113495bSYour Name 	ndl_active_state_array = (wmi_dcc_ndl_active_state_config *)buf_ptr;
427*5113495bSYour Name 	qdf_mem_copy(ndl_active_state_array,
428*5113495bSYour Name 		     update_ndl_param->dcc_ndl_active_state_list,
429*5113495bSYour Name 		     update_ndl_param->dcc_ndl_active_state_list_len);
430*5113495bSYour Name 	for (i = 0; i < active_state_count; i++) {
431*5113495bSYour Name 		WMITLV_SET_HDR(&ndl_active_state_array[i].tlv_header,
432*5113495bSYour Name 			WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config,
433*5113495bSYour Name 			WMITLV_GET_STRUCT_TLVLEN(
434*5113495bSYour Name 			    wmi_dcc_ndl_active_state_config));
435*5113495bSYour Name 	}
436*5113495bSYour Name 	buf_ptr += update_ndl_param->dcc_ndl_active_state_list_len;
437*5113495bSYour Name 
438*5113495bSYour Name 	/* Send the WMI command */
439*5113495bSYour Name 	wmi_mtrace(WMI_DCC_UPDATE_NDL_CMDID, cmd->vdev_id, 0);
440*5113495bSYour Name 	qdf_status = wmi_unified_cmd_send(wmi_handle, buf, len,
441*5113495bSYour Name 					  WMI_DCC_UPDATE_NDL_CMDID);
442*5113495bSYour Name 	/* If there is an error, set the completion event */
443*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(qdf_status)) {
444*5113495bSYour Name 		wmi_err("Failed to send WMI message: %d", qdf_status);
445*5113495bSYour Name 		wmi_buf_free(buf);
446*5113495bSYour Name 	}
447*5113495bSYour Name 
448*5113495bSYour Name 	return qdf_status;
449*5113495bSYour Name }
450*5113495bSYour Name 
451*5113495bSYour Name /**
452*5113495bSYour Name  * send_ocb_set_config_cmd_tlv() - send the OCB config to the FW
453*5113495bSYour Name  * @wmi_handle: pointer to the wmi handle
454*5113495bSYour Name  * @config: the OCB configuration
455*5113495bSYour Name  *
456*5113495bSYour Name  * Return: 0 on success
457*5113495bSYour Name  */
send_ocb_set_config_cmd_tlv(wmi_unified_t wmi_handle,struct ocb_config * config)458*5113495bSYour Name static QDF_STATUS send_ocb_set_config_cmd_tlv(wmi_unified_t wmi_handle,
459*5113495bSYour Name 					      struct ocb_config *config)
460*5113495bSYour Name {
461*5113495bSYour Name 	QDF_STATUS ret;
462*5113495bSYour Name 	wmi_ocb_set_config_cmd_fixed_param *cmd;
463*5113495bSYour Name 	wmi_channel *chan;
464*5113495bSYour Name 	wmi_ocb_channel *ocb_chan;
465*5113495bSYour Name 	wmi_qos_parameter *qos_param;
466*5113495bSYour Name 	wmi_dcc_ndl_chan *ndl_chan;
467*5113495bSYour Name 	wmi_dcc_ndl_active_state_config *ndl_active_config;
468*5113495bSYour Name 	wmi_ocb_schedule_element *sched_elem;
469*5113495bSYour Name 	uint8_t *buf_ptr;
470*5113495bSYour Name 	wmi_buf_t buf;
471*5113495bSYour Name 	int32_t len;
472*5113495bSYour Name 	int32_t i, j, active_state_count;
473*5113495bSYour Name 
474*5113495bSYour Name 	/*
475*5113495bSYour Name 	 * Validate the dcc_ndl_chan_list_len and count the number of active
476*5113495bSYour Name 	 * states. Validate dcc_ndl_active_state_list_len.
477*5113495bSYour Name 	 */
478*5113495bSYour Name 	active_state_count = 0;
479*5113495bSYour Name 	if (config->dcc_ndl_chan_list_len) {
480*5113495bSYour Name 		if (!config->dcc_ndl_chan_list ||
481*5113495bSYour Name 			config->dcc_ndl_chan_list_len !=
482*5113495bSYour Name 			config->channel_count * sizeof(wmi_dcc_ndl_chan)) {
483*5113495bSYour Name 			wmi_err("NDL channel is invalid. List len: %d",
484*5113495bSYour Name 				 config->dcc_ndl_chan_list_len);
485*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
486*5113495bSYour Name 		}
487*5113495bSYour Name 
488*5113495bSYour Name 		for (i = 0, ndl_chan = config->dcc_ndl_chan_list;
489*5113495bSYour Name 				i < config->channel_count; ++i, ++ndl_chan)
490*5113495bSYour Name 			active_state_count +=
491*5113495bSYour Name 				WMI_NDL_NUM_ACTIVE_STATE_GET(ndl_chan);
492*5113495bSYour Name 
493*5113495bSYour Name 		if (active_state_count) {
494*5113495bSYour Name 			if (!config->dcc_ndl_active_state_list ||
495*5113495bSYour Name 				config->dcc_ndl_active_state_list_len !=
496*5113495bSYour Name 				active_state_count *
497*5113495bSYour Name 				sizeof(wmi_dcc_ndl_active_state_config)) {
498*5113495bSYour Name 				wmi_err("NDL active state is invalid");
499*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
500*5113495bSYour Name 			}
501*5113495bSYour Name 		}
502*5113495bSYour Name 	}
503*5113495bSYour Name 
504*5113495bSYour Name 	len = sizeof(*cmd) +
505*5113495bSYour Name 		WMI_TLV_HDR_SIZE + config->channel_count *
506*5113495bSYour Name 			sizeof(wmi_channel) +
507*5113495bSYour Name 		WMI_TLV_HDR_SIZE + config->channel_count *
508*5113495bSYour Name 			sizeof(wmi_ocb_channel) +
509*5113495bSYour Name 		WMI_TLV_HDR_SIZE + config->channel_count *
510*5113495bSYour Name 			sizeof(wmi_qos_parameter) * WMI_MAX_NUM_AC +
511*5113495bSYour Name 		WMI_TLV_HDR_SIZE + config->dcc_ndl_chan_list_len +
512*5113495bSYour Name 		WMI_TLV_HDR_SIZE + active_state_count *
513*5113495bSYour Name 			sizeof(wmi_dcc_ndl_active_state_config) +
514*5113495bSYour Name 		WMI_TLV_HDR_SIZE + config->schedule_size *
515*5113495bSYour Name 			sizeof(wmi_ocb_schedule_element);
516*5113495bSYour Name 	buf = wmi_buf_alloc(wmi_handle, len);
517*5113495bSYour Name 	if (!buf) {
518*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
519*5113495bSYour Name 	}
520*5113495bSYour Name 
521*5113495bSYour Name 	buf_ptr = (uint8_t *)wmi_buf_data(buf);
522*5113495bSYour Name 	cmd = (wmi_ocb_set_config_cmd_fixed_param *)buf_ptr;
523*5113495bSYour Name 	WMITLV_SET_HDR(&cmd->tlv_header,
524*5113495bSYour Name 		WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param,
525*5113495bSYour Name 		WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_set_config_cmd_fixed_param));
526*5113495bSYour Name 	cmd->vdev_id = config->vdev_id;
527*5113495bSYour Name 	cmd->channel_count = config->channel_count;
528*5113495bSYour Name 	cmd->schedule_size = config->schedule_size;
529*5113495bSYour Name 	cmd->flags = config->flags;
530*5113495bSYour Name 	buf_ptr += sizeof(*cmd);
531*5113495bSYour Name 
532*5113495bSYour Name 	/* Add the wmi_channel info */
533*5113495bSYour Name 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
534*5113495bSYour Name 		       config->channel_count * sizeof(wmi_channel));
535*5113495bSYour Name 	buf_ptr += WMI_TLV_HDR_SIZE;
536*5113495bSYour Name 	for (i = 0; i < config->channel_count; i++) {
537*5113495bSYour Name 		chan = (wmi_channel *)buf_ptr;
538*5113495bSYour Name 		WMITLV_SET_HDR(&chan->tlv_header,
539*5113495bSYour Name 			       WMITLV_TAG_STRUC_wmi_channel,
540*5113495bSYour Name 			       WMITLV_GET_STRUCT_TLVLEN(wmi_channel));
541*5113495bSYour Name 		chan->mhz = config->channels[i].chan_freq;
542*5113495bSYour Name 		chan->band_center_freq1 = config->channels[i].chan_freq;
543*5113495bSYour Name 		chan->band_center_freq2 = 0;
544*5113495bSYour Name 		chan->info = 0;
545*5113495bSYour Name 
546*5113495bSYour Name 		WMI_SET_CHANNEL_MODE(chan, config->channels[i].ch_mode);
547*5113495bSYour Name 		WMI_SET_CHANNEL_MAX_POWER(chan, config->channels[i].max_pwr);
548*5113495bSYour Name 		WMI_SET_CHANNEL_MIN_POWER(chan, config->channels[i].min_pwr);
549*5113495bSYour Name 		WMI_SET_CHANNEL_MAX_TX_POWER(chan, config->channels[i].max_pwr);
550*5113495bSYour Name 		WMI_SET_CHANNEL_REG_POWER(chan, config->channels[i].reg_pwr);
551*5113495bSYour Name 		WMI_SET_CHANNEL_ANTENNA_MAX(chan,
552*5113495bSYour Name 					    config->channels[i].antenna_max);
553*5113495bSYour Name 
554*5113495bSYour Name 		if (config->channels[i].bandwidth < 10)
555*5113495bSYour Name 			WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_QUARTER_RATE);
556*5113495bSYour Name 		else if (config->channels[i].bandwidth < 20)
557*5113495bSYour Name 			WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_HALF_RATE);
558*5113495bSYour Name 		buf_ptr += sizeof(*chan);
559*5113495bSYour Name 	}
560*5113495bSYour Name 
561*5113495bSYour Name 	/* Add the wmi_ocb_channel info */
562*5113495bSYour Name 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
563*5113495bSYour Name 		       config->channel_count * sizeof(wmi_ocb_channel));
564*5113495bSYour Name 	buf_ptr += WMI_TLV_HDR_SIZE;
565*5113495bSYour Name 	for (i = 0; i < config->channel_count; i++) {
566*5113495bSYour Name 		ocb_chan = (wmi_ocb_channel *)buf_ptr;
567*5113495bSYour Name 		WMITLV_SET_HDR(&ocb_chan->tlv_header,
568*5113495bSYour Name 			       WMITLV_TAG_STRUC_wmi_ocb_channel,
569*5113495bSYour Name 			       WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_channel));
570*5113495bSYour Name 		ocb_chan->bandwidth = config->channels[i].bandwidth;
571*5113495bSYour Name 		WMI_CHAR_ARRAY_TO_MAC_ADDR(
572*5113495bSYour Name 					config->channels[i].mac_address.bytes,
573*5113495bSYour Name 					&ocb_chan->mac_address);
574*5113495bSYour Name 		buf_ptr += sizeof(*ocb_chan);
575*5113495bSYour Name 	}
576*5113495bSYour Name 
577*5113495bSYour Name 	/* Add the wmi_qos_parameter info */
578*5113495bSYour Name 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
579*5113495bSYour Name 		config->channel_count * sizeof(wmi_qos_parameter)*WMI_MAX_NUM_AC);
580*5113495bSYour Name 	buf_ptr += WMI_TLV_HDR_SIZE;
581*5113495bSYour Name 	/* WMI_MAX_NUM_AC parameters for each channel */
582*5113495bSYour Name 	for (i = 0; i < config->channel_count; i++) {
583*5113495bSYour Name 		for (j = 0; j < WMI_MAX_NUM_AC; j++) {
584*5113495bSYour Name 			qos_param = (wmi_qos_parameter *)buf_ptr;
585*5113495bSYour Name 			WMITLV_SET_HDR(&qos_param->tlv_header,
586*5113495bSYour Name 				WMITLV_TAG_STRUC_wmi_qos_parameter,
587*5113495bSYour Name 				WMITLV_GET_STRUCT_TLVLEN(wmi_qos_parameter));
588*5113495bSYour Name 			qos_param->aifsn =
589*5113495bSYour Name 				config->channels[i].qos_params[j].aifsn;
590*5113495bSYour Name 			qos_param->cwmin =
591*5113495bSYour Name 				config->channels[i].qos_params[j].cwmin;
592*5113495bSYour Name 			qos_param->cwmax =
593*5113495bSYour Name 				config->channels[i].qos_params[j].cwmax;
594*5113495bSYour Name 			buf_ptr += sizeof(*qos_param);
595*5113495bSYour Name 		}
596*5113495bSYour Name 	}
597*5113495bSYour Name 
598*5113495bSYour Name 	/* Add the wmi_dcc_ndl_chan (per channel) */
599*5113495bSYour Name 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
600*5113495bSYour Name 		       config->dcc_ndl_chan_list_len);
601*5113495bSYour Name 	buf_ptr += WMI_TLV_HDR_SIZE;
602*5113495bSYour Name 	if (config->dcc_ndl_chan_list_len) {
603*5113495bSYour Name 		ndl_chan = (wmi_dcc_ndl_chan *)buf_ptr;
604*5113495bSYour Name 		qdf_mem_copy(ndl_chan, config->dcc_ndl_chan_list,
605*5113495bSYour Name 			     config->dcc_ndl_chan_list_len);
606*5113495bSYour Name 		for (i = 0; i < config->channel_count; i++)
607*5113495bSYour Name 			WMITLV_SET_HDR(&(ndl_chan[i].tlv_header),
608*5113495bSYour Name 				WMITLV_TAG_STRUC_wmi_dcc_ndl_chan,
609*5113495bSYour Name 				WMITLV_GET_STRUCT_TLVLEN(wmi_dcc_ndl_chan));
610*5113495bSYour Name 		buf_ptr += config->dcc_ndl_chan_list_len;
611*5113495bSYour Name 	}
612*5113495bSYour Name 
613*5113495bSYour Name 	/* Add the wmi_dcc_ndl_active_state_config */
614*5113495bSYour Name 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, active_state_count *
615*5113495bSYour Name 		       sizeof(wmi_dcc_ndl_active_state_config));
616*5113495bSYour Name 	buf_ptr += WMI_TLV_HDR_SIZE;
617*5113495bSYour Name 	if (active_state_count) {
618*5113495bSYour Name 		ndl_active_config = (wmi_dcc_ndl_active_state_config *)buf_ptr;
619*5113495bSYour Name 		qdf_mem_copy(ndl_active_config,
620*5113495bSYour Name 			config->dcc_ndl_active_state_list,
621*5113495bSYour Name 			active_state_count * sizeof(*ndl_active_config));
622*5113495bSYour Name 		for (i = 0; i < active_state_count; ++i)
623*5113495bSYour Name 			WMITLV_SET_HDR(&(ndl_active_config[i].tlv_header),
624*5113495bSYour Name 			  WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config,
625*5113495bSYour Name 			  WMITLV_GET_STRUCT_TLVLEN(
626*5113495bSYour Name 				wmi_dcc_ndl_active_state_config));
627*5113495bSYour Name 		buf_ptr += active_state_count *
628*5113495bSYour Name 			sizeof(*ndl_active_config);
629*5113495bSYour Name 	}
630*5113495bSYour Name 
631*5113495bSYour Name 	/* Add the wmi_ocb_schedule_element info */
632*5113495bSYour Name 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
633*5113495bSYour Name 		config->schedule_size * sizeof(wmi_ocb_schedule_element));
634*5113495bSYour Name 	buf_ptr += WMI_TLV_HDR_SIZE;
635*5113495bSYour Name 	for (i = 0; i < config->schedule_size; i++) {
636*5113495bSYour Name 		sched_elem = (wmi_ocb_schedule_element *)buf_ptr;
637*5113495bSYour Name 		WMITLV_SET_HDR(&sched_elem->tlv_header,
638*5113495bSYour Name 			WMITLV_TAG_STRUC_wmi_ocb_schedule_element,
639*5113495bSYour Name 			WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_schedule_element));
640*5113495bSYour Name 		sched_elem->channel_freq = config->schedule[i].chan_freq;
641*5113495bSYour Name 		sched_elem->total_duration = config->schedule[i].total_duration;
642*5113495bSYour Name 		sched_elem->guard_interval = config->schedule[i].guard_interval;
643*5113495bSYour Name 		buf_ptr += sizeof(*sched_elem);
644*5113495bSYour Name 	}
645*5113495bSYour Name 
646*5113495bSYour Name 	wmi_mtrace(WMI_OCB_SET_CONFIG_CMDID, cmd->vdev_id, 0);
647*5113495bSYour Name 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
648*5113495bSYour Name 				   WMI_OCB_SET_CONFIG_CMDID);
649*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(ret)) {
650*5113495bSYour Name 		wmi_err("Failed to set OCB config");
651*5113495bSYour Name 		wmi_buf_free(buf);
652*5113495bSYour Name 	}
653*5113495bSYour Name 
654*5113495bSYour Name 	return ret;
655*5113495bSYour Name }
656*5113495bSYour Name 
657*5113495bSYour Name /**
658*5113495bSYour Name  * extract_ocb_channel_config_resp_tlv() - extract ocb channel config resp
659*5113495bSYour Name  * @wmi_handle: wmi handle
660*5113495bSYour Name  * @evt_buf: wmi event buffer
661*5113495bSYour Name  * @status: status buffer
662*5113495bSYour Name  *
663*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success
664*5113495bSYour Name  */
extract_ocb_channel_config_resp_tlv(wmi_unified_t wmi_handle,void * evt_buf,uint32_t * status)665*5113495bSYour Name static QDF_STATUS extract_ocb_channel_config_resp_tlv(wmi_unified_t wmi_handle,
666*5113495bSYour Name 						      void *evt_buf,
667*5113495bSYour Name 						      uint32_t *status)
668*5113495bSYour Name {
669*5113495bSYour Name 	WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *param_tlvs;
670*5113495bSYour Name 	wmi_ocb_set_config_resp_event_fixed_param *fix_param;
671*5113495bSYour Name 
672*5113495bSYour Name 	param_tlvs = evt_buf;
673*5113495bSYour Name 	fix_param = param_tlvs->fixed_param;
674*5113495bSYour Name 
675*5113495bSYour Name 	*status = fix_param->status;
676*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
677*5113495bSYour Name }
678*5113495bSYour Name 
679*5113495bSYour Name /**
680*5113495bSYour Name  * extract_ocb_tsf_timer_tlv() - extract TSF timer from event buffer
681*5113495bSYour Name  * @wmi_handle: wmi handle
682*5113495bSYour Name  * @evt_buf: wmi event buffer
683*5113495bSYour Name  * @resp: response buffer
684*5113495bSYour Name  *
685*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success
686*5113495bSYour Name  */
extract_ocb_tsf_timer_tlv(wmi_unified_t wmi_handle,void * evt_buf,struct ocb_get_tsf_timer_response * resp)687*5113495bSYour Name static QDF_STATUS extract_ocb_tsf_timer_tlv(wmi_unified_t wmi_handle,
688*5113495bSYour Name 			void *evt_buf, struct ocb_get_tsf_timer_response *resp)
689*5113495bSYour Name {
690*5113495bSYour Name 	WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *param_tlvs;
691*5113495bSYour Name 	wmi_ocb_get_tsf_timer_resp_event_fixed_param *fix_param;
692*5113495bSYour Name 
693*5113495bSYour Name 	param_tlvs = evt_buf;
694*5113495bSYour Name 	fix_param = param_tlvs->fixed_param;
695*5113495bSYour Name 	resp->vdev_id = fix_param->vdev_id;
696*5113495bSYour Name 	resp->timer_high = fix_param->tsf_timer_high;
697*5113495bSYour Name 	resp->timer_low = fix_param->tsf_timer_low;
698*5113495bSYour Name 
699*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
700*5113495bSYour Name }
701*5113495bSYour Name 
702*5113495bSYour Name /**
703*5113495bSYour Name  * extract_ocb_ndl_resp_tlv() - extract TSF timer from event buffer
704*5113495bSYour Name  * @wmi_handle: wmi handle
705*5113495bSYour Name  * @evt_buf: wmi event buffer
706*5113495bSYour Name  * @resp: response buffer
707*5113495bSYour Name  *
708*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success
709*5113495bSYour Name  */
extract_ocb_ndl_resp_tlv(wmi_unified_t wmi_handle,void * evt_buf,struct ocb_dcc_update_ndl_response * resp)710*5113495bSYour Name static QDF_STATUS extract_ocb_ndl_resp_tlv(wmi_unified_t wmi_handle,
711*5113495bSYour Name 		void *evt_buf, struct ocb_dcc_update_ndl_response *resp)
712*5113495bSYour Name {
713*5113495bSYour Name 	WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *param_tlvs;
714*5113495bSYour Name 	wmi_dcc_update_ndl_resp_event_fixed_param *fix_param;
715*5113495bSYour Name 
716*5113495bSYour Name 	param_tlvs = evt_buf;
717*5113495bSYour Name 	fix_param = param_tlvs->fixed_param;
718*5113495bSYour Name 	resp->vdev_id = fix_param->vdev_id;
719*5113495bSYour Name 	resp->status = fix_param->status;
720*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
721*5113495bSYour Name }
722*5113495bSYour Name 
723*5113495bSYour Name /**
724*5113495bSYour Name  * extract_ocb_dcc_stats_tlv() - extract DCC stats from event buffer
725*5113495bSYour Name  * @wmi_handle: wmi handle
726*5113495bSYour Name  * @evt_buf: wmi event buffer
727*5113495bSYour Name  * @resp: response buffer
728*5113495bSYour Name  *
729*5113495bSYour Name  * Since length of stats is variable, buffer for DCC stats will be allocated
730*5113495bSYour Name  * in this function. The caller must free the buffer.
731*5113495bSYour Name  *
732*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success
733*5113495bSYour Name  */
extract_ocb_dcc_stats_tlv(wmi_unified_t wmi_handle,void * evt_buf,struct ocb_dcc_get_stats_response ** resp)734*5113495bSYour Name static QDF_STATUS extract_ocb_dcc_stats_tlv(wmi_unified_t wmi_handle,
735*5113495bSYour Name 		void *evt_buf, struct ocb_dcc_get_stats_response **resp)
736*5113495bSYour Name {
737*5113495bSYour Name 	struct ocb_dcc_get_stats_response *response;
738*5113495bSYour Name 	WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *param_tlvs;
739*5113495bSYour Name 	wmi_dcc_get_stats_resp_event_fixed_param *fix_param;
740*5113495bSYour Name 
741*5113495bSYour Name 	param_tlvs = (WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *)evt_buf;
742*5113495bSYour Name 	fix_param = param_tlvs->fixed_param;
743*5113495bSYour Name 
744*5113495bSYour Name 	/* Allocate and populate the response */
745*5113495bSYour Name 	if (fix_param->num_channels > ((WMI_SVC_MSG_MAX_SIZE -
746*5113495bSYour Name 	    sizeof(*fix_param)) / sizeof(wmi_dcc_ndl_stats_per_channel)) ||
747*5113495bSYour Name 	    fix_param->num_channels > param_tlvs->num_stats_per_channel_list) {
748*5113495bSYour Name 		wmi_warn("Too many channels:%d actual:%d",
749*5113495bSYour Name 			 fix_param->num_channels,
750*5113495bSYour Name 			 param_tlvs->num_stats_per_channel_list);
751*5113495bSYour Name 		*resp = NULL;
752*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
753*5113495bSYour Name 	}
754*5113495bSYour Name 	response = qdf_mem_malloc(sizeof(*response) + fix_param->num_channels *
755*5113495bSYour Name 				  sizeof(wmi_dcc_ndl_stats_per_channel));
756*5113495bSYour Name 	*resp = response;
757*5113495bSYour Name 	if (!response)
758*5113495bSYour Name 		return  QDF_STATUS_E_NOMEM;
759*5113495bSYour Name 
760*5113495bSYour Name 	response->vdev_id = fix_param->vdev_id;
761*5113495bSYour Name 	response->num_channels = fix_param->num_channels;
762*5113495bSYour Name 	response->channel_stats_array_len =
763*5113495bSYour Name 		fix_param->num_channels *
764*5113495bSYour Name 		sizeof(wmi_dcc_ndl_stats_per_channel);
765*5113495bSYour Name 	response->channel_stats_array = ((uint8_t *)response) +
766*5113495bSYour Name 					sizeof(*response);
767*5113495bSYour Name 	qdf_mem_copy(response->channel_stats_array,
768*5113495bSYour Name 		     param_tlvs->stats_per_channel_list,
769*5113495bSYour Name 		     response->channel_stats_array_len);
770*5113495bSYour Name 
771*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
772*5113495bSYour Name }
773*5113495bSYour Name 
wmi_ocb_attach_tlv(wmi_unified_t wmi_handle)774*5113495bSYour Name void wmi_ocb_attach_tlv(wmi_unified_t wmi_handle)
775*5113495bSYour Name {
776*5113495bSYour Name 	struct wmi_ops *ops = wmi_handle->ops;
777*5113495bSYour Name 
778*5113495bSYour Name 	ops->send_ocb_set_utc_time_cmd = send_ocb_set_utc_time_cmd_tlv;
779*5113495bSYour Name 	ops->send_ocb_get_tsf_timer_cmd = send_ocb_get_tsf_timer_cmd_tlv;
780*5113495bSYour Name 	ops->send_dcc_clear_stats_cmd = send_dcc_clear_stats_cmd_tlv;
781*5113495bSYour Name 	ops->send_dcc_get_stats_cmd = send_dcc_get_stats_cmd_tlv;
782*5113495bSYour Name 	ops->send_dcc_update_ndl_cmd = send_dcc_update_ndl_cmd_tlv;
783*5113495bSYour Name 	ops->send_ocb_set_config_cmd = send_ocb_set_config_cmd_tlv;
784*5113495bSYour Name 	ops->send_ocb_stop_timing_advert_cmd =
785*5113495bSYour Name 			send_ocb_stop_timing_advert_cmd_tlv;
786*5113495bSYour Name 	ops->send_ocb_start_timing_advert_cmd =
787*5113495bSYour Name 			send_ocb_start_timing_advert_cmd_tlv;
788*5113495bSYour Name 	ops->extract_ocb_chan_config_resp =
789*5113495bSYour Name 			extract_ocb_channel_config_resp_tlv;
790*5113495bSYour Name 	ops->extract_ocb_tsf_timer = extract_ocb_tsf_timer_tlv;
791*5113495bSYour Name 	ops->extract_dcc_update_ndl_resp = extract_ocb_ndl_resp_tlv;
792*5113495bSYour Name 	ops->extract_dcc_stats = extract_ocb_dcc_stats_tlv;
793*5113495bSYour Name }
794