xref: /wlan-dirver/qca-wifi-host-cmn/wmi/src/wmi_unified_cp_stats_tlv.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "osdep.h"
18 #include "wmi.h"
19 #include "wmi_unified_priv.h"
20 #include "wmi_unified_param.h"
21 #include "target_if_cp_stats.h"
22 #include <wlan_cp_stats_public_structs.h>
23 
24 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
25 #ifdef WLAN_SUPPORT_TWT
26 static uint32_t
27 get_stats_req_twt_dialog_id(struct infra_cp_stats_cmd_info *req)
28 {
29 	return req->dialog_id;
30 }
31 
32 static enum WMI_HOST_GET_STATS_TWT_STATUS
33 wmi_get_converted_twt_get_stats_status(WMI_GET_STATS_TWT_STATUS_T tgt_status)
34 {
35 	switch (tgt_status) {
36 	case WMI_GET_STATS_TWT_STATUS_OK:
37 		return WMI_HOST_GET_STATS_TWT_STATUS_OK;
38 	case WMI_GET_STATS_TWT_STATUS_DIALOG_ID_NOT_EXIST:
39 		return WMI_HOST_GET_STATS_TWT_STATUS_DIALOG_ID_NOT_EXIST;
40 	case WMI_GET_STATS_TWT_STATUS_INVALID_PARAM:
41 		return WMI_HOST_GET_STATS_TWT_STATUS_INVALID_PARAM;
42 	default:
43 		return WMI_HOST_GET_STATS_TWT_STATUS_UNKNOWN_ERROR;
44 	}
45 }
46 
47 static inline
48 void wmi_extract_ctrl_path_twt_stats_tlv(void *tag_buf,
49 					 struct twt_infra_cp_stats_event *param)
50 {
51 	wmi_ctrl_path_twt_stats_struct *wmi_stats_buf =
52 			(wmi_ctrl_path_twt_stats_struct *)tag_buf;
53 
54 	param->dialog_id = wmi_stats_buf->dialog_id;
55 	param->status = wmi_get_converted_twt_get_stats_status(wmi_stats_buf->status);
56 	param->num_sp_cycles = wmi_stats_buf->num_sp_cycles;
57 	param->avg_sp_dur_us = wmi_stats_buf->avg_sp_dur_us;
58 	param->min_sp_dur_us = wmi_stats_buf->min_sp_dur_us;
59 	param->max_sp_dur_us = wmi_stats_buf->max_sp_dur_us;
60 	param->tx_mpdu_per_sp = wmi_stats_buf->tx_mpdu_per_sp;
61 	param->rx_mpdu_per_sp = wmi_stats_buf->rx_mpdu_per_sp;
62 	param->tx_bytes_per_sp = wmi_stats_buf->tx_bytes_per_sp;
63 	param->rx_bytes_per_sp = wmi_stats_buf->rx_bytes_per_sp;
64 
65 	wmi_debug("dialog_id = %u status = %u", wmi_stats_buf->dialog_id,
66 		  wmi_stats_buf->status);
67 	wmi_debug("num_sp_cycles = %u avg_sp_dur_us = 0x%x, \
68 		  min_sp_dur_us = 0x%x, max_sp_dur_us = 0x%x",
69 		  wmi_stats_buf->num_sp_cycles, wmi_stats_buf->avg_sp_dur_us,
70 		  wmi_stats_buf->min_sp_dur_us, wmi_stats_buf->max_sp_dur_us);
71 	wmi_debug("tx_mpdu_per_sp 0x%x, rx_mpdu_per_sp = 0x%x, \
72 		  tx_bytes_per_sp = 0x%x, rx_bytes_per_sp = 0x%x",
73 		  wmi_stats_buf->tx_mpdu_per_sp, wmi_stats_buf->rx_mpdu_per_sp,
74 		  wmi_stats_buf->tx_bytes_per_sp,
75 		  wmi_stats_buf->rx_bytes_per_sp);
76 }
77 
78 static void wmi_twt_extract_stats_struct(void *tag_buf,
79 					 struct infra_cp_stats_event *params)
80 {
81 	struct twt_infra_cp_stats_event *twt_params;
82 
83 	twt_params = params->twt_infra_cp_stats +
84 		     params->num_twt_infra_cp_stats;
85 
86 	wmi_debug("TWT stats struct found - num_twt_cp_stats %d",
87 		  params->num_twt_infra_cp_stats);
88 
89 	params->num_twt_infra_cp_stats++;
90 	wmi_extract_ctrl_path_twt_stats_tlv(tag_buf, twt_params);
91 }
92 #else
93 static inline
94 uint32_t get_stats_req_twt_dialog_id(struct infra_cp_stats_cmd_info *req)
95 {
96 	return 0;
97 }
98 
99 static void wmi_twt_extract_stats_struct(void *tag_buf,
100 					 struct infra_cp_stats_event *params)
101 {
102 }
103 #endif /* WLAN_SUPPORT_TWT */
104 
105 /*
106  * wmi_stats_extract_tag_struct: function to extract tag structs
107  * @tag_type: tag type that is to be printed
108  * @tag_buf: pointer to the tag structure
109  * @params: buffer to hold parameters extracted from response event
110  *
111  * Return: None
112  */
113 static void wmi_stats_extract_tag_struct(uint32_t tag_type, void *tag_buf,
114 					 struct infra_cp_stats_event *params)
115 {
116 	wmi_debug("tag_type %d", tag_type);
117 
118 	switch (tag_type) {
119 	case WMITLV_TAG_STRUC_wmi_ctrl_path_pdev_stats_struct:
120 		break;
121 
122 	case WMITLV_TAG_STRUC_wmi_ctrl_path_mem_stats_struct:
123 		break;
124 
125 	case WMITLV_TAG_STRUC_wmi_ctrl_path_twt_stats_struct:
126 		wmi_twt_extract_stats_struct(tag_buf, params);
127 		break;
128 
129 	default:
130 		break;
131 	}
132 }
133 
134 /*
135  * wmi_stats_handler: parse the wmi event and fill the stats values
136  * @buff: Buffer containing wmi event
137  * @len: length of event buffer
138  * @params: buffer to hold parameters extracted from response event
139  *
140  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
141  */
142 QDF_STATUS wmi_stats_handler(void *buff, int32_t len,
143 			     struct infra_cp_stats_event *params)
144 {
145 	WMI_CTRL_PATH_STATS_EVENTID_param_tlvs *param_buf;
146 	wmi_ctrl_path_stats_event_fixed_param *ev;
147 	uint8_t *buf_ptr = (uint8_t *)buff;
148 	uint32_t curr_tlv_tag;
149 	uint32_t curr_tlv_len;
150 	uint8_t *tag_start_ptr;
151 
152 	param_buf = (WMI_CTRL_PATH_STATS_EVENTID_param_tlvs *)buff;
153 	if (!param_buf) {
154 		wmi_err_rl("param_buf is NULL");
155 		return QDF_STATUS_E_FAILURE;
156 	}
157 	ev = (wmi_ctrl_path_stats_event_fixed_param *)param_buf->fixed_param;
158 
159 	curr_tlv_tag = WMITLV_GET_TLVTAG(ev->tlv_header);
160 	curr_tlv_len = WMITLV_GET_TLVLEN(ev->tlv_header);
161 	buf_ptr = (uint8_t *)param_buf->fixed_param;
162 	wmi_debug("Fixed param more %d req_id %d status %d", ev->more,
163 		  ev->request_id, ev->status);
164 	params->request_id = ev->request_id;
165 	params->status = ev->status;
166 
167 	/* buffer should point to next TLV in event */
168 	buf_ptr += (curr_tlv_len + WMI_TLV_HDR_SIZE);
169 	len -= (curr_tlv_len + WMI_TLV_HDR_SIZE);
170 
171 	curr_tlv_tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr));
172 	curr_tlv_len = WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr));
173 
174 	wmi_debug("curr_tlv_len %d curr_tlv_tag %d rem_len %d", len,
175 		  curr_tlv_len, curr_tlv_tag);
176 
177 	while ((len >= curr_tlv_len) &&
178 	       (curr_tlv_tag >= WMITLV_TAG_FIRST_ARRAY_ENUM)) {
179 		if (curr_tlv_tag == WMITLV_TAG_ARRAY_STRUC) {
180 			/* Move to next WMITLV_TAG_ARRAY_STRUC */
181 			buf_ptr += WMI_TLV_HDR_SIZE;
182 			len -= WMI_TLV_HDR_SIZE;
183 			if (len <= 0)
184 				break;
185 		}
186 		curr_tlv_tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr));
187 		curr_tlv_len = WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr));
188 
189 		wmi_debug("curr_tlv_len %d curr_tlv_tag %d rem_len %d",
190 			  len, curr_tlv_len, curr_tlv_tag);
191 		if (curr_tlv_len) {
192 			/* point to the tag inside WMITLV_TAG_ARRAY_STRUC */
193 			tag_start_ptr = buf_ptr + WMI_TLV_HDR_SIZE;
194 			curr_tlv_tag = WMITLV_GET_TLVTAG(
195 						WMITLV_GET_HDR(tag_start_ptr));
196 			wmi_stats_extract_tag_struct(curr_tlv_tag,
197 						     (void *)tag_start_ptr,
198 						     params);
199 		}
200 		/* Move to next tag */
201 		buf_ptr += curr_tlv_len + WMI_TLV_HDR_SIZE;
202 		len -= (curr_tlv_len + WMI_TLV_HDR_SIZE);
203 
204 		if (len <= 0)
205 			break;
206 	}
207 
208 	return QDF_STATUS_SUCCESS;
209 }
210 
211 /**
212  * extract_infra_cp_stats_tlv - api to extract stats information from
213  * event buffer
214  * @wmi_handle:  wmi handle
215  * @evt_buf:     event buffer
216  * @evt_buf_len: length of the event buffer
217  * @params:      buffer to populate more flag
218  *
219  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
220  */
221 QDF_STATUS
222 extract_infra_cp_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf,
223 			   uint32_t evt_buf_len,
224 			   struct infra_cp_stats_event *params)
225 {
226 	wmi_stats_handler(evt_buf, evt_buf_len, params);
227 	return QDF_STATUS_SUCCESS;
228 }
229 
230 /**
231  * prepare_infra_cp_stats_buf() - Allocate and prepate wmi cmd request buffer
232  * @wmi_handle: wmi handle
233  * @stats_req: Request parameters to be filled in wmi cmd request buffer
234  * @req_buf_len: length of the output wmi cmd buffer allocated
235  *
236  * Return: Valid wmi buffer pointer on success and NULL pointer for failure
237  */
238 static wmi_buf_t
239 prepare_infra_cp_stats_buf(wmi_unified_t wmi_handle,
240 			   struct infra_cp_stats_cmd_info *stats_req,
241 			   uint32_t *req_buf_len)
242 {
243 	wmi_request_ctrl_path_stats_cmd_fixed_param *cmd_fixed_param;
244 	uint32_t index;
245 	wmi_buf_t req_buf;
246 	uint8_t *buf_ptr;
247 	uint32_t *pdev_id_array;
248 	uint32_t *vdev_id_array;
249 	uint8_t *mac_addr_array;
250 	uint32_t *dialog_id_array;
251 	uint32_t num_pdev_ids = stats_req->num_pdev_ids;
252 	uint32_t num_vdev_ids = stats_req->num_vdev_ids;
253 	uint32_t num_mac_addr_list = stats_req->num_mac_addr_list;
254 	uint32_t num_dialog_ids = INFRA_CP_STATS_MAX_REQ_TWT_DIALOG_ID;
255 
256 	/* Calculate total buffer length */
257 	*req_buf_len = (sizeof(wmi_request_ctrl_path_stats_cmd_fixed_param) +
258 		       WMI_TLV_HDR_SIZE + (sizeof(A_UINT32) * (num_pdev_ids)) +
259 		       WMI_TLV_HDR_SIZE + sizeof(A_UINT32) * (num_vdev_ids) +
260 		       WMI_TLV_HDR_SIZE +
261 		       sizeof(wmi_mac_addr) * (num_mac_addr_list) +
262 		       WMI_TLV_HDR_SIZE +
263 		       (sizeof(A_UINT32) * (num_dialog_ids)));
264 	req_buf = wmi_buf_alloc(wmi_handle, *req_buf_len);
265 	if (!req_buf)
266 		return NULL;
267 
268 	cmd_fixed_param = (wmi_request_ctrl_path_stats_cmd_fixed_param *)
269 				wmi_buf_data(req_buf);
270 
271 	/*Set TLV header*/
272 	WMITLV_SET_HDR(&cmd_fixed_param->tlv_header,
273 		WMITLV_TAG_STRUC_wmi_request_ctrl_path_stats_cmd_fixed_param,
274 		WMITLV_GET_STRUCT_TLVLEN(
275 				wmi_request_ctrl_path_stats_cmd_fixed_param));
276 
277 	index = get_infra_cp_stats_id(stats_req->stats_id);
278 	cmd_fixed_param->stats_id_mask = (1 << index);
279 
280 	cmd_fixed_param->request_id = stats_req->action;
281 	cmd_fixed_param->action = get_infra_cp_stats_action(stats_req->action);
282 
283 	buf_ptr = (uint8_t *)cmd_fixed_param;
284 	/* Setting tlv header for pdev id arrays*/
285 	buf_ptr = buf_ptr + sizeof(*cmd_fixed_param);
286 	pdev_id_array = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE);
287 	WMITLV_SET_HDR(buf_ptr,  WMITLV_TAG_ARRAY_UINT32,
288 		       sizeof(A_UINT32) * num_pdev_ids);
289 
290 	/* Setting tlv header for vdev id arrays*/
291 	buf_ptr = buf_ptr + WMI_TLV_HDR_SIZE +
292 		  (sizeof(A_UINT32) * num_pdev_ids);
293 	vdev_id_array = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE);
294 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
295 		       sizeof(A_UINT32) * num_vdev_ids);
296 
297 	/* Setting tlv header for mac addr arrays*/
298 	buf_ptr = buf_ptr + WMI_TLV_HDR_SIZE +
299 		  (sizeof(A_UINT32) * num_vdev_ids);
300 	mac_addr_array = buf_ptr + WMI_TLV_HDR_SIZE;
301 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC,
302 		       sizeof(wmi_mac_addr) * num_mac_addr_list);
303 
304 	/* Setting tlv header for dialog id arrays*/
305 	buf_ptr = buf_ptr + WMI_TLV_HDR_SIZE +
306 		  sizeof(wmi_mac_addr) * num_mac_addr_list;
307 	dialog_id_array = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE);
308 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
309 		       sizeof(A_UINT32) * num_dialog_ids);
310 
311 	for (index = 0; index < num_pdev_ids; index++)
312 		pdev_id_array[index] = stats_req->pdev_id[index];
313 
314 	for (index = 0; index < num_vdev_ids; index++)
315 		vdev_id_array[index] = stats_req->vdev_id[index];
316 
317 	for (index = 0; index < num_mac_addr_list; index++) {
318 		qdf_mem_copy(mac_addr_array, stats_req->peer_mac_addr[index],
319 			     QDF_MAC_ADDR_SIZE);
320 		mac_addr_array += QDF_MAC_ADDR_SIZE;
321 	}
322 
323 	dialog_id_array[0] = get_stats_req_twt_dialog_id(stats_req);
324 
325 	wmi_debug("stats_id_mask 0x%x action 0x%x dialog_id %d",
326 		  cmd_fixed_param->stats_id_mask, cmd_fixed_param->action,
327 		  dialog_id_array[0]);
328 	wmi_debug("num_pdev_ids %d num_vdev_ids %d num_dialog_ids %d \
329 		   num_mac_addr %d", num_pdev_ids, num_vdev_ids,
330 		   num_dialog_ids, num_mac_addr_list);
331 
332 	return req_buf;
333 }
334 
335 /**
336  * send_infra_cp_stats_request_cmd_tlv() - Prepare and send infra_cp_stats
337  * wmi cmd to firmware
338  * @wmi_handle: wmi handle
339  * @param: Pointer to request structure
340  *
341  * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes
342  * on failure
343  */
344 static QDF_STATUS
345 send_infra_cp_stats_request_cmd_tlv(wmi_unified_t wmi_handle,
346 				    struct infra_cp_stats_cmd_info *param)
347 {
348 	uint32_t len;
349 	wmi_buf_t buf;
350 	QDF_STATUS status;
351 
352 	buf = prepare_infra_cp_stats_buf(wmi_handle, param, &len);
353 	if (!buf)
354 		return QDF_STATUS_E_NOMEM;
355 
356 	wmi_debug("buf_len %d", len);
357 
358 	wmi_mtrace(WMI_REQUEST_CTRL_PATH_STATS_CMDID, NO_SESSION, 0);
359 	status = wmi_unified_cmd_send(wmi_handle, buf,
360 				      len, WMI_REQUEST_CTRL_PATH_STATS_CMDID);
361 
362 	if (QDF_IS_STATUS_ERROR(status)) {
363 		wmi_buf_free(buf);
364 		return QDF_STATUS_E_FAILURE;
365 	}
366 
367 	return QDF_STATUS_SUCCESS;
368 }
369 #else
370 static inline QDF_STATUS
371 send_infra_cp_stats_request_cmd_tlv(wmi_unified_t wmi_handle,
372 				    struct infra_cp_stats_cmd_info *param)
373 {
374 	return QDF_STATUS_SUCCESS;
375 }
376 #endif
377 
378 #ifdef QCA_WIFI_EMULATION
379 static QDF_STATUS
380 send_stats_request_cmd_tlv(wmi_unified_t wmi_handle,
381 			   uint8_t macaddr[QDF_MAC_ADDR_SIZE],
382 			   struct stats_request_params *param)
383 {
384 	return QDF_STATUS_SUCCESS;
385 }
386 #else
387 /**
388  * send_stats_request_cmd_tlv() - WMI request stats function
389  * @param wmi_handle: handle to WMI.
390  * @param macaddr: MAC address
391  * @param param: pointer to hold stats request parameter
392  *
393  * Return: 0  on success and -ve on failure.
394  */
395 static QDF_STATUS
396 send_stats_request_cmd_tlv(wmi_unified_t wmi_handle,
397 			   uint8_t macaddr[QDF_MAC_ADDR_SIZE],
398 			   struct stats_request_params *param)
399 {
400 	int32_t ret;
401 	wmi_request_stats_cmd_fixed_param *cmd;
402 	wmi_buf_t buf;
403 	uint16_t len = sizeof(wmi_request_stats_cmd_fixed_param);
404 
405 	buf = wmi_buf_alloc(wmi_handle, len);
406 	if (!buf)
407 		return QDF_STATUS_E_NOMEM;
408 
409 	cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf);
410 	WMITLV_SET_HDR(&cmd->tlv_header,
411 		       WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param,
412 		       WMITLV_GET_STRUCT_TLVLEN
413 			       (wmi_request_stats_cmd_fixed_param));
414 	cmd->stats_id = param->stats_id;
415 	cmd->vdev_id = param->vdev_id;
416 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
417 							wmi_handle,
418 							param->pdev_id);
419 
420 	WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr);
421 
422 	wmi_debug("STATS REQ STATS_ID:%d VDEV_ID:%d PDEV_ID:%d-->",
423 		 cmd->stats_id, cmd->vdev_id, cmd->pdev_id);
424 
425 	wmi_mtrace(WMI_REQUEST_STATS_CMDID, cmd->vdev_id, 0);
426 	ret = wmi_unified_cmd_send_pm_chk(wmi_handle, buf, len,
427 					  WMI_REQUEST_STATS_CMDID);
428 
429 	if (ret) {
430 		wmi_err("Failed to send stats request to fw =%d", ret);
431 		wmi_buf_free(buf);
432 	}
433 
434 	return qdf_status_from_os_return(ret);
435 }
436 #endif
437 
438 #ifdef WLAN_FEATURE_BIG_DATA_STATS
439 /**
440  * send_big_data_stats_request_cmd_tlv () - send big data stats cmd
441  * @wmi_handle: wmi handle
442  * @param : pointer to command request param
443  *
444  * Return: QDF_STATUS_SUCCESS for success or error code
445  */
446 static QDF_STATUS
447 send_big_data_stats_request_cmd_tlv(wmi_unified_t wmi_handle,
448 				    struct stats_request_params *param)
449 {
450 	int32_t ret = 0;
451 	wmi_vdev_get_big_data_p2_cmd_fixed_param *cmd;
452 	wmi_buf_t buf;
453 	uint16_t len = sizeof(wmi_vdev_get_big_data_p2_cmd_fixed_param);
454 
455 	buf = wmi_buf_alloc(wmi_handle, len);
456 	if (!buf)
457 		return QDF_STATUS_E_NOMEM;
458 
459 	cmd = (wmi_vdev_get_big_data_p2_cmd_fixed_param *)wmi_buf_data(buf);
460 	WMITLV_SET_HDR(
461 		&cmd->tlv_header,
462 		WMITLV_TAG_STRUC_wmi_vdev_get_big_data_p2_cmd_fixed_param,
463 		WMITLV_GET_STRUCT_TLVLEN
464 		(wmi_vdev_get_big_data_p2_cmd_fixed_param));
465 
466 	cmd->vdev_id = param->vdev_id;
467 
468 	wmi_debug("STATS VDEV_ID:%d -->", cmd->vdev_id);
469 
470 	wmi_mtrace(WMI_VDEV_GET_BIG_DATA_P2_CMDID, cmd->vdev_id, 0);
471 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
472 				   WMI_VDEV_GET_BIG_DATA_P2_CMDID);
473 
474 	if (ret) {
475 		wmi_err("Failed to send big data stats request to fw =%d", ret);
476 		wmi_buf_free(buf);
477 	}
478 
479 	return qdf_status_from_os_return(ret);
480 }
481 #endif
482 
483 /**
484  * extract_all_stats_counts_tlv() - extract all stats count from event
485  * @param wmi_handle: wmi handle
486  * @param evt_buf: pointer to event buffer
487  * @param stats_param: Pointer to hold stats count
488  *
489  * Return: QDF_STATUS_SUCCESS for success or error code
490  */
491 static QDF_STATUS
492 extract_all_stats_counts_tlv(wmi_unified_t wmi_handle, void *evt_buf,
493 			     wmi_host_stats_event *stats_param)
494 {
495 	wmi_stats_event_fixed_param *ev;
496 	wmi_per_chain_rssi_stats *rssi_event;
497 	WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
498 	uint64_t min_data_len;
499 	uint32_t i;
500 
501 	qdf_mem_zero(stats_param, sizeof(*stats_param));
502 	param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf;
503 	ev = (wmi_stats_event_fixed_param *) param_buf->fixed_param;
504 	rssi_event = param_buf->chain_stats;
505 	if (!ev) {
506 		wmi_err("event fixed param NULL");
507 		return QDF_STATUS_E_FAILURE;
508 	}
509 
510 	if (param_buf->num_data > WMI_SVC_MSG_MAX_SIZE - sizeof(*ev)) {
511 		wmi_err("num_data : %u is invalid", param_buf->num_data);
512 		return QDF_STATUS_E_FAULT;
513 	}
514 
515 	for (i = 1; i <= WMI_REQUEST_VDEV_EXTD_STAT; i = i << 1) {
516 		switch (ev->stats_id & i) {
517 		case WMI_REQUEST_PEER_STAT:
518 			stats_param->stats_id |= WMI_HOST_REQUEST_PEER_STAT;
519 			break;
520 
521 		case WMI_REQUEST_AP_STAT:
522 			stats_param->stats_id |= WMI_HOST_REQUEST_AP_STAT;
523 			break;
524 
525 		case WMI_REQUEST_PDEV_STAT:
526 			stats_param->stats_id |= WMI_HOST_REQUEST_PDEV_STAT;
527 			break;
528 
529 		case WMI_REQUEST_VDEV_STAT:
530 			stats_param->stats_id |= WMI_HOST_REQUEST_VDEV_STAT;
531 			break;
532 
533 		case WMI_REQUEST_BCNFLT_STAT:
534 			stats_param->stats_id |= WMI_HOST_REQUEST_BCNFLT_STAT;
535 			break;
536 
537 		case WMI_REQUEST_VDEV_RATE_STAT:
538 			stats_param->stats_id |=
539 				WMI_HOST_REQUEST_VDEV_RATE_STAT;
540 			break;
541 
542 		case WMI_REQUEST_BCN_STAT:
543 			stats_param->stats_id |= WMI_HOST_REQUEST_BCN_STAT;
544 			break;
545 		case WMI_REQUEST_PEER_EXTD_STAT:
546 			stats_param->stats_id |= WMI_REQUEST_PEER_EXTD_STAT;
547 			break;
548 
549 		case WMI_REQUEST_PEER_EXTD2_STAT:
550 			stats_param->stats_id |=
551 				WMI_HOST_REQUEST_PEER_ADV_STATS;
552 			break;
553 
554 		case WMI_REQUEST_PMF_BCN_PROTECT_STAT:
555 			stats_param->stats_id |=
556 				WMI_HOST_REQUEST_PMF_BCN_PROTECT_STAT;
557 			break;
558 
559 		case WMI_REQUEST_VDEV_EXTD_STAT:
560 			stats_param->stats_id |=
561 				WMI_HOST_REQUEST_VDEV_PRB_FILS_STAT;
562 			break;
563 		}
564 	}
565 
566 	/* ev->num_*_stats may cause uint32_t overflow, so use uint64_t
567 	 * to save total length calculated
568 	 */
569 	min_data_len =
570 		(((uint64_t)ev->num_pdev_stats) * sizeof(wmi_pdev_stats)) +
571 		(((uint64_t)ev->num_vdev_stats) * sizeof(wmi_vdev_stats)) +
572 		(((uint64_t)ev->num_peer_stats) * sizeof(wmi_peer_stats)) +
573 		(((uint64_t)ev->num_bcnflt_stats) *
574 		 sizeof(wmi_bcnfilter_stats_t)) +
575 		(((uint64_t)ev->num_chan_stats) * sizeof(wmi_chan_stats)) +
576 		(((uint64_t)ev->num_mib_stats) * sizeof(wmi_mib_stats)) +
577 		(((uint64_t)ev->num_bcn_stats) * sizeof(wmi_bcn_stats)) +
578 		(((uint64_t)ev->num_peer_extd_stats) *
579 		 sizeof(wmi_peer_extd_stats)) +
580 		(((uint64_t)ev->num_mib_extd_stats) *
581 		 sizeof(wmi_mib_extd_stats));
582 	if (param_buf->num_data != min_data_len) {
583 		wmi_err("data len: %u isn't same as calculated: %llu",
584 			 param_buf->num_data, min_data_len);
585 		return QDF_STATUS_E_FAULT;
586 	}
587 
588 	stats_param->last_event = ev->last_event;
589 	stats_param->num_pdev_stats = ev->num_pdev_stats;
590 	stats_param->num_pdev_ext_stats = 0;
591 	stats_param->num_vdev_stats = ev->num_vdev_stats;
592 	stats_param->num_peer_stats = ev->num_peer_stats;
593 	stats_param->num_peer_extd_stats = ev->num_peer_extd_stats;
594 	stats_param->num_bcnflt_stats = ev->num_bcnflt_stats;
595 	stats_param->num_chan_stats = ev->num_chan_stats;
596 	stats_param->num_mib_stats = ev->num_mib_stats;
597 	stats_param->num_mib_extd_stats = ev->num_mib_extd_stats;
598 	stats_param->num_bcn_stats = ev->num_bcn_stats;
599 	stats_param->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host(
600 							wmi_handle,
601 							ev->pdev_id);
602 
603 	/* if chain_stats is not populated */
604 	if (!param_buf->chain_stats || !param_buf->num_chain_stats)
605 		return QDF_STATUS_SUCCESS;
606 
607 	if (WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats !=
608 	    WMITLV_GET_TLVTAG(rssi_event->tlv_header))
609 		return QDF_STATUS_SUCCESS;
610 
611 	if (WMITLV_GET_STRUCT_TLVLEN(wmi_per_chain_rssi_stats) !=
612 	    WMITLV_GET_TLVLEN(rssi_event->tlv_header))
613 		return QDF_STATUS_SUCCESS;
614 
615 	if (rssi_event->num_per_chain_rssi_stats >=
616 	    WMITLV_GET_TLVLEN(rssi_event->tlv_header)) {
617 		wmi_err("num_per_chain_rssi_stats:%u is out of bounds",
618 			 rssi_event->num_per_chain_rssi_stats);
619 		return QDF_STATUS_E_INVAL;
620 	}
621 	stats_param->num_rssi_stats = rssi_event->num_per_chain_rssi_stats;
622 
623 	if (param_buf->vdev_extd_stats)
624 		stats_param->num_vdev_extd_stats =
625 			param_buf->num_vdev_extd_stats;
626 
627 	/* if peer_adv_stats is not populated */
628 	if (param_buf->num_peer_extd2_stats)
629 		stats_param->num_peer_adv_stats =
630 			param_buf->num_peer_extd2_stats;
631 
632 	return QDF_STATUS_SUCCESS;
633 }
634 
635 /**
636  * extract_pdev_tx_stats() - extract pdev tx stats from event
637  */
638 static void extract_pdev_tx_stats(wmi_host_dbg_tx_stats *tx,
639 				  struct wlan_dbg_tx_stats *tx_stats)
640 {
641 	/* Tx Stats */
642 	tx->comp_queued = tx_stats->comp_queued;
643 	tx->comp_delivered = tx_stats->comp_delivered;
644 	tx->msdu_enqued = tx_stats->msdu_enqued;
645 	tx->mpdu_enqued = tx_stats->mpdu_enqued;
646 	tx->wmm_drop = tx_stats->wmm_drop;
647 	tx->local_enqued = tx_stats->local_enqued;
648 	tx->local_freed = tx_stats->local_freed;
649 	tx->hw_queued = tx_stats->hw_queued;
650 	tx->hw_reaped = tx_stats->hw_reaped;
651 	tx->underrun = tx_stats->underrun;
652 	tx->tx_abort = tx_stats->tx_abort;
653 	tx->mpdus_requed = tx_stats->mpdus_requed;
654 	tx->data_rc = tx_stats->data_rc;
655 	tx->self_triggers = tx_stats->self_triggers;
656 	tx->sw_retry_failure = tx_stats->sw_retry_failure;
657 	tx->illgl_rate_phy_err = tx_stats->illgl_rate_phy_err;
658 	tx->pdev_cont_xretry = tx_stats->pdev_cont_xretry;
659 	tx->pdev_tx_timeout = tx_stats->pdev_tx_timeout;
660 	tx->pdev_resets = tx_stats->pdev_resets;
661 	tx->stateless_tid_alloc_failure = tx_stats->stateless_tid_alloc_failure;
662 	tx->phy_underrun = tx_stats->phy_underrun;
663 	tx->txop_ovf = tx_stats->txop_ovf;
664 
665 	return;
666 }
667 
668 
669 /**
670  * extract_pdev_rx_stats() - extract pdev rx stats from event
671  */
672 static void extract_pdev_rx_stats(wmi_host_dbg_rx_stats *rx,
673 				  struct wlan_dbg_rx_stats *rx_stats)
674 {
675 	/* Rx Stats */
676 	rx->mid_ppdu_route_change = rx_stats->mid_ppdu_route_change;
677 	rx->status_rcvd = rx_stats->status_rcvd;
678 	rx->r0_frags = rx_stats->r0_frags;
679 	rx->r1_frags = rx_stats->r1_frags;
680 	rx->r2_frags = rx_stats->r2_frags;
681 	/* Only TLV */
682 	rx->r3_frags = 0;
683 	rx->htt_msdus = rx_stats->htt_msdus;
684 	rx->htt_mpdus = rx_stats->htt_mpdus;
685 	rx->loc_msdus = rx_stats->loc_msdus;
686 	rx->loc_mpdus = rx_stats->loc_mpdus;
687 	rx->oversize_amsdu = rx_stats->oversize_amsdu;
688 	rx->phy_errs = rx_stats->phy_errs;
689 	rx->phy_err_drop = rx_stats->phy_err_drop;
690 	rx->mpdu_errs = rx_stats->mpdu_errs;
691 
692 	return;
693 }
694 
695 /**
696  * extract_pdev_stats_tlv() - extract pdev stats from event
697  * @param wmi_handle: wmi handle
698  * @param evt_buf: pointer to event buffer
699  * @param index: Index into pdev stats
700  * @param pdev_stats: Pointer to hold pdev stats
701  *
702  * Return: QDF_STATUS_SUCCESS for success or error code
703  */
704 static QDF_STATUS
705 extract_pdev_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, uint32_t index,
706 		       wmi_host_pdev_stats *pdev_stats)
707 {
708 	WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
709 	wmi_stats_event_fixed_param *ev_param;
710 	uint8_t *data;
711 
712 	param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf;
713 	ev_param = (wmi_stats_event_fixed_param *) param_buf->fixed_param;
714 	pdev_stats->pdev_id =
715 	     wmi_handle->ops->convert_pdev_id_target_to_host(wmi_handle,
716 							     ev_param->pdev_id);
717 
718 	data = param_buf->data;
719 
720 	if (index < ev_param->num_pdev_stats) {
721 		wmi_pdev_stats *ev = (wmi_pdev_stats *) ((data) +
722 				(index * sizeof(wmi_pdev_stats)));
723 
724 		pdev_stats->chan_nf = ev->chan_nf;
725 		pdev_stats->tx_frame_count = ev->tx_frame_count;
726 		pdev_stats->rx_frame_count = ev->rx_frame_count;
727 		pdev_stats->rx_clear_count = ev->rx_clear_count;
728 		pdev_stats->cycle_count = ev->cycle_count;
729 		pdev_stats->phy_err_count = ev->phy_err_count;
730 		pdev_stats->chan_tx_pwr = ev->chan_tx_pwr;
731 
732 		extract_pdev_tx_stats(&(pdev_stats->pdev_stats.tx),
733 			&(ev->pdev_stats.tx));
734 		extract_pdev_rx_stats(&(pdev_stats->pdev_stats.rx),
735 			&(ev->pdev_stats.rx));
736 	}
737 
738 	return QDF_STATUS_SUCCESS;
739 }
740 
741 /**
742  * extract_vdev_stats_tlv() - extract vdev stats from event
743  * @param wmi_handle: wmi handle
744  * @param evt_buf: pointer to event buffer
745  * @param index: Index into vdev stats
746  * @param vdev_stats: Pointer to hold vdev stats
747  *
748  * Return: QDF_STATUS_SUCCESS for success or error code
749  */
750 static QDF_STATUS extract_vdev_stats_tlv(wmi_unified_t wmi_handle,
751 	void *evt_buf, uint32_t index, wmi_host_vdev_stats *vdev_stats)
752 {
753 	WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
754 	wmi_stats_event_fixed_param *ev_param;
755 	uint8_t *data;
756 
757 	param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf;
758 	ev_param = (wmi_stats_event_fixed_param *) param_buf->fixed_param;
759 	data = (uint8_t *) param_buf->data;
760 
761 	if (index < ev_param->num_vdev_stats) {
762 		wmi_vdev_stats *ev = (wmi_vdev_stats *) ((data) +
763 				((ev_param->num_pdev_stats) *
764 				sizeof(wmi_pdev_stats)) +
765 				(index * sizeof(wmi_vdev_stats)));
766 
767 		vdev_stats->vdev_id = ev->vdev_id;
768 		vdev_stats->vdev_snr.bcn_snr = ev->vdev_snr.bcn_snr;
769 		vdev_stats->vdev_snr.dat_snr = ev->vdev_snr.dat_snr;
770 
771 		OS_MEMCPY(vdev_stats->tx_frm_cnt, ev->tx_frm_cnt,
772 			sizeof(ev->tx_frm_cnt));
773 		vdev_stats->rx_frm_cnt = ev->rx_frm_cnt;
774 		OS_MEMCPY(vdev_stats->multiple_retry_cnt,
775 				ev->multiple_retry_cnt,
776 				sizeof(ev->multiple_retry_cnt));
777 		OS_MEMCPY(vdev_stats->fail_cnt, ev->fail_cnt,
778 				sizeof(ev->fail_cnt));
779 		vdev_stats->rts_fail_cnt = ev->rts_fail_cnt;
780 		vdev_stats->rts_succ_cnt = ev->rts_succ_cnt;
781 		vdev_stats->rx_err_cnt = ev->rx_err_cnt;
782 		vdev_stats->rx_discard_cnt = ev->rx_discard_cnt;
783 		vdev_stats->ack_fail_cnt = ev->ack_fail_cnt;
784 		OS_MEMCPY(vdev_stats->tx_rate_history, ev->tx_rate_history,
785 			sizeof(ev->tx_rate_history));
786 		OS_MEMCPY(vdev_stats->bcn_rssi_history, ev->bcn_rssi_history,
787 			sizeof(ev->bcn_rssi_history));
788 
789 	}
790 
791 	return QDF_STATUS_SUCCESS;
792 }
793 
794 /**
795  * extract_peer_stats_tlv() - extract peer stats from event
796  * @param wmi_handle: wmi handle
797  * @param evt_buf: pointer to event buffer
798  * @param index: Index into peer stats
799  * @param peer_stats: Pointer to hold peer stats
800  *
801  * Return: QDF_STATUS_SUCCESS for success or error code
802  */
803 static QDF_STATUS
804 extract_peer_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, uint32_t index,
805 		       wmi_host_peer_stats *peer_stats)
806 {
807 	WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
808 	wmi_stats_event_fixed_param *ev_param;
809 	uint8_t *data;
810 
811 	param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf;
812 	ev_param = (wmi_stats_event_fixed_param *) param_buf->fixed_param;
813 	data = (uint8_t *) param_buf->data;
814 
815 	if (index < ev_param->num_peer_stats) {
816 		wmi_peer_stats *ev = (wmi_peer_stats *) ((data) +
817 			((ev_param->num_pdev_stats) * sizeof(wmi_pdev_stats)) +
818 			((ev_param->num_vdev_stats) * sizeof(wmi_vdev_stats)) +
819 			(index * sizeof(wmi_peer_stats)));
820 
821 		OS_MEMSET(peer_stats, 0, sizeof(wmi_host_peer_stats));
822 
823 		OS_MEMCPY(&(peer_stats->peer_macaddr),
824 			&(ev->peer_macaddr), sizeof(wmi_mac_addr));
825 
826 		peer_stats->peer_rssi = ev->peer_rssi;
827 		peer_stats->peer_tx_rate = ev->peer_tx_rate;
828 		peer_stats->peer_rx_rate = ev->peer_rx_rate;
829 	}
830 
831 	return QDF_STATUS_SUCCESS;
832 }
833 
834 /**
835  * extract_peer_extd_stats_tlv() - extract extended peer stats from event
836  * @param wmi_handle: wmi handle
837  * @param evt_buf: pointer to event buffer
838  * @param index: Index into extended peer stats
839  * @param peer_extd_stats: Pointer to hold extended peer stats
840  *
841  * Return: QDF_STATUS_SUCCESS for success or error code
842  */
843 static QDF_STATUS
844 extract_peer_extd_stats_tlv(wmi_unified_t wmi_handle,
845 			    void *evt_buf, uint32_t index,
846 			    wmi_host_peer_extd_stats *peer_extd_stats)
847 {
848 	WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
849 	wmi_stats_event_fixed_param *ev_param;
850 	uint8_t *data;
851 
852 	param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *)evt_buf;
853 	ev_param = (wmi_stats_event_fixed_param *)param_buf->fixed_param;
854 	data = (uint8_t *)param_buf->data;
855 	if (!data)
856 		return QDF_STATUS_E_FAILURE;
857 
858 	if (index < ev_param->num_peer_extd_stats) {
859 		wmi_peer_extd_stats *ev = (wmi_peer_extd_stats *) (data +
860 			(ev_param->num_pdev_stats * sizeof(wmi_pdev_stats)) +
861 			(ev_param->num_vdev_stats * sizeof(wmi_vdev_stats)) +
862 			(ev_param->num_peer_stats * sizeof(wmi_peer_stats)) +
863 			(ev_param->num_bcnflt_stats *
864 			sizeof(wmi_bcnfilter_stats_t)) +
865 			(ev_param->num_chan_stats * sizeof(wmi_chan_stats)) +
866 			(ev_param->num_mib_stats * sizeof(wmi_mib_stats)) +
867 			(ev_param->num_bcn_stats * sizeof(wmi_bcn_stats)) +
868 			(index * sizeof(wmi_peer_extd_stats)));
869 
870 		qdf_mem_zero(peer_extd_stats, sizeof(wmi_host_peer_extd_stats));
871 		qdf_mem_copy(&peer_extd_stats->peer_macaddr, &ev->peer_macaddr,
872 			     sizeof(wmi_mac_addr));
873 
874 		peer_extd_stats->rx_mc_bc_cnt = ev->rx_mc_bc_cnt;
875 	}
876 
877 	return QDF_STATUS_SUCCESS;
878 
879 }
880 
881 /**
882  * extract_pmf_bcn_protect_stats_tlv() - extract pmf bcn stats from event
883  * @wmi_handle: wmi handle
884  * @evt_buf: pointer to event buffer
885  * @pmf_bcn_stats: Pointer to hold pmf bcn protect stats
886  *
887  * Return: QDF_STATUS_SUCCESS for success or error code
888  */
889 
890 static QDF_STATUS
891 extract_pmf_bcn_protect_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf,
892 				  wmi_host_pmf_bcn_protect_stats *pmf_bcn_stats)
893 {
894 	WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
895 	wmi_stats_event_fixed_param *ev_param;
896 
897 	param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *)evt_buf;
898 	if (!param_buf)
899 		return QDF_STATUS_E_FAILURE;
900 
901 	ev_param = (wmi_stats_event_fixed_param *)param_buf->fixed_param;
902 
903 	if ((ev_param->stats_id & WMI_REQUEST_PMF_BCN_PROTECT_STAT) &&
904 	    param_buf->pmf_bcn_protect_stats) {
905 		pmf_bcn_stats->igtk_mic_fail_cnt =
906 			param_buf->pmf_bcn_protect_stats->igtk_mic_fail_cnt;
907 		pmf_bcn_stats->igtk_replay_cnt =
908 			param_buf->pmf_bcn_protect_stats->igtk_replay_cnt;
909 		pmf_bcn_stats->bcn_mic_fail_cnt =
910 			param_buf->pmf_bcn_protect_stats->bcn_mic_fail_cnt;
911 		pmf_bcn_stats->bcn_replay_cnt =
912 			param_buf->pmf_bcn_protect_stats->bcn_replay_cnt;
913 	}
914 
915 	return QDF_STATUS_SUCCESS;
916 }
917 
918 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
919 static void wmi_infra_cp_stats_ops_attach_tlv(struct wmi_ops *ops)
920 {
921 	ops->send_infra_cp_stats_request_cmd =
922 					send_infra_cp_stats_request_cmd_tlv;
923 }
924 #else
925 static void wmi_infra_cp_stats_ops_attach_tlv(struct wmi_ops *ops)
926 {
927 }
928 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */
929 
930 void wmi_cp_stats_attach_tlv(wmi_unified_t wmi_handle)
931 {
932 	struct wmi_ops *ops = wmi_handle->ops;
933 
934 	ops->send_stats_request_cmd = send_stats_request_cmd_tlv;
935 #ifdef WLAN_FEATURE_BIG_DATA_STATS
936 	ops->send_big_data_stats_request_cmd =
937 				send_big_data_stats_request_cmd_tlv;
938 #endif
939 	ops->extract_all_stats_count = extract_all_stats_counts_tlv;
940 	ops->extract_pdev_stats = extract_pdev_stats_tlv;
941 	ops->extract_vdev_stats = extract_vdev_stats_tlv;
942 	ops->extract_peer_stats = extract_peer_stats_tlv;
943 	ops->extract_peer_extd_stats = extract_peer_extd_stats_tlv;
944 	wmi_infra_cp_stats_ops_attach_tlv(ops);
945 	ops->extract_pmf_bcn_protect_stats = extract_pmf_bcn_protect_stats_tlv,
946 
947 	wmi_mc_cp_stats_attach_tlv(wmi_handle);
948 }
949