xref: /wlan-dirver/qcacld-3.0/core/wma/src/wma_utils.c (revision 97e365d9e5ce32a345184c7cfde6c8a546251918)
1 /*
2  * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  *  DOC:    wma_utis.c
21  *  This file contains utilities and stats related functions.
22  */
23 
24 /* Header files */
25 
26 #include "wma.h"
27 #include "wma_api.h"
28 #include "cds_api.h"
29 #include "wmi_unified_api.h"
30 #include "wlan_qct_sys.h"
31 #include "wni_api.h"
32 #include "ani_global.h"
33 #include "wmi_unified.h"
34 #include "wni_cfg.h"
35 
36 #include "qdf_nbuf.h"
37 #include "qdf_types.h"
38 #include "qdf_mem.h"
39 
40 #include "wma_types.h"
41 #include "lim_api.h"
42 #include "lim_session_utils.h"
43 
44 #include "cds_utils.h"
45 
46 #if !defined(REMOVE_PKT_LOG)
47 #include "pktlog_ac.h"
48 #endif /* REMOVE_PKT_LOG */
49 
50 #include "dbglog_host.h"
51 #include "csr_api.h"
52 #include "ol_fw.h"
53 
54 #include "wma_internal.h"
55 #include "wlan_policy_mgr_api.h"
56 #include "wmi_unified_param.h"
57 #include "linux/ieee80211.h"
58 #include <cdp_txrx_handle.h>
59 #include <cdp_txrx_peer_ops.h>
60 #include "cds_reg_service.h"
61 #include "target_if.h"
62 #include <wlan_utility.h>
63 #include <wlan_mlme_main.h>
64 #include "host_diag_core_log.h"
65 #include <wlan_mlme_api.h>
66 #include <../../core/src/vdev_mgr_ops.h>
67 
68 /* MCS Based rate table */
69 /* HT MCS parameters with Nss = 1 */
70 static struct index_data_rate_type mcs_nss1[] = {
71 	/* MCS L20  S20   L40   S40 */
72 	{0,  {65,  72},  {135,  150 } },
73 	{1,  {130, 144}, {270,  300 } },
74 	{2,  {195, 217}, {405,  450 } },
75 	{3,  {260, 289}, {540,  600 } },
76 	{4,  {390, 433}, {815,  900 } },
77 	{5,  {520, 578}, {1080, 1200} },
78 	{6,  {585, 650}, {1215, 1350} },
79 	{7,  {650, 722}, {1350, 1500} }
80 };
81 
82 /* HT MCS parameters with Nss = 2 */
83 static struct index_data_rate_type mcs_nss2[] = {
84 	/* MCS L20  S20    L40   S40 */
85 	{0,  {130,  144},  {270,  300 } },
86 	{1,  {260,  289},  {540,  600 } },
87 	{2,  {390,  433},  {810,  900 } },
88 	{3,  {520,  578},  {1080, 1200} },
89 	{4,  {780,  867},  {1620, 1800} },
90 	{5,  {1040, 1156}, {2160, 2400} },
91 	{6,  {1170, 1300}, {2430, 2700} },
92 	{7,  {1300, 1440}, {2700, 3000} }
93 };
94 
95 /* MCS Based VHT rate table */
96 /* MCS parameters with Nss = 1*/
97 static struct index_vht_data_rate_type vht_mcs_nss1[] = {
98 	/* MCS L20  S20    L40   S40    L80   S80 */
99 	{0,  {65,   72 }, {135,  150},  {293,  325} },
100 	{1,  {130,  144}, {270,  300},  {585,  650} },
101 	{2,  {195,  217}, {405,  450},  {878,  975} },
102 	{3,  {260,  289}, {540,  600},  {1170, 1300} },
103 	{4,  {390,  433}, {810,  900},  {1755, 1950} },
104 	{5,  {520,  578}, {1080, 1200}, {2340, 2600} },
105 	{6,  {585,  650}, {1215, 1350}, {2633, 2925} },
106 	{7,  {650,  722}, {1350, 1500}, {2925, 3250} },
107 	{8,  {780,  867}, {1620, 1800}, {3510, 3900} },
108 	{9,  {865,  960}, {1800, 2000}, {3900, 4333} }
109 };
110 
111 /*MCS parameters with Nss = 2*/
112 static struct index_vht_data_rate_type vht_mcs_nss2[] = {
113 	/* MCS L20  S20    L40    S40    L80    S80 */
114 	{0,  {130,  144},  {270,  300},  { 585,  650} },
115 	{1,  {260,  289},  {540,  600},  {1170, 1300} },
116 	{2,  {390,  433},  {810,  900},  {1755, 1950} },
117 	{3,  {520,  578},  {1080, 1200}, {2340, 2600} },
118 	{4,  {780,  867},  {1620, 1800}, {3510, 3900} },
119 	{5,  {1040, 1156}, {2160, 2400}, {4680, 5200} },
120 	{6,  {1170, 1300}, {2430, 2700}, {5265, 5850} },
121 	{7,  {1300, 1444}, {2700, 3000}, {5850, 6500} },
122 	{8,  {1560, 1733}, {3240, 3600}, {7020, 7800} },
123 	{9,  {1730, 1920}, {3600, 4000}, {7800, 8667} }
124 };
125 
126 #ifdef BIG_ENDIAN_HOST
127 
128 /* ############# function definitions ############ */
129 
130 /**
131  * wma_swap_bytes() - swap bytes
132  * @pv: buffer
133  * @n: swap bytes
134  *
135  * Return: none
136  */
137 void wma_swap_bytes(void *pv, uint32_t n)
138 {
139 	int32_t no_words;
140 	int32_t i;
141 	uint32_t *word_ptr;
142 
143 	no_words = n / sizeof(uint32_t);
144 	word_ptr = (uint32_t *) pv;
145 	for (i = 0; i < no_words; i++)
146 		*(word_ptr + i) = __cpu_to_le32(*(word_ptr + i));
147 }
148 
149 #define SWAPME(x, len) wma_swap_bytes(&x, len)
150 #endif /* BIG_ENDIAN_HOST */
151 
152 /**
153  * wma_mcs_rate_match() - find the match mcs rate
154  * @match_rate:	the rate to look up
155  * @is_sgi:	return if the SGI rate is found
156  * @nss:	the nss in use
157  * @nss1_rate:	the nss1 rate
158  * @nss1_srate:	the nss1 SGI rate
159  * @nss2_rate:	the nss2 rate
160  * @nss2_srate:	the nss2 SGI rate
161  *
162  * This is a helper function to find the match of the tx_rate
163  * in terms of the nss1/nss2 rate with non-SGI/SGI.
164  *
165  * Return: the found rate or 0 otherwise
166  */
167 static inline uint16_t wma_mcs_rate_match(uint16_t match_rate, bool *is_sgi,
168 					  uint8_t *nss, uint16_t nss1_rate,
169 					  uint16_t nss1_srate,
170 					  uint16_t nss2_rate,
171 					  uint16_t nss2_srate)
172 {
173 	WMA_LOGD("%s match_rate: %d, %d %d %d %d",
174 		__func__, match_rate, nss1_rate, nss1_srate, nss2_rate,
175 		nss2_srate);
176 
177 	if (match_rate == nss1_rate) {
178 		*nss = 1;
179 		return nss1_rate;
180 	} else if (match_rate == nss1_srate) {
181 		*is_sgi = true;
182 		*nss = 1;
183 		return nss1_srate;
184 	} else if (*nss == 2 && match_rate == nss2_rate)
185 		return nss2_rate;
186 	else if (*nss == 2 && match_rate == nss2_srate) {
187 		*is_sgi = true;
188 		return nss2_srate;
189 	} else
190 		return 0;
191 }
192 
193 uint8_t wma_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags,
194 			uint8_t *nss, uint8_t *mcs_rate_flag)
195 {
196 	uint8_t  index = 0;
197 	uint16_t match_rate = 0;
198 	bool is_sgi = false;
199 
200 	WMA_LOGD("%s rate:%d rate_flgs: 0x%x, nss: %d",
201 		 __func__, max_rate, rate_flags, *nss);
202 
203 	*mcs_rate_flag = rate_flags;
204 	*mcs_rate_flag &= ~TX_RATE_SGI;
205 	for (index = 0; index < MAX_VHT_MCS_IDX; index++) {
206 		if (rate_flags & TX_RATE_VHT80) {
207 			/* check for vht80 nss1/2 rate set */
208 			match_rate = wma_mcs_rate_match(max_rate, &is_sgi, nss,
209 					vht_mcs_nss1[index].ht80_rate[0],
210 					vht_mcs_nss1[index].ht80_rate[1],
211 					vht_mcs_nss2[index].ht80_rate[0],
212 					vht_mcs_nss2[index].ht80_rate[1]);
213 			if (match_rate)
214 				goto rate_found;
215 		}
216 		if ((rate_flags & TX_RATE_VHT40) |
217 		    (rate_flags & TX_RATE_VHT80)) {
218 			/* check for vht40 nss1/2 rate set */
219 			match_rate = wma_mcs_rate_match(max_rate, &is_sgi, nss,
220 					vht_mcs_nss1[index].ht40_rate[0],
221 					vht_mcs_nss1[index].ht40_rate[1],
222 					vht_mcs_nss2[index].ht40_rate[0],
223 					vht_mcs_nss2[index].ht40_rate[1]);
224 			if (match_rate) {
225 				*mcs_rate_flag &= ~TX_RATE_VHT80;
226 				goto rate_found;
227 			}
228 		}
229 		if ((rate_flags & TX_RATE_VHT20) |
230 		    (rate_flags & TX_RATE_VHT40) |
231 		    (rate_flags & TX_RATE_VHT80)) {
232 			/* check for vht20 nss1/2 rate set */
233 			match_rate = wma_mcs_rate_match(max_rate, &is_sgi, nss,
234 					vht_mcs_nss1[index].ht20_rate[0],
235 					vht_mcs_nss1[index].ht20_rate[1],
236 					vht_mcs_nss2[index].ht20_rate[0],
237 					vht_mcs_nss2[index].ht20_rate[1]);
238 			if (match_rate) {
239 				*mcs_rate_flag &= ~(TX_RATE_VHT80 |
240 						TX_RATE_VHT40);
241 				goto rate_found;
242 			}
243 		}
244 	}
245 	for (index = 0; index < MAX_HT_MCS_IDX; index++) {
246 		if (rate_flags & TX_RATE_HT40) {
247 			/* check for ht40 nss1/2 rate set */
248 			match_rate = wma_mcs_rate_match(max_rate, &is_sgi, nss,
249 					mcs_nss1[index].ht40_rate[0],
250 					mcs_nss1[index].ht40_rate[1],
251 					mcs_nss2[index].ht40_rate[0],
252 					mcs_nss2[index].ht40_rate[1]);
253 			if (match_rate) {
254 				*mcs_rate_flag = TX_RATE_HT40;
255 				if (*nss == 2)
256 					index += MAX_HT_MCS_IDX;
257 				goto rate_found;
258 			}
259 		}
260 		if ((rate_flags & TX_RATE_HT20) ||
261 			(rate_flags & TX_RATE_HT40)) {
262 			/* check for ht20 nss1/2 rate set */
263 			match_rate = wma_mcs_rate_match(max_rate, &is_sgi, nss,
264 					mcs_nss1[index].ht20_rate[0],
265 					mcs_nss1[index].ht20_rate[1],
266 					mcs_nss2[index].ht20_rate[0],
267 					mcs_nss2[index].ht20_rate[1]);
268 			if (match_rate) {
269 				*mcs_rate_flag = TX_RATE_HT20;
270 				if (*nss == 2)
271 					index += MAX_HT_MCS_IDX;
272 				goto rate_found;
273 			}
274 		}
275 	}
276 
277 rate_found:
278 	/* set SGI flag only if this is SGI rate */
279 	if (match_rate && is_sgi == true)
280 		*mcs_rate_flag |= TX_RATE_SGI;
281 
282 	WMA_LOGD("%s - match_rate: %d index: %d rate_flag: 0x%x is_sgi: %d",
283 		 __func__, match_rate, index, *mcs_rate_flag, is_sgi);
284 
285 	return match_rate ? index : INVALID_MCS_IDX;
286 }
287 
288 void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id,
289 					int32_t rssi)
290 {
291 	struct sir_lost_link_info *lost_link_info;
292 	QDF_STATUS qdf_status;
293 	struct scheduler_msg sme_msg = {0};
294 
295 	if (vdev_id >= wma->max_bssid) {
296 		WMA_LOGE("%s: received invalid vdev_id %d",
297 			 __func__, vdev_id);
298 		return;
299 	}
300 
301 	/* report lost link information only for STA mode */
302 	if (wma_is_vdev_up(vdev_id) &&
303 	    (WMI_VDEV_TYPE_STA == wma->interfaces[vdev_id].type) &&
304 	    (0 == wma->interfaces[vdev_id].sub_type)) {
305 		lost_link_info = qdf_mem_malloc(sizeof(*lost_link_info));
306 		if (!lost_link_info)
307 			return;
308 
309 		lost_link_info->vdev_id = vdev_id;
310 		lost_link_info->rssi = rssi;
311 		sme_msg.type = eWNI_SME_LOST_LINK_INFO_IND;
312 		sme_msg.bodyptr = lost_link_info;
313 		sme_msg.bodyval = 0;
314 		WMA_LOGD("%s: post msg to SME, bss_idx %d, rssi %d",  __func__,
315 			 lost_link_info->vdev_id, lost_link_info->rssi);
316 
317 		qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA,
318 						    QDF_MODULE_ID_SME,
319 						    QDF_MODULE_ID_SME,
320 						    &sme_msg);
321 		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
322 			WMA_LOGE("%s: fail to post msg to SME", __func__);
323 			qdf_mem_free(lost_link_info);
324 		}
325 	}
326 }
327 
328 /**
329  * host_map_smps_mode() - map fw smps mode to enum eSmpsModeValue
330  * @fw_smps_mode: fw smps mode
331  *
332  * Return: return enum eSmpsModeValue
333  */
334 enum eSmpsModeValue host_map_smps_mode(A_UINT32 fw_smps_mode)
335 {
336 	enum eSmpsModeValue smps_mode = SMPS_MODE_DISABLED;
337 
338 	switch (fw_smps_mode) {
339 	case WMI_SMPS_FORCED_MODE_STATIC:
340 		smps_mode = STATIC_SMPS_MODE;
341 		break;
342 	case WMI_SMPS_FORCED_MODE_DYNAMIC:
343 		smps_mode = DYNAMIC_SMPS_MODE;
344 		break;
345 	default:
346 		smps_mode = SMPS_MODE_DISABLED;
347 	}
348 
349 	return smps_mode;
350 }
351 
352 /**
353  * wma_smps_mode_to_force_mode_param() - Map smps mode to force
354  * mode commmand param
355  * @smps_mode: SMPS mode according to the protocol
356  *
357  * Return: int > 0 for success else failure
358  */
359 int wma_smps_mode_to_force_mode_param(uint8_t smps_mode)
360 {
361 	int param = -EINVAL;
362 
363 	switch (smps_mode) {
364 	case STATIC_SMPS_MODE:
365 		param = WMI_SMPS_FORCED_MODE_STATIC;
366 		break;
367 	case DYNAMIC_SMPS_MODE:
368 		param = WMI_SMPS_FORCED_MODE_DYNAMIC;
369 		break;
370 	case SMPS_MODE_DISABLED:
371 		param = WMI_SMPS_FORCED_MODE_DISABLED;
372 		break;
373 	default:
374 		WMA_LOGE(FL("smps mode cannot be mapped :%d "),
375 			 smps_mode);
376 	}
377 	return param;
378 }
379 
380 #ifdef WLAN_FEATURE_STATS_EXT
381 /**
382  * wma_stats_ext_event_handler() - extended stats event handler
383  * @handle:     wma handle
384  * @event_buf:  event buffer received from fw
385  * @len:        length of data
386  *
387  * Return: 0 for success or error code
388  */
389 int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf,
390 				uint32_t len)
391 {
392 	WMI_STATS_EXT_EVENTID_param_tlvs *param_buf;
393 	tSirStatsExtEvent *stats_ext_event;
394 	wmi_stats_ext_event_fixed_param *stats_ext_info;
395 	QDF_STATUS status;
396 	struct scheduler_msg cds_msg = {0};
397 	uint8_t *buf_ptr;
398 	uint32_t alloc_len;
399 
400 	WMA_LOGD("%s: Posting stats ext event to SME", __func__);
401 
402 	param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *) event_buf;
403 	if (!param_buf) {
404 		WMA_LOGE("%s: Invalid stats ext event buf", __func__);
405 		return -EINVAL;
406 	}
407 
408 	stats_ext_info = param_buf->fixed_param;
409 	buf_ptr = (uint8_t *) stats_ext_info;
410 
411 	alloc_len = sizeof(tSirStatsExtEvent);
412 	alloc_len += stats_ext_info->data_len;
413 
414 	if (stats_ext_info->data_len > (WMI_SVC_MSG_MAX_SIZE -
415 	    WMI_TLV_HDR_SIZE - sizeof(*stats_ext_info)) ||
416 	    stats_ext_info->data_len > param_buf->num_data) {
417 		WMA_LOGE("Excess data_len:%d, num_data:%d",
418 			stats_ext_info->data_len, param_buf->num_data);
419 		return -EINVAL;
420 	}
421 	stats_ext_event = qdf_mem_malloc(alloc_len);
422 	if (!stats_ext_event)
423 		return -ENOMEM;
424 
425 	buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE;
426 
427 	stats_ext_event->vdev_id = stats_ext_info->vdev_id;
428 	stats_ext_event->event_data_len = stats_ext_info->data_len;
429 	qdf_mem_copy(stats_ext_event->event_data,
430 		     buf_ptr, stats_ext_event->event_data_len);
431 
432 	cds_msg.type = eWNI_SME_STATS_EXT_EVENT;
433 	cds_msg.bodyptr = (void *)stats_ext_event;
434 	cds_msg.bodyval = 0;
435 
436 	status = scheduler_post_message(QDF_MODULE_ID_WMA,
437 					QDF_MODULE_ID_SME,
438 					QDF_MODULE_ID_SME, &cds_msg);
439 	if (status != QDF_STATUS_SUCCESS) {
440 		qdf_mem_free(stats_ext_event);
441 		return -EFAULT;
442 	}
443 
444 	WMA_LOGD("%s: stats ext event Posted to SME", __func__);
445 	return 0;
446 }
447 #endif /* WLAN_FEATURE_STATS_EXT */
448 
449 
450 /**
451  * wma_profile_data_report_event_handler() - fw profiling handler
452  * @handle:     wma handle
453  * @event_buf:  event buffer received from fw
454  * @len:        length of data
455  *
456  * Return: 0 for success or error code
457  */
458 int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf,
459 				uint32_t len)
460 {
461 	WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *param_buf;
462 	wmi_wlan_profile_ctx_t *profile_ctx;
463 	wmi_wlan_profile_t *profile_data;
464 	uint32_t i = 0;
465 	uint32_t entries;
466 	uint8_t *buf_ptr;
467 	char temp_str[150];
468 
469 	param_buf = (WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *) event_buf;
470 	if (!param_buf) {
471 		WMA_LOGE("%s: Invalid profile data event buf", __func__);
472 		return -EINVAL;
473 	}
474 	profile_ctx = param_buf->profile_ctx;
475 	buf_ptr = (uint8_t *)profile_ctx;
476 	buf_ptr = buf_ptr + sizeof(wmi_wlan_profile_ctx_t) + WMI_TLV_HDR_SIZE;
477 	profile_data = (wmi_wlan_profile_t *) buf_ptr;
478 	entries = profile_ctx->bin_count;
479 
480 	if (entries > param_buf->num_profile_data) {
481 		WMA_LOGE("FW bin count %d more than data %d in TLV hdr",
482 			 entries,
483 			 param_buf->num_profile_data);
484 		return -EINVAL;
485 	}
486 
487 	QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
488 				"Profile data stats\n");
489 	QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
490 		"TOT: %d\n"
491 		"tx_msdu_cnt: %d\n"
492 		"tx_mpdu_cnt: %d\n"
493 		"tx_ppdu_cnt: %d\n"
494 		"rx_msdu_cnt: %d\n"
495 		"rx_mpdu_cnt: %d\n"
496 		"bin_count: %d\n",
497 		profile_ctx->tot,
498 		profile_ctx->tx_msdu_cnt,
499 		profile_ctx->tx_mpdu_cnt,
500 		profile_ctx->tx_ppdu_cnt,
501 		profile_ctx->rx_msdu_cnt,
502 		profile_ctx->rx_mpdu_cnt,
503 		profile_ctx->bin_count);
504 
505 	QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
506 		  "Profile ID: Count: TOT: Min: Max: hist_intvl: hist[0]: hist[1]:hist[2]");
507 
508 	for (i = 0; i < entries; i++) {
509 		if (i == WMI_WLAN_PROFILE_MAX_BIN_CNT)
510 			break;
511 		snprintf(temp_str, sizeof(temp_str),
512 			 " %d : %d : %d : %d : %d : %d : %d : %d : %d",
513 			profile_data[i].id,
514 			profile_data[i].cnt,
515 			profile_data[i].tot,
516 			profile_data[i].min,
517 			profile_data[i].max,
518 			profile_data[i].hist_intvl,
519 			profile_data[i].hist[0],
520 			profile_data[i].hist[1],
521 			profile_data[i].hist[2]);
522 		QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
523 			"%s", temp_str);
524 	}
525 
526 	return 0;
527 }
528 
529 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
530 
531 #define WMA_FILL_TX_STATS(eve, msg)   do {\
532 	(msg)->msdus = (eve)->tx_msdu_cnt;\
533 	(msg)->mpdus = (eve)->tx_mpdu_cnt;\
534 	(msg)->ppdus = (eve)->tx_ppdu_cnt;\
535 	(msg)->bytes = (eve)->tx_bytes;\
536 	(msg)->drops = (eve)->tx_msdu_drop_cnt;\
537 	(msg)->drop_bytes = (eve)->tx_drop_bytes;\
538 	(msg)->retries = (eve)->tx_mpdu_retry_cnt;\
539 	(msg)->failed = (eve)->tx_mpdu_fail_cnt;\
540 } while (0)
541 
542 #define WMA_FILL_RX_STATS(eve, msg)       do {\
543 	(msg)->mpdus = (eve)->mac_rx_mpdu_cnt;\
544 	(msg)->bytes = (eve)->mac_rx_bytes;\
545 	(msg)->ppdus = (eve)->phy_rx_ppdu_cnt;\
546 	(msg)->ppdu_bytes = (eve)->phy_rx_bytes;\
547 	(msg)->mpdu_retry = (eve)->rx_mpdu_retry_cnt;\
548 	(msg)->mpdu_dup = (eve)->rx_mpdu_dup_cnt;\
549 	(msg)->mpdu_discard = (eve)->rx_mpdu_discard_cnt;\
550 } while (0)
551 
552 /**
553  * wma_get_ll_stats_ext_buf() - alloc result buffer for MAC counters
554  * @len: buffer length output
555  * @peer_num: peer number
556  * @fixed_param: fixed parameters in WMI event
557  *
558  * Structure of the stats message
559  * LL_EXT_STATS
560  *  |
561  *  |--Channel stats[1~n]
562  *  |--Peer[1~n]
563  *      |
564  *      +---Signal
565  *      +---TX
566  *      |    +---BE
567  *      |    +---BK
568  *      |    +---VI
569  *      |    +---VO
570  *      |
571  *      +---RX
572  *           +---BE
573  *           +---BK
574  *           +---VI
575  *           +---VO
576  * For each Access Category, the arregation and mcs
577  * stats are as this:
578  *  TX
579  *   +-BE/BK/VI/VO
580  *         +----tx_mpdu_aggr_array
581  *         +----tx_succ_mcs_array
582  *         +----tx_fail_mcs_array
583  *         +----tx_delay_array
584  *  RX
585  *   +-BE/BK/VI/VO
586  *         +----rx_mpdu_aggr_array
587  *         +----rx_mcs_array
588  *
589  * return: Address for result buffer.
590  */
591 static tSirLLStatsResults *wma_get_ll_stats_ext_buf(uint32_t *len,
592 						    uint32_t peer_num,
593 			wmi_report_stats_event_fixed_param *fixed_param)
594 {
595 	tSirLLStatsResults *buf;
596 	uint32_t buf_len;
597 	uint32_t total_array_len, total_peer_len;
598 	bool excess_data = false;
599 
600 	if (!len || !fixed_param) {
601 		WMA_LOGE(FL("Invalid input parameters."));
602 		return NULL;
603 	}
604 
605 	/*
606 	 * Result buffer has a structure like this:
607 	 *     ---------------------------------
608 	 *     |      trigger_cond_i           |
609 	 *     +-------------------------------+
610 	 *     |      cca_chgd_bitmap          |
611 	 *     +-------------------------------+
612 	 *     |      sig_chgd_bitmap          |
613 	 *     +-------------------------------+
614 	 *     |      tx_chgd_bitmap           |
615 	 *     +-------------------------------+
616 	 *     |      rx_chgd_bitmap           |
617 	 *     +-------------------------------+
618 	 *     |      peer_num                 |
619 	 *     +-------------------------------+
620 	 *     |      channel_num              |
621 	 *     +-------------------------------+
622 	 *     |      tx_mpdu_aggr_array_len   |
623 	 *     +-------------------------------+
624 	 *     |      tx_succ_mcs_array_len    |
625 	 *     +-------------------------------+
626 	 *     |      tx_fail_mcs_array_len    |
627 	 *     +-------------------------------+
628 	 *     |      tx_delay_array_len       |
629 	 *     +-------------------------------+
630 	 *     |      rx_mpdu_aggr_array_len   |
631 	 *     +-------------------------------+
632 	 *     |      rx_mcs_array_len         |
633 	 *     +-------------------------------+
634 	 *     |      pointer to CCA stats     |
635 	 *     +-------------------------------+
636 	 *     |      CCA stats                |
637 	 *     +-------------------------------+
638 	 *     |      peer_stats               |----+
639 	 *     +-------------------------------+    |
640 	 *     | TX aggr/mcs parameters array  |    |
641 	 *     | Length of this buffer is      |    |
642 	 *     | not fixed.                    |<-+ |
643 	 *     +-------------------------------+  | |
644 	 *     |      per peer tx stats        |--+ |
645 	 *     |         BE                    | <--+
646 	 *     |         BK                    |    |
647 	 *     |         VI                    |    |
648 	 *     |         VO                    |    |
649 	 *     +-------------------------------+    |
650 	 *     | TX aggr/mcs parameters array  |    |
651 	 *     | Length of this buffer is      |    |
652 	 *     | not fixed.                    |<-+ |
653 	 *     +-------------------------------+  | |
654 	 *     |      peer peer rx stats       |--+ |
655 	 *     |         BE                    | <--+
656 	 *     |         BK                    |
657 	 *     |         VI                    |
658 	 *     |         VO                    |
659 	 *     ---------------------------------
660 	 */
661 
662 	buf_len = sizeof(tSirLLStatsResults) +
663 		  sizeof(struct sir_wifi_ll_ext_stats);
664 	do {
665 		if (fixed_param->num_chan_cca_stats > (WMI_SVC_MSG_MAX_SIZE /
666 		    sizeof(struct sir_wifi_chan_cca_stats))) {
667 			excess_data = true;
668 			break;
669 		}
670 		buf_len += (fixed_param->num_chan_cca_stats *
671 				sizeof(struct sir_wifi_chan_cca_stats));
672 		if (fixed_param->tx_mpdu_aggr_array_len >
673 		    WMI_SVC_MSG_MAX_SIZE) {
674 			excess_data = true;
675 			break;
676 		} else {
677 			total_array_len = fixed_param->tx_mpdu_aggr_array_len;
678 		}
679 		if (fixed_param->tx_succ_mcs_array_len >
680 		    (WMI_SVC_MSG_MAX_SIZE - total_array_len)) {
681 			excess_data = true;
682 			break;
683 		} else {
684 			total_array_len += fixed_param->tx_succ_mcs_array_len;
685 		}
686 		if (fixed_param->tx_fail_mcs_array_len >
687 		    (WMI_SVC_MSG_MAX_SIZE - total_array_len)) {
688 			excess_data = true;
689 			break;
690 		} else {
691 			total_array_len += fixed_param->tx_fail_mcs_array_len;
692 		}
693 		if (fixed_param->tx_ppdu_delay_array_len >
694 		    (WMI_SVC_MSG_MAX_SIZE - total_array_len)) {
695 			excess_data = true;
696 			break;
697 		} else {
698 			total_array_len += fixed_param->tx_ppdu_delay_array_len;
699 		}
700 		if (fixed_param->rx_mpdu_aggr_array_len >
701 		    (WMI_SVC_MSG_MAX_SIZE - total_array_len)) {
702 			excess_data = true;
703 			break;
704 		} else {
705 			total_array_len += fixed_param->rx_mpdu_aggr_array_len;
706 		}
707 		if (fixed_param->rx_mcs_array_len >
708 		    (WMI_SVC_MSG_MAX_SIZE - total_array_len)) {
709 			excess_data = true;
710 			break;
711 		} else {
712 			total_array_len += fixed_param->rx_mcs_array_len;
713 		}
714 
715 		if (total_array_len > (WMI_SVC_MSG_MAX_SIZE /
716 		    (sizeof(uint32_t) * WLAN_MAX_AC))) {
717 			excess_data = true;
718 			break;
719 		} else {
720 			total_peer_len = (sizeof(uint32_t) * WLAN_MAX_AC *
721 					 total_array_len) +
722 					 (WLAN_MAX_AC *
723 					 (sizeof(struct sir_wifi_tx) +
724 					 sizeof(struct sir_wifi_rx)));
725 		}
726 		if (total_peer_len > WMI_SVC_MSG_MAX_SIZE) {
727 			excess_data = true;
728 			break;
729 		}
730 		if (peer_num > WMI_SVC_MSG_MAX_SIZE / (total_peer_len +
731 		    sizeof(struct sir_wifi_ll_ext_peer_stats))) {
732 			excess_data = true;
733 			break;
734 		} else {
735 			buf_len += peer_num *
736 				   (sizeof(struct sir_wifi_ll_ext_peer_stats) +
737 				    total_peer_len);
738 		}
739 	} while (0);
740 
741 	if (excess_data || (buf_len > WMI_SVC_MSG_MAX_SIZE)) {
742 		WMA_LOGE("%s: excess wmi buffer: peer %d cca %d tx_mpdu %d tx_succ%d tx_fail %d tx_ppdu %d rx_mpdu %d rx_mcs %d",
743 			 __func__, peer_num, fixed_param->num_chan_cca_stats,
744 			 fixed_param->tx_mpdu_aggr_array_len,
745 			 fixed_param->tx_succ_mcs_array_len,
746 			 fixed_param->tx_fail_mcs_array_len,
747 			 fixed_param->tx_ppdu_delay_array_len,
748 			 fixed_param->rx_mpdu_aggr_array_len,
749 			 fixed_param->rx_mcs_array_len);
750 		return NULL;
751 	}
752 
753 	buf = qdf_mem_malloc(buf_len);
754 	if (!buf)
755 		*len = 0;
756 	else
757 		*len = buf_len;
758 
759 	return buf;
760 }
761 
762 /**
763  * wma_fill_tx_stats() - Fix TX stats into result buffer
764  * @ll_stats: LL stats buffer
765  * @fix_param: parameters with fixed length in WMI event
766  * @param_buf: parameters without fixed length in WMI event
767  * @buf: buffer for TLV parameters
768  *
769  * Return: QDF_STATUS
770  */
771 static QDF_STATUS
772 wma_fill_tx_stats(struct sir_wifi_ll_ext_stats *ll_stats,
773 		  wmi_report_stats_event_fixed_param *fix_param,
774 		  WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf,
775 		  uint8_t **buf, uint32_t *buf_length)
776 {
777 	uint8_t *result;
778 	uint32_t i, j, k;
779 	wmi_peer_ac_tx_stats *wmi_peer_tx;
780 	wmi_tx_stats *wmi_tx;
781 	struct sir_wifi_tx *tx_stats;
782 	struct sir_wifi_ll_ext_peer_stats *peer_stats;
783 	uint32_t *tx_mpdu_aggr, *tx_succ_mcs, *tx_fail_mcs, *tx_delay;
784 	uint32_t len, dst_len, param_len, tx_mpdu_aggr_array_len,
785 		 tx_succ_mcs_array_len, tx_fail_mcs_array_len,
786 		 tx_delay_array_len;
787 
788 	result = *buf;
789 	dst_len = *buf_length;
790 	tx_mpdu_aggr_array_len = fix_param->tx_mpdu_aggr_array_len;
791 	ll_stats->tx_mpdu_aggr_array_len = tx_mpdu_aggr_array_len;
792 	tx_succ_mcs_array_len = fix_param->tx_succ_mcs_array_len;
793 	ll_stats->tx_succ_mcs_array_len = tx_succ_mcs_array_len;
794 	tx_fail_mcs_array_len = fix_param->tx_fail_mcs_array_len;
795 	ll_stats->tx_fail_mcs_array_len = tx_fail_mcs_array_len;
796 	tx_delay_array_len = fix_param->tx_ppdu_delay_array_len;
797 	ll_stats->tx_delay_array_len = tx_delay_array_len;
798 	wmi_peer_tx = param_buf->peer_ac_tx_stats;
799 	wmi_tx = param_buf->tx_stats;
800 
801 	len = fix_param->num_peer_ac_tx_stats *
802 		WLAN_MAX_AC * tx_mpdu_aggr_array_len * sizeof(uint32_t);
803 	param_len = param_buf->num_tx_mpdu_aggr * sizeof(uint32_t);
804 	if (len <= dst_len && len <= param_len && param_buf->tx_mpdu_aggr) {
805 		tx_mpdu_aggr = (uint32_t *)result;
806 		qdf_mem_copy(tx_mpdu_aggr, param_buf->tx_mpdu_aggr, len);
807 		result += len;
808 		dst_len -= len;
809 	} else {
810 		WMA_LOGE(FL("TX_MPDU_AGGR invalid arg, %d, %d, %d"),
811 			 len, dst_len, param_len);
812 		return QDF_STATUS_E_FAILURE;
813 	}
814 
815 	len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC *
816 		tx_succ_mcs_array_len * sizeof(uint32_t);
817 	param_len = param_buf->num_tx_succ_mcs * sizeof(uint32_t);
818 	if (len <= dst_len && len <= param_len && param_buf->tx_succ_mcs) {
819 		tx_succ_mcs = (uint32_t *)result;
820 		qdf_mem_copy(tx_succ_mcs, param_buf->tx_succ_mcs, len);
821 		result += len;
822 		dst_len -= len;
823 	} else {
824 		WMA_LOGE(FL("TX_SUCC_MCS invalid arg, %d, %d, %d"),
825 			 len, dst_len, param_len);
826 		return QDF_STATUS_E_FAILURE;
827 	}
828 
829 	len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC *
830 		tx_fail_mcs_array_len * sizeof(uint32_t);
831 	param_len = param_buf->num_tx_fail_mcs * sizeof(uint32_t);
832 	if (len <= dst_len && len <= param_len && param_buf->tx_fail_mcs) {
833 		tx_fail_mcs = (uint32_t *)result;
834 		qdf_mem_copy(tx_fail_mcs, param_buf->tx_fail_mcs, len);
835 		result += len;
836 		dst_len -= len;
837 	} else {
838 		WMA_LOGE(FL("TX_FAIL_MCS invalid arg, %d, %d %d"),
839 			 len, dst_len, param_len);
840 		return QDF_STATUS_E_FAILURE;
841 	}
842 
843 	len = fix_param->num_peer_ac_tx_stats *
844 		WLAN_MAX_AC * tx_delay_array_len * sizeof(uint32_t);
845 	param_len = param_buf->num_tx_ppdu_delay * sizeof(uint32_t);
846 	if (len <= dst_len && len <= param_len && param_buf->tx_ppdu_delay) {
847 		tx_delay = (uint32_t *)result;
848 		qdf_mem_copy(tx_delay, param_buf->tx_ppdu_delay, len);
849 		result += len;
850 		dst_len -= len;
851 	} else {
852 		WMA_LOGE(FL("TX_DELAY invalid arg, %d, %d, %d"),
853 			 len, dst_len, param_len);
854 		return QDF_STATUS_E_FAILURE;
855 	}
856 
857 	/* per peer tx stats */
858 	peer_stats = ll_stats->peer_stats;
859 	if (!wmi_peer_tx || !wmi_tx || !peer_stats) {
860 		WMA_LOGE(FL("Invalid arg, peer_tx %pK, wmi_tx %pK stats %pK"),
861 			 wmi_peer_tx, wmi_tx, peer_stats);
862 		return QDF_STATUS_E_FAILURE;
863 	}
864 
865 	for (i = 0; i < fix_param->num_peer_ac_tx_stats; i++) {
866 		uint32_t peer_id = wmi_peer_tx[i].peer_id;
867 		struct sir_wifi_tx *ac;
868 		wmi_tx_stats *wmi_tx_stats;
869 
870 		for (j = 0; j < ll_stats->peer_num; j++) {
871 			peer_stats += j;
872 			if (peer_stats->peer_id == WIFI_INVALID_PEER_ID ||
873 			    peer_stats->peer_id == peer_id)
874 				break;
875 		}
876 
877 		if (j < ll_stats->peer_num) {
878 			peer_stats->peer_id = wmi_peer_tx[i].peer_id;
879 			peer_stats->vdev_id = wmi_peer_tx[i].vdev_id;
880 			tx_stats = (struct sir_wifi_tx *)result;
881 			for (k = 0; k < WLAN_MAX_AC; k++) {
882 				wmi_tx_stats = &wmi_tx[i * WLAN_MAX_AC + k];
883 				ac = &tx_stats[k];
884 				WMA_FILL_TX_STATS(wmi_tx_stats, ac);
885 				ac->mpdu_aggr_size = tx_mpdu_aggr;
886 				ac->aggr_len = tx_mpdu_aggr_array_len *
887 							sizeof(uint32_t);
888 				ac->success_mcs_len = tx_succ_mcs_array_len *
889 							sizeof(uint32_t);
890 				ac->success_mcs = tx_succ_mcs;
891 				ac->fail_mcs = tx_fail_mcs;
892 				ac->fail_mcs_len = tx_fail_mcs_array_len *
893 							sizeof(uint32_t);
894 				ac->delay = tx_delay;
895 				ac->delay_len = tx_delay_array_len *
896 							sizeof(uint32_t);
897 				peer_stats->ac_stats[k].tx_stats = ac;
898 				peer_stats->ac_stats[k].type = k;
899 				tx_mpdu_aggr += tx_mpdu_aggr_array_len;
900 				tx_succ_mcs += tx_succ_mcs_array_len;
901 				tx_fail_mcs += tx_fail_mcs_array_len;
902 				tx_delay += tx_delay_array_len;
903 			}
904 			result += WLAN_MAX_AC * sizeof(struct sir_wifi_tx);
905 		} else {
906 			/*
907 			 * Buffer for Peer TX counter overflow.
908 			 * There is peer ID mismatch between TX, RX,
909 			 * signal counters.
910 			 */
911 			WMA_LOGE(FL("One peer TX info is dropped."));
912 
913 			tx_mpdu_aggr += tx_mpdu_aggr_array_len * WLAN_MAX_AC;
914 			tx_succ_mcs += tx_succ_mcs_array_len * WLAN_MAX_AC;
915 			tx_fail_mcs += tx_fail_mcs_array_len * WLAN_MAX_AC;
916 			tx_delay += tx_delay_array_len * WLAN_MAX_AC;
917 		}
918 	}
919 	*buf = result;
920 	*buf_length = dst_len;
921 
922 	return QDF_STATUS_SUCCESS;
923 }
924 
925 /**
926  * wma_fill_rx_stats() - Fix RX stats into result buffer
927  * @ll_stats: LL stats buffer
928  * @fix_param: parameters with fixed length in WMI event
929  * @param_buf: parameters without fixed length in WMI event
930  * @buf: buffer for TLV parameters
931  *
932  * Return: QDF_STATUS
933  */
934 static QDF_STATUS
935 wma_fill_rx_stats(struct sir_wifi_ll_ext_stats *ll_stats,
936 		  wmi_report_stats_event_fixed_param *fix_param,
937 		  WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf,
938 		  uint8_t **buf, uint32_t *buf_length)
939 {
940 	uint8_t *result;
941 	uint32_t i, j, k;
942 	uint32_t *rx_mpdu_aggr, *rx_mcs;
943 	wmi_rx_stats *wmi_rx;
944 	wmi_peer_ac_rx_stats *wmi_peer_rx;
945 	struct sir_wifi_rx *rx_stats;
946 	struct sir_wifi_ll_ext_peer_stats *peer_stats;
947 	uint32_t len, dst_len, param_len,
948 		 rx_mpdu_aggr_array_len, rx_mcs_array_len;
949 
950 	rx_mpdu_aggr_array_len = fix_param->rx_mpdu_aggr_array_len;
951 	ll_stats->rx_mpdu_aggr_array_len = rx_mpdu_aggr_array_len;
952 	rx_mcs_array_len = fix_param->rx_mcs_array_len;
953 	ll_stats->rx_mcs_array_len = rx_mcs_array_len;
954 	wmi_peer_rx = param_buf->peer_ac_rx_stats;
955 	wmi_rx = param_buf->rx_stats;
956 
957 	result = *buf;
958 	dst_len = *buf_length;
959 	len = sizeof(uint32_t) * (fix_param->num_peer_ac_rx_stats *
960 				  WLAN_MAX_AC * rx_mpdu_aggr_array_len);
961 	param_len = param_buf->num_rx_mpdu_aggr * sizeof(uint32_t);
962 	if (len <= dst_len && len <= param_len && param_buf->rx_mpdu_aggr) {
963 		rx_mpdu_aggr = (uint32_t *)result;
964 		qdf_mem_copy(rx_mpdu_aggr, param_buf->rx_mpdu_aggr, len);
965 		result += len;
966 		dst_len -= len;
967 	} else {
968 		WMA_LOGE(FL("RX_MPDU_AGGR invalid arg %d, %d, %d"),
969 			 len, dst_len, param_len);
970 		return QDF_STATUS_E_FAILURE;
971 	}
972 
973 	len = sizeof(uint32_t) * (fix_param->num_peer_ac_rx_stats *
974 				  WLAN_MAX_AC * rx_mcs_array_len);
975 	param_len = param_buf->num_rx_mcs * sizeof(uint32_t);
976 	if (len <= dst_len && len <= param_len && param_buf->rx_mcs) {
977 		rx_mcs = (uint32_t *)result;
978 		qdf_mem_copy(rx_mcs, param_buf->rx_mcs, len);
979 		result += len;
980 		dst_len -= len;
981 	} else {
982 		WMA_LOGE(FL("RX_MCS invalid arg %d, %d, %d"),
983 			 len, dst_len, param_len);
984 		return QDF_STATUS_E_FAILURE;
985 	}
986 
987 	/* per peer rx stats */
988 	peer_stats = ll_stats->peer_stats;
989 	if (!wmi_peer_rx || !wmi_rx || !peer_stats) {
990 		WMA_LOGE(FL("Invalid arg, peer_rx %pK, wmi_rx %pK stats %pK"),
991 			 wmi_peer_rx, wmi_rx, peer_stats);
992 		return QDF_STATUS_E_FAILURE;
993 	}
994 	for (i = 0; i < fix_param->num_peer_ac_rx_stats; i++) {
995 		uint32_t peer_id = wmi_peer_rx[i].peer_id;
996 		struct sir_wifi_rx *ac;
997 		wmi_rx_stats *wmi_rx_stats;
998 
999 		for (j = 0; j < ll_stats->peer_num; j++) {
1000 			peer_stats += j;
1001 			if ((peer_stats->peer_id == WIFI_INVALID_PEER_ID) ||
1002 			    (peer_stats->peer_id == peer_id))
1003 				break;
1004 		}
1005 
1006 		if (j < ll_stats->peer_num) {
1007 			peer_stats->peer_id = wmi_peer_rx[i].peer_id;
1008 			peer_stats->vdev_id = wmi_peer_rx[i].vdev_id;
1009 			peer_stats->sta_ps_inds = wmi_peer_rx[i].sta_ps_inds;
1010 			peer_stats->sta_ps_durs = wmi_peer_rx[i].sta_ps_durs;
1011 			peer_stats->rx_probe_reqs =
1012 						wmi_peer_rx[i].rx_probe_reqs;
1013 			peer_stats->rx_oth_mgmts = wmi_peer_rx[i].rx_oth_mgmts;
1014 			rx_stats = (struct sir_wifi_rx *)result;
1015 
1016 			for (k = 0; k < WLAN_MAX_AC; k++) {
1017 				wmi_rx_stats = &wmi_rx[i * WLAN_MAX_AC + k];
1018 				ac = &rx_stats[k];
1019 				WMA_FILL_RX_STATS(wmi_rx_stats, ac);
1020 				ac->mpdu_aggr = rx_mpdu_aggr;
1021 				ac->aggr_len = rx_mpdu_aggr_array_len *
1022 							sizeof(uint32_t);
1023 				ac->mcs = rx_mcs;
1024 				ac->mcs_len = rx_mcs_array_len *
1025 							sizeof(uint32_t);
1026 				peer_stats->ac_stats[k].rx_stats = ac;
1027 				peer_stats->ac_stats[k].type = k;
1028 				rx_mpdu_aggr += rx_mpdu_aggr_array_len;
1029 				rx_mcs += rx_mcs_array_len;
1030 			}
1031 			result += WLAN_MAX_AC * sizeof(struct sir_wifi_rx);
1032 		} else {
1033 			/*
1034 			 * Buffer for Peer RX counter overflow.
1035 			 * There is peer ID mismatch between TX, RX,
1036 			 * signal counters.
1037 			 */
1038 			WMA_LOGE(FL("One peer RX info is dropped."));
1039 			rx_mpdu_aggr += rx_mpdu_aggr_array_len * WLAN_MAX_AC;
1040 			rx_mcs += rx_mcs_array_len * WLAN_MAX_AC;
1041 		}
1042 	}
1043 	*buf = result;
1044 	*buf_length = dst_len;
1045 
1046 	return QDF_STATUS_SUCCESS;
1047 }
1048 
1049 /**
1050  * wma_ll_stats_evt_handler() - handler for MAC layer counters.
1051  * @handle - wma handle
1052  * @event - FW event
1053  * @len - length of FW event
1054  *
1055  * return: 0 success.
1056  */
1057 static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event,
1058 				    u_int32_t len)
1059 {
1060 	WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf;
1061 	wmi_report_stats_event_fixed_param *fixed_param;
1062 	tSirLLStatsResults *link_stats_results;
1063 	wmi_chan_cca_stats *wmi_cca_stats;
1064 	wmi_peer_signal_stats *wmi_peer_signal;
1065 	struct sir_wifi_ll_ext_stats *ll_stats;
1066 	struct sir_wifi_ll_ext_peer_stats *peer_stats;
1067 	struct sir_wifi_chan_cca_stats *cca_stats;
1068 	struct sir_wifi_peer_signal_stats *peer_signal;
1069 	uint8_t *result;
1070 	uint32_t i, peer_num, result_size, dst_len;
1071 	struct mac_context *mac;
1072 	struct scheduler_msg sme_msg = { 0 };
1073 	QDF_STATUS qdf_status;
1074 
1075 	mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE);
1076 	if (!mac) {
1077 		WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1078 		return -EINVAL;
1079 	}
1080 
1081 	if (!mac->sme.link_layer_stats_ext_cb) {
1082 		WMA_LOGD("%s: HDD callback is null", __func__);
1083 		return -EINVAL;
1084 	}
1085 
1086 	WMA_LOGD("%s: Posting MAC counters event to HDD", __func__);
1087 
1088 	param_buf = (WMI_REPORT_STATS_EVENTID_param_tlvs *)event;
1089 	if (!param_buf) {
1090 		WMA_LOGD("%s: param_buf is null", __func__);
1091 		return -EINVAL;
1092 	}
1093 	fixed_param = param_buf->fixed_param;
1094 	if (!fixed_param) {
1095 		WMA_LOGD("%s: fixed_param is null", __func__);
1096 		return -EINVAL;
1097 	}
1098 	wmi_cca_stats = param_buf->chan_cca_stats;
1099 	wmi_peer_signal = param_buf->peer_signal_stats;
1100 	if (fixed_param->num_peer_signal_stats >
1101 		param_buf->num_peer_signal_stats ||
1102 		fixed_param->num_peer_ac_tx_stats >
1103 		param_buf->num_peer_ac_tx_stats ||
1104 		fixed_param->num_peer_ac_rx_stats >
1105 		param_buf->num_peer_ac_rx_stats) {
1106 		WMA_LOGE("%s: excess num_peer_signal_stats:%d, num_peer_ac_tx_stats:%d, num_peer_ac_rx_stats:%d",
1107 			__func__, fixed_param->num_peer_signal_stats,
1108 			fixed_param->num_peer_ac_tx_stats,
1109 			fixed_param->num_peer_ac_rx_stats);
1110 		return -EINVAL;
1111 	}
1112 
1113 	/* Get the MAX of three peer numbers */
1114 	peer_num = fixed_param->num_peer_signal_stats >
1115 			fixed_param->num_peer_ac_tx_stats ?
1116 			fixed_param->num_peer_signal_stats :
1117 			fixed_param->num_peer_ac_tx_stats;
1118 	peer_num = peer_num > fixed_param->num_peer_ac_rx_stats ?
1119 			peer_num : fixed_param->num_peer_ac_rx_stats;
1120 
1121 	if (peer_num == 0)
1122 		return -EINVAL;
1123 
1124 	link_stats_results = wma_get_ll_stats_ext_buf(&result_size,
1125 						      peer_num,
1126 						      fixed_param);
1127 	if (!link_stats_results) {
1128 		WMA_LOGE("%s: Fail to allocate stats buffer", __func__);
1129 		return -EINVAL;
1130 	}
1131 	link_stats_results->paramId = WMI_LL_STATS_EXT_MAC_COUNTER;
1132 	link_stats_results->num_peers = peer_num;
1133 	link_stats_results->peer_event_number = 1;
1134 	link_stats_results->moreResultToFollow = 0;
1135 
1136 	ll_stats = (struct sir_wifi_ll_ext_stats *)link_stats_results->results;
1137 	ll_stats->trigger_cond_id = fixed_param->trigger_cond_id;
1138 	ll_stats->cca_chgd_bitmap = fixed_param->cca_chgd_bitmap;
1139 	ll_stats->sig_chgd_bitmap = fixed_param->sig_chgd_bitmap;
1140 	ll_stats->tx_chgd_bitmap = fixed_param->tx_chgd_bitmap;
1141 	ll_stats->rx_chgd_bitmap = fixed_param->rx_chgd_bitmap;
1142 	ll_stats->channel_num = fixed_param->num_chan_cca_stats;
1143 	ll_stats->peer_num = peer_num;
1144 
1145 	result = (uint8_t *)ll_stats->stats;
1146 	if (!result) {
1147 		WMA_LOGE("%s: result is null", __func__);
1148 		qdf_mem_free(link_stats_results);
1149 		return -EINVAL;
1150 	}
1151 	peer_stats = (struct sir_wifi_ll_ext_peer_stats *)result;
1152 	ll_stats->peer_stats = peer_stats;
1153 
1154 	for (i = 0; i < peer_num && peer_stats; i++) {
1155 		peer_stats[i].peer_id = WIFI_INVALID_PEER_ID;
1156 		peer_stats[i].vdev_id = WIFI_INVALID_VDEV_ID;
1157 	}
1158 
1159 	/* Per peer signal */
1160 	result_size -= sizeof(struct sir_wifi_ll_ext_stats);
1161 	dst_len = sizeof(struct sir_wifi_peer_signal_stats);
1162 	for (i = 0;
1163 	     i < fixed_param->num_peer_signal_stats &&
1164 	     peer_stats && wmi_peer_signal;
1165 	     i++) {
1166 		peer_stats[i].peer_id = wmi_peer_signal->peer_id;
1167 		peer_stats[i].vdev_id = wmi_peer_signal->vdev_id;
1168 		peer_signal = &peer_stats[i].peer_signal_stats;
1169 
1170 		WMA_LOGD("%d antennas for peer %d",
1171 			 wmi_peer_signal->num_chains_valid,
1172 			 wmi_peer_signal->peer_id);
1173 		if (dst_len <= result_size && peer_signal) {
1174 			peer_signal->vdev_id = wmi_peer_signal->vdev_id;
1175 			peer_signal->peer_id = wmi_peer_signal->peer_id;
1176 			peer_signal->num_chain =
1177 					wmi_peer_signal->num_chains_valid;
1178 			qdf_mem_copy(peer_signal->per_ant_snr,
1179 				     wmi_peer_signal->per_chain_snr,
1180 				     sizeof(peer_signal->per_ant_snr));
1181 			qdf_mem_copy(peer_signal->nf,
1182 				     wmi_peer_signal->per_chain_nf,
1183 				     sizeof(peer_signal->nf));
1184 			qdf_mem_copy(peer_signal->per_ant_rx_mpdus,
1185 				     wmi_peer_signal->per_antenna_rx_mpdus,
1186 				     sizeof(peer_signal->per_ant_rx_mpdus));
1187 			qdf_mem_copy(peer_signal->per_ant_tx_mpdus,
1188 				     wmi_peer_signal->per_antenna_tx_mpdus,
1189 				     sizeof(peer_signal->per_ant_tx_mpdus));
1190 			result_size -= dst_len;
1191 		} else {
1192 			WMA_LOGE(FL("Invalid length of PEER signal."));
1193 		}
1194 		wmi_peer_signal++;
1195 	}
1196 
1197 	result += peer_num * sizeof(struct sir_wifi_ll_ext_peer_stats);
1198 	cca_stats = (struct sir_wifi_chan_cca_stats *)result;
1199 	ll_stats->cca = cca_stats;
1200 	dst_len = sizeof(*cca_stats);
1201 	for (i = 0;
1202 	     i < ll_stats->channel_num && cca_stats && wmi_cca_stats;
1203 	     i++) {
1204 		if (dst_len <= result_size) {
1205 			cca_stats->vdev_id = wmi_cca_stats->vdev_id;
1206 			cca_stats->idle_time = wmi_cca_stats->idle_time;
1207 			cca_stats->tx_time = wmi_cca_stats->tx_time;
1208 			cca_stats->rx_in_bss_time =
1209 				wmi_cca_stats->rx_in_bss_time;
1210 			cca_stats->rx_out_bss_time =
1211 				wmi_cca_stats->rx_out_bss_time;
1212 			cca_stats->rx_busy_time = wmi_cca_stats->rx_busy_time;
1213 			cca_stats->rx_in_bad_cond_time =
1214 				wmi_cca_stats->rx_in_bad_cond_time;
1215 			cca_stats->tx_in_bad_cond_time =
1216 				wmi_cca_stats->tx_in_bad_cond_time;
1217 			cca_stats->wlan_not_avail_time =
1218 				wmi_cca_stats->wlan_not_avail_time;
1219 			result_size -= dst_len;
1220 		} else {
1221 			WMA_LOGE(FL("Invalid length of CCA."));
1222 		}
1223 		cca_stats++;
1224 	}
1225 
1226 	result += i * sizeof(struct sir_wifi_chan_cca_stats);
1227 	qdf_status = wma_fill_tx_stats(ll_stats, fixed_param, param_buf,
1228 				       &result, &result_size);
1229 	if (QDF_IS_STATUS_SUCCESS(qdf_status))
1230 		qdf_status = wma_fill_rx_stats(ll_stats, fixed_param, param_buf,
1231 					       &result, &result_size);
1232 	if (QDF_IS_STATUS_SUCCESS(qdf_status)) {
1233 		sme_msg.type = eWMI_SME_LL_STATS_IND;
1234 		sme_msg.bodyptr = (void *)link_stats_results;
1235 		sme_msg.bodyval = 0;
1236 		qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA,
1237 						    QDF_MODULE_ID_SME,
1238 						    QDF_MODULE_ID_SME,
1239 						    &sme_msg);
1240 	}
1241 
1242 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1243 		qdf_mem_free(link_stats_results);
1244 		return -EINVAL;
1245 	}
1246 
1247 	return 0;
1248 }
1249 
1250 /**
1251  * wma_unified_link_peer_stats_event_handler() - peer stats event handler
1252  * @handle:          wma handle
1253  * @cmd_param_info:  data received with event from fw
1254  * @len:             length of data
1255  *
1256  * Return: 0 for success or error code
1257  */
1258 static int wma_unified_link_peer_stats_event_handler(void *handle,
1259 						     uint8_t *cmd_param_info,
1260 						     uint32_t len)
1261 {
1262 	WMI_PEER_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
1263 	wmi_peer_stats_event_fixed_param *fixed_param;
1264 	wmi_peer_link_stats *peer_stats, *temp_peer_stats;
1265 	wmi_rate_stats *rate_stats;
1266 	tSirLLStatsResults *link_stats_results;
1267 	uint8_t *results, *t_peer_stats, *t_rate_stats;
1268 	uint32_t count, rate_cnt;
1269 	uint32_t total_num_rates = 0;
1270 	uint32_t next_res_offset, next_peer_offset, next_rate_offset;
1271 	size_t peer_info_size, peer_stats_size, rate_stats_size;
1272 	size_t link_stats_results_size;
1273 	bool excess_data = false;
1274 	uint32_t buf_len = 0;
1275 
1276 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1277 
1278 	if (!mac) {
1279 		WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1280 		return -EINVAL;
1281 	}
1282 
1283 	if (!mac->sme.link_layer_stats_cb) {
1284 		WMA_LOGD("%s: HDD callback is null", __func__);
1285 		return -EINVAL;
1286 	}
1287 
1288 	param_tlvs = (WMI_PEER_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
1289 	if (!param_tlvs) {
1290 		WMA_LOGA("%s: Invalid stats event", __func__);
1291 		return -EINVAL;
1292 	}
1293 	/*
1294 	 * cmd_param_info contains
1295 	 * wmi_peer_stats_event_fixed_param fixed_param;
1296 	 * num_peers * size of(struct wmi_peer_link_stats)
1297 	 * total_num_rates * size of(struct wmi_rate_stats)
1298 	 * total_num_rates is the sum of the rates of all the peers.
1299 	 */
1300 	fixed_param = param_tlvs->fixed_param;
1301 	peer_stats = param_tlvs->peer_stats;
1302 	rate_stats = param_tlvs->peer_rate_stats;
1303 
1304 	if (!fixed_param || !peer_stats ||
1305 	    (peer_stats->num_rates && !rate_stats)) {
1306 		WMA_LOGA("%s: Invalid param_tlvs for Peer Stats", __func__);
1307 		return -EINVAL;
1308 	}
1309 
1310 	do {
1311 		if (fixed_param->num_peers >
1312 		    WMI_SVC_MSG_MAX_SIZE/sizeof(wmi_peer_link_stats) ||
1313 		    fixed_param->num_peers > param_tlvs->num_peer_stats) {
1314 			excess_data = true;
1315 			break;
1316 		} else {
1317 			buf_len = fixed_param->num_peers *
1318 				sizeof(wmi_peer_link_stats);
1319 		}
1320 		temp_peer_stats = (wmi_peer_link_stats *) peer_stats;
1321 		for (count = 0; count < fixed_param->num_peers; count++) {
1322 			if (temp_peer_stats->num_rates >
1323 			    WMI_SVC_MSG_MAX_SIZE / sizeof(wmi_rate_stats)) {
1324 				excess_data = true;
1325 				break;
1326 			} else {
1327 				total_num_rates += temp_peer_stats->num_rates;
1328 				if (total_num_rates >
1329 				    WMI_SVC_MSG_MAX_SIZE /
1330 				    sizeof(wmi_rate_stats) || total_num_rates >
1331 				    param_tlvs->num_peer_rate_stats) {
1332 					excess_data = true;
1333 					break;
1334 				}
1335 				buf_len += temp_peer_stats->num_rates *
1336 					sizeof(wmi_rate_stats);
1337 			}
1338 			temp_peer_stats++;
1339 		}
1340 	} while (0);
1341 
1342 	if (excess_data ||
1343 	    (buf_len > WMI_SVC_MSG_MAX_SIZE - sizeof(*fixed_param))) {
1344 		WMA_LOGE("excess wmi buffer: rates:%d, peers:%d",
1345 			peer_stats->num_rates, fixed_param->num_peers);
1346 		return -EINVAL;
1347 	}
1348 
1349 	peer_stats_size = sizeof(struct wifi_peer_stat);
1350 	peer_info_size = sizeof(struct wifi_peer_info);
1351 	rate_stats_size = sizeof(struct wifi_rate_stat);
1352 	link_stats_results_size =
1353 		sizeof(*link_stats_results) + peer_stats_size +
1354 		(fixed_param->num_peers * peer_info_size) +
1355 		(total_num_rates * rate_stats_size);
1356 
1357 	link_stats_results = qdf_mem_malloc(link_stats_results_size);
1358 	if (!link_stats_results)
1359 		return -ENOMEM;
1360 
1361 	qdf_mem_zero(link_stats_results, link_stats_results_size);
1362 
1363 	link_stats_results->paramId = WMI_LINK_STATS_ALL_PEER;
1364 	link_stats_results->rspId = fixed_param->request_id;
1365 	link_stats_results->ifaceId = 0;
1366 	link_stats_results->num_peers = fixed_param->num_peers;
1367 	link_stats_results->peer_event_number = fixed_param->peer_event_number;
1368 	link_stats_results->moreResultToFollow = fixed_param->more_data;
1369 
1370 	qdf_mem_copy(link_stats_results->results,
1371 		     &fixed_param->num_peers, peer_stats_size);
1372 
1373 	results = (uint8_t *) link_stats_results->results;
1374 	t_peer_stats = (uint8_t *) peer_stats;
1375 	t_rate_stats = (uint8_t *) rate_stats;
1376 	next_res_offset = peer_stats_size;
1377 	next_peer_offset = WMI_TLV_HDR_SIZE;
1378 	next_rate_offset = WMI_TLV_HDR_SIZE;
1379 	for (rate_cnt = 0; rate_cnt < fixed_param->num_peers; rate_cnt++) {
1380 		qdf_mem_copy(results + next_res_offset,
1381 			     t_peer_stats + next_peer_offset, peer_info_size);
1382 		next_res_offset += peer_info_size;
1383 
1384 		/* Copy rate stats associated with this peer */
1385 		for (count = 0; count < peer_stats->num_rates; count++) {
1386 			rate_stats++;
1387 
1388 			qdf_mem_copy(results + next_res_offset,
1389 				     t_rate_stats + next_rate_offset,
1390 				     rate_stats_size);
1391 			next_res_offset += rate_stats_size;
1392 			next_rate_offset += sizeof(*rate_stats);
1393 		}
1394 		next_peer_offset += sizeof(*peer_stats);
1395 		peer_stats++;
1396 	}
1397 
1398 	/* call hdd callback with Link Layer Statistics
1399 	 * vdev_id/ifacId in link_stats_results will be
1400 	 * used to retrieve the correct HDD context
1401 	 */
1402 	mac->sme.link_layer_stats_cb(mac->hdd_handle,
1403 				     WMA_LINK_LAYER_STATS_RESULTS_RSP,
1404 				     link_stats_results,
1405 				     mac->sme.ll_stats_context);
1406 	qdf_mem_free(link_stats_results);
1407 
1408 	return 0;
1409 }
1410 
1411 /**
1412  * wma_unified_radio_tx_mem_free() - Free radio tx power stats memory
1413  * @handle: WMI handle
1414  *
1415  * Return: 0 on success, error number otherwise.
1416  */
1417 int wma_unified_radio_tx_mem_free(void *handle)
1418 {
1419 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
1420 	struct wifi_radio_stats *rs_results;
1421 	uint32_t i = 0;
1422 
1423 	if (!wma_handle->link_stats_results)
1424 		return 0;
1425 
1426 	rs_results = (struct wifi_radio_stats *)
1427 				&wma_handle->link_stats_results->results[0];
1428 	for (i = 0; i < wma_handle->link_stats_results->num_radio; i++) {
1429 		if (rs_results->tx_time_per_power_level) {
1430 			qdf_mem_free(rs_results->tx_time_per_power_level);
1431 			rs_results->tx_time_per_power_level = NULL;
1432 		}
1433 
1434 		if (rs_results->channels) {
1435 			qdf_mem_free(rs_results->channels);
1436 			rs_results->channels = NULL;
1437 		}
1438 		rs_results++;
1439 	}
1440 
1441 	qdf_mem_free(wma_handle->link_stats_results);
1442 	wma_handle->link_stats_results = NULL;
1443 
1444 	return 0;
1445 }
1446 
1447 /**
1448  * wma_unified_radio_tx_power_level_stats_event_handler() - tx power level stats
1449  * @handle: WMI handle
1450  * @cmd_param_info: command param info
1451  * @len: Length of @cmd_param_info
1452  *
1453  * This is the WMI event handler function to receive radio stats tx
1454  * power level stats.
1455  *
1456  * Return: 0 on success, error number otherwise.
1457  */
1458 static int wma_unified_radio_tx_power_level_stats_event_handler(void *handle,
1459 			u_int8_t *cmd_param_info, u_int32_t len)
1460 {
1461 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
1462 	WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *param_tlvs;
1463 	wmi_tx_power_level_stats_evt_fixed_param *fixed_param;
1464 	uint8_t *tx_power_level_values;
1465 	tSirLLStatsResults *link_stats_results;
1466 	struct wifi_radio_stats *rs_results;
1467 	uint32_t max_total_num_tx_power_levels = MAX_TPC_LEVELS * NUM_OF_BANDS *
1468 						MAX_SPATIAL_STREAM_ANY_V3;
1469 
1470 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1471 
1472 	if (!mac) {
1473 		WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1474 		return -EINVAL;
1475 	}
1476 
1477 	if (!mac->sme.link_layer_stats_cb) {
1478 		WMA_LOGD("%s: HDD callback is null", __func__);
1479 		return -EINVAL;
1480 	}
1481 
1482 	param_tlvs = (WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *)
1483 								cmd_param_info;
1484 	if (!param_tlvs) {
1485 		WMA_LOGA("%s: Invalid tx power level stats event", __func__);
1486 		return -EINVAL;
1487 	}
1488 
1489 	fixed_param = param_tlvs->fixed_param;
1490 	if (!fixed_param) {
1491 		WMA_LOGA("%s:Invalid param_tlvs for Radio tx_power level Stats",
1492 			 __func__);
1493 		return -EINVAL;
1494 	}
1495 
1496 	link_stats_results = wma_handle->link_stats_results;
1497 	if (!link_stats_results) {
1498 		WMA_LOGA("%s: link_stats_results is NULL", __func__);
1499 		return -EINVAL;
1500 	}
1501 
1502 	WMA_LOGD("%s: tot_num_tx_pwr_lvls: %u num_tx_pwr_lvls: %u pwr_lvl_offset: %u radio_id: %u",
1503 			__func__, fixed_param->total_num_tx_power_levels,
1504 			 fixed_param->num_tx_power_levels,
1505 			 fixed_param->power_level_offset,
1506 			 fixed_param->radio_id);
1507 
1508 	if (fixed_param->num_tx_power_levels > ((WMI_SVC_MSG_MAX_SIZE -
1509 	    sizeof(*fixed_param)) / sizeof(uint32_t)) ||
1510 	    fixed_param->num_tx_power_levels >
1511 	    param_tlvs->num_tx_time_per_power_level) {
1512 		WMA_LOGE("%s: excess tx_power buffers:%d, num_tx_time_per_power_level:%d",
1513 			__func__, fixed_param->num_tx_power_levels,
1514 			param_tlvs->num_tx_time_per_power_level);
1515 		return -EINVAL;
1516 	}
1517 
1518 	if (fixed_param->radio_id >= link_stats_results->num_radio) {
1519 		WMA_LOGE("%s: Invalid radio_id %d num_radio %d",
1520 			 __func__, fixed_param->radio_id,
1521 			 link_stats_results->num_radio);
1522 		return -EINVAL;
1523 	}
1524 
1525 	if (fixed_param->total_num_tx_power_levels >
1526 	    max_total_num_tx_power_levels) {
1527 		WMA_LOGD("Invalid total_num_tx_power_levels %d",
1528 			 fixed_param->total_num_tx_power_levels);
1529 		return -EINVAL;
1530 	}
1531 
1532 	rs_results = (struct wifi_radio_stats *) &link_stats_results->results[0] +
1533 							 fixed_param->radio_id;
1534 	tx_power_level_values = (uint8_t *) param_tlvs->tx_time_per_power_level;
1535 
1536 	if (rs_results->total_num_tx_power_levels &&
1537 	    fixed_param->total_num_tx_power_levels >
1538 		rs_results->total_num_tx_power_levels) {
1539 		WMA_LOGE("%s: excess tx_power buffers:%d, total_num_tx_power_levels:%d",
1540 			 __func__, fixed_param->total_num_tx_power_levels,
1541 			 rs_results->total_num_tx_power_levels);
1542 		return -EINVAL;
1543 	}
1544 
1545 	rs_results->total_num_tx_power_levels =
1546 				fixed_param->total_num_tx_power_levels;
1547 	if (!rs_results->total_num_tx_power_levels) {
1548 		link_stats_results->nr_received++;
1549 		goto post_stats;
1550 	}
1551 
1552 	if ((fixed_param->power_level_offset >
1553 	    rs_results->total_num_tx_power_levels) ||
1554 	    (fixed_param->num_tx_power_levels >
1555 	    rs_results->total_num_tx_power_levels -
1556 	    fixed_param->power_level_offset)) {
1557 		WMA_LOGE("%s: Invalid offset %d total_num %d num %d",
1558 			 __func__, fixed_param->power_level_offset,
1559 			 rs_results->total_num_tx_power_levels,
1560 			 fixed_param->num_tx_power_levels);
1561 		return -EINVAL;
1562 	}
1563 
1564 	if (!rs_results->tx_time_per_power_level) {
1565 		rs_results->tx_time_per_power_level = qdf_mem_malloc(
1566 				sizeof(uint32_t) *
1567 				rs_results->total_num_tx_power_levels);
1568 		if (!rs_results->tx_time_per_power_level) {
1569 			/* In error case, atleast send the radio stats without
1570 			 * tx_power_level stats */
1571 			rs_results->total_num_tx_power_levels = 0;
1572 			link_stats_results->nr_received++;
1573 			goto post_stats;
1574 		}
1575 	}
1576 	qdf_mem_copy(&rs_results->tx_time_per_power_level[
1577 					fixed_param->power_level_offset],
1578 		tx_power_level_values,
1579 		sizeof(uint32_t) * fixed_param->num_tx_power_levels);
1580 	if (rs_results->total_num_tx_power_levels ==
1581 	   (fixed_param->num_tx_power_levels +
1582 					 fixed_param->power_level_offset)) {
1583 		link_stats_results->moreResultToFollow = 0;
1584 		link_stats_results->nr_received++;
1585 	}
1586 
1587 	WMA_LOGD("%s: moreResultToFollow: %u nr: %u nr_received: %u",
1588 			__func__, link_stats_results->moreResultToFollow,
1589 			link_stats_results->num_radio,
1590 			link_stats_results->nr_received);
1591 
1592 	/* If still data to receive, return from here */
1593 	if (link_stats_results->moreResultToFollow)
1594 		return 0;
1595 
1596 post_stats:
1597 	if (link_stats_results->num_radio != link_stats_results->nr_received) {
1598 		/* Not received all radio stats yet, don't post yet */
1599 		return 0;
1600 	}
1601 
1602 	/* call hdd callback with Link Layer Statistics
1603 	 * vdev_id/ifacId in link_stats_results will be
1604 	 * used to retrieve the correct HDD context
1605 	 */
1606 	mac->sme.link_layer_stats_cb(mac->hdd_handle,
1607 		WMA_LINK_LAYER_STATS_RESULTS_RSP,
1608 		link_stats_results,
1609 		mac->sme.ll_stats_context);
1610 	wma_unified_radio_tx_mem_free(handle);
1611 
1612 	return 0;
1613 }
1614 
1615 /**
1616  * wma_unified_link_radio_stats_event_handler() - radio link stats event handler
1617  * @handle:          wma handle
1618  * @cmd_param_info:  data received with event from fw
1619  * @len:             length of data
1620  *
1621  * Return: 0 for success or error code
1622  */
1623 static int wma_unified_link_radio_stats_event_handler(void *handle,
1624 						      uint8_t *cmd_param_info,
1625 						      uint32_t len)
1626 {
1627 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
1628 	WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
1629 	wmi_radio_link_stats_event_fixed_param *fixed_param;
1630 	wmi_radio_link_stats *radio_stats;
1631 	wmi_channel_stats *channel_stats;
1632 	tSirLLStatsResults *link_stats_results;
1633 	uint8_t *results, *t_radio_stats, *t_channel_stats;
1634 	uint32_t next_chan_offset, count;
1635 	size_t radio_stats_size, chan_stats_size;
1636 	size_t link_stats_results_size;
1637 	struct wifi_radio_stats *rs_results;
1638 	struct wifi_channel_stats *chn_results;
1639 
1640 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1641 
1642 	if (!mac) {
1643 		WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1644 		return -EINVAL;
1645 	}
1646 
1647 	if (!mac->sme.link_layer_stats_cb) {
1648 		WMA_LOGD("%s: HDD callback is null", __func__);
1649 		return -EINVAL;
1650 	}
1651 
1652 	param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
1653 	if (!param_tlvs) {
1654 		WMA_LOGA("%s: Invalid stats event", __func__);
1655 		return -EINVAL;
1656 	}
1657 
1658 	/*
1659 	 * cmd_param_info contains
1660 	 * wmi_radio_link_stats_event_fixed_param fixed_param;
1661 	 * size of(struct wmi_radio_link_stats);
1662 	 * num_channels * size of(struct wmi_channel_stats)
1663 	 */
1664 	fixed_param = param_tlvs->fixed_param;
1665 	radio_stats = param_tlvs->radio_stats;
1666 	channel_stats = param_tlvs->channel_stats;
1667 
1668 	if (!fixed_param || !radio_stats ||
1669 	    (radio_stats->num_channels && !channel_stats)) {
1670 		WMA_LOGA("%s: Invalid param_tlvs for Radio Stats", __func__);
1671 		return -EINVAL;
1672 	}
1673 	if (radio_stats->num_channels >
1674 		(NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS) ||
1675 		radio_stats->num_channels > param_tlvs->num_channel_stats) {
1676 		WMA_LOGE("%s: Too many channels %d",
1677 			__func__, radio_stats->num_channels);
1678 		return -EINVAL;
1679 	}
1680 
1681 	radio_stats_size = sizeof(struct wifi_radio_stats);
1682 	chan_stats_size = sizeof(struct wifi_channel_stats);
1683 	if (fixed_param->num_radio >
1684 		(UINT_MAX - sizeof(*link_stats_results))/radio_stats_size) {
1685 		WMA_LOGE("excess num_radio %d is leading to int overflow",
1686 			fixed_param->num_radio);
1687 		return -EINVAL;
1688 	}
1689 	link_stats_results_size = sizeof(*link_stats_results) +
1690 				  fixed_param->num_radio * radio_stats_size;
1691 
1692 	if (radio_stats->radio_id >= fixed_param->num_radio) {
1693 		WMA_LOGE("%s, invalid radio id:%d, num radio:%d",
1694 			__func__, radio_stats->radio_id,
1695 			fixed_param->num_radio);
1696 		return -EINVAL;
1697 	}
1698 
1699 	if (!wma_handle->link_stats_results) {
1700 		wma_handle->link_stats_results = qdf_mem_malloc(
1701 						link_stats_results_size);
1702 		if (!wma_handle->link_stats_results)
1703 			return -ENOMEM;
1704 	}
1705 	link_stats_results = wma_handle->link_stats_results;
1706 	if (link_stats_results->num_radio == 0) {
1707 		link_stats_results->num_radio = fixed_param->num_radio;
1708 	} else if (link_stats_results->num_radio < fixed_param->num_radio) {
1709 		/*
1710 		 * The link stats results size allocated based on num_radio of
1711 		 * first event must be same as following events. Otherwise these
1712 		 * events may be spoofed. Drop all of them and report error.
1713 		 */
1714 		WMA_LOGE("Invalid following WMI_RADIO_LINK_STATS_EVENTID. Discarding this set");
1715 		wma_unified_radio_tx_mem_free(handle);
1716 		return -EINVAL;
1717 	}
1718 
1719 	WMA_LOGD("Radio stats Fixed Param:");
1720 	WMA_LOGD("req_id: %u num_radio: %u more_radio_events: %u",
1721 		 fixed_param->request_id, fixed_param->num_radio,
1722 		 fixed_param->more_radio_events);
1723 
1724 	WMA_LOGD("Radio Info: radio_id: %u on_time: %u tx_time: %u rx_time: %u on_time_scan: %u",
1725 		radio_stats->radio_id, radio_stats->on_time,
1726 		radio_stats->tx_time, radio_stats->rx_time,
1727 		radio_stats->on_time_scan);
1728 	WMA_LOGD("on_time_nbd: %u on_time_gscan: %u on_time_roam_scan: %u",
1729 		radio_stats->on_time_nbd,
1730 		radio_stats->on_time_gscan, radio_stats->on_time_roam_scan);
1731 	WMA_LOGD("on_time_pno_scan: %u on_time_hs20: %u num_channels: %u",
1732 		radio_stats->on_time_pno_scan, radio_stats->on_time_hs20,
1733 		radio_stats->num_channels);
1734 	WMA_LOGD("on_time_host_scan: %u, on_time_lpi_scan: %u",
1735 		radio_stats->on_time_host_scan, radio_stats->on_time_lpi_scan);
1736 
1737 	link_stats_results->paramId = WMI_LINK_STATS_RADIO;
1738 	link_stats_results->rspId = fixed_param->request_id;
1739 	link_stats_results->ifaceId = 0;
1740 	link_stats_results->peer_event_number = 0;
1741 
1742 	/*
1743 	 * Backward compatibility:
1744 	 * There are firmware(s) which will send Radio stats only with
1745 	 * more_radio_events set to 0 and firmware which sends Radio stats
1746 	 * followed by tx_power level stats with more_radio_events set to 1.
1747 	 * if more_radio_events is set to 1, buffer the radio stats and
1748 	 * wait for tx_power_level stats.
1749 	 */
1750 	link_stats_results->moreResultToFollow = fixed_param->more_radio_events;
1751 
1752 	results = (uint8_t *) link_stats_results->results;
1753 	t_radio_stats = (uint8_t *) radio_stats;
1754 	t_channel_stats = (uint8_t *) channel_stats;
1755 
1756 	rs_results = (struct wifi_radio_stats *) &results[0] + radio_stats->radio_id;
1757 	rs_results->radio = radio_stats->radio_id;
1758 	rs_results->on_time = radio_stats->on_time;
1759 	rs_results->tx_time = radio_stats->tx_time;
1760 	rs_results->rx_time = radio_stats->rx_time;
1761 	rs_results->on_time_scan = radio_stats->on_time_scan;
1762 	rs_results->on_time_nbd = radio_stats->on_time_nbd;
1763 	rs_results->on_time_gscan = radio_stats->on_time_gscan;
1764 	rs_results->on_time_roam_scan = radio_stats->on_time_roam_scan;
1765 	rs_results->on_time_pno_scan = radio_stats->on_time_pno_scan;
1766 	rs_results->on_time_hs20 = radio_stats->on_time_hs20;
1767 	rs_results->total_num_tx_power_levels = 0;
1768 	if (rs_results->tx_time_per_power_level) {
1769 		qdf_mem_free(rs_results->tx_time_per_power_level);
1770 		rs_results->tx_time_per_power_level = NULL;
1771 	}
1772 	if (rs_results->channels) {
1773 		qdf_mem_free(rs_results->channels);
1774 		rs_results->channels = NULL;
1775 	}
1776 	rs_results->num_channels = radio_stats->num_channels;
1777 	rs_results->on_time_host_scan = radio_stats->on_time_host_scan;
1778 	rs_results->on_time_lpi_scan = radio_stats->on_time_lpi_scan;
1779 	if (rs_results->num_channels) {
1780 		rs_results->channels = qdf_mem_malloc(
1781 					radio_stats->num_channels *
1782 					chan_stats_size);
1783 		if (!rs_results->channels) {
1784 			wma_unified_radio_tx_mem_free(handle);
1785 			return -ENOMEM;
1786 		}
1787 
1788 		chn_results = (struct wifi_channel_stats *) &rs_results->channels[0];
1789 		next_chan_offset = WMI_TLV_HDR_SIZE;
1790 		WMA_LOGD("Channel Stats Info");
1791 		for (count = 0; count < radio_stats->num_channels; count++) {
1792 			WMA_LOGD("channel_width %u center_freq %u center_freq0 %u",
1793 				 channel_stats->channel_width,
1794 				 channel_stats->center_freq,
1795 				 channel_stats->center_freq0);
1796 			WMA_LOGD("center_freq1 %u radio_awake_time %u cca_busy_time %u",
1797 				 channel_stats->center_freq1,
1798 				 channel_stats->radio_awake_time,
1799 				 channel_stats->cca_busy_time);
1800 			channel_stats++;
1801 
1802 			qdf_mem_copy(chn_results,
1803 				     t_channel_stats + next_chan_offset,
1804 				     chan_stats_size);
1805 			chn_results++;
1806 			next_chan_offset += sizeof(*channel_stats);
1807 		}
1808 	}
1809 
1810 	if (link_stats_results->moreResultToFollow) {
1811 		/* More results coming, don't post yet */
1812 		return 0;
1813 	}
1814 	link_stats_results->nr_received++;
1815 
1816 	if (link_stats_results->num_radio != link_stats_results->nr_received) {
1817 		/* Not received all radio stats yet, don't post yet */
1818 		return 0;
1819 	}
1820 
1821 	mac->sme.link_layer_stats_cb(mac->hdd_handle,
1822 				     WMA_LINK_LAYER_STATS_RESULTS_RSP,
1823 				     link_stats_results,
1824 				     mac->sme.ll_stats_context);
1825 	wma_unified_radio_tx_mem_free(handle);
1826 
1827 	return 0;
1828 }
1829 
1830 #ifdef WLAN_PEER_PS_NOTIFICATION
1831 /**
1832  * wma_peer_ps_evt_handler() - handler for PEER power state change.
1833  * @handle: wma handle
1834  * @event: FW event
1835  * @len: length of FW event
1836  *
1837  * Once peer STA power state changes, an event will be indicated by
1838  * FW. This function send a link layer state change msg to HDD. HDD
1839  * link layer callback will converts the event to NL msg.
1840  *
1841  * Return: 0 Success. Others fail.
1842  */
1843 static int wma_peer_ps_evt_handler(void *handle, u_int8_t *event,
1844 				   u_int32_t len)
1845 {
1846 	WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *param_buf;
1847 	wmi_peer_sta_ps_statechange_event_fixed_param *fixed_param;
1848 	struct wifi_peer_stat *peer_stat;
1849 	struct wifi_peer_info *peer_info;
1850 	tSirLLStatsResults *link_stats_results;
1851 	tSirMacAddr mac_address;
1852 	uint32_t result_len;
1853 	cds_msg_t sme_msg = { 0 };
1854 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
1855 
1856 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1857 
1858 	if (!mac) {
1859 		WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1860 		return -EINVAL;
1861 	}
1862 
1863 	if (!mac->sme.link_layer_stats_ext_cb) {
1864 		WMA_LOGD("%s: HDD callback is null", __func__);
1865 		return -EINVAL;
1866 	}
1867 
1868 	WMA_LOGD("%s: Posting Peer Stats PS event to HDD", __func__);
1869 
1870 	param_buf = (WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *)event;
1871 	fixed_param = param_buf->fixed_param;
1872 
1873 	result_len = sizeof(tSirLLStatsResults) +
1874 			sizeof(struct wifi_peer_stat) +
1875 			sizeof(struct wifi_peer_info);
1876 	link_stats_results = qdf_mem_malloc(result_len);
1877 	if (!link_stats_results)
1878 		return -EINVAL;
1879 
1880 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&fixed_param->peer_macaddr, &mac_address[0]);
1881 	WMA_LOGD("Peer power state change event from FW");
1882 	WMA_LOGD("Fixed Param:");
1883 	WMA_LOGD("MAC address: %2x:%2x:%2x:%2x:%2x:%2x, Power state: %d",
1884 		 mac_address[0], mac_address[1], mac_address[2],
1885 		 mac_address[3], mac_address[4], mac_address[5],
1886 		 fixed_param->peer_ps_state);
1887 
1888 	link_stats_results->paramId            = WMI_LL_STATS_EXT_PS_CHG;
1889 	link_stats_results->num_peers          = 1;
1890 	link_stats_results->peer_event_number  = 1;
1891 	link_stats_results->moreResultToFollow = 0;
1892 
1893 	peer_stat = (struct wifi_peer_stat *)link_stats_results->results;
1894 	peer_stat->numPeers = 1;
1895 	peer_info = (struct wifi_peer_info *)peer_stat->peer_info;
1896 	qdf_mem_copy(&peer_info->peer_macaddr,
1897 		     &mac_address,
1898 		     sizeof(tSirMacAddr));
1899 	peer_info->power_saving = fixed_param->peer_ps_state;
1900 
1901 	sme_msg.type = eWMI_SME_LL_STATS_IND;
1902 	sme_msg.bodyptr = link_stats_results;
1903 	sme_msg.bodyval = 0;
1904 
1905 	qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA,
1906 					    QDF_MODULE_ID_SME,
1907 					    QDF_MODULE_ID_SME, &sme_msg);
1908 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1909 		WMA_LOGE("%s: Fail to post ps change ind msg", __func__);
1910 		qdf_mem_free(link_stats_results);
1911 	}
1912 
1913 	return 0;
1914 }
1915 #else
1916 /**
1917  * wma_peer_ps_evt_handler() - handler for PEER power state change.
1918  * @handle: wma handle
1919  * @event: FW event
1920  * @len: length of FW event
1921  *
1922  * Once peer STA power state changes, an event will be indicated by
1923  * FW. This function send a link layer state change msg to HDD. HDD
1924  * link layer callback will converts the event to NL msg.
1925  *
1926  * Return: 0 Success. Others fail.
1927  */
1928 static inline int wma_peer_ps_evt_handler(void *handle, u_int8_t *event,
1929 					  u_int32_t len)
1930 {
1931 	return 0;
1932 }
1933 #endif
1934 
1935 /**
1936  * wma_register_ll_stats_event_handler() - register link layer stats related
1937  *                                         event handler
1938  * @wma_handle: wma handle
1939  *
1940  * Return: none
1941  */
1942 void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle)
1943 {
1944 	if (!wma_handle) {
1945 		WMA_LOGE("%s: wma_handle is NULL", __func__);
1946 		return;
1947 	}
1948 
1949 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1950 				wmi_iface_link_stats_event_id,
1951 				wma_unified_link_iface_stats_event_handler,
1952 				WMA_RX_SERIALIZER_CTX);
1953 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1954 				wmi_peer_link_stats_event_id,
1955 				wma_unified_link_peer_stats_event_handler,
1956 				WMA_RX_SERIALIZER_CTX);
1957 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1958 				wmi_radio_link_stats_link,
1959 				wma_unified_link_radio_stats_event_handler,
1960 				WMA_RX_SERIALIZER_CTX);
1961 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1962 			wmi_radio_tx_power_level_stats_event_id,
1963 			wma_unified_radio_tx_power_level_stats_event_handler,
1964 			WMA_RX_SERIALIZER_CTX);
1965 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1966 					   wmi_peer_sta_ps_statechg_event_id,
1967 					   wma_peer_ps_evt_handler,
1968 					   WMA_RX_SERIALIZER_CTX);
1969 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1970 					   wmi_report_stats_event_id,
1971 					   wma_ll_stats_evt_handler,
1972 					   WMA_RX_SERIALIZER_CTX);
1973 
1974 }
1975 
1976 QDF_STATUS wma_process_ll_stats_clear_req(tp_wma_handle wma,
1977 				 const tpSirLLStatsClearReq clearReq)
1978 {
1979 	uint8_t *addr;
1980 	struct ll_stats_clear_params cmd = {0};
1981 	int ret;
1982 	struct wlan_objmgr_vdev *vdev;
1983 
1984 	if (!clearReq || !wma) {
1985 		WMA_LOGE("%s: input pointer is NULL", __func__);
1986 		return QDF_STATUS_E_FAILURE;
1987 	}
1988 
1989 	vdev = wma->interfaces[clearReq->staId].vdev;
1990 	if (!vdev) {
1991 		WMA_LOGE("%s: vdev is NULL for vdev_%d",
1992 			 __func__, clearReq->staId);
1993 		return QDF_STATUS_E_FAILURE;
1994 	}
1995 
1996 	if (!wlan_vdev_get_dp_handle(vdev)) {
1997 		WMA_LOGE("%s: vdev_id %d dp handle is NULL",
1998 			 __func__, clearReq->staId);
1999 		return QDF_STATUS_E_FAILURE;
2000 	}
2001 
2002 	cmd.stop_req = clearReq->stopReq;
2003 	cmd.vdev_id = clearReq->staId;
2004 	cmd.stats_clear_mask = clearReq->statsClearReqMask;
2005 
2006 	vdev = wma->interfaces[clearReq->staId].vdev;
2007 	if (!vdev) {
2008 		WMA_LOGE("%s: Failed to get vdev for vdev_%d",
2009 			 __func__, clearReq->staId);
2010 		return QDF_STATUS_E_FAILURE;
2011 	}
2012 	addr = wlan_vdev_mlme_get_macaddr(vdev);
2013 	if (!addr) {
2014 		WMA_LOGE("%s: Failed to get macaddr for vdev_%d",
2015 			 __func__, clearReq->staId);
2016 		return QDF_STATUS_E_FAILURE;
2017 	}
2018 	qdf_mem_copy(cmd.peer_macaddr.bytes, addr, QDF_MAC_ADDR_SIZE);
2019 	ret = wmi_unified_process_ll_stats_clear_cmd(wma->wmi_handle, &cmd);
2020 	if (ret) {
2021 		WMA_LOGE("%s: Failed to send clear link stats req", __func__);
2022 		return QDF_STATUS_E_FAILURE;
2023 	}
2024 
2025 	return QDF_STATUS_SUCCESS;
2026 }
2027 
2028 /**
2029  * wma_process_ll_stats_set_req() - link layer stats set request
2030  * @wma:       wma handle
2031  * @setReq:  ll stats set request command params
2032  *
2033  * Return: QDF_STATUS_SUCCESS for success or error code
2034  */
2035 QDF_STATUS wma_process_ll_stats_set_req(tp_wma_handle wma,
2036 				 const tpSirLLStatsSetReq setReq)
2037 {
2038 	struct ll_stats_set_params cmd = {0};
2039 	int ret;
2040 
2041 	if (!setReq || !wma) {
2042 		WMA_LOGE("%s: input pointer is NULL", __func__);
2043 		return QDF_STATUS_E_FAILURE;
2044 	}
2045 
2046 	cmd.mpdu_size_threshold = setReq->mpduSizeThreshold;
2047 	cmd.aggressive_statistics_gathering =
2048 		setReq->aggressiveStatisticsGathering;
2049 
2050 	ret = wmi_unified_process_ll_stats_set_cmd(wma->wmi_handle,
2051 					 &cmd);
2052 	if (ret) {
2053 		WMA_LOGE("%s: Failed to send set link stats request", __func__);
2054 		return QDF_STATUS_E_FAILURE;
2055 	}
2056 
2057 	return QDF_STATUS_SUCCESS;
2058 }
2059 
2060 QDF_STATUS wma_process_ll_stats_get_req(tp_wma_handle wma,
2061 				 const tpSirLLStatsGetReq getReq)
2062 {
2063 	struct wlan_objmgr_vdev *vdev;
2064 	uint8_t *addr;
2065 	struct ll_stats_get_params cmd = {0};
2066 	int ret;
2067 
2068 	if (!getReq || !wma) {
2069 		WMA_LOGE("%s: input pointer is NULL", __func__);
2070 		return QDF_STATUS_E_FAILURE;
2071 	}
2072 
2073 	if (!wma_is_vdev_valid(getReq->staId)) {
2074 		WMA_LOGE("%s: vdev:%d not created yet", __func__,
2075 			 getReq->staId);
2076 		return QDF_STATUS_E_FAILURE;
2077 	}
2078 
2079 	cmd.req_id = getReq->reqId;
2080 	cmd.param_id_mask = getReq->paramIdMask;
2081 	cmd.vdev_id = getReq->staId;
2082 
2083 	vdev = wma->interfaces[getReq->staId].vdev;
2084 	if (!vdev) {
2085 		WMA_LOGE("%s: Failed to get vdev for vdev_%d",
2086 			 __func__, getReq->staId);
2087 		return QDF_STATUS_E_FAILURE;
2088 	}
2089 	addr = wlan_vdev_mlme_get_macaddr(vdev);
2090 	if (!addr) {
2091 		WMA_LOGE("%s: Failed to get macaddr for vdev_%d",
2092 			 __func__, getReq->staId);
2093 		return QDF_STATUS_E_FAILURE;
2094 	}
2095 	qdf_mem_copy(cmd.peer_macaddr.bytes, addr, QDF_MAC_ADDR_SIZE);
2096 	ret = wmi_unified_process_ll_stats_get_cmd(wma->wmi_handle, &cmd);
2097 	if (ret) {
2098 		WMA_LOGE("%s: Failed to send get link stats request", __func__);
2099 		return QDF_STATUS_E_FAILURE;
2100 	}
2101 
2102 	return QDF_STATUS_SUCCESS;
2103 }
2104 
2105 /**
2106  * wma_unified_link_iface_stats_event_handler() - link iface stats event handler
2107  * @wma:wma handle
2108  * @cmd_param_info: data from event
2109  * @len: length
2110  *
2111  * Return: 0 for success or error code
2112  */
2113 int wma_unified_link_iface_stats_event_handler(void *handle,
2114 					       uint8_t *cmd_param_info,
2115 					       uint32_t len)
2116 {
2117 	tp_wma_handle wma_handle = (tp_wma_handle)handle;
2118 	WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
2119 	wmi_iface_link_stats_event_fixed_param *fixed_param;
2120 	wmi_iface_link_stats *link_stats, *iface_link_stats;
2121 	wmi_wmm_ac_stats *ac_stats, *iface_ac_stats;
2122 	wmi_iface_offload_stats *offload_stats, *iface_offload_stats;
2123 	tSirLLStatsResults *link_stats_results;
2124 	struct wifi_interface_stats *iface_stat;
2125 	uint32_t count;
2126 	size_t link_stats_size, ac_stats_size, iface_info_size;
2127 	size_t link_stats_results_size, offload_stats_size;
2128 	size_t total_ac_size, total_offload_size;
2129 	bool db2dbm_enabled;
2130 
2131 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
2132 
2133 	if (!mac) {
2134 		WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
2135 		return -EINVAL;
2136 	}
2137 
2138 	if (!mac->sme.link_layer_stats_cb) {
2139 		WMA_LOGD("%s: HDD callback is null", __func__);
2140 		return -EINVAL;
2141 	}
2142 
2143 	param_tlvs = (WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
2144 	if (!param_tlvs) {
2145 		WMA_LOGA("%s: Invalid stats event", __func__);
2146 		return -EINVAL;
2147 	}
2148 
2149 	/*
2150 	 * cmd_param_info contains
2151 	 * wmi_iface_link_stats_event_fixed_param fixed_param;
2152 	 * wmi_iface_link_stats iface_link_stats;
2153 	 * iface_link_stats->num_ac * size of(struct wmi_wmm_ac_stats)
2154 	 * fixed_param->num_offload_stats * size of(wmi_iface_offload_stats);
2155 	 */
2156 	fixed_param = param_tlvs->fixed_param;
2157 	link_stats = param_tlvs->iface_link_stats;
2158 	ac_stats = param_tlvs->ac;
2159 	offload_stats = param_tlvs->iface_offload_stats;
2160 
2161 	if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats) ||
2162 	    (fixed_param->num_offload_stats && !offload_stats)) {
2163 		WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__);
2164 		return -EINVAL;
2165 	}
2166 	if (link_stats->num_ac > WIFI_AC_MAX || link_stats->num_ac >
2167 	    param_tlvs->num_ac) {
2168 		WMA_LOGE("%s: Excess data received from firmware num_ac %d, param_tlvs->num_ac %d",
2169 			 __func__, link_stats->num_ac, param_tlvs->num_ac);
2170 		return -EINVAL;
2171 	}
2172 	if (fixed_param->num_offload_stats > WMI_OFFLOAD_STATS_TYPE_MAX ||
2173 	    fixed_param->num_offload_stats >
2174 	    param_tlvs->num_iface_offload_stats) {
2175 		WMA_LOGE("%s: Excess num offload stats recvd from fw: %d, um_iface_offload_stats: %d",
2176 			__func__, fixed_param->num_offload_stats,
2177 			param_tlvs->num_iface_offload_stats);
2178 		return -EINVAL;
2179 	}
2180 
2181 	link_stats_size = sizeof(struct wifi_interface_stats);
2182 	iface_info_size = sizeof(struct wifi_interface_info);
2183 
2184 	ac_stats_size = sizeof(wmi_wmm_ac_stats);
2185 	offload_stats_size = sizeof(wmi_iface_offload_stats);
2186 
2187 	total_ac_size = ac_stats_size * WIFI_AC_MAX;
2188 	total_offload_size = offload_stats_size * WMI_OFFLOAD_STATS_TYPE_MAX +
2189 			      member_size(struct wifi_interface_stats,
2190 					  num_offload_stats);
2191 
2192 	link_stats_results_size = sizeof(*link_stats_results) +	link_stats_size;
2193 
2194 	link_stats_results = qdf_mem_malloc(link_stats_results_size);
2195 	if (!link_stats_results)
2196 		return -ENOMEM;
2197 
2198 	qdf_mem_zero(link_stats_results, link_stats_results_size);
2199 
2200 	link_stats_results->paramId = WMI_LINK_STATS_IFACE;
2201 	link_stats_results->rspId = fixed_param->request_id;
2202 	link_stats_results->ifaceId = fixed_param->vdev_id;
2203 	link_stats_results->num_peers = link_stats->num_peers;
2204 	link_stats_results->peer_event_number = 0;
2205 	link_stats_results->moreResultToFollow = 0;
2206 
2207 	/* results is copied to struct wifi_interface_stats in upper layer
2208 	 *   struct wifi_interface_stats
2209 	 *    - struct wifi_interface_info (all fields except roaming is
2210 	 *                             filled by host in the upper layer)
2211 	 *    - various members of struct wifi_interface_stats (from
2212 	 *                             wmi_iface_link_stats)
2213 	 *    - ACs information (from wmi_wmm_ac_stats)
2214 	 *    - num_offload_stats (from fixed param)
2215 	 *    - offload stats (from wmi_iface_offload_stats)
2216 	 */
2217 
2218 	iface_stat = (struct wifi_interface_stats *)link_stats_results->results;
2219 
2220 	iface_link_stats = &iface_stat->link_stats;
2221 	*iface_link_stats = *link_stats;
2222 	db2dbm_enabled = wmi_service_enabled(wma_handle->wmi_handle,
2223 					     wmi_service_hw_db2dbm_support);
2224 	if (!db2dbm_enabled) {
2225 		/* FW doesn't indicate support for HW db2dbm conversion */
2226 		iface_link_stats->rssi_mgmt += WMA_TGT_NOISE_FLOOR_DBM;
2227 		iface_link_stats->rssi_data += WMA_TGT_NOISE_FLOOR_DBM;
2228 		iface_link_stats->rssi_ack += WMA_TGT_NOISE_FLOOR_DBM;
2229 	}
2230 	WMA_LOGD("db2dbm: %d, rssi_mgmt: %d, rssi_data: %d, rssi_ack: %d",
2231 		 db2dbm_enabled, iface_link_stats->rssi_mgmt,
2232 		 iface_link_stats->rssi_data, iface_link_stats->rssi_ack);
2233 
2234 	/* Copy roaming state */
2235 	iface_stat->info.roaming = link_stats->roam_state;
2236 
2237 	iface_ac_stats = &iface_stat->ac_stats[0];
2238 	for (count = 0; count < link_stats->num_ac; count++) {
2239 		*iface_ac_stats = *ac_stats;
2240 		ac_stats++;
2241 		iface_ac_stats++;
2242 	}
2243 
2244 	/* Copy wmi_iface_offload_stats to wifi_iface_offload_stat */
2245 	iface_stat->num_offload_stats = fixed_param->num_offload_stats;
2246 	iface_offload_stats = &iface_stat->offload_stats[0];
2247 	for (count = 0; count < fixed_param->num_offload_stats; count++) {
2248 		*iface_offload_stats = *offload_stats;
2249 		offload_stats++;
2250 		iface_offload_stats++;
2251 	}
2252 
2253 	/* call hdd callback with Link Layer Statistics
2254 	 * vdev_id/ifacId in link_stats_results will be
2255 	 * used to retrieve the correct HDD context
2256 	 */
2257 	mac->sme.link_layer_stats_cb(mac->hdd_handle,
2258 				     WMA_LINK_LAYER_STATS_RESULTS_RSP,
2259 				     link_stats_results,
2260 				     mac->sme.ll_stats_context);
2261 	qdf_mem_free(link_stats_results);
2262 
2263 	return 0;
2264 }
2265 
2266 /**
2267  * wma_config_stats_ext_threshold - set threthold for MAC counters
2268  * @wma: wma handler
2269  * @threshold: threhold for MAC counters
2270  *
2271  * For each MAC layer counter, FW holds two copies. One is the current value.
2272  * The other is the last report. Once a current counter's increment is larger
2273  * than the threshold, FW will indicate that counter to host even if the
2274  * monitoring timer does not expire.
2275  *
2276  * Return: None
2277  */
2278 void wma_config_stats_ext_threshold(tp_wma_handle wma,
2279 				    struct sir_ll_ext_stats_threshold *thresh)
2280 {
2281 	QDF_STATUS status;
2282 	uint32_t len, tag, hdr_len;
2283 	uint8_t *buf_ptr;
2284 	wmi_buf_t buf;
2285 	wmi_pdev_set_stats_threshold_cmd_fixed_param *cmd;
2286 	wmi_chan_cca_stats_thresh *cca;
2287 	wmi_peer_signal_stats_thresh *signal;
2288 	wmi_tx_stats_thresh *tx;
2289 	wmi_rx_stats_thresh *rx;
2290 
2291 	if (!thresh) {
2292 		WMA_LOGE(FL("Invalid threshold input."));
2293 		return;
2294 	}
2295 
2296 	len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param) +
2297 	      sizeof(wmi_chan_cca_stats_thresh) +
2298 	      sizeof(wmi_peer_signal_stats_thresh) +
2299 	      sizeof(wmi_tx_stats_thresh) +
2300 	      sizeof(wmi_rx_stats_thresh) +
2301 	      5 * WMI_TLV_HDR_SIZE;
2302 	buf = wmi_buf_alloc(wma->wmi_handle, len);
2303 	if (!buf)
2304 		return;
2305 
2306 	buf_ptr = (u_int8_t *)wmi_buf_data(buf);
2307 	tag = WMITLV_TAG_STRUC_wmi_pdev_set_stats_threshold_cmd_fixed_param;
2308 	hdr_len = WMITLV_GET_STRUCT_TLVLEN(
2309 			wmi_pdev_set_stats_threshold_cmd_fixed_param);
2310 	WMA_LOGD(FL("Setting fixed parameters. tag=%d, len=%d"), tag, hdr_len);
2311 	cmd = (wmi_pdev_set_stats_threshold_cmd_fixed_param *)buf_ptr;
2312 	WMITLV_SET_HDR(&cmd->tlv_header, tag, hdr_len);
2313 	cmd->enable_thresh = thresh->enable;
2314 	cmd->use_thresh_bitmap = thresh->enable_bitmap;
2315 	cmd->gbl_thresh = thresh->global_threshold;
2316 	cmd->cca_thresh_enable_bitmap = thresh->cca_bitmap;
2317 	cmd->signal_thresh_enable_bitmap = thresh->signal_bitmap;
2318 	cmd->tx_thresh_enable_bitmap = thresh->tx_bitmap;
2319 	cmd->rx_thresh_enable_bitmap = thresh->rx_bitmap;
2320 	len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param);
2321 
2322 	tag = WMITLV_TAG_STRUC_wmi_chan_cca_stats_thresh,
2323 	hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_chan_cca_stats_thresh);
2324 	cca = (wmi_chan_cca_stats_thresh *)(buf_ptr + len);
2325 	WMITLV_SET_HDR(&cca->tlv_header, tag, hdr_len);
2326 	WMA_LOGD(FL("Setting cca parameters. tag=%d, len=%d"), tag, hdr_len);
2327 	cca->idle_time = thresh->cca.idle_time;
2328 	cca->tx_time = thresh->cca.tx_time;
2329 	cca->rx_in_bss_time = thresh->cca.rx_in_bss_time;
2330 	cca->rx_out_bss_time = thresh->cca.rx_out_bss_time;
2331 	cca->rx_busy_time = thresh->cca.rx_busy_time;
2332 	cca->rx_in_bad_cond_time = thresh->cca.rx_in_bad_cond_time;
2333 	cca->tx_in_bad_cond_time = thresh->cca.tx_in_bad_cond_time;
2334 	cca->wlan_not_avail_time = thresh->cca.wlan_not_avail_time;
2335 	WMA_LOGD(FL("idle time=%d, tx_time=%d, in_bss=%d, out_bss=%d"),
2336 		 cca->idle_time, cca->tx_time,
2337 		 cca->rx_in_bss_time, cca->rx_out_bss_time);
2338 	WMA_LOGD(FL("rx_busy=%d, rx_bad=%d, tx_bad=%d, not_avail=%d"),
2339 		 cca->rx_busy_time, cca->rx_in_bad_cond_time,
2340 		 cca->tx_in_bad_cond_time, cca->wlan_not_avail_time);
2341 	len += sizeof(wmi_chan_cca_stats_thresh);
2342 
2343 	signal = (wmi_peer_signal_stats_thresh *)(buf_ptr + len);
2344 	tag = WMITLV_TAG_STRUC_wmi_peer_signal_stats_thresh;
2345 	hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_peer_signal_stats_thresh);
2346 	WMA_LOGD(FL("Setting signal parameters. tag=%d, len=%d"), tag, hdr_len);
2347 	WMITLV_SET_HDR(&signal->tlv_header, tag, hdr_len);
2348 	signal->per_chain_snr = thresh->signal.snr;
2349 	signal->per_chain_nf = thresh->signal.nf;
2350 	WMA_LOGD(FL("snr=%d, nf=%d"), signal->per_chain_snr,
2351 		 signal->per_chain_nf);
2352 	len += sizeof(wmi_peer_signal_stats_thresh);
2353 
2354 	tx = (wmi_tx_stats_thresh *)(buf_ptr + len);
2355 	tag = WMITLV_TAG_STRUC_wmi_tx_stats_thresh;
2356 	hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_tx_stats_thresh);
2357 	WMA_LOGD(FL("Setting TX parameters. tag=%d, len=%d"), tag, len);
2358 	WMITLV_SET_HDR(&tx->tlv_header, tag, hdr_len);
2359 	tx->tx_msdu_cnt = thresh->tx.msdu;
2360 	tx->tx_mpdu_cnt = thresh->tx.mpdu;
2361 	tx->tx_ppdu_cnt = thresh->tx.ppdu;
2362 	tx->tx_bytes = thresh->tx.bytes;
2363 	tx->tx_msdu_drop_cnt = thresh->tx.msdu_drop;
2364 	tx->tx_drop_bytes = thresh->tx.byte_drop;
2365 	tx->tx_mpdu_retry_cnt = thresh->tx.mpdu_retry;
2366 	tx->tx_mpdu_fail_cnt = thresh->tx.mpdu_fail;
2367 	tx->tx_ppdu_fail_cnt = thresh->tx.ppdu_fail;
2368 	tx->tx_mpdu_aggr = thresh->tx.aggregation;
2369 	tx->tx_succ_mcs = thresh->tx.succ_mcs;
2370 	tx->tx_fail_mcs = thresh->tx.fail_mcs;
2371 	tx->tx_ppdu_delay = thresh->tx.delay;
2372 	WMA_LOGD(FL("msdu=%d, mpdu=%d, ppdu=%d, bytes=%d, msdu_drop=%d"),
2373 		 tx->tx_msdu_cnt, tx->tx_mpdu_cnt, tx->tx_ppdu_cnt,
2374 		 tx->tx_bytes, tx->tx_msdu_drop_cnt);
2375 	WMA_LOGD(FL("byte_drop=%d, mpdu_retry=%d, mpdu_fail=%d, ppdu_fail=%d"),
2376 		 tx->tx_drop_bytes, tx->tx_mpdu_retry_cnt,
2377 		 tx->tx_mpdu_fail_cnt, tx->tx_ppdu_fail_cnt);
2378 	WMA_LOGD(FL("aggr=%d, succ_mcs=%d, fail_mcs=%d, delay=%d"),
2379 		 tx->tx_mpdu_aggr, tx->tx_succ_mcs, tx->tx_fail_mcs,
2380 		 tx->tx_ppdu_delay);
2381 	len += sizeof(wmi_tx_stats_thresh);
2382 
2383 	rx = (wmi_rx_stats_thresh *)(buf_ptr + len);
2384 	tag = WMITLV_TAG_STRUC_wmi_rx_stats_thresh,
2385 	hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_rx_stats_thresh);
2386 	WMITLV_SET_HDR(&rx->tlv_header, tag, hdr_len);
2387 	WMA_LOGD(FL("Setting RX parameters. tag=%d, len=%d"), tag, hdr_len);
2388 	rx->mac_rx_mpdu_cnt = thresh->rx.mpdu;
2389 	rx->mac_rx_bytes = thresh->rx.bytes;
2390 	rx->phy_rx_ppdu_cnt = thresh->rx.ppdu;
2391 	rx->phy_rx_bytes = thresh->rx.ppdu_bytes;
2392 	rx->rx_disorder_cnt = thresh->rx.disorder;
2393 	rx->rx_mpdu_retry_cnt = thresh->rx.mpdu_retry;
2394 	rx->rx_mpdu_dup_cnt = thresh->rx.mpdu_dup;
2395 	rx->rx_mpdu_discard_cnt = thresh->rx.mpdu_discard;
2396 	rx->rx_mpdu_aggr = thresh->rx.aggregation;
2397 	rx->rx_mcs = thresh->rx.mcs;
2398 	rx->sta_ps_inds = thresh->rx.ps_inds;
2399 	rx->sta_ps_durs = thresh->rx.ps_durs;
2400 	rx->rx_probe_reqs = thresh->rx.probe_reqs;
2401 	rx->rx_oth_mgmts = thresh->rx.other_mgmt;
2402 	WMA_LOGD(FL("rx_mpdu=%d, rx_bytes=%d, rx_ppdu=%d, rx_pbytes=%d"),
2403 		 rx->mac_rx_mpdu_cnt, rx->mac_rx_bytes,
2404 		 rx->phy_rx_ppdu_cnt, rx->phy_rx_bytes);
2405 	WMA_LOGD(FL("disorder=%d, rx_dup=%d, rx_aggr=%d, rx_mcs=%d"),
2406 		 rx->rx_disorder_cnt, rx->rx_mpdu_dup_cnt,
2407 		 rx->rx_mpdu_aggr, rx->rx_mcs);
2408 	WMA_LOGD(FL("rx_ind=%d, rx_dur=%d, rx_probe=%d, rx_mgmt=%d"),
2409 		 rx->sta_ps_inds, rx->sta_ps_durs,
2410 		 rx->rx_probe_reqs, rx->rx_oth_mgmts);
2411 	len += sizeof(wmi_rx_stats_thresh);
2412 
2413 	WMA_LOGA("WMA --> WMI_PDEV_SET_STATS_THRESHOLD_CMDID(0x%x), length=%d",
2414 		 WMI_PDEV_SET_STATS_THRESHOLD_CMDID, len);
2415 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
2416 				      WMI_PDEV_SET_STATS_THRESHOLD_CMDID);
2417 	if (QDF_IS_STATUS_ERROR(status))
2418 		wmi_buf_free(buf);
2419 }
2420 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
2421 
2422 /**
2423  * wma_post_link_status() - post link status to SME
2424  * @pGetLinkStatus: SME Link status
2425  * @link_status: Link status
2426  *
2427  * Return: none
2428  */
2429 void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus,
2430 			  uint8_t link_status)
2431 {
2432 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
2433 	struct scheduler_msg sme_msg = { 0 };
2434 
2435 	pGetLinkStatus->linkStatus = link_status;
2436 	sme_msg.type = eWNI_SME_LINK_STATUS_IND;
2437 	sme_msg.bodyptr = pGetLinkStatus;
2438 	sme_msg.bodyval = 0;
2439 
2440 	qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA,
2441 					    QDF_MODULE_ID_SME,
2442 					    QDF_MODULE_ID_SME, &sme_msg);
2443 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
2444 		WMA_LOGE("%s: Fail to post link status ind msg", __func__);
2445 		qdf_mem_free(pGetLinkStatus);
2446 	}
2447 }
2448 
2449 int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info,
2450 				  uint32_t len)
2451 {
2452 	tp_wma_handle wma = (tp_wma_handle) handle;
2453 	WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *param_buf;
2454 	wmi_vdev_rate_stats_event_fixed_param *event;
2455 	wmi_vdev_rate_ht_info *ht_info;
2456 	struct wma_txrx_node *intr = wma->interfaces;
2457 	uint8_t link_status = LINK_STATUS_LEGACY;
2458 	uint32_t i, rate_flag;
2459 	QDF_STATUS status;
2460 
2461 	param_buf =
2462 	      (WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *) cmd_param_info;
2463 	if (!param_buf) {
2464 		WMA_LOGA("%s: Invalid stats event", __func__);
2465 		return -EINVAL;
2466 	}
2467 
2468 	event = (wmi_vdev_rate_stats_event_fixed_param *)
2469 						param_buf->fixed_param;
2470 	ht_info = (wmi_vdev_rate_ht_info *) param_buf->ht_info;
2471 
2472 	WMA_LOGD("num_vdev_stats: %d", event->num_vdev_stats);
2473 
2474 	if (event->num_vdev_stats > ((WMI_SVC_MSG_MAX_SIZE -
2475 	    sizeof(*event)) / sizeof(*ht_info)) ||
2476 	    event->num_vdev_stats > param_buf->num_ht_info) {
2477 		WMA_LOGE("%s: excess vdev_stats buffers:%d, num_ht_info:%d",
2478 			__func__, event->num_vdev_stats,
2479 			param_buf->num_ht_info);
2480 		return -EINVAL;
2481 	}
2482 
2483 	status = wma_get_vdev_rate_flag(intr[ht_info->vdevid].vdev, &rate_flag);
2484 	if (QDF_IS_STATUS_ERROR(status)) {
2485 		WMA_LOGE("%s: Failed to get rate flag",	__func__);
2486 		return -EINVAL;
2487 	}
2488 
2489 	for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) {
2490 		WMA_LOGD("%s vdevId:%d  tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d",
2491 			__func__, ht_info->vdevid, ht_info->tx_nss,
2492 			ht_info->rx_nss, ht_info->tx_preamble,
2493 			ht_info->rx_preamble);
2494 		if (ht_info->vdevid < wma->max_bssid
2495 		    && intr[ht_info->vdevid].plink_status_req) {
2496 			if (ht_info->tx_nss || ht_info->rx_nss)
2497 				link_status = LINK_STATUS_MIMO;
2498 
2499 			if ((ht_info->tx_preamble == LINK_RATE_VHT) ||
2500 			    (ht_info->rx_preamble == LINK_RATE_VHT))
2501 				link_status |= LINK_STATUS_VHT;
2502 
2503 			if (intr[ht_info->vdevid].nss == 2)
2504 				link_status |= LINK_SUPPORT_MIMO;
2505 
2506 			if (rate_flag &
2507 				(TX_RATE_VHT20 | TX_RATE_VHT40 |
2508 				TX_RATE_VHT80))
2509 				link_status |= LINK_SUPPORT_VHT;
2510 
2511 			wma_post_link_status(
2512 					intr[ht_info->vdevid].plink_status_req,
2513 					link_status);
2514 			intr[ht_info->vdevid].plink_status_req = NULL;
2515 			link_status = LINK_STATUS_LEGACY;
2516 		}
2517 
2518 		ht_info++;
2519 	}
2520 
2521 	return 0;
2522 }
2523 
2524 int wma_rso_cmd_status_event_handler(wmi_roam_event_fixed_param *wmi_event)
2525 {
2526 	struct rso_cmd_status *rso_status;
2527 	struct scheduler_msg sme_msg = {0};
2528 	QDF_STATUS qdf_status;
2529 
2530 	rso_status = qdf_mem_malloc(sizeof(*rso_status));
2531 	if (!rso_status)
2532 		return -ENOMEM;
2533 
2534 	rso_status->vdev_id = wmi_event->vdev_id;
2535 	if (WMI_ROAM_NOTIF_SCAN_MODE_SUCCESS == wmi_event->notif)
2536 		rso_status->status = true;
2537 	else if (WMI_ROAM_NOTIF_SCAN_MODE_FAIL == wmi_event->notif)
2538 		rso_status->status = false;
2539 	sme_msg.type = eWNI_SME_RSO_CMD_STATUS_IND;
2540 	sme_msg.bodyptr = rso_status;
2541 	sme_msg.bodyval = 0;
2542 	WMA_LOGD("%s: Post RSO cmd status to SME",  __func__);
2543 
2544 	qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA,
2545 					    QDF_MODULE_ID_SME,
2546 					    QDF_MODULE_ID_SME, &sme_msg);
2547 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
2548 		WMA_LOGE("%s: fail to post RSO cmd status to SME", __func__);
2549 		qdf_mem_free(rso_status);
2550 	}
2551 	return 0;
2552 }
2553 
2554 /**
2555  * wma_fill_peer_info() - fill SIR peer info from WMI peer info struct
2556  * @wma: wma interface
2557  * @stats_info: WMI peer info pointer
2558  * @peer_info: SIR peer info pointer
2559  *
2560  * This function will fill SIR peer info from WMI peer info struct
2561  *
2562  * Return: None
2563  */
2564 static void wma_fill_peer_info(tp_wma_handle wma,
2565 		wmi_peer_stats_info *stats_info,
2566 		struct sir_peer_info_ext *peer_info)
2567 {
2568 	peer_info->tx_packets = stats_info->tx_packets.low_32;
2569 	peer_info->tx_bytes = stats_info->tx_bytes.high_32;
2570 	peer_info->tx_bytes <<= 32;
2571 	peer_info->tx_bytes += stats_info->tx_bytes.low_32;
2572 	peer_info->rx_packets = stats_info->rx_packets.low_32;
2573 	peer_info->rx_bytes = stats_info->rx_bytes.high_32;
2574 	peer_info->rx_bytes <<= 32;
2575 	peer_info->rx_bytes += stats_info->rx_bytes.low_32;
2576 	peer_info->tx_retries = stats_info->tx_retries;
2577 	peer_info->tx_failed = stats_info->tx_failed;
2578 	peer_info->rssi = stats_info->peer_rssi;
2579 	peer_info->tx_rate = stats_info->last_tx_bitrate_kbps;
2580 	peer_info->tx_rate_code = stats_info->last_tx_rate_code;
2581 	peer_info->rx_rate = stats_info->last_rx_bitrate_kbps;
2582 	peer_info->rx_rate_code = stats_info->last_rx_rate_code;
2583 }
2584 
2585 /**
2586  * wma_peer_info_ext_rsp() - process peer ext info ext
2587  * @handle: wma interface
2588  * @buf: wmi event buf pointer
2589  *
2590  * This function will send eWNI_SME_GET_PEER_INFO_EXT_IND to SME
2591  *
2592  * Return: 0 on success, error code otherwise
2593  */
2594 static QDF_STATUS wma_peer_info_ext_rsp(tp_wma_handle wma, u_int8_t *buf)
2595 {
2596 	wmi_peer_stats_info_event_fixed_param *event;
2597 	wmi_peer_stats_info *stats_info;
2598 	struct sir_peer_info_ext_resp *resp;
2599 	struct sir_peer_info_ext *peer_info;
2600 	struct scheduler_msg sme_msg = {0};
2601 	int i, j = 0;
2602 	QDF_STATUS qdf_status;
2603 
2604 	event = (wmi_peer_stats_info_event_fixed_param *)buf;
2605 	stats_info = (wmi_peer_stats_info *)(buf +
2606 			sizeof(wmi_peer_stats_info_event_fixed_param));
2607 
2608 	if (wma->get_one_peer_info) {
2609 		resp = qdf_mem_malloc(sizeof(struct sir_peer_info_ext_resp) +
2610 				sizeof(resp->info[0]));
2611 		if (!resp)
2612 			return QDF_STATUS_E_NOMEM;
2613 
2614 		resp->count = 0;
2615 		peer_info = &resp->info[0];
2616 		for (i = 0; i < event->num_peers; i++) {
2617 			WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr,
2618 					peer_info->peer_macaddr.bytes);
2619 
2620 			if (!qdf_mem_cmp(peer_info->peer_macaddr.bytes,
2621 					wma->peer_macaddr.bytes,
2622 					QDF_MAC_ADDR_SIZE)) {
2623 				wma_fill_peer_info(wma, stats_info, peer_info);
2624 				resp->count++;
2625 				break;
2626 			}
2627 
2628 			stats_info = stats_info + 1;
2629 		}
2630 	} else {
2631 		resp = qdf_mem_malloc(sizeof(struct sir_peer_info_ext_resp) +
2632 				event->num_peers * sizeof(resp->info[0]));
2633 		if (!resp)
2634 			return QDF_STATUS_E_NOMEM;
2635 
2636 		resp->count = event->num_peers;
2637 		for (i = 0; i < event->num_peers; i++) {
2638 			peer_info = &resp->info[j];
2639 			WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr,
2640 					peer_info->peer_macaddr.bytes);
2641 
2642 			if (!qdf_mem_cmp(peer_info->peer_macaddr.bytes,
2643 					wma->myaddr, QDF_MAC_ADDR_SIZE)) {
2644 				resp->count = resp->count - 1;
2645 			} else {
2646 				wma_fill_peer_info(wma, stats_info, peer_info);
2647 				j++;
2648 			}
2649 			stats_info = stats_info + 1;
2650 		}
2651 	}
2652 
2653 	sme_msg.type = eWNI_SME_GET_PEER_INFO_EXT_IND;
2654 	sme_msg.bodyptr = resp;
2655 	sme_msg.bodyval = 0;
2656 
2657 	qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA,
2658 					    QDF_MODULE_ID_SME,
2659 					    QDF_MODULE_ID_SME, &sme_msg);
2660 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
2661 		WMA_LOGE("%s: Fail to post get peer info msg", __func__);
2662 		qdf_mem_free(resp);
2663 	}
2664 
2665 	return qdf_status;
2666 }
2667 
2668 /**
2669  * dump_peer_stats_info() - dump wmi peer info struct
2670  * @event: wmi peer info fixed param pointer
2671  * @peer_stats: wmi peer stats info pointer
2672  *
2673  * This function will dump wmi peer info struct
2674  *
2675  * Return: None
2676  */
2677 static void dump_peer_stats_info(wmi_peer_stats_info_event_fixed_param *event,
2678 		wmi_peer_stats_info *peer_stats)
2679 {
2680 	int i;
2681 	wmi_peer_stats_info *stats = peer_stats;
2682 	u_int8_t mac[6];
2683 
2684 	WMA_LOGI("%s vdev_id %d, num_peers %d more_data %d",
2685 			__func__, event->vdev_id,
2686 			event->num_peers, event->more_data);
2687 
2688 	for (i = 0; i < event->num_peers; i++) {
2689 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats->peer_macaddr, mac);
2690 		WMA_LOGI("%s mac %pM", __func__, mac);
2691 		WMA_LOGI("%s tx_bytes %d %d tx_packets %d %d",
2692 				__func__,
2693 				stats->tx_bytes.low_32,
2694 				stats->tx_bytes.high_32,
2695 				stats->tx_packets.low_32,
2696 				stats->tx_packets.high_32);
2697 		WMA_LOGI("%s rx_bytes %d %d rx_packets %d %d",
2698 				__func__,
2699 				stats->rx_bytes.low_32,
2700 				stats->rx_bytes.high_32,
2701 				stats->rx_packets.low_32,
2702 				stats->rx_packets.high_32);
2703 		WMA_LOGI("%s tx_retries %d tx_failed %d",
2704 				__func__, stats->tx_retries, stats->tx_failed);
2705 		WMA_LOGI("%s tx_rate_code %x rx_rate_code %x",
2706 				__func__,
2707 				stats->last_tx_rate_code,
2708 				stats->last_rx_rate_code);
2709 		WMA_LOGI("%s tx_rate %x rx_rate %x",
2710 				__func__,
2711 				stats->last_tx_bitrate_kbps,
2712 				stats->last_rx_bitrate_kbps);
2713 		WMA_LOGI("%s peer_rssi %d", __func__, stats->peer_rssi);
2714 		stats++;
2715 	}
2716 }
2717 
2718 int wma_peer_info_event_handler(void *handle, u_int8_t *cmd_param_info,
2719 				   u_int32_t len)
2720 {
2721 	tp_wma_handle wma = (tp_wma_handle) handle;
2722 	WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf;
2723 	wmi_peer_stats_info_event_fixed_param *event;
2724 	u_int32_t buf_size;
2725 	u_int8_t *buf;
2726 
2727 	param_buf =
2728 		(WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)cmd_param_info;
2729 	if (!param_buf) {
2730 		WMA_LOGA("%s: Invalid stats event", __func__);
2731 		return -EINVAL;
2732 	}
2733 
2734 	WMA_LOGI("%s Recv WMI_PEER_STATS_INFO_EVENTID", __func__);
2735 	event = param_buf->fixed_param;
2736 	if (event->num_peers >
2737 	    ((WMI_SVC_MSG_MAX_SIZE -
2738 	      sizeof(wmi_peer_stats_info_event_fixed_param))/
2739 	      sizeof(wmi_peer_stats_info)) || event->num_peers >
2740 	      param_buf->num_peer_stats_info) {
2741 		WMA_LOGE("Excess num of peers from fw: %d, num_peer_stats_info:%d",
2742 			event->num_peers, param_buf->num_peer_stats_info);
2743 		return -EINVAL;
2744 	}
2745 	buf_size = sizeof(wmi_peer_stats_info_event_fixed_param) +
2746 		sizeof(wmi_peer_stats_info) * event->num_peers;
2747 	buf = qdf_mem_malloc(buf_size);
2748 	if (!buf)
2749 		return -ENOMEM;
2750 
2751 	qdf_mem_copy(buf, param_buf->fixed_param,
2752 			sizeof(wmi_peer_stats_info_event_fixed_param));
2753 	qdf_mem_copy((buf + sizeof(wmi_peer_stats_info_event_fixed_param)),
2754 			param_buf->peer_stats_info,
2755 			sizeof(wmi_peer_stats_info) * event->num_peers);
2756 	WMA_LOGI("%s dump peer stats info", __func__);
2757 	dump_peer_stats_info(event, param_buf->peer_stats_info);
2758 
2759 	wma_peer_info_ext_rsp(wma, buf);
2760 	qdf_mem_free(buf);
2761 
2762 	return 0;
2763 }
2764 
2765 /**
2766  * wma_send_link_speed() - send link speed to SME
2767  * @link_speed: link speed
2768  *
2769  * Return: QDF_STATUS_SUCCESS for success or error code
2770  */
2771 QDF_STATUS wma_send_link_speed(uint32_t link_speed)
2772 {
2773 	struct mac_context *mac_ctx;
2774 	struct link_speed_info *ls_ind;
2775 
2776 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
2777 	if (!mac_ctx) {
2778 		WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
2779 		return QDF_STATUS_E_INVAL;
2780 	}
2781 
2782 	ls_ind = qdf_mem_malloc(sizeof(*ls_ind));
2783 	if (!ls_ind)
2784 		return QDF_STATUS_E_NOMEM;
2785 
2786 	ls_ind->estLinkSpeed = link_speed;
2787 	if (mac_ctx->sme.link_speed_cb)
2788 		mac_ctx->sme.link_speed_cb(ls_ind,
2789 					   mac_ctx->sme.link_speed_context);
2790 	else
2791 		WMA_LOGD("%s: link_speed_cb is null", __func__);
2792 	qdf_mem_free(ls_ind);
2793 
2794 	return QDF_STATUS_SUCCESS;
2795 }
2796 
2797 /**
2798  * wma_link_speed_event_handler() - link speed event handler
2799  * @handle: wma handle
2800  * @cmd_param_info: event data
2801  * @len: length
2802  *
2803  * Return: 0 for success or error code
2804  */
2805 int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info,
2806 				 uint32_t len)
2807 {
2808 	WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *param_buf;
2809 	wmi_peer_estimated_linkspeed_event_fixed_param *event;
2810 	QDF_STATUS qdf_status;
2811 
2812 	param_buf = (WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *)
2813 							 cmd_param_info;
2814 	if (!param_buf) {
2815 		WMA_LOGE("%s: Invalid linkspeed event", __func__);
2816 		return -EINVAL;
2817 	}
2818 	event = param_buf->fixed_param;
2819 	qdf_status = wma_send_link_speed(event->est_linkspeed_kbps);
2820 	if (!QDF_IS_STATUS_SUCCESS(qdf_status))
2821 		return -EINVAL;
2822 	return 0;
2823 }
2824 
2825 #define BIG_ENDIAN_MAX_DEBUG_BUF   500
2826 /**
2827  * wma_unified_debug_print_event_handler() - debug print event handler
2828  * @handle: wma handle
2829  * @datap: data pointer
2830  * @len: length
2831  *
2832  * Return: 0 for success or error code
2833  */
2834 int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap,
2835 					  uint32_t len)
2836 {
2837 	WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf;
2838 	uint8_t *data;
2839 	uint32_t datalen;
2840 
2841 	param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *) datap;
2842 	if (!param_buf || !param_buf->data) {
2843 		WMA_LOGE("Get NULL point message from FW");
2844 		return -ENOMEM;
2845 	}
2846 	data = param_buf->data;
2847 	datalen = param_buf->num_data;
2848 	if (datalen > WMI_SVC_MSG_MAX_SIZE) {
2849 		WMA_LOGE("Received data len %d exceeds max value %d",
2850 				datalen, WMI_SVC_MSG_MAX_SIZE);
2851 		return QDF_STATUS_E_FAILURE;
2852 	}
2853 	data[datalen - 1] = '\0';
2854 
2855 #ifdef BIG_ENDIAN_HOST
2856 	{
2857 		if (datalen >= BIG_ENDIAN_MAX_DEBUG_BUF) {
2858 			WMA_LOGE("%s Invalid data len %d, limiting to max",
2859 				 __func__, datalen);
2860 			datalen = BIG_ENDIAN_MAX_DEBUG_BUF - 1;
2861 		}
2862 		char dbgbuf[BIG_ENDIAN_MAX_DEBUG_BUF] = { 0 };
2863 
2864 		memcpy(dbgbuf, data, datalen);
2865 		SWAPME(dbgbuf, datalen);
2866 		WMA_LOGD("FIRMWARE:%s", dbgbuf);
2867 		return 0;
2868 	}
2869 #else
2870 	WMA_LOGD("FIRMWARE:%s", data);
2871 	return 0;
2872 #endif /* BIG_ENDIAN_HOST */
2873 }
2874 
2875 /**
2876  * wma_peer_phymode() - get phymode
2877  * @nw_type: nw type
2878  * @sta_type: sta type
2879  * @is_ht: is ht supported
2880  * @ch_width: supported channel width
2881  * @is_vht: is vht supported
2882  * @is_he: is HE supported
2883  *
2884  * Return: WLAN_PHY_MODE
2885  */
2886 WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type,
2887 			       uint8_t is_ht, uint8_t ch_width,
2888 			       uint8_t is_vht, bool is_he)
2889 {
2890 	WLAN_PHY_MODE phymode = MODE_UNKNOWN;
2891 
2892 	switch (nw_type) {
2893 	case eSIR_11B_NW_TYPE:
2894 #ifdef FEATURE_WLAN_TDLS
2895 	if (STA_ENTRY_TDLS_PEER == sta_type) {
2896 		if (is_vht) {
2897 			if (CH_WIDTH_80MHZ == ch_width)
2898 				phymode = MODE_11AC_VHT80;
2899 			else
2900 				phymode = (CH_WIDTH_40MHZ == ch_width) ?
2901 					  MODE_11AC_VHT40 :
2902 					  MODE_11AC_VHT20;
2903 		} else if (is_ht) {
2904 			phymode = (CH_WIDTH_40MHZ == ch_width) ?
2905 				  MODE_11NG_HT40 : MODE_11NG_HT20;
2906 		} else
2907 			phymode = MODE_11B;
2908 	} else
2909 #endif /* FEATURE_WLAN_TDLS */
2910 	{
2911 		phymode = MODE_11B;
2912 		if (is_ht || is_vht || is_he)
2913 			WMA_LOGE("HT/VHT is enabled with 11B NW type");
2914 	}
2915 		break;
2916 	case eSIR_11G_NW_TYPE:
2917 		if (!(is_ht || is_vht || is_he)) {
2918 			phymode = MODE_11G;
2919 			break;
2920 		}
2921 		if (CH_WIDTH_40MHZ < ch_width)
2922 			WMA_LOGE("80/160 MHz BW sent in 11G, configured 40MHz");
2923 		if (ch_width)
2924 			phymode = (is_he) ? MODE_11AX_HE40_2G : (is_vht) ?
2925 					MODE_11AC_VHT40_2G : MODE_11NG_HT40;
2926 		else
2927 			phymode = (is_he) ? MODE_11AX_HE20_2G : (is_vht) ?
2928 					MODE_11AC_VHT20_2G : MODE_11NG_HT20;
2929 		break;
2930 	case eSIR_11A_NW_TYPE:
2931 		if (!(is_ht || is_vht || is_he)) {
2932 			phymode = MODE_11A;
2933 			break;
2934 		}
2935 		if (is_he) {
2936 			if (ch_width == CH_WIDTH_160MHZ)
2937 				phymode = MODE_11AX_HE160;
2938 			else if (ch_width == CH_WIDTH_80P80MHZ)
2939 				phymode = MODE_11AX_HE80_80;
2940 			else if (ch_width == CH_WIDTH_80MHZ)
2941 				phymode = MODE_11AX_HE80;
2942 			else
2943 				phymode = (ch_width) ?
2944 					  MODE_11AX_HE40 : MODE_11AX_HE20;
2945 		} else if (is_vht) {
2946 			if (ch_width == CH_WIDTH_160MHZ)
2947 				phymode = MODE_11AC_VHT160;
2948 			else if (ch_width == CH_WIDTH_80P80MHZ)
2949 				phymode = MODE_11AC_VHT80_80;
2950 			else if (ch_width == CH_WIDTH_80MHZ)
2951 				phymode = MODE_11AC_VHT80;
2952 			else
2953 				phymode = (ch_width) ?
2954 					  MODE_11AC_VHT40 : MODE_11AC_VHT20;
2955 		} else
2956 			phymode = (ch_width) ? MODE_11NA_HT40 : MODE_11NA_HT20;
2957 		break;
2958 	default:
2959 		WMA_LOGE("%s: Invalid nw type %d", __func__, nw_type);
2960 		break;
2961 	}
2962 	WMA_LOGD(FL("nw_type %d is_ht %d ch_width %d is_vht %d is_he %d phymode %d"),
2963 		 nw_type, is_ht, ch_width, is_vht, is_he, phymode);
2964 
2965 	return phymode;
2966 }
2967 
2968 /**
2969  * wma_txrx_fw_stats_reset() - reset txrx fw statistics
2970  * @wma_handle: wma handle
2971  * @vdev_id: vdev id
2972  * @value: value
2973  *
2974  * Return: 0 for success or return error
2975  */
2976 int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle,
2977 				uint8_t vdev_id, uint32_t value)
2978 {
2979 	struct ol_txrx_stats_req req;
2980 	struct cdp_vdev *vdev;
2981 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2982 
2983 	if (!soc) {
2984 		WMA_LOGE("%s:SOC context is NULL", __func__);
2985 		return -EINVAL;
2986 	}
2987 
2988 	vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
2989 	if (!vdev) {
2990 		WMA_LOGE("%s:Invalid vdev handle", __func__);
2991 		return -EINVAL;
2992 	}
2993 	qdf_mem_zero(&req, sizeof(req));
2994 	req.stats_type_reset_mask = value;
2995 	cdp_fw_stats_get(soc, vdev, &req, false, false);
2996 
2997 	return 0;
2998 }
2999 
3000 #ifdef HELIUMPLUS
3001 #define SET_UPLOAD_MASK(_mask, _rate_info)	\
3002 	((_mask) = 1 << (_rate_info ## _V2))
3003 #else  /* !HELIUMPLUS */
3004 #define SET_UPLOAD_MASK(_mask, _rate_info)	\
3005 	((_mask) = 1 << (_rate_info))
3006 #endif
3007 
3008 #if defined(HELIUMPLUS) || defined(QCN7605_SUPPORT)
3009 static bool wma_is_valid_fw_stats_cmd(uint32_t value)
3010 {
3011 	if (value > (HTT_DBG_NUM_STATS + 1) ||
3012 		value == (HTT_DBG_STATS_RX_RATE_INFO + 1) ||
3013 		value == (HTT_DBG_STATS_TX_RATE_INFO + 1) ||
3014 		value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) {
3015 		WMA_LOGE("%s: Not supported", __func__);
3016 		return false;
3017 	}
3018 	return true;
3019 }
3020 #else
3021 static bool wma_is_valid_fw_stats_cmd(uint32_t value)
3022 {
3023 	if (value > (HTT_DBG_NUM_STATS + 1) ||
3024 		value == (HTT_DBG_STATS_RX_RATE_INFO_V2 + 1) ||
3025 		value == (HTT_DBG_STATS_TX_RATE_INFO_V2 + 1) ||
3026 		value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) {
3027 		WMA_LOGE("%s: Not supported", __func__);
3028 		return false;
3029 	}
3030 	return true;
3031 }
3032 #endif
3033 
3034 /**
3035  * wma_set_txrx_fw_stats_level() - set txrx fw stats level
3036  * @wma_handle: wma handle
3037  * @vdev_id: vdev id
3038  * @value: value
3039  *
3040  * Return: 0 for success or return error
3041  */
3042 int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle,
3043 				    uint8_t vdev_id, uint32_t value)
3044 {
3045 	struct ol_txrx_stats_req req;
3046 	struct cdp_vdev *vdev;
3047 	uint32_t l_up_mask;
3048 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3049 
3050 	if (!soc) {
3051 		WMA_LOGE("%s:SOC context is NULL", __func__);
3052 		return -EINVAL;
3053 	}
3054 
3055 	vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
3056 	if (!vdev) {
3057 		WMA_LOGE("%s:Invalid vdev handle", __func__);
3058 		return -EINVAL;
3059 	}
3060 
3061 	if (wma_is_valid_fw_stats_cmd(value) == false)
3062 		return -EINVAL;
3063 
3064 	qdf_mem_zero(&req, sizeof(req));
3065 	req.print.verbose = 1;
3066 
3067 	/* TODO: Need to check how to avoid mem leak*/
3068 	l_up_mask = 1 << (value - 1);
3069 	req.stats_type_upload_mask = l_up_mask;
3070 
3071 	cdp_fw_stats_get(soc, vdev, &req, false, true);
3072 
3073 	return 0;
3074 }
3075 
3076 /**
3077  * wma_get_cca_stats() - send request to fw to get CCA
3078  * @wma_handle: wma handle
3079  * @vdev_id: vdev id
3080  *
3081  * Return: QDF status
3082  */
3083 QDF_STATUS wma_get_cca_stats(tp_wma_handle wma_handle,
3084 				uint8_t vdev_id)
3085 {
3086 	if (wmi_unified_congestion_request_cmd(wma_handle->wmi_handle,
3087 			vdev_id)) {
3088 		WMA_LOGE("Failed to congestion request to fw");
3089 		return QDF_STATUS_E_FAILURE;
3090 	}
3091 	return QDF_STATUS_SUCCESS;
3092 }
3093 
3094 /**
3095  * wma_get_beacon_buffer_by_vdev_id() - get the beacon buffer from vdev ID
3096  * @vdev_id: vdev id
3097  * @buffer_size: size of buffer
3098  *
3099  * Return: none
3100  */
3101 void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size)
3102 {
3103 	tp_wma_handle wma;
3104 	struct beacon_info *beacon;
3105 	uint8_t *buf;
3106 	uint32_t buf_size;
3107 
3108 	wma = cds_get_context(QDF_MODULE_ID_WMA);
3109 	if (!wma) {
3110 		WMA_LOGE("%s: Invalid WMA handle", __func__);
3111 		return NULL;
3112 	}
3113 
3114 	if (vdev_id >= wma->max_bssid) {
3115 		WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
3116 		return NULL;
3117 	}
3118 
3119 	if (!wma_is_vdev_in_ap_mode(wma, vdev_id)) {
3120 		WMA_LOGE("%s: vdevid %d is not in AP mode", __func__, vdev_id);
3121 		return NULL;
3122 	}
3123 
3124 	beacon = wma->interfaces[vdev_id].beacon;
3125 
3126 	if (!beacon) {
3127 		WMA_LOGE("%s: beacon invalid", __func__);
3128 		return NULL;
3129 	}
3130 
3131 	qdf_spin_lock_bh(&beacon->lock);
3132 
3133 	buf_size = qdf_nbuf_len(beacon->buf);
3134 	buf = qdf_mem_malloc(buf_size);
3135 	if (!buf) {
3136 		qdf_spin_unlock_bh(&beacon->lock);
3137 		return NULL;
3138 	}
3139 
3140 	qdf_mem_copy(buf, qdf_nbuf_data(beacon->buf), buf_size);
3141 
3142 	qdf_spin_unlock_bh(&beacon->lock);
3143 
3144 	if (buffer_size)
3145 		*buffer_size = buf_size;
3146 
3147 	return buf;
3148 }
3149 
3150 uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id)
3151 {
3152 	tp_wma_handle wma;
3153 	struct wlan_objmgr_vdev *vdev;
3154 
3155 	wma = cds_get_context(QDF_MODULE_ID_WMA);
3156 	if (!wma) {
3157 		WMA_LOGE("%s: Invalid WMA handle", __func__);
3158 		return NULL;
3159 	}
3160 
3161 	if (vdev_id >= wma->max_bssid) {
3162 		WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
3163 		return NULL;
3164 	}
3165 	vdev = wma->interfaces[vdev_id].vdev;
3166 	if (!vdev) {
3167 		WMA_LOGE("%s: Invalid vdev for vdev_id %u", __func__, vdev_id);
3168 		return NULL;
3169 	}
3170 	return wlan_vdev_mlme_get_macaddr(vdev);
3171 }
3172 
3173 QDF_STATUS wma_get_connection_info(uint8_t vdev_id,
3174 		struct policy_mgr_vdev_entry_info *conn_table_entry)
3175 {
3176 	struct wma_txrx_node *wma_conn_table_entry;
3177 
3178 	wma_conn_table_entry = wma_get_interface_by_vdev_id(vdev_id);
3179 	if (!wma_conn_table_entry) {
3180 		WMA_LOGE("%s: can't find vdev_id %d in WMA table", __func__, vdev_id);
3181 		return QDF_STATUS_E_FAILURE;
3182 	}
3183 	conn_table_entry->chan_width = wma_conn_table_entry->chan_width;
3184 	conn_table_entry->mac_id = wma_conn_table_entry->mac_id;
3185 	conn_table_entry->mhz = wma_conn_table_entry->mhz;
3186 	conn_table_entry->sub_type = wma_conn_table_entry->sub_type;
3187 	conn_table_entry->type = wma_conn_table_entry->type;
3188 
3189 	return QDF_STATUS_SUCCESS;
3190 }
3191 
3192 QDF_STATUS wma_ndi_update_connection_info(uint8_t vdev_id,
3193 				struct nan_datapath_channel_info *ndp_chan_info)
3194 {
3195 	struct wma_txrx_node *wma_iface_entry;
3196 
3197 	wma_iface_entry = wma_get_interface_by_vdev_id(vdev_id);
3198 	if (!wma_iface_entry) {
3199 		WMA_LOGE("%s: can't find vdev_id %d in WMA table", __func__, vdev_id);
3200 		return QDF_STATUS_E_FAILURE;
3201 	}
3202 
3203 	if (WMI_VDEV_TYPE_NDI != wma_iface_entry->type) {
3204 		WMA_LOGE("%s: Given vdev id(%d) not of type NDI!",
3205 			 __func__, vdev_id);
3206 		return QDF_STATUS_E_FAILURE;
3207 	}
3208 
3209 	if (!ndp_chan_info) {
3210 		WMA_LOGE("%s: Provided chan info is NULL!", __func__);
3211 		return QDF_STATUS_E_FAILURE;
3212 	}
3213 
3214 	wma_iface_entry->chan_width = ndp_chan_info->ch_width;
3215 	wma_iface_entry->mhz = ndp_chan_info->freq;
3216 	wma_iface_entry->nss = ndp_chan_info->nss;
3217 	wma_iface_entry->mac_id = ndp_chan_info->mac_id;
3218 
3219 	return QDF_STATUS_SUCCESS;
3220 }
3221 
3222 /**
3223  * wma_get_interface_by_vdev_id() - lookup interface entry using vdev ID
3224  * @vdev_id: vdev id
3225  *
3226  * Return: entry from vdev table
3227  */
3228 struct wma_txrx_node  *wma_get_interface_by_vdev_id(uint8_t vdev_id)
3229 {
3230 	tp_wma_handle wma;
3231 
3232 	wma = cds_get_context(QDF_MODULE_ID_WMA);
3233 	if (!wma) {
3234 		WMA_LOGE("%s: Invalid WMA handle", __func__);
3235 		return NULL;
3236 	}
3237 
3238 	if (vdev_id >= wma->max_bssid) {
3239 		WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
3240 		return NULL;
3241 	}
3242 
3243 	return &wma->interfaces[vdev_id];
3244 }
3245 
3246 /**
3247  * wma_update_intf_hw_mode_params() - Update WMA params
3248  * @vdev_id: VDEV id whose params needs to be updated
3249  * @mac_id: MAC id to be updated
3250  * @cfgd_hw_mode_index: HW mode index from which Tx and Rx SS will be updated
3251  *
3252  * Updates the MAC id, tx spatial stream, rx spatial stream in WMA
3253  *
3254  * Return: None
3255  */
3256 void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id,
3257 				    uint32_t cfgd_hw_mode_index)
3258 {
3259 	tp_wma_handle wma;
3260 	struct policy_mgr_hw_mode_params hw_mode;
3261 	QDF_STATUS status;
3262 
3263 	wma = cds_get_context(QDF_MODULE_ID_WMA);
3264 	if (!wma) {
3265 		WMA_LOGE("%s: Invalid WMA handle", __func__);
3266 		return;
3267 	}
3268 
3269 	if (!wma->interfaces) {
3270 		WMA_LOGE("%s: Interface is NULL", __func__);
3271 		return;
3272 	}
3273 
3274 	status = policy_mgr_get_hw_mode_from_idx(wma->psoc, cfgd_hw_mode_index,
3275 						 &hw_mode);
3276 	if (!QDF_IS_STATUS_SUCCESS(status)) {
3277 		WMA_LOGE("%s: cfgd_hw_mode_index %d not found", __func__,
3278 			 cfgd_hw_mode_index);
3279 		return;
3280 	}
3281 	wma->interfaces[vdev_id].mac_id = mac_id;
3282 	if (mac_id == 0)
3283 		wma->interfaces[vdev_id].tx_streams =
3284 			hw_mode.mac0_tx_ss;
3285 	else
3286 		wma->interfaces[vdev_id].tx_streams =
3287 			hw_mode.mac1_tx_ss;
3288 
3289 	WMA_LOGD("%s: vdev %d, update tx ss:%d mac %d hw_mode_id %d",
3290 		 __func__,
3291 		 vdev_id,
3292 		 wma->interfaces[vdev_id].tx_streams,
3293 		 mac_id,
3294 		 cfgd_hw_mode_index);
3295 }
3296 
3297 /**
3298  * wma_get_vht_ch_width - return vht channel width
3299  *
3300  * Return: return vht channel width
3301  */
3302 uint32_t wma_get_vht_ch_width(void)
3303 {
3304 	uint32_t fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ;
3305 	tp_wma_handle wm_hdl = cds_get_context(QDF_MODULE_ID_WMA);
3306 	struct target_psoc_info *tgt_hdl;
3307 	int vht_cap_info;
3308 
3309 	if (!wm_hdl)
3310 		return fw_ch_wd;
3311 
3312 	tgt_hdl = wlan_psoc_get_tgt_if_handle(wm_hdl->psoc);
3313 	if (!tgt_hdl)
3314 		return fw_ch_wd;
3315 
3316 	vht_cap_info = target_if_get_vht_cap_info(tgt_hdl);
3317 	if (vht_cap_info & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ)
3318 		fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ;
3319 	else if (vht_cap_info & WMI_VHT_CAP_CH_WIDTH_160MHZ)
3320 		fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ;
3321 
3322 	return fw_ch_wd;
3323 }
3324 
3325 /**
3326  * wma_get_num_of_setbits_from_bitmask() - to get num of setbits from bitmask
3327  * @mask: given bitmask
3328  *
3329  * This helper function should return number of setbits from bitmask
3330  *
3331  * Return: number of setbits from bitmask
3332  */
3333 uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask)
3334 {
3335 	uint32_t num_of_setbits = 0;
3336 
3337 	while (mask) {
3338 		mask &= (mask - 1);
3339 		num_of_setbits++;
3340 	}
3341 	return num_of_setbits;
3342 }
3343 
3344 /**
3345  * wma_is_csa_offload_enabled - checks fw CSA offload capability
3346  *
3347  * Return: true or false
3348  */
3349 
3350 bool wma_is_csa_offload_enabled(void)
3351 {
3352 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3353 
3354 	if (!wma)
3355 		return false;
3356 
3357 	return wmi_service_enabled(wma->wmi_handle,
3358 				   wmi_service_csa_offload);
3359 }
3360 
3361 bool wma_is_mbssid_enabled(void)
3362 {
3363 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3364 
3365 	if (!wma)
3366 		return false;
3367 
3368 	return wmi_service_enabled(wma->wmi_handle,
3369 				   wmi_service_infra_mbssid);
3370 }
3371 
3372 #ifdef FEATURE_FW_LOG_PARSING
3373 /**
3374  * wma_config_debug_module_cmd - set debug log config
3375  * @wmi_handle: wmi layer handle
3376  * @param: debug log parameter
3377  * @val: debug log value
3378  * @module_id_bitmap: debug module id bitmap
3379  * @bitmap_len:  debug module bitmap length
3380  *
3381  * Return: QDF_STATUS_SUCCESS for success or error code
3382  */
3383 QDF_STATUS
3384 wma_config_debug_module_cmd(wmi_unified_t wmi_handle, A_UINT32 param,
3385 			    A_UINT32 val, A_UINT32 *module_id_bitmap,
3386 			    A_UINT32 bitmap_len)
3387 {
3388 	struct dbglog_params dbg_param;
3389 
3390 	dbg_param.param = param;
3391 	dbg_param.val = val;
3392 	dbg_param.module_id_bitmap = module_id_bitmap;
3393 	dbg_param.bitmap_len = bitmap_len;
3394 
3395 	return wmi_unified_dbglog_cmd_send(wmi_handle, &dbg_param);
3396 }
3397 #endif
3398 #ifdef FEATURE_P2P_LISTEN_OFFLOAD
3399 /**
3400  * wma_is_p2p_lo_capable() - if driver is capable of p2p listen offload
3401  *
3402  * This function checks if driver is capable of p2p listen offload
3403  *    true: capable of p2p offload
3404  *    false: not capable
3405  *
3406  * Return: true - capable, false - not capable
3407  */
3408 bool wma_is_p2p_lo_capable(void)
3409 {
3410 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3411 
3412 	if (wma) {
3413 		return wmi_service_enabled
3414 				(wma->wmi_handle,
3415 				 wmi_service_p2p_listen_offload_support);
3416 	}
3417 
3418 	return 0;
3419 }
3420 #endif
3421 
3422 bool wma_capability_enhanced_mcast_filter(void)
3423 {
3424 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3425 
3426 	if (wma) {
3427 		return wmi_service_enabled(wma->wmi_handle,
3428 					   wmi_service_enhanced_mcast_filter);
3429 	}
3430 
3431 	return 0;
3432 }
3433 
3434 
3435 bool wma_is_vdev_up(uint8_t vdev_id)
3436 {
3437 	struct wlan_objmgr_vdev *vdev;
3438 	tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA);
3439 	bool is_up = false;
3440 
3441 	if (!wma) {
3442 		WMA_LOGE("%s: WMA context is invald!", __func__);
3443 		return is_up;
3444 	}
3445 
3446 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id,
3447 			WLAN_LEGACY_WMA_ID);
3448 	if (vdev) {
3449 		is_up = QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(vdev));
3450 		wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID);
3451 	}
3452 	return is_up;
3453 }
3454 
3455 void wma_acquire_wakelock(qdf_wake_lock_t *wl, uint32_t msec)
3456 {
3457 	t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA);
3458 
3459 	cds_host_diag_log_work(wl, msec, WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
3460 	qdf_wake_lock_timeout_acquire(wl, msec);
3461 	qdf_runtime_pm_prevent_suspend(&wma->wmi_cmd_rsp_runtime_lock);
3462 }
3463 
3464 void wma_release_wakelock(qdf_wake_lock_t *wl)
3465 {
3466 	t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA);
3467 
3468 	qdf_wake_lock_release(wl, WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
3469 	qdf_runtime_pm_allow_suspend(&wma->wmi_cmd_rsp_runtime_lock);
3470 }
3471 
3472 QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id)
3473 {
3474 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
3475 	struct wma_txrx_node *iface = &wma->interfaces[vdev_id];
3476 	struct vdev_mlme_obj *vdev_mlme = NULL;
3477 
3478 	if (!wma_is_vdev_valid(vdev_id)) {
3479 		WMA_LOGE("%s: Invalid vdev id:%d", __func__, vdev_id);
3480 		return status;
3481 	}
3482 
3483 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev);
3484 	if (!vdev_mlme) {
3485 		WMA_LOGE("Failed to get vdev mlme obj for vdev id %d", vdev_id);
3486 		return status;
3487 	}
3488 
3489 	/*
3490 	 * Reset the dynamic nss chains config to the ini values, as when the
3491 	 * vdev gets its started again, this would be a fresh connection,
3492 	 * and we dont want the config of previous connection to affect the
3493 	 * current connection.
3494 	 */
3495 	qdf_mem_copy(mlme_get_dynamic_vdev_config(iface->vdev),
3496 		     mlme_get_ini_vdev_config(iface->vdev),
3497 		     sizeof(struct wlan_mlme_nss_chains));
3498 
3499 	status = vdev_mgr_stop_send(vdev_mlme);
3500 
3501 	return status;
3502 }
3503 
3504 QDF_STATUS wma_get_rcpi_req(WMA_HANDLE handle,
3505 			    struct sme_rcpi_req *rcpi_request)
3506 {
3507 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
3508 	struct rcpi_req  cmd = {0};
3509 	struct wma_txrx_node *iface;
3510 	struct sme_rcpi_req *node_rcpi_req;
3511 
3512 	WMA_LOGD("%s: Enter", __func__);
3513 	iface = &wma_handle->interfaces[rcpi_request->session_id];
3514 	/* command is in progress */
3515 	if (iface->rcpi_req) {
3516 		WMA_LOGE("%s : previous rcpi request is pending", __func__);
3517 		return QDF_STATUS_SUCCESS;
3518 	}
3519 
3520 	node_rcpi_req = qdf_mem_malloc(sizeof(*node_rcpi_req));
3521 	if (!node_rcpi_req)
3522 		return QDF_STATUS_E_NOMEM;
3523 
3524 	*node_rcpi_req = *rcpi_request;
3525 	iface->rcpi_req = node_rcpi_req;
3526 
3527 	cmd.vdev_id = rcpi_request->session_id;
3528 	qdf_mem_copy(cmd.mac_addr, &rcpi_request->mac_addr, QDF_MAC_ADDR_SIZE);
3529 	cmd.measurement_type = rcpi_request->measurement_type;
3530 
3531 	if (wmi_unified_send_request_get_rcpi_cmd(wma_handle->wmi_handle,
3532 						  &cmd)) {
3533 		WMA_LOGE("%s: Failed to send WMI_REQUEST_RCPI_CMDID",
3534 			 __func__);
3535 		iface->rcpi_req = NULL;
3536 		qdf_mem_free(node_rcpi_req);
3537 		return QDF_STATUS_E_FAILURE;
3538 	}
3539 
3540 	WMA_LOGD("%s: Exit", __func__);
3541 
3542 	return QDF_STATUS_SUCCESS;
3543 }
3544 
3545 int wma_rcpi_event_handler(void *handle, uint8_t *cmd_param_info,
3546 			   uint32_t len)
3547 {
3548 	struct rcpi_res res = {0};
3549 	struct sme_rcpi_req *rcpi_req;
3550 	struct qdf_mac_addr qdf_mac;
3551 	struct wma_txrx_node *iface;
3552 	QDF_STATUS status = QDF_STATUS_SUCCESS;
3553 	tp_wma_handle wma_handle = (tp_wma_handle)handle;
3554 
3555 	status = wmi_extract_rcpi_response_event(wma_handle->wmi_handle,
3556 						 cmd_param_info, &res);
3557 	if (status == QDF_STATUS_E_INVAL)
3558 		return -EINVAL;
3559 
3560 	if (res.vdev_id >= wma_handle->max_bssid) {
3561 		WMA_LOGE("%s: received invalid vdev_id %d",
3562 			 __func__, res.vdev_id);
3563 		return -EINVAL;
3564 	}
3565 
3566 	iface = &wma_handle->interfaces[res.vdev_id];
3567 	if (!iface->rcpi_req) {
3568 		WMI_LOGE("rcpi_req buffer not available");
3569 		return 0;
3570 	}
3571 
3572 	rcpi_req = iface->rcpi_req;
3573 	if (!rcpi_req->rcpi_callback) {
3574 		iface->rcpi_req = NULL;
3575 		qdf_mem_free(rcpi_req);
3576 		return 0;
3577 	}
3578 
3579 	if ((res.measurement_type == RCPI_MEASUREMENT_TYPE_INVALID) ||
3580 	    (res.vdev_id != rcpi_req->session_id) ||
3581 	    (res.measurement_type != rcpi_req->measurement_type) ||
3582 	    (qdf_mem_cmp(res.mac_addr, &rcpi_req->mac_addr,
3583 			 QDF_MAC_ADDR_SIZE))) {
3584 		WMI_LOGE("invalid rcpi_response");
3585 		iface->rcpi_req = NULL;
3586 		qdf_mem_free(rcpi_req);
3587 		return 0;
3588 	}
3589 
3590 	qdf_mem_copy(&qdf_mac, res.mac_addr, QDF_MAC_ADDR_SIZE);
3591 	(rcpi_req->rcpi_callback)(rcpi_req->rcpi_context, qdf_mac,
3592 				  res.rcpi_value, status);
3593 	iface->rcpi_req = NULL;
3594 	qdf_mem_free(rcpi_req);
3595 
3596 	return 0;
3597 }
3598 
3599 /**
3600  * wma_set_roam_offload_flag() -  Set roam offload flag to fw
3601  * @wma:     wma handle
3602  * @vdev_id: vdev id
3603  * @is_set:  set or clear
3604  *
3605  * Return: none
3606  */
3607 static void wma_set_roam_offload_flag(tp_wma_handle wma, uint8_t vdev_id,
3608 				      bool is_set)
3609 {
3610 	QDF_STATUS status;
3611 	uint32_t flag = 0;
3612 	bool disable_4way_hs_offload;
3613 
3614 	if (is_set) {
3615 		flag = WMI_ROAM_FW_OFFLOAD_ENABLE_FLAG |
3616 		       WMI_ROAM_BMISS_FINAL_SCAN_ENABLE_FLAG;
3617 
3618 		wlan_mlme_get_4way_hs_offload(wma->psoc,
3619 					      &disable_4way_hs_offload);
3620 		/*
3621 		 * If 4-way HS offload is disabled then let supplicant handle
3622 		 * 4way HS and firmware will still do LFR3.0 till reassoc phase.
3623 		 */
3624 		if (disable_4way_hs_offload)
3625 			flag |= WMI_VDEV_PARAM_SKIP_ROAM_EAPOL_4WAY_HANDSHAKE;
3626 	}
3627 
3628 	WMA_LOGD("%s: vdev_id:%d, is_set:%d, flag:%d",
3629 		 __func__, vdev_id, is_set, flag);
3630 
3631 	status = wma_vdev_set_param(wma->wmi_handle, vdev_id,
3632 				    WMI_VDEV_PARAM_ROAM_FW_OFFLOAD, flag);
3633 	if (QDF_IS_STATUS_ERROR(status))
3634 		WMA_LOGE("Failed to set WMI_VDEV_PARAM_ROAM_FW_OFFLOAD");
3635 }
3636 
3637 void wma_update_roam_offload_flag(void *handle,
3638 				  struct roam_init_params *params)
3639 {
3640 	tp_wma_handle wma = handle;
3641 	struct wma_txrx_node *iface;
3642 
3643 	WMA_LOGD("%s: vdev_id:%d, is_connected:%d", __func__,
3644 		 params->vdev_id, params->enable);
3645 
3646 	if (!wma_is_vdev_valid(params->vdev_id)) {
3647 		WMA_LOGE("%s: vdev_id: %d is not active", __func__,
3648 			 params->vdev_id);
3649 		return;
3650 	}
3651 
3652 	iface = &wma->interfaces[params->vdev_id];
3653 
3654 	if ((iface->type != WMI_VDEV_TYPE_STA) ||
3655 	    (iface->sub_type != 0)) {
3656 		WMA_LOGE("%s: this isn't a STA: %d",
3657 			 __func__, params->vdev_id);
3658 		return;
3659 	}
3660 
3661 	wma_set_roam_offload_flag(wma, params->vdev_id, params->enable);
3662 }
3663 
3664 QDF_STATUS wma_send_vdev_down_to_fw(t_wma_handle *wma, uint8_t vdev_id)
3665 {
3666 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
3667 	struct wma_txrx_node *iface = &wma->interfaces[vdev_id];
3668 	struct vdev_mlme_obj *vdev_mlme;
3669 
3670 	if (!wma_is_vdev_valid(vdev_id)) {
3671 		WMA_LOGE("%s: Invalid vdev id:%d", __func__, vdev_id);
3672 		return status;
3673 	}
3674 
3675 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev);
3676 	if (!vdev_mlme) {
3677 		WMA_LOGE("Failed to get vdev mlme obj for vdev id %d", vdev_id);
3678 		return status;
3679 	}
3680 
3681 	wma->interfaces[vdev_id].roaming_in_progress = false;
3682 
3683 	status = vdev_mgr_down_send(vdev_mlme);
3684 
3685 	return status;
3686 }
3687 
3688 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
3689 tSirWifiPeerType wmi_to_sir_peer_type(enum wmi_peer_type type)
3690 {
3691 	switch (type) {
3692 	case WMI_PEER_TYPE_DEFAULT:
3693 		return WIFI_PEER_STA;
3694 	case WMI_PEER_TYPE_BSS:
3695 		return WIFI_PEER_AP;
3696 	case WMI_PEER_TYPE_TDLS:
3697 		return WIFI_PEER_TDLS;
3698 	case WMI_PEER_TYPE_NAN_DATA:
3699 		return WIFI_PEER_NAN;
3700 	default:
3701 		WMA_LOGE("Cannot map wmi_peer_type %d to HAL peer type", type);
3702 		return WIFI_PEER_INVALID;
3703 	}
3704 }
3705 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
3706 
3707 #ifdef FEATURE_WLAN_DYNAMIC_CVM
3708 /**
3709  * wma_set_vc_mode_config() - set voltage corner mode config to FW.
3710  * @wma_handle:	pointer to wma handle.
3711  * @vc_bitmap:	value needs to set to firmware.
3712  *
3713  * At the time of driver startup, set operating voltage corner mode
3714  * for differenet phymode and bw configurations.
3715  *
3716  * Return: QDF_STATUS.
3717  */
3718 QDF_STATUS wma_set_vc_mode_config(void *wma_handle,
3719 		uint32_t vc_bitmap)
3720 {
3721 	int32_t ret;
3722 	tp_wma_handle wma = (tp_wma_handle)wma_handle;
3723 	struct pdev_params pdevparam;
3724 
3725 	pdevparam.param_id = WMI_PDEV_UPDATE_WDCVS_ALGO;
3726 	pdevparam.param_value = vc_bitmap;
3727 
3728 	ret = wmi_unified_pdev_param_send(wma->wmi_handle,
3729 			&pdevparam,
3730 			WMA_WILDCARD_PDEV_ID);
3731 	if (ret) {
3732 		WMA_LOGE("Fail to Set Voltage Corner config (0x%x)",
3733 			vc_bitmap);
3734 		return QDF_STATUS_E_FAILURE;
3735 	}
3736 
3737 	WMA_LOGD("Successfully Set Voltage Corner config (0x%x)",
3738 		vc_bitmap);
3739 
3740 	return QDF_STATUS_SUCCESS;
3741 }
3742 #endif
3743 
3744 int wma_chip_power_save_failure_detected_handler(void *handle,
3745 						 uint8_t  *cmd_param_info,
3746 						 uint32_t len)
3747 {
3748 	tp_wma_handle wma = (tp_wma_handle)handle;
3749 	WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *param_buf;
3750 	wmi_chip_power_save_failure_detected_fixed_param  *event;
3751 	struct chip_pwr_save_fail_detected_params  pwr_save_fail_params;
3752 	struct mac_context *mac = (struct mac_context *)cds_get_context(
3753 						QDF_MODULE_ID_PE);
3754 	if (!wma) {
3755 		WMA_LOGE("%s: wma_handle is NULL", __func__);
3756 		return -EINVAL;
3757 	}
3758 	if (!mac) {
3759 		WMA_LOGE("%s: Invalid mac context", __func__);
3760 		return -EINVAL;
3761 	}
3762 	if (!mac->sme.chip_power_save_fail_cb) {
3763 		WMA_LOGE("%s: Callback not registered", __func__);
3764 		return -EINVAL;
3765 	}
3766 
3767 	param_buf =
3768 	(WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *)
3769 	cmd_param_info;
3770 	if (!param_buf) {
3771 		WMA_LOGE("%s: Invalid pwr_save_fail_params breached event",
3772 			 __func__);
3773 		return -EINVAL;
3774 	}
3775 	event = param_buf->fixed_param;
3776 	pwr_save_fail_params.failure_reason_code =
3777 				event->power_save_failure_reason_code;
3778 	pwr_save_fail_params.wake_lock_bitmap[0] =
3779 				event->protocol_wake_lock_bitmap[0];
3780 	pwr_save_fail_params.wake_lock_bitmap[1] =
3781 				event->protocol_wake_lock_bitmap[1];
3782 	pwr_save_fail_params.wake_lock_bitmap[2] =
3783 				event->protocol_wake_lock_bitmap[2];
3784 	pwr_save_fail_params.wake_lock_bitmap[3] =
3785 				event->protocol_wake_lock_bitmap[3];
3786 	mac->sme.chip_power_save_fail_cb(mac->hdd_handle,
3787 				&pwr_save_fail_params);
3788 
3789 	WMA_LOGD("%s: Invoke HDD pwr_save_fail callback", __func__);
3790 	return 0;
3791 }
3792 
3793 int wma_roam_scan_stats_event_handler(void *handle, uint8_t *event,
3794 				      uint32_t len)
3795 {
3796 	tp_wma_handle wma_handle;
3797 	wmi_unified_t wmi_handle;
3798 	struct sir_roam_scan_stats *roam_scan_stats_req = NULL;
3799 	struct wma_txrx_node *iface = NULL;
3800 	struct wmi_roam_scan_stats_res *res = NULL;
3801 	int ret = 0;
3802 	uint32_t vdev_id;
3803 	QDF_STATUS status;
3804 
3805 	wma_handle = handle;
3806 	if (!wma_handle) {
3807 		WMA_LOGE(FL("NULL wma_handle"));
3808 		return -EINVAL;
3809 	}
3810 
3811 	wmi_handle = wma_handle->wmi_handle;
3812 	if (!wmi_handle) {
3813 		WMA_LOGE(FL("NULL wmi_handle"));
3814 		return -EINVAL;
3815 	}
3816 
3817 	status = wmi_extract_roam_scan_stats_res_evt(wmi_handle, event,
3818 						     &vdev_id,
3819 						     &res);
3820 
3821 	/* vdev_id can be invalid though status is success, hence validate */
3822 	if (vdev_id >= wma_handle->max_bssid) {
3823 		WMA_LOGE(FL("Received invalid vdev_id: %d"), vdev_id);
3824 		ret  = -EINVAL;
3825 		goto free_res;
3826 	}
3827 
3828 	/* Get interface for valid vdev_id */
3829 	iface = &wma_handle->interfaces[vdev_id];
3830 	if (!iface) {
3831 		WMI_LOGE(FL("Interface not available for vdev_id: %d"),
3832 			 vdev_id);
3833 		ret  = -EINVAL;
3834 		goto free_res;
3835 	}
3836 
3837 	roam_scan_stats_req = iface->roam_scan_stats_req;
3838 	iface->roam_scan_stats_req = NULL;
3839 	if (!roam_scan_stats_req) {
3840 		WMI_LOGE(FL("No pending request vdev_id: %d"), vdev_id);
3841 		ret  = -EINVAL;
3842 		goto free_res;
3843 	}
3844 
3845 	if (!QDF_IS_STATUS_SUCCESS(status) ||
3846 	    !roam_scan_stats_req->cb ||
3847 	    roam_scan_stats_req->vdev_id != vdev_id) {
3848 		WMI_LOGE(FL("roam_scan_stats buffer not available"));
3849 		ret = -EINVAL;
3850 		goto free_roam_scan_stats_req;
3851 	}
3852 
3853 	roam_scan_stats_req->cb(roam_scan_stats_req->context, res);
3854 
3855 free_roam_scan_stats_req:
3856 	qdf_mem_free(roam_scan_stats_req);
3857 	roam_scan_stats_req = NULL;
3858 
3859 free_res:
3860 	qdf_mem_free(res);
3861 	res = NULL;
3862 
3863 	return ret;
3864 }
3865 
3866 QDF_STATUS wma_get_roam_scan_stats(WMA_HANDLE handle,
3867 				   struct sir_roam_scan_stats *req)
3868 {
3869 	tp_wma_handle wma_handle = (tp_wma_handle)handle;
3870 	struct wmi_roam_scan_stats_req cmd = {0};
3871 	struct wma_txrx_node *iface;
3872 	struct sir_roam_scan_stats *node_req = NULL;
3873 
3874 	WMA_LOGD("%s: Enter", __func__);
3875 	iface = &wma_handle->interfaces[req->vdev_id];
3876 	/* command is in progress */
3877 	if (iface->roam_scan_stats_req) {
3878 		WMA_LOGE(FL("previous roam scan stats req is pending"));
3879 		return QDF_STATUS_SUCCESS;
3880 	}
3881 
3882 	node_req = qdf_mem_malloc(sizeof(*node_req));
3883 	if (!node_req)
3884 		return QDF_STATUS_E_NOMEM;
3885 
3886 	*node_req = *req;
3887 	iface->roam_scan_stats_req = node_req;
3888 	cmd.vdev_id = req->vdev_id;
3889 
3890 	if (wmi_unified_send_roam_scan_stats_cmd(wma_handle->wmi_handle,
3891 						 &cmd)) {
3892 		WMA_LOGE("%s: Failed to send WMI_REQUEST_ROAM_SCAN_STATS_CMDID",
3893 			 __func__);
3894 		iface->roam_scan_stats_req = NULL;
3895 		qdf_mem_free(node_req);
3896 		return QDF_STATUS_E_FAILURE;
3897 	}
3898 
3899 	WMA_LOGD("%s: Exit", __func__);
3900 
3901 	return QDF_STATUS_SUCCESS;
3902 }
3903 
3904 void wma_remove_bss_peer_on_vdev_start_failure(tp_wma_handle wma,
3905 					       uint8_t vdev_id)
3906 {
3907 	struct cdp_pdev *pdev;
3908 	void *peer = NULL;
3909 	uint8_t peer_id;
3910 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3911 	QDF_STATUS status;
3912 	struct qdf_mac_addr bss_peer;
3913 	struct wma_txrx_node *iface;
3914 
3915 	iface = &wma->interfaces[vdev_id];
3916 
3917 	status = mlme_get_vdev_bss_peer_mac_addr(iface->vdev, &bss_peer);
3918 	if (QDF_IS_STATUS_ERROR(status)) {
3919 		WMA_LOGE("%s: Failed to get bssid", __func__);
3920 		return;
3921 	}
3922 
3923 	WMA_LOGE("%s: ADD BSS failure for vdev %d", __func__, vdev_id);
3924 
3925 	pdev = cds_get_context(QDF_MODULE_ID_TXRX);
3926 	if (!pdev) {
3927 		WMA_LOGE("%s: Failed to get pdev", __func__);
3928 		return;
3929 	}
3930 
3931 	peer = cdp_peer_find_by_addr(soc, pdev, bss_peer.bytes,
3932 				     &peer_id);
3933 	if (!peer) {
3934 		WMA_LOGE("%s Failed to find peer %pM",
3935 			 __func__, bss_peer.bytes);
3936 		return;
3937 	}
3938 
3939 	wma_remove_peer(wma, bss_peer.bytes, vdev_id, peer, false);
3940 }
3941 
3942 QDF_STATUS wma_sta_vdev_up_send(struct vdev_mlme_obj *vdev_mlme,
3943 				uint16_t data_len, void *data)
3944 {
3945 	uint8_t vdev_id;
3946 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3947 	QDF_STATUS status;
3948 	struct wma_txrx_node *iface;
3949 
3950 	if (!wma) {
3951 		WMA_LOGE("%s wma handle is NULL", __func__);
3952 		return QDF_STATUS_E_INVAL;
3953 	}
3954 	vdev_id = wlan_vdev_get_id(vdev_mlme->vdev);
3955 	iface = &wma->interfaces[vdev_id];
3956 	vdev_mlme->proto.sta.assoc_id = iface->aid;
3957 
3958 	status = vdev_mgr_up_send(vdev_mlme);
3959 
3960 	if (QDF_IS_STATUS_ERROR(status)) {
3961 		WMA_LOGE("%s: Failed to send vdev up cmd: vdev %d",
3962 			 __func__, vdev_id);
3963 		policy_mgr_set_do_hw_mode_change_flag(
3964 			wma->psoc, false);
3965 		status = QDF_STATUS_E_FAILURE;
3966 	} else {
3967 		wma_set_vdev_mgmt_rate(wma, vdev_id);
3968 		if (iface->beacon_filter_enabled)
3969 			wma_add_beacon_filter(
3970 					wma,
3971 					&iface->beacon_filter);
3972 	}
3973 
3974 	return QDF_STATUS_SUCCESS;
3975 }
3976 
3977 bool wma_get_hidden_ssid_restart_in_progress(struct wma_txrx_node *iface)
3978 {
3979 	if (!iface)
3980 		return false;
3981 
3982 	return ap_mlme_is_hidden_ssid_restart_in_progress(iface->vdev);
3983 }
3984 
3985 bool wma_get_channel_switch_in_progress(struct wma_txrx_node *iface)
3986 {
3987 	if (!iface)
3988 		return false;
3989 
3990 	return mlme_is_chan_switch_in_progress(iface->vdev);
3991 }
3992 
3993 static QDF_STATUS wma_vdev_send_start_resp(tp_wma_handle wma,
3994 					  struct add_bss_rsp *add_bss_rsp)
3995 {
3996 	WMA_LOGD(FL("Sending add bss rsp to umac(vdev %d status %d)"),
3997 		 add_bss_rsp->vdev_id, add_bss_rsp->status);
3998 	lim_handle_add_bss_rsp(wma->mac_context, add_bss_rsp);
3999 
4000 	return QDF_STATUS_SUCCESS;
4001 }
4002 
4003 QDF_STATUS wma_sta_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme,
4004 					    uint16_t data_len, void *data)
4005 {
4006 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4007 	enum vdev_assoc_type assoc_type;
4008 
4009 	if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev)) {
4010 		mlme_set_chan_switch_in_progress(vdev_mlme->vdev, false);
4011 		lim_process_switch_channel_rsp(wma->mac_context, data);
4012 		return QDF_STATUS_SUCCESS;
4013 	}
4014 
4015 	assoc_type = mlme_get_assoc_type(vdev_mlme->vdev);
4016 	switch (assoc_type) {
4017 	case VDEV_ASSOC:
4018 	case VDEV_REASSOC:
4019 		lim_process_switch_channel_rsp(wma->mac_context, data);
4020 		break;
4021 	case VDEV_FT_REASSOC:
4022 		lim_handle_add_bss_rsp(wma->mac_context, data);
4023 		break;
4024 	default:
4025 		WMA_LOGE(FL("assoc_type %d is invalid"), assoc_type);
4026 	}
4027 
4028 	return QDF_STATUS_SUCCESS;
4029 }
4030 
4031 QDF_STATUS wma_sta_mlme_vdev_roam_notify(struct vdev_mlme_obj *vdev_mlme,
4032 					 uint16_t data_len, void *data)
4033 {
4034 	tp_wma_handle wma;
4035 	int ret;
4036 	QDF_STATUS status = QDF_STATUS_SUCCESS;
4037 
4038 	wma = cds_get_context(QDF_MODULE_ID_WMA);
4039 	if (!wma) {
4040 		WMA_LOGE("%s wma handle is NULL", __func__);
4041 		return QDF_STATUS_E_INVAL;
4042 	}
4043 
4044 	ret = wma_mlme_roam_synch_event_handler_cb(wma, data, data_len);
4045 	if (ret != 0) {
4046 		wma_err("Failed to process roam synch event");
4047 		status = QDF_STATUS_E_FAILURE;
4048 	}
4049 
4050 	return status;
4051 }
4052 
4053 QDF_STATUS wma_ap_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme,
4054 					   uint16_t data_len, void *data)
4055 {
4056 	tp_wma_handle wma;
4057 	QDF_STATUS status = QDF_STATUS_SUCCESS;
4058 	struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev;
4059 	uint8_t vdev_id;
4060 
4061 	wma = cds_get_context(QDF_MODULE_ID_WMA);
4062 	if (!wma) {
4063 		WMA_LOGE("%s wma handle is NULL", __func__);
4064 		return QDF_STATUS_E_INVAL;
4065 	}
4066 
4067 	if (mlme_is_chan_switch_in_progress(vdev)) {
4068 		mlme_set_chan_switch_in_progress(vdev, false);
4069 		lim_process_switch_channel_rsp(wma->mac_context, data);
4070 	} else if (ap_mlme_is_hidden_ssid_restart_in_progress(vdev)) {
4071 		vdev_id = vdev->vdev_objmgr.vdev_id;
4072 		lim_process_mlm_update_hidden_ssid_rsp(wma->mac_context,
4073 						       vdev_id);
4074 		ap_mlme_set_hidden_ssid_restart_in_progress(vdev, false);
4075 	} else {
4076 		status = wma_vdev_send_start_resp(wma, data);
4077 	}
4078 
4079 	return status;
4080 }
4081 
4082 QDF_STATUS wma_mlme_vdev_stop_continue(struct vdev_mlme_obj *vdev_mlme,
4083 				       uint16_t data_len, void *data)
4084 {
4085 	return __wma_handle_vdev_stop_rsp(
4086 			(struct vdev_stop_response *)data);
4087 }
4088 
4089 QDF_STATUS wma_ap_mlme_vdev_down_send(struct vdev_mlme_obj *vdev_mlme,
4090 				      uint16_t data_len, void *data)
4091 {
4092 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4093 
4094 	if (!wma) {
4095 		WMA_LOGE("%s wma handle is NULL", __func__);
4096 		return QDF_STATUS_E_INVAL;
4097 	}
4098 
4099 	wma_send_vdev_down(wma, data);
4100 
4101 	return QDF_STATUS_SUCCESS;
4102 }
4103 
4104 QDF_STATUS
4105 wma_mlme_vdev_notify_down_complete(struct vdev_mlme_obj *vdev_mlme,
4106 				   uint16_t data_len, void *data)
4107 {
4108 	tp_wma_handle wma;
4109 	QDF_STATUS status;
4110 	uint32_t vdev_stop_type;
4111 	struct del_bss_resp *resp = (struct del_bss_resp *)data;
4112 
4113 	if (mlme_is_connection_fail(vdev_mlme->vdev) ||
4114 	    mlme_get_vdev_start_failed(vdev_mlme->vdev)) {
4115 		WMA_LOGD("%s Vdev start req failed, no action required",
4116 			 __func__);
4117 		mlme_set_connection_fail(vdev_mlme->vdev, false);
4118 		mlme_set_vdev_start_failed(vdev_mlme->vdev, false);
4119 		return QDF_STATUS_SUCCESS;
4120 	}
4121 
4122 	wma = cds_get_context(QDF_MODULE_ID_WMA);
4123 	if (!wma) {
4124 		WMA_LOGE("%s wma handle is NULL", __func__);
4125 		status = QDF_STATUS_E_INVAL;
4126 		goto end;
4127 	}
4128 
4129 	status = mlme_get_vdev_stop_type(wma->interfaces[resp->vdev_id].vdev,
4130 					 &vdev_stop_type);
4131 	if (QDF_IS_STATUS_ERROR(status)) {
4132 		WMA_LOGE("%s: Failed to get msg_type", __func__);
4133 		status = QDF_STATUS_E_INVAL;
4134 		goto end;
4135 	}
4136 
4137 	if (vdev_stop_type == WMA_DELETE_BSS_HO_FAIL_REQ) {
4138 		resp->status = QDF_STATUS_SUCCESS;
4139 		wma_send_msg_high_priority(wma, WMA_DELETE_BSS_HO_FAIL_RSP,
4140 					   (void *)resp, 0);
4141 		return QDF_STATUS_SUCCESS;
4142 	}
4143 
4144 	if (vdev_stop_type == WMA_SET_LINK_STATE) {
4145 		lim_join_result_callback(wma->mac_context,
4146 					 wlan_vdev_get_id(vdev_mlme->vdev));
4147 	} else {
4148 		wma_send_del_bss_response(wma, resp);
4149 		return QDF_STATUS_SUCCESS;
4150 	}
4151 
4152 end:
4153 	qdf_mem_free(resp);
4154 
4155 	return status;
4156 }
4157 
4158 QDF_STATUS wma_ap_mlme_vdev_stop_start_send(struct vdev_mlme_obj *vdev_mlme,
4159 					    enum vdev_cmd_type type,
4160 					    uint16_t data_len, void *data)
4161 {
4162 	tp_wma_handle wma;
4163 	struct add_bss_rsp *add_bss_rsp = data;
4164 
4165 	wma = cds_get_context(QDF_MODULE_ID_WMA);
4166 	if (!wma) {
4167 		WMA_LOGE("%s wma handle is NULL", __func__);
4168 		return QDF_STATUS_E_INVAL;
4169 	}
4170 
4171 	if (wma_send_vdev_stop_to_fw(wma, add_bss_rsp->vdev_id))
4172 		WMA_LOGE(FL("Failed to send vdev stop for vdev id %d"),
4173 			 add_bss_rsp->vdev_id);
4174 
4175 	wma_remove_bss_peer_on_vdev_start_failure(wma, add_bss_rsp->vdev_id);
4176 
4177 	return wma_vdev_send_start_resp(wma, add_bss_rsp);
4178 }
4179 
4180 QDF_STATUS wma_mon_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme,
4181 					    uint16_t data_len, void *data)
4182 {
4183 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4184 
4185 	if (!wma) {
4186 		WMA_LOGE("%s wma handle is NULL", __func__);
4187 		return QDF_STATUS_E_INVAL;
4188 	}
4189 
4190 	if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev))
4191 		mlme_set_chan_switch_in_progress(vdev_mlme->vdev, false);
4192 
4193 	lim_process_switch_channel_rsp(wma->mac_context, data);
4194 
4195 	return QDF_STATUS_SUCCESS;
4196 }
4197 
4198 QDF_STATUS wma_mon_mlme_vdev_up_send(struct vdev_mlme_obj *vdev_mlme,
4199 				     uint16_t data_len, void *data)
4200 {
4201 	uint8_t vdev_id;
4202 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4203 	QDF_STATUS status;
4204 	struct wma_txrx_node *iface;
4205 
4206 	if (!wma) {
4207 		WMA_LOGE("%s wma handle is NULL", __func__);
4208 		return QDF_STATUS_E_INVAL;
4209 	}
4210 	vdev_id = wlan_vdev_get_id(vdev_mlme->vdev);
4211 	iface = &wma->interfaces[vdev_id];
4212 	vdev_mlme->proto.sta.assoc_id = 0;
4213 
4214 	status = vdev_mgr_up_send(vdev_mlme);
4215 	if (QDF_IS_STATUS_ERROR(status))
4216 		WMA_LOGE("%s: Failed to send vdev up cmd: vdev %d",
4217 			 __func__, vdev_id);
4218 
4219 	return status;
4220 }
4221 
4222 QDF_STATUS wma_mon_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme,
4223 				       uint16_t data_len, void *data)
4224 {
4225 	uint8_t vdev_id;
4226 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4227 	QDF_STATUS status;
4228 
4229 	if (!wma) {
4230 		WMA_LOGE("%s wma handle is NULL", __func__);
4231 		return QDF_STATUS_E_INVAL;
4232 	}
4233 	vdev_id = wlan_vdev_get_id(vdev_mlme->vdev);
4234 
4235 	status = wma_send_vdev_stop_to_fw(wma, vdev_id);
4236 
4237 	if (QDF_IS_STATUS_ERROR(status))
4238 		WMA_LOGE("%s: Failed to send vdev stop cmd: vdev %d",
4239 			 __func__, vdev_id);
4240 
4241 	wlan_vdev_mlme_sm_deliver_evt(vdev_mlme->vdev,
4242 				      WLAN_VDEV_SM_EV_MLME_DOWN_REQ,
4243 				      0,
4244 				      NULL);
4245 
4246 	return status;
4247 }
4248 
4249 QDF_STATUS wma_mon_mlme_vdev_down_send(struct vdev_mlme_obj *vdev_mlme,
4250 				       uint16_t data_len, void *data)
4251 {
4252 	uint8_t vdev_id;
4253 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4254 	QDF_STATUS status;
4255 
4256 	if (!wma) {
4257 		WMA_LOGE("%s wma handle is NULL", __func__);
4258 		return QDF_STATUS_E_INVAL;
4259 	}
4260 	vdev_id = wlan_vdev_get_id(vdev_mlme->vdev);
4261 
4262 	status = wma_send_vdev_down_to_fw(wma, vdev_id);
4263 
4264 	if (QDF_IS_STATUS_ERROR(status))
4265 		WMA_LOGE("%s: Failed to send vdev down cmd: vdev %d",
4266 			 __func__, vdev_id);
4267 
4268 	wlan_vdev_mlme_sm_deliver_evt(vdev_mlme->vdev,
4269 				      WLAN_VDEV_SM_EV_DOWN_COMPLETE,
4270 				      0,
4271 				      NULL);
4272 
4273 	return status;
4274 }
4275 
4276 #ifdef FEATURE_WLM_STATS
4277 int wma_wlm_stats_req(int vdev_id, uint32_t bitmask, uint32_t max_size,
4278 		      wma_wlm_stats_cb cb, void *cookie)
4279 {
4280 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
4281 	wmi_unified_t wmi_handle;
4282 	wmi_buf_t wmi_buf;
4283 	uint32_t buf_len, tlv_tag, tlv_len;
4284 	wmi_request_wlm_stats_cmd_fixed_param *cmd;
4285 	QDF_STATUS status;
4286 
4287 	if (!wma_handle) {
4288 		wma_err("Invalid wma handle");
4289 		return -EINVAL;
4290 	}
4291 
4292 	wmi_handle = wma_handle->wmi_handle;
4293 	if (!wmi_handle) {
4294 		wma_err("Invalid wmi handle for wlm_stats_event_handler");
4295 		return -EINVAL;
4296 	}
4297 
4298 	if (!wmi_service_enabled(wmi_handle, wmi_service_wlm_stats_support)) {
4299 		wma_err("Feature not supported by firmware");
4300 		return -ENOTSUPP;
4301 	}
4302 
4303 	wma_handle->wlm_data.wlm_stats_cookie = cookie;
4304 	wma_handle->wlm_data.wlm_stats_callback = cb;
4305 	wma_handle->wlm_data.wlm_stats_max_size = max_size;
4306 
4307 	buf_len = sizeof(*cmd);
4308 	wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, buf_len);
4309 	if (!wmi_buf)
4310 		return -EINVAL;
4311 
4312 	cmd = (void *)wmi_buf_data(wmi_buf);
4313 
4314 	tlv_tag = WMITLV_TAG_STRUC_wmi_request_wlm_stats_cmd_fixed_param;
4315 	tlv_len =
4316 		WMITLV_GET_STRUCT_TLVLEN(wmi_request_wlm_stats_cmd_fixed_param);
4317 	WMITLV_SET_HDR(&cmd->tlv_header, tlv_tag, tlv_len);
4318 
4319 	cmd->vdev_id = vdev_id;
4320 	cmd->request_bitmask = bitmask;
4321 	status = wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, buf_len,
4322 				      WMI_REQUEST_WLM_STATS_CMDID);
4323 	if (QDF_IS_STATUS_ERROR(status)) {
4324 		wmi_buf_free(wmi_buf);
4325 		return -EINVAL;
4326 	}
4327 	/* info logging per test team request */
4328 	wma_info("---->sent request for vdev:%d", vdev_id);
4329 
4330 	return 0;
4331 }
4332 
4333 int wma_wlm_stats_rsp(void *wma_ctx, uint8_t *event, uint32_t evt_len)
4334 {
4335 	WMI_WLM_STATS_EVENTID_param_tlvs *param_tlvs;
4336 	wmi_wlm_stats_event_fixed_param *param;
4337 	tp_wma_handle wma_handle = wma_ctx;
4338 	char *data;
4339 	void *cookie;
4340 	uint32_t *raw_data;
4341 	uint32_t len, buffer_size, raw_data_num, i;
4342 
4343 	if (!wma_handle) {
4344 		wma_err("Invalid wma handle");
4345 		return -EINVAL;
4346 	}
4347 	if (!wma_handle->wlm_data.wlm_stats_callback) {
4348 		wma_err("No callback registered");
4349 		return -EINVAL;
4350 	}
4351 
4352 	param_tlvs = (WMI_WLM_STATS_EVENTID_param_tlvs *)event;
4353 	param = param_tlvs->fixed_param;
4354 	if (!param) {
4355 		wma_err("Fix size param is not present, something is wrong");
4356 		return -EINVAL;
4357 	}
4358 
4359 	/* info logging per test team request */
4360 	wma_info("---->Received response for vdev:%d", param->vdev_id);
4361 
4362 	raw_data = param_tlvs->data;
4363 	raw_data_num = param_tlvs->num_data;
4364 
4365 	len = 0;
4366 	buffer_size = wma_handle->wlm_data.wlm_stats_max_size;
4367 	data = qdf_mem_malloc(buffer_size);
4368 	if (!data)
4369 		return -ENOMEM;
4370 
4371 	len += qdf_scnprintf(data + len, buffer_size - len, "\n%x ",
4372 			     param->request_bitmask);
4373 	len += qdf_scnprintf(data + len, buffer_size - len, "%x ",
4374 			     param->vdev_id);
4375 	len += qdf_scnprintf(data + len, buffer_size - len, "%x ",
4376 			     param->timestamp);
4377 	len += qdf_scnprintf(data + len, buffer_size - len, "%x ",
4378 			     param->req_interval);
4379 	if (!raw_data)
4380 		goto send_data;
4381 
4382 	len += qdf_scnprintf(data + len, buffer_size - len, "\ndata:\n");
4383 
4384 	for (i = 0; i < raw_data_num; i++)
4385 		len += qdf_scnprintf(data + len, buffer_size - len, "%x ",
4386 				     *raw_data++);
4387 
4388 send_data:
4389 	cookie = wma_handle->wlm_data.wlm_stats_cookie;
4390 	wma_handle->wlm_data.wlm_stats_callback(cookie, data);
4391 
4392 	qdf_mem_free(data);
4393 
4394 	return 0;
4395 }
4396 #endif /* FEATURE_WLM_STATS */
4397 
4398 #ifdef FEATURE_WLAN_DIAG_SUPPORT
4399 static QDF_STATUS wma_send_cold_boot_cal_data(uint8_t *data,
4400 		wmi_cold_boot_cal_data_fixed_param *event)
4401 {
4402 	struct host_log_cold_boot_cal_data_type *log_ptr = NULL;
4403 
4404 	WLAN_HOST_DIAG_LOG_ALLOC(log_ptr,
4405 				 struct host_log_cold_boot_cal_data_type,
4406 				 LOG_WLAN_COLD_BOOT_CAL_DATA_C);
4407 
4408 	if (!log_ptr)
4409 		return QDF_STATUS_E_NOMEM;
4410 
4411 	log_ptr->version = VERSION_LOG_WLAN_COLD_BOOT_CAL_DATA_C;
4412 	log_ptr->cb_cal_data_len = event->data_len;
4413 	log_ptr->flags = event->flags;
4414 	qdf_mem_copy(log_ptr->cb_cal_data, data, log_ptr->cb_cal_data_len);
4415 
4416 	WLAN_HOST_DIAG_LOG_REPORT(log_ptr);
4417 
4418 	return QDF_STATUS_SUCCESS;
4419 }
4420 #else
4421 static QDF_STATUS wma_send_cold_boot_cal_data(uint8_t *data,
4422 		wmi_cold_boot_cal_data_fixed_param *event)
4423 {
4424 	return QDF_STATUS_SUCCESS;
4425 }
4426 #endif
4427 
4428 int wma_cold_boot_cal_event_handler(void *wma_ctx, uint8_t *event_buff,
4429 				    uint32_t len)
4430 {
4431 	WMI_PDEV_COLD_BOOT_CAL_DATA_EVENTID_param_tlvs *param_buf;
4432 	wmi_cold_boot_cal_data_fixed_param *event;
4433 	QDF_STATUS status;
4434 	tp_wma_handle wma_handle = (tp_wma_handle)wma_ctx;
4435 
4436 	if (!wma_handle) {
4437 		wma_err("NULL wma handle");
4438 		return -EINVAL;
4439 	}
4440 
4441 	param_buf =
4442 		   (WMI_PDEV_COLD_BOOT_CAL_DATA_EVENTID_param_tlvs *)event_buff;
4443 	if (!param_buf) {
4444 		wma_err("Invalid Cold Boot Cal Event");
4445 		return -EINVAL;
4446 	}
4447 
4448 	event = param_buf->fixed_param;
4449 	if ((event->data_len > param_buf->num_data) ||
4450 	    (param_buf->num_data > HOST_LOG_MAX_COLD_BOOT_CAL_DATA_SIZE)) {
4451 		WMA_LOGE("Excess data_len:%d, num_data:%d", event->data_len,
4452 			 param_buf->num_data);
4453 		return -EINVAL;
4454 	}
4455 
4456 	status = wma_send_cold_boot_cal_data((uint8_t *)param_buf->data, event);
4457 	if (status != QDF_STATUS_SUCCESS) {
4458 		wma_err("Cold Boot Cal Diag log not sent");
4459 		return -ENOMEM;
4460 	}
4461 
4462 	return 0;
4463 }
4464