1 /*
2  * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include "osdep.h"
19 #include "wmi.h"
20 #include "wmi_unified_priv.h"
21 #include "wmi_unified_param.h"
22 
23 /**
24  * extract_per_chain_rssi_stats_tlv() - api to extract rssi stats from event
25  * buffer
26  * @wmi_handle: wmi handle
27  * @evt_buf: pointer to event buffer
28  * @index: Index into vdev stats
29  * @rssi_stats: Pointer to hold rssi stats
30  *
31  * Return: QDF_STATUS_SUCCESS for success or error code
32  */
33 static QDF_STATUS
extract_per_chain_rssi_stats_tlv(wmi_unified_t wmi_handle,void * evt_buf,uint32_t index,struct wmi_host_per_chain_rssi_stats * rssi_stats)34 extract_per_chain_rssi_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf,
35 			       uint32_t index,
36 			       struct wmi_host_per_chain_rssi_stats *rssi_stats)
37 {
38 	uint8_t *data;
39 	wmi_rssi_stats *fw_rssi_stats;
40 	wmi_per_chain_rssi_stats *rssi_event;
41 	WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
42 
43 	if (!evt_buf) {
44 		wmi_err("evt_buf is null");
45 		return QDF_STATUS_E_NULL_VALUE;
46 	}
47 
48 	param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf;
49 	rssi_event = param_buf->chain_stats;
50 
51 	if (index >= rssi_event->num_per_chain_rssi_stats) {
52 		wmi_err("Invalid index: %u", index);
53 		return QDF_STATUS_E_INVAL;
54 	}
55 
56 	data = ((uint8_t *)(&rssi_event[1])) + WMI_TLV_HDR_SIZE;
57 	fw_rssi_stats = &((wmi_rssi_stats *)data)[index];
58 	if (fw_rssi_stats->vdev_id >= WLAN_UMAC_PDEV_MAX_VDEVS)
59 		return QDF_STATUS_E_INVAL;
60 
61 	rssi_stats->vdev_id = fw_rssi_stats->vdev_id;
62 	qdf_mem_copy(rssi_stats->rssi_avg_beacon,
63 		     fw_rssi_stats->rssi_avg_beacon,
64 		     sizeof(fw_rssi_stats->rssi_avg_beacon));
65 	qdf_mem_copy(rssi_stats->rssi_avg_data,
66 		     fw_rssi_stats->rssi_avg_data,
67 		     sizeof(fw_rssi_stats->rssi_avg_data));
68 	qdf_mem_copy(&rssi_stats->peer_macaddr,
69 		     &fw_rssi_stats->peer_macaddr,
70 		     sizeof(fw_rssi_stats->peer_macaddr));
71 
72 	return QDF_STATUS_SUCCESS;
73 }
74 
75 /**
76  * extract_peer_adv_stats_tlv() - extract adv peer stats from event
77  * @wmi_handle: wmi handle
78  * @evt_buf: pointer to event buffer
79  * @peer_adv_stats: Pointer to hold adv peer stats
80  *
81  * Return: QDF_STATUS_SUCCESS for success or error code
82  */
extract_peer_adv_stats_tlv(wmi_unified_t wmi_handle,void * evt_buf,struct wmi_host_peer_adv_stats * peer_adv_stats)83 static QDF_STATUS extract_peer_adv_stats_tlv(wmi_unified_t wmi_handle,
84 					     void *evt_buf,
85 					     struct wmi_host_peer_adv_stats
86 					     *peer_adv_stats)
87 {
88 	WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
89 	wmi_peer_extd2_stats *adv_stats;
90 	int i;
91 
92 	param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *)evt_buf;
93 
94 	adv_stats = param_buf->peer_extd2_stats;
95 	if (!adv_stats) {
96 		wmi_debug("no peer_adv stats in event buffer");
97 		return QDF_STATUS_E_INVAL;
98 	}
99 
100 	for (i = 0; i < param_buf->num_peer_extd2_stats; i++) {
101 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&adv_stats[i].peer_macaddr,
102 					   peer_adv_stats[i].peer_macaddr);
103 		peer_adv_stats[i].fcs_count = adv_stats[i].rx_fcs_err;
104 		peer_adv_stats[i].rx_bytes =
105 				(uint64_t)adv_stats[i].rx_bytes_u32 <<
106 				WMI_LOWER_BITS_SHIFT_32 |
107 				adv_stats[i].rx_bytes_l32;
108 		peer_adv_stats[i].rx_count = adv_stats[i].rx_mpdus;
109 	}
110 
111 	return QDF_STATUS_SUCCESS;
112 }
113 
114 #ifdef WLAN_FEATURE_MIB_STATS
115 /**
116  * extract_mib_stats_tlv() - extract mib stats from event
117  * @wmi_handle: wmi handle
118  * @evt_buf: pointer to event buffer
119  * @mib_stats: pointer to hold mib stats
120  *
121  * Return: QDF_STATUS_SUCCESS for success or error code
122  */
extract_mib_stats_tlv(wmi_unified_t wmi_handle,void * evt_buf,struct mib_stats_metrics * mib_stats)123 static QDF_STATUS extract_mib_stats_tlv(wmi_unified_t wmi_handle,
124 					void *evt_buf,
125 					struct mib_stats_metrics
126 					*mib_stats)
127 {
128 	WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
129 	wmi_stats_event_fixed_param *ev_param;
130 	uint8_t *data;
131 	wmi_mib_stats *ev;
132 	wmi_mib_extd_stats *ev_extd;
133 
134 	param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *)evt_buf;
135 	ev_param = (wmi_stats_event_fixed_param *)param_buf->fixed_param;
136 	data = (uint8_t *)param_buf->data;
137 
138 	ev = (wmi_mib_stats *)(data +
139 	      ev_param->num_pdev_stats * sizeof(wmi_pdev_stats) +
140 	      ev_param->num_vdev_stats * sizeof(wmi_vdev_stats) +
141 	      ev_param->num_peer_stats * sizeof(wmi_peer_stats) +
142 	      ev_param->num_bcnflt_stats *
143 	      sizeof(wmi_bcnfilter_stats_t) +
144 	      ev_param->num_chan_stats * sizeof(wmi_chan_stats));
145 
146 	qdf_mem_zero(mib_stats, sizeof(*mib_stats));
147 
148 	mib_stats->mib_counters.tx_frags =
149 		ev->tx_mpdu_grp_frag_cnt;
150 	mib_stats->mib_counters.group_tx_frames =
151 		ev->tx_msdu_grp_frm_cnt;
152 	mib_stats->mib_counters.failed_cnt = ev->tx_msdu_fail_cnt;
153 	mib_stats->mib_counters.rx_frags = ev->rx_mpdu_frag_cnt;
154 	mib_stats->mib_counters.group_rx_frames =
155 		ev->rx_msdu_grp_frm_cnt;
156 	mib_stats->mib_counters.fcs_error_cnt =
157 		ev->rx_mpdu_fcs_err;
158 	mib_stats->mib_counters.tx_frames =
159 		ev->tx_msdu_frm_cnt;
160 	mib_stats->mib_mac_statistics.retry_cnt =
161 		ev->tx_msdu_retry_cnt;
162 	mib_stats->mib_mac_statistics.frame_dup_cnt =
163 		ev->rx_frm_dup_cnt;
164 	mib_stats->mib_mac_statistics.rts_success_cnt =
165 		ev->tx_rts_success_cnt;
166 	mib_stats->mib_mac_statistics.rts_fail_cnt =
167 		ev->tx_rts_fail_cnt;
168 
169 	mib_stats->mib_qos_counters.qos_tx_frag_cnt =
170 		 ev->tx_Qos_mpdu_grp_frag_cnt;
171 	mib_stats->mib_qos_counters.qos_retry_cnt =
172 		ev->tx_Qos_msdu_retry_UP;
173 	mib_stats->mib_qos_counters.qos_failed_cnt =
174 		ev->tx_Qos_msdu_fail_UP;
175 	mib_stats->mib_qos_counters.qos_frame_dup_cnt =
176 		ev->rx_Qos_frm_dup_cnt_UP;
177 	mib_stats->mib_qos_counters.qos_rts_success_cnt =
178 		ev->tx_Qos_rts_success_cnt_UP;
179 	mib_stats->mib_qos_counters.qos_rts_fail_cnt =
180 		ev->tx_Qos_rts_fail_cnt_UP;
181 	mib_stats->mib_qos_counters.qos_rx_frag_cnt =
182 		ev->rx_Qos_mpdu_frag_cnt_UP;
183 	mib_stats->mib_qos_counters.qos_tx_frame_cnt =
184 		ev->tx_Qos_msdu_frm_cnt_UP;
185 	mib_stats->mib_qos_counters.qos_discarded_frame_cnt =
186 		ev->rx_Qos_msdu_discard_cnt_UP;
187 	mib_stats->mib_qos_counters.qos_mpdu_rx_cnt =
188 		ev->rx_Qos_mpdu_cnt;
189 	mib_stats->mib_qos_counters.qos_retries_rx_cnt =
190 		ev->rx_Qos_mpdu_retryBit_cnt;
191 
192 	mib_stats->mib_rsna_stats.tkip_icv_err =
193 		ev->rsna_TKIP_icv_err_cnt;
194 	mib_stats->mib_rsna_stats.tkip_replays =
195 		ev->rsna_TKIP_replay_err_cnt;
196 	mib_stats->mib_rsna_stats.ccmp_decrypt_err =
197 		ev->rsna_CCMP_decrypt_err_cnt;
198 	mib_stats->mib_rsna_stats.ccmp_replays =
199 		ev->rsna_CCMP_replay_err_cnt;
200 
201 	mib_stats->mib_counters_group3.tx_ampdu_cnt =
202 		ev->tx_ampdu_cnt;
203 	mib_stats->mib_counters_group3.tx_mpdus_in_ampdu_cnt =
204 		ev->tx_mpdu_cnt_in_ampdu;
205 	mib_stats->mib_counters_group3.tx_octets_in_ampdu_cnt =
206 		ev->tx_octets_in_ampdu.upload.high;
207 	mib_stats->mib_counters_group3.tx_octets_in_ampdu_cnt =
208 		mib_stats->mib_counters_group3.tx_octets_in_ampdu_cnt << 32;
209 	mib_stats->mib_counters_group3.tx_octets_in_ampdu_cnt +=
210 		ev->tx_octets_in_ampdu.upload.low;
211 
212 	mib_stats->mib_counters_group3.ampdu_rx_cnt =
213 		ev->rx_ampdu_cnt;
214 	mib_stats->mib_counters_group3.mpdu_in_rx_ampdu_cnt =
215 		ev->rx_mpdu_cnt_in_ampdu;
216 	mib_stats->mib_counters_group3.rx_octets_in_ampdu_cnt =
217 		ev->rx_octets_in_ampdu.upload.rx_octets_in_ampdu_high;
218 	mib_stats->mib_counters_group3.rx_octets_in_ampdu_cnt =
219 		mib_stats->mib_counters_group3.rx_octets_in_ampdu_cnt << 32;
220 	mib_stats->mib_counters_group3.rx_octets_in_ampdu_cnt +=
221 		ev->rx_octets_in_ampdu.upload.rx_octets_in_ampdu_low;
222 
223 	if (ev_param->num_mib_extd_stats) {
224 		ev_extd = (wmi_mib_extd_stats *)((uint8_t *)ev +
225 			   ev_param->num_mib_stats * sizeof(wmi_mib_stats) +
226 			   ev_param->num_bcn_stats * sizeof(wmi_bcn_stats) +
227 			   ev_param->num_peer_extd_stats *
228 			   sizeof(wmi_peer_extd_stats));
229 		mib_stats->mib_mac_statistics.multi_retry_cnt =
230 			ev_extd->tx_msdu_multi_retry_cnt;
231 		mib_stats->mib_mac_statistics.tx_ack_fail_cnt =
232 			ev_extd->tx_ack_fail_cnt;
233 
234 		mib_stats->mib_qos_counters.qos_multi_retry_cnt =
235 			ev_extd->tx_qos_msdu_multi_retry_up;
236 		mib_stats->mib_qos_counters.tx_qos_ack_fail_cnt_up =
237 			ev_extd->tx_qos_ack_fail_cnt_up;
238 
239 		mib_stats->mib_rsna_stats.cmac_icv_err =
240 			ev_extd->rsna_cmac_icv_err_cnt;
241 		mib_stats->mib_rsna_stats.cmac_replays =
242 			ev_extd->rsna_cmac_replay_err_cnt;
243 
244 		mib_stats->mib_counters_group3.rx_ampdu_deli_crc_err_cnt =
245 			ev_extd->rx_ampdu_deli_crc_err_cnt;
246 	}
247 
248 	return QDF_STATUS_SUCCESS;
249 }
250 
wmi_cp_stats_attach_mib_stats_tlv(struct wmi_ops * ops)251 static void wmi_cp_stats_attach_mib_stats_tlv(struct wmi_ops *ops)
252 {
253 	ops->extract_mib_stats = extract_mib_stats_tlv;
254 }
255 #else
wmi_cp_stats_attach_mib_stats_tlv(struct wmi_ops * ops)256 static void wmi_cp_stats_attach_mib_stats_tlv(struct wmi_ops *ops)
257 {
258 }
259 #endif /* WLAN_FEATURE_MIB_STATS */
260 
261 /**
262  * send_request_peer_stats_info_cmd_tlv() - WMI request peer stats function
263  * @wmi_handle: handle to WMI.
264  * @param: pointer to hold peer stats request parameter
265  *
266  * Return: QDF_STATUS
267  */
268 static QDF_STATUS
send_request_peer_stats_info_cmd_tlv(wmi_unified_t wmi_handle,struct peer_stats_request_params * param)269 send_request_peer_stats_info_cmd_tlv(wmi_unified_t wmi_handle,
270 				     struct peer_stats_request_params *param)
271 {
272 	int32_t ret;
273 	wmi_request_peer_stats_info_cmd_fixed_param *cmd;
274 	wmi_buf_t buf;
275 	uint16_t len = sizeof(wmi_request_peer_stats_info_cmd_fixed_param);
276 
277 	buf = wmi_buf_alloc(wmi_handle, len);
278 	if (!buf)
279 		return QDF_STATUS_E_NOMEM;
280 
281 	cmd = (wmi_request_peer_stats_info_cmd_fixed_param *)wmi_buf_data(buf);
282 	WMITLV_SET_HDR(&cmd->tlv_header,
283 		   WMITLV_TAG_STRUC_wmi_request_peer_stats_info_cmd_fixed_param,
284 		   WMITLV_GET_STRUCT_TLVLEN(
285 				  wmi_request_peer_stats_info_cmd_fixed_param));
286 	cmd->request_type = param->request_type;
287 	cmd->vdev_id = param->vdev_id;
288 	WMI_CHAR_ARRAY_TO_MAC_ADDR(param->peer_mac_addr, &cmd->peer_macaddr);
289 	cmd->reset_after_request = param->reset_after_request;
290 
291 	wmi_debug("PEER STATS REQ VDEV_ID:%d PEER:"QDF_MAC_ADDR_FMT" TYPE:%d RESET:%d",
292 		 cmd->vdev_id, QDF_MAC_ADDR_REF(param->peer_mac_addr),
293 		 cmd->request_type,
294 		 cmd->reset_after_request);
295 
296 	wmi_mtrace(WMI_REQUEST_PEER_STATS_INFO_CMDID, cmd->vdev_id, 0);
297 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
298 				   WMI_REQUEST_PEER_STATS_INFO_CMDID);
299 	if (ret) {
300 		wmi_err("Failed to send peer stats request to fw =%d", ret);
301 		wmi_buf_free(buf);
302 	}
303 
304 	return qdf_status_from_os_return(ret);
305 }
306 
307 /**
308  * extract_peer_stats_count_tlv() - extract peer stats count from event
309  * @wmi_handle: wmi handle
310  * @evt_buf: pointer to event buffer
311  * @stats_param: Pointer to hold stats count
312  *
313  * Return: QDF_STATUS_SUCCESS for success or error code
314  */
315 static QDF_STATUS
extract_peer_stats_count_tlv(wmi_unified_t wmi_handle,void * evt_buf,wmi_host_stats_event * stats_param)316 extract_peer_stats_count_tlv(wmi_unified_t wmi_handle, void *evt_buf,
317 			     wmi_host_stats_event *stats_param)
318 {
319 	WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf;
320 	wmi_peer_stats_info_event_fixed_param *ev_param;
321 
322 	param_buf = (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)evt_buf;
323 	if (!param_buf)
324 		return QDF_STATUS_E_FAILURE;
325 
326 	ev_param = param_buf->fixed_param;
327 	if (!ev_param)
328 		return QDF_STATUS_E_FAILURE;
329 
330 	if (!param_buf->num_peer_stats_info ||
331 	    param_buf->num_peer_stats_info < ev_param->num_peers) {
332 		wmi_err_rl("actual num of peers stats info: %d is less than provided peers: %d",
333 			   param_buf->num_peer_stats_info, ev_param->num_peers);
334 		return QDF_STATUS_E_FAULT;
335 	}
336 
337 	if (!stats_param)
338 		return QDF_STATUS_E_FAILURE;
339 
340 	stats_param->num_peer_stats_info_ext = ev_param->num_peers;
341 
342 	return QDF_STATUS_SUCCESS;
343 }
344 
dump_peer_stats_info(wmi_peer_stats_info * stats)345 static void dump_peer_stats_info(wmi_peer_stats_info *stats)
346 {
347 	u_int8_t mac[6];
348 	int i;
349 
350 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats->peer_macaddr, mac);
351 	wmi_debug("mac "QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(mac));
352 	wmi_debug("tx_bytes %d %d tx_packets %d %d tx_retries %d tx_failed %d",
353 		 stats->tx_bytes.low_32,
354 		 stats->tx_bytes.high_32,
355 		 stats->tx_packets.low_32,
356 		 stats->tx_packets.high_32,
357 		 stats->tx_retries, stats->tx_failed);
358 	wmi_debug("rx_bytes %d %d rx_packets %d %d",
359 		 stats->rx_bytes.low_32,
360 		 stats->rx_bytes.high_32,
361 		 stats->rx_packets.low_32,
362 		 stats->rx_packets.high_32);
363 	wmi_debug("tx_rate_code %x rx_rate_code %x tx_rate %x rx_rate %x peer_rssi %d tx_succeed %d",
364 		 stats->last_tx_rate_code,
365 		 stats->last_rx_rate_code,
366 		 stats->last_tx_bitrate_kbps,
367 		 stats->last_rx_bitrate_kbps,
368 		 stats->peer_rssi, stats->tx_succeed);
369 	for (i = 0; i < WMI_MAX_CHAINS; i++)
370 		wmi_debug("chain%d_rssi %d", i, stats->peer_rssi_per_chain[i]);
371 }
372 
373 /**
374  * extract_peer_tx_pkt_per_mcs_tlv() - extract peer tx packets per MCS
375  * from event
376  * @wmi_handle: wmi handle
377  * @evt_buf: pointer to event buffer
378  * @index: Index into vdev stats
379  * @peer_stats_info: Pointer to hold peer stats info
380  *
381  * Return: QDF_STATUS_SUCCESS for success or error code
382  */
383 static QDF_STATUS
extract_peer_tx_pkt_per_mcs_tlv(wmi_unified_t wmi_handle,void * evt_buf,uint32_t index,wmi_host_peer_stats_info * peer_stats_info)384 extract_peer_tx_pkt_per_mcs_tlv(wmi_unified_t wmi_handle, void *evt_buf,
385 				uint32_t index,
386 				wmi_host_peer_stats_info *peer_stats_info)
387 {
388 	WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf;
389 	int i, j;
390 
391 	param_buf = (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)evt_buf;
392 
393 	if (index + peer_stats_info->num_tx_rate_counts <=
394 					param_buf->num_tx_rate_counts) {
395 		peer_stats_info->tx_pkt_per_mcs =
396 			qdf_mem_malloc(
397 			peer_stats_info->num_tx_rate_counts * sizeof(uint32_t));
398 
399 		if (!peer_stats_info->tx_pkt_per_mcs)
400 			return QDF_STATUS_E_NOMEM;
401 		wmi_debug("Tx rate counts");
402 		for (j = 0, i = index; j < peer_stats_info->num_tx_rate_counts;
403 		     j++, i++) {
404 			peer_stats_info->tx_pkt_per_mcs[j] =
405 						param_buf->tx_rate_counts[i];
406 			wmi_nofl_debug("MCS [%d] %d", j,
407 				       peer_stats_info->tx_pkt_per_mcs[j]);
408 		}
409 	} else {
410 		wmi_err("invalid idx %d curr peer tx_rate_counts %d total tx_rate_count %d",
411 			index, peer_stats_info->num_tx_rate_counts,
412 			param_buf->num_tx_rate_counts);
413 	}
414 	return QDF_STATUS_SUCCESS;
415 }
416 
417 /**
418  * extract_peer_rx_pkt_per_mcs_tlv() - extract peer rx rpackets per MCS
419  * from event
420  * @wmi_handle: wmi handle
421  * @evt_buf: pointer to event buffer
422  * @index: Index into vdev stats
423  * @peer_stats_info: Pointer to hold peer stats info
424  *
425  * Return: QDF_STATUS_SUCCESS for success or error code
426  */
427 static QDF_STATUS
extract_peer_rx_pkt_per_mcs_tlv(wmi_unified_t wmi_handle,void * evt_buf,uint32_t index,wmi_host_peer_stats_info * peer_stats_info)428 extract_peer_rx_pkt_per_mcs_tlv(wmi_unified_t wmi_handle, void *evt_buf,
429 				uint32_t index,
430 				wmi_host_peer_stats_info *peer_stats_info)
431 {
432 	WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf;
433 	int i, j;
434 
435 	param_buf = (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)evt_buf;
436 
437 	if (index + peer_stats_info->num_rx_rate_counts <=
438 					param_buf->num_rx_rate_counts) {
439 		peer_stats_info->rx_pkt_per_mcs =
440 			qdf_mem_malloc(
441 			peer_stats_info->num_rx_rate_counts * sizeof(uint32_t));
442 
443 		if (!peer_stats_info->rx_pkt_per_mcs)
444 			return QDF_STATUS_E_NOMEM;
445 		wmi_debug("Rx rate counts");
446 		for (j = 0, i = index; j < peer_stats_info->num_rx_rate_counts;
447 		     j++, i++) {
448 			peer_stats_info->rx_pkt_per_mcs[j] =
449 						param_buf->rx_rate_counts[i];
450 			wmi_nofl_debug("MCS [%d] %d", j,
451 				       peer_stats_info->rx_pkt_per_mcs[j]);
452 		}
453 	} else {
454 		wmi_err("invalid idx %d curr peer rx_rate_counts %d total rx_rate_count %d",
455 			index, peer_stats_info->num_rx_rate_counts,
456 			param_buf->num_rx_rate_counts);
457 	}
458 	return QDF_STATUS_SUCCESS;
459 }
460 
461 /**
462  * extract_peer_stats_info_tlv() - extract peer stats info from event
463  * @wmi_handle: wmi handle
464  * @evt_buf: pointer to event buffer
465  * @index: Index into vdev stats
466  * @peer_stats_info: Pointer to hold peer stats info
467  *
468  * Return: QDF_STATUS_SUCCESS for success or error code
469  */
470 static QDF_STATUS
extract_peer_stats_info_tlv(wmi_unified_t wmi_handle,void * evt_buf,uint32_t index,wmi_host_peer_stats_info * peer_stats_info)471 extract_peer_stats_info_tlv(wmi_unified_t wmi_handle, void *evt_buf,
472 			    uint32_t index,
473 			    wmi_host_peer_stats_info *peer_stats_info)
474 {
475 	WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf;
476 	wmi_peer_stats_info_event_fixed_param *ev_param;
477 
478 	param_buf = (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)evt_buf;
479 	ev_param = param_buf->fixed_param;
480 
481 	if (index < ev_param->num_peers) {
482 		wmi_peer_stats_info *ev = &param_buf->peer_stats_info[index];
483 		int i;
484 
485 		dump_peer_stats_info(ev);
486 
487 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->peer_macaddr,
488 					   peer_stats_info->peer_macaddr.bytes);
489 		peer_stats_info->tx_packets = ev->tx_packets.low_32;
490 		peer_stats_info->tx_bytes = ev->tx_bytes.high_32;
491 		peer_stats_info->tx_bytes <<= 32;
492 		peer_stats_info->tx_bytes += ev->tx_bytes.low_32;
493 		peer_stats_info->rx_packets = ev->rx_packets.low_32;
494 		peer_stats_info->rx_bytes = ev->rx_bytes.high_32;
495 		peer_stats_info->rx_bytes <<= 32;
496 		peer_stats_info->rx_bytes += ev->rx_bytes.low_32;
497 		peer_stats_info->tx_retries = ev->tx_retries;
498 		peer_stats_info->tx_failed = ev->tx_failed;
499 		peer_stats_info->tx_succeed = ev->tx_succeed;
500 		peer_stats_info->peer_rssi = ev->peer_rssi;
501 		peer_stats_info->last_tx_bitrate_kbps =
502 						ev->last_tx_bitrate_kbps;
503 		peer_stats_info->last_tx_rate_code = ev->last_tx_rate_code;
504 		peer_stats_info->last_rx_bitrate_kbps =
505 						ev->last_rx_bitrate_kbps;
506 		peer_stats_info->last_rx_rate_code = ev->last_rx_rate_code;
507 		for (i = 0; i < WMI_MAX_CHAINS; i++)
508 			peer_stats_info->peer_rssi_per_chain[i] =
509 						     ev->peer_rssi_per_chain[i];
510 		peer_stats_info->num_tx_rate_counts = ev->num_tx_rate_counts;
511 		peer_stats_info->num_rx_rate_counts = ev->num_rx_rate_counts;
512 	}
513 
514 	return QDF_STATUS_SUCCESS;
515 }
516 
517 #ifdef WLAN_FEATURE_BIG_DATA_STATS
518 /**
519  * extract_big_data_stats_tlv() - extract big data from event
520  * @wmi_handle: wmi handle
521  * @evt_buf: pointer to event buffer
522  * @stats: Pointer to hold big data stats
523  *
524  * Return: QDF_STATUS_SUCCESS for success or error code
525  */
526 static QDF_STATUS
extract_big_data_stats_tlv(wmi_unified_t wmi_handle,void * evt_buf,struct big_data_stats_event * stats)527 extract_big_data_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf,
528 			   struct big_data_stats_event *stats)
529 {
530 	WMI_VDEV_SEND_BIG_DATA_P2_EVENTID_param_tlvs *param_buf;
531 	wmi_vdev_send_big_data_p2_event_fixed_param *event;
532 	wmi_big_data_dp_stats_tlv_param *dp_stats_param_buf;
533 
534 	param_buf = (WMI_VDEV_SEND_BIG_DATA_P2_EVENTID_param_tlvs *)evt_buf;
535 	if (!param_buf) {
536 		wmi_err("invalid buffer");
537 		return QDF_STATUS_E_FAILURE;
538 	}
539 
540 	event = param_buf->fixed_param;
541 	if (!event) {
542 		wmi_err("invalid fixed param");
543 		return QDF_STATUS_E_FAILURE;
544 	}
545 
546 	dp_stats_param_buf = param_buf->big_data_dp_stats;
547 	if (!dp_stats_param_buf) {
548 		wmi_err("invalid dp stats param");
549 		return QDF_STATUS_E_FAILURE;
550 	}
551 
552 	stats->vdev_id = event->vdev_id;
553 	stats->ani_level = event->ani_level;
554 	stats->tsf_out_of_sync = event->tsf_out_of_sync;
555 
556 	stats->last_data_tx_pwr = dp_stats_param_buf->last_data_tx_pwr;
557 	stats->target_power_dsss = dp_stats_param_buf->target_power_dsss;
558 	stats->target_power_ofdm = dp_stats_param_buf->target_power_ofdm;
559 	stats->last_tx_data_rix = dp_stats_param_buf->last_tx_data_rix;
560 	stats->last_tx_data_rate_kbps =
561 		dp_stats_param_buf->last_tx_data_rate_kbps;
562 
563 	return QDF_STATUS_SUCCESS;
564 }
565 #endif
566 
567 #ifdef WLAN_FEATURE_BIG_DATA_STATS
568 static void
wmi_attach_big_data_stats_handler(struct wmi_ops * ops)569 wmi_attach_big_data_stats_handler(struct wmi_ops *ops)
570 {
571 	ops->extract_big_data_stats = extract_big_data_stats_tlv;
572 }
573 #else
574 static void
wmi_attach_big_data_stats_handler(struct wmi_ops * ops)575 wmi_attach_big_data_stats_handler(struct wmi_ops *ops)
576 {}
577 #endif
578 
wmi_mc_cp_stats_attach_tlv(wmi_unified_t wmi_handle)579 void wmi_mc_cp_stats_attach_tlv(wmi_unified_t wmi_handle)
580 {
581 	struct wmi_ops *ops = wmi_handle->ops;
582 
583 	ops->extract_per_chain_rssi_stats = extract_per_chain_rssi_stats_tlv;
584 	ops->extract_peer_adv_stats = extract_peer_adv_stats_tlv;
585 	wmi_cp_stats_attach_mib_stats_tlv(ops);
586 	ops->send_request_peer_stats_info_cmd =
587 		send_request_peer_stats_info_cmd_tlv;
588 	ops->extract_peer_stats_count = extract_peer_stats_count_tlv;
589 	ops->extract_peer_stats_info = extract_peer_stats_info_tlv;
590 	wmi_handle->ops->extract_peer_tx_pkt_per_mcs =
591 					extract_peer_tx_pkt_per_mcs_tlv;
592 	wmi_handle->ops->extract_peer_rx_pkt_per_mcs =
593 					extract_peer_rx_pkt_per_mcs_tlv;
594 	wmi_attach_big_data_stats_handler(ops);
595 }
596