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