1 /*
2 * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2024 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 */
wma_swap_bytes(void * pv,uint32_t n)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
wma_mcs_rate_match(uint16_t raw_rate,bool is_he,const uint16_t * nss1_rate,const uint16_t * nss2_rate,uint8_t * nss,enum txrate_gi * guard_interval)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 */
wma_match_he_rate(uint16_t raw_rate,enum tx_rate_info rate_flags,bool is_he_mcs_12_13_supported,uint8_t * nss,uint8_t * dcm,enum txrate_gi * guard_interval,enum tx_rate_info * mcs_rate_flag,uint8_t * p_index)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
wma_match_he_rate(uint16_t raw_rate,enum tx_rate_info rate_flags,bool is_he_mcs_12_13_supported,uint8_t * nss,uint8_t * dcm,enum txrate_gi * guard_interval,enum tx_rate_info * mcs_rate_flag,uint8_t * p_index)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
wma_get_mcs_idx(uint16_t raw_rate,enum tx_rate_info rate_flags,bool is_he_mcs_12_13_supported,uint8_t * nss,uint8_t * dcm,enum txrate_gi * guard_interval,enum tx_rate_info * mcs_rate_flag)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
wma_lost_link_info_handler(tp_wma_handle wma,uint32_t vdev_id,int32_t rssi)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 */
host_map_smps_mode(A_UINT32 fw_smps_mode)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 */
wma_smps_mode_to_force_mode_param(uint8_t smps_mode)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
wma_stats_ext_event_handler(void * handle,uint8_t * event_buf,uint32_t len)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
wma_stats_ext_event_handler(void * handle,uint8_t * event_buf,uint32_t len)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 */
wma_profile_data_report_event_handler(void * handle,uint8_t * event_buf,uint32_t len)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 */
wma_get_ll_stats_ext_buf(uint32_t * len,uint32_t peer_num,wmi_report_stats_event_fixed_param * fixed_param)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
wma_fill_tx_stats(struct sir_wifi_ll_ext_stats * ll_stats,wmi_report_stats_event_fixed_param * fix_param,WMI_REPORT_STATS_EVENTID_param_tlvs * param_buf,uint8_t ** buf,uint32_t * buf_length)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
wma_fill_rx_stats(struct sir_wifi_ll_ext_stats * ll_stats,wmi_report_stats_event_fixed_param * fix_param,WMI_REPORT_STATS_EVENTID_param_tlvs * param_buf,uint8_t ** buf,uint32_t * buf_length)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 */
wma_ll_stats_evt_handler(void * handle,u_int8_t * event,u_int32_t len)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
wma_get_mlo_per_link_stats_cap(wmi_unified_t wmi_handle)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
wma_get_mlo_per_link_stats_cap(wmi_unified_t wmi_handle)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 */
wma_get_dp_peer_stats(wmi_unified_t wmi_handle,struct cdp_peer_stats * dp_stats,uint8_t * peer_mac)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 */
wma_unified_link_peer_stats_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)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 */
wma_unified_link_stats_results_mem_free(tSirLLStatsResults * link_stats_results)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
__wma_unified_radio_tx_mem_free(tp_wma_handle wma_handle)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 */
wma_unified_radio_tx_mem_free(void * handle)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
__wma_unified_radio_tx_power_level_stats_event_handler(tp_wma_handle wma_handle,u_int8_t * cmd_param_info,u_int32_t len)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 */
wma_unified_radio_tx_power_level_stats_event_handler(void * handle,u_int8_t * cmd_param_info,u_int32_t len)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
wma_copy_chan_stats(uint32_t num_chan,struct wifi_channel_stats * channels,struct wifi_radio_stats * rs_results)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
__wma_unified_link_radio_stats_event_handler(tp_wma_handle wma_handle,uint8_t * cmd_param_info,uint32_t len)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 */
wma_unified_link_radio_stats_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)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 */
wma_peer_ps_evt_handler(void * handle,u_int8_t * event,u_int32_t len)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 */
wma_peer_ps_evt_handler(void * handle,u_int8_t * event,u_int32_t len)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 */
wma_register_ll_stats_event_handler(tp_wma_handle wma_handle)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
wma_process_ll_stats_clear_req(tp_wma_handle wma,const tpSirLLStatsClearReq clearReq)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 */
wma_process_ll_stats_set_req(tp_wma_handle wma,const tpSirLLStatsSetReq setReq)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
wma_send_ll_stats_get_cmd(tp_wma_handle wma_handle,struct ll_stats_get_params * cmd)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
wma_send_ll_stats_get_cmd(tp_wma_handle wma_handle,struct ll_stats_get_params * cmd)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
wma_update_params_for_mlo_stats(tp_wma_handle wma,const tpSirLLStatsGetReq getReq,struct ll_stats_get_params * cmd)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
wma_update_params_for_mlo_stats(tp_wma_handle wma,const tpSirLLStatsGetReq getReq,struct ll_stats_get_params * cmd)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
wma_process_ll_stats_get_req(tp_wma_handle wma,const tpSirLLStatsGetReq getReq)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 */
wma_unified_link_iface_stats_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)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 */
wma_config_stats_ext_threshold(tp_wma_handle wma,struct sir_ll_ext_stats_threshold * thresh)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 */
wma_post_link_status(tAniGetLinkStatus * pGetLinkStatus,uint8_t link_status)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
wma_link_status_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)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
wma_rso_cmd_status_event_handler(uint8_t vdev_id,enum cm_roam_notif notif)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 */
wma_send_link_speed(uint32_t link_speed)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 */
wma_link_speed_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)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 */
wma_unified_debug_print_event_handler(void * handle,uint8_t * datap,uint32_t len)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
wma_peer_phymode(tSirNwType nw_type,uint8_t sta_type,uint8_t is_ht,uint8_t ch_width,uint8_t is_vht,bool is_he,bool is_eht)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 */
wma_txrx_fw_stats_reset(tp_wma_handle wma_handle,uint8_t vdev_id,uint32_t value)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)
wma_is_valid_fw_stats_cmd(uint32_t value)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
wma_is_valid_fw_stats_cmd(uint32_t value)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 */
wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle,uint8_t vdev_id,uint32_t value)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 */
wma_get_cca_stats(tp_wma_handle wma_handle,uint8_t vdev_id)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 */
wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id,uint32_t * buffer_size)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
wma_get_vdev_address_by_vdev_id(uint8_t vdev_id)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
wma_get_connection_info(uint8_t vdev_id,struct policy_mgr_vdev_entry_info * conn_table_entry)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
wma_ndi_update_connection_info(uint8_t vdev_id,struct nan_datapath_channel_info * ndp_chan_info)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 */
wma_get_interface_by_vdev_id(uint8_t vdev_id)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
wma_get_rmf_status(uint8_t vdev_id)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 */
wma_update_intf_hw_mode_params(uint32_t vdev_id,uint32_t mac_id,uint32_t cfgd_hw_mode_index)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 */
wma_get_vht_ch_width(void)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 */
wma_get_num_of_setbits_from_bitmask(uint32_t mask)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
wma_is_csa_offload_enabled(void)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
wma_is_mbssid_enabled(void)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
wma_config_debug_module_cmd(wmi_unified_t wmi_handle,A_UINT32 param,A_UINT32 val,A_UINT32 * module_id_bitmap,A_UINT32 bitmap_len)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 */
wma_is_p2p_lo_capable(void)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
wma_get_roam_scan_ch(wmi_unified_t wmi_handle,uint8_t vdev_id)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
wma_capability_enhanced_mcast_filter(void)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
wma_is_vdev_up(uint8_t vdev_id)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
wma_acquire_wakelock(qdf_wake_lock_t * wl,uint32_t msec)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
wma_release_wakelock(qdf_wake_lock_t * wl)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
wma_send_vdev_stop_to_fw(t_wma_handle * wma,uint8_t vdev_id)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
wma_get_rcpi_req(WMA_HANDLE handle,struct sme_rcpi_req * rcpi_request)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
wma_rcpi_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)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
wma_send_vdev_down_to_fw(t_wma_handle * wma,uint8_t vdev_id)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
wmi_to_sir_peer_type(enum wmi_peer_type type)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 */
wma_set_vc_mode_config(void * wma_handle,uint32_t vc_bitmap)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
wma_chip_power_save_failure_detected_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)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
wma_roam_scan_stats_event_handler(void * handle,uint8_t * event,uint32_t len)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
wma_get_roam_scan_stats(WMA_HANDLE handle,struct sir_roam_scan_stats * req)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
wma_remove_bss_peer_on_failure(tp_wma_handle wma,uint8_t vdev_id)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_delete_peer_mlo(wma->psoc, bss_peer.bytes);
4453
4454 wma_remove_peer(wma, bss_peer.bytes, vdev_id, false);
4455 }
4456
wma_remove_bss_peer_before_join(tp_wma_handle wma,uint8_t vdev_id,void * cm_join_req)4457 QDF_STATUS wma_remove_bss_peer_before_join(
4458 tp_wma_handle wma, uint8_t vdev_id,
4459 void *cm_join_req)
4460 {
4461 uint8_t *mac_addr;
4462 struct wma_target_req *del_req;
4463 QDF_STATUS qdf_status;
4464 struct qdf_mac_addr bssid;
4465 enum QDF_OPMODE mode;
4466 struct wlan_objmgr_vdev *vdev;
4467
4468 if (!wma || !wma->interfaces)
4469 return QDF_STATUS_E_FAILURE;
4470
4471 if (vdev_id >= WLAN_MAX_VDEVS) {
4472 wma_err("Invalid vdev id %d", vdev_id);
4473 return QDF_STATUS_E_INVAL;
4474 }
4475 vdev = wma->interfaces[vdev_id].vdev;
4476 if (!vdev) {
4477 wma_err("Invalid vdev, %d", vdev_id);
4478 return QDF_STATUS_E_FAILURE;
4479 }
4480
4481 mode = wlan_vdev_mlme_get_opmode(vdev);
4482 if (mode != QDF_STA_MODE && mode != QDF_P2P_CLIENT_MODE) {
4483 wma_err("unexpected mode %d vdev %d", mode, vdev_id);
4484 return QDF_STATUS_E_FAILURE;
4485 }
4486
4487 qdf_status = wlan_vdev_get_bss_peer_mac(vdev, &bssid);
4488 if (QDF_IS_STATUS_ERROR(qdf_status)) {
4489 wma_err("Failed to get bssid for vdev_id: %d", vdev_id);
4490 return qdf_status;
4491 }
4492 mac_addr = bssid.bytes;
4493
4494 wma_delete_peer_mlo(wma->psoc, mac_addr);
4495
4496 qdf_status = wma_remove_peer(wma, mac_addr, vdev_id, false);
4497
4498 if (QDF_IS_STATUS_ERROR(qdf_status)) {
4499 wma_err("wma_remove_peer failed vdev_id:%d", vdev_id);
4500 return qdf_status;
4501 }
4502
4503 if (cds_is_driver_recovering())
4504 return QDF_STATUS_E_FAILURE;
4505
4506 if (wmi_service_enabled(wma->wmi_handle,
4507 wmi_service_sync_delete_cmds)) {
4508 wma_debug("Wait for the peer delete. vdev_id %d", vdev_id);
4509 del_req = wma_fill_hold_req(wma, vdev_id,
4510 WMA_DELETE_STA_REQ,
4511 WMA_DELETE_STA_CONNECT_RSP,
4512 cm_join_req,
4513 WMA_DELETE_STA_TIMEOUT);
4514 if (!del_req) {
4515 wma_err("Failed to allocate request. vdev_id %d",
4516 vdev_id);
4517 qdf_status = QDF_STATUS_E_NOMEM;
4518 } else {
4519 qdf_status = QDF_STATUS_E_PENDING;
4520 }
4521 }
4522
4523 return qdf_status;
4524 }
4525
wma_sta_vdev_up_send(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4526 QDF_STATUS wma_sta_vdev_up_send(struct vdev_mlme_obj *vdev_mlme,
4527 uint16_t data_len, void *data)
4528 {
4529 uint8_t vdev_id;
4530 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4531 QDF_STATUS status;
4532 struct wma_txrx_node *iface;
4533
4534 if (!wma)
4535 return QDF_STATUS_E_INVAL;
4536
4537 vdev_id = wlan_vdev_get_id(vdev_mlme->vdev);
4538 iface = &wma->interfaces[vdev_id];
4539 vdev_mlme->proto.sta.assoc_id = iface->aid;
4540
4541 status = vdev_mgr_up_send(vdev_mlme);
4542
4543 if (QDF_IS_STATUS_ERROR(status)) {
4544 wma_err("Failed to send vdev up cmd: vdev %d", vdev_id);
4545 status = QDF_STATUS_E_FAILURE;
4546 } else {
4547 wma_set_vdev_mgmt_rate(wma, vdev_id);
4548 if (iface->beacon_filter_enabled)
4549 wma_add_beacon_filter(
4550 wma,
4551 &iface->beacon_filter);
4552 }
4553
4554 return QDF_STATUS_SUCCESS;
4555 }
4556
wma_get_hidden_ssid_restart_in_progress(struct wma_txrx_node * iface)4557 bool wma_get_hidden_ssid_restart_in_progress(struct wma_txrx_node *iface)
4558 {
4559 if (!iface)
4560 return false;
4561
4562 return ap_mlme_is_hidden_ssid_restart_in_progress(iface->vdev);
4563 }
4564
wma_get_channel_switch_in_progress(struct wma_txrx_node * iface)4565 bool wma_get_channel_switch_in_progress(struct wma_txrx_node *iface)
4566 {
4567 if (!iface)
4568 return false;
4569
4570 return mlme_is_chan_switch_in_progress(iface->vdev);
4571 }
4572
wma_vdev_send_start_resp(tp_wma_handle wma,struct add_bss_rsp * add_bss_rsp)4573 static QDF_STATUS wma_vdev_send_start_resp(tp_wma_handle wma,
4574 struct add_bss_rsp *add_bss_rsp)
4575 {
4576 wma_debug("Sending add bss rsp to umac(vdev %d status %d)",
4577 add_bss_rsp->vdev_id, add_bss_rsp->status);
4578 lim_handle_add_bss_rsp(wma->mac_context, add_bss_rsp);
4579
4580 return QDF_STATUS_SUCCESS;
4581 }
4582
wma_sta_mlme_vdev_start_continue(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4583 QDF_STATUS wma_sta_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme,
4584 uint16_t data_len, void *data)
4585 {
4586 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4587 enum vdev_assoc_type assoc_type;
4588
4589 if (!wma)
4590 return QDF_STATUS_E_FAILURE;
4591
4592 if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev)) {
4593 mlme_set_chan_switch_in_progress(vdev_mlme->vdev, false);
4594 lim_process_switch_channel_rsp(wma->mac_context, data);
4595 return QDF_STATUS_SUCCESS;
4596 }
4597
4598 assoc_type = mlme_get_assoc_type(vdev_mlme->vdev);
4599 switch (assoc_type) {
4600 case VDEV_ASSOC:
4601 case VDEV_REASSOC:
4602 lim_process_switch_channel_rsp(wma->mac_context, data);
4603 break;
4604 case VDEV_FT_REASSOC:
4605 lim_handle_add_bss_rsp(wma->mac_context, data);
4606 break;
4607 default:
4608 wma_err("assoc_type %d is invalid", assoc_type);
4609 }
4610
4611 return QDF_STATUS_SUCCESS;
4612 }
4613
wma_ap_mlme_vdev_start_continue(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4614 QDF_STATUS wma_ap_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme,
4615 uint16_t data_len, void *data)
4616 {
4617 tp_wma_handle wma;
4618 QDF_STATUS status = QDF_STATUS_SUCCESS;
4619 struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev;
4620 uint8_t vdev_id;
4621
4622 wma = cds_get_context(QDF_MODULE_ID_WMA);
4623 if (!wma)
4624 return QDF_STATUS_E_INVAL;
4625
4626 if (mlme_is_chan_switch_in_progress(vdev)) {
4627 mlme_set_chan_switch_in_progress(vdev, false);
4628 lim_process_switch_channel_rsp(wma->mac_context, data);
4629 } else if (ap_mlme_is_hidden_ssid_restart_in_progress(vdev)) {
4630 vdev_id = vdev->vdev_objmgr.vdev_id;
4631 lim_process_mlm_update_hidden_ssid_rsp(wma->mac_context,
4632 vdev_id);
4633 ap_mlme_set_hidden_ssid_restart_in_progress(vdev, false);
4634 } else {
4635 status = wma_vdev_send_start_resp(wma, data);
4636 }
4637
4638 return status;
4639 }
4640
wma_mlme_vdev_stop_continue(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4641 QDF_STATUS wma_mlme_vdev_stop_continue(struct vdev_mlme_obj *vdev_mlme,
4642 uint16_t data_len, void *data)
4643 {
4644 return __wma_handle_vdev_stop_rsp(
4645 (struct vdev_stop_response *)data);
4646 }
4647
wma_ap_mlme_vdev_down_send(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4648 QDF_STATUS wma_ap_mlme_vdev_down_send(struct vdev_mlme_obj *vdev_mlme,
4649 uint16_t data_len, void *data)
4650 {
4651 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4652
4653 if (!wma)
4654 return QDF_STATUS_E_INVAL;
4655
4656 return wma_send_vdev_down(wma, data);
4657 }
4658
4659 QDF_STATUS
wma_mlme_vdev_notify_down_complete(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4660 wma_mlme_vdev_notify_down_complete(struct vdev_mlme_obj *vdev_mlme,
4661 uint16_t data_len, void *data)
4662 {
4663 tp_wma_handle wma;
4664 QDF_STATUS status;
4665 uint32_t vdev_stop_type;
4666 struct del_bss_resp *resp = (struct del_bss_resp *)data;
4667
4668 if (mlme_is_connection_fail(vdev_mlme->vdev) ||
4669 mlme_get_vdev_start_failed(vdev_mlme->vdev)) {
4670 wma_debug("Vdev start req failed, no action required");
4671 mlme_set_connection_fail(vdev_mlme->vdev, false);
4672 mlme_set_vdev_start_failed(vdev_mlme->vdev, false);
4673 return QDF_STATUS_SUCCESS;
4674 }
4675
4676 wma = cds_get_context(QDF_MODULE_ID_WMA);
4677 if (!wma) {
4678 status = QDF_STATUS_E_INVAL;
4679 goto end;
4680 }
4681
4682 status = mlme_get_vdev_stop_type(wma->interfaces[resp->vdev_id].vdev,
4683 &vdev_stop_type);
4684 if (QDF_IS_STATUS_ERROR(status)) {
4685 wma_err("Failed to get vdev stop type for vdev_id: %d",
4686 resp->vdev_id);
4687 status = QDF_STATUS_E_INVAL;
4688 goto end;
4689 }
4690
4691 /*
4692 * Need reset vdev_stop_type to 0 here, otherwise the vdev_stop_type
4693 * would be taken to next BSS stop in some stress test, then cause
4694 * unexpected behavior.
4695 */
4696 mlme_set_vdev_stop_type(wma->interfaces[resp->vdev_id].vdev, 0);
4697
4698 if (vdev_stop_type == WMA_DELETE_BSS_HO_FAIL_REQ) {
4699 resp->status = QDF_STATUS_SUCCESS;
4700 wma_send_msg_high_priority(wma, WMA_DELETE_BSS_HO_FAIL_RSP,
4701 (void *)resp, 0);
4702 return QDF_STATUS_SUCCESS;
4703 }
4704
4705 if (vdev_stop_type == WMA_SET_LINK_STATE) {
4706 lim_join_result_callback(wma->mac_context,
4707 wlan_vdev_get_id(vdev_mlme->vdev));
4708 } else {
4709 wma_send_del_bss_response(wma, resp);
4710 return QDF_STATUS_SUCCESS;
4711 }
4712
4713 end:
4714 qdf_mem_free(resp);
4715
4716 return status;
4717 }
4718
wma_ap_mlme_vdev_stop_start_send(struct vdev_mlme_obj * vdev_mlme,enum vdev_cmd_type type,uint16_t data_len,void * data)4719 QDF_STATUS wma_ap_mlme_vdev_stop_start_send(struct vdev_mlme_obj *vdev_mlme,
4720 enum vdev_cmd_type type,
4721 uint16_t data_len, void *data)
4722 {
4723 tp_wma_handle wma;
4724 struct add_bss_rsp *add_bss_rsp = data;
4725
4726 wma = cds_get_context(QDF_MODULE_ID_WMA);
4727 if (!wma)
4728 return QDF_STATUS_E_INVAL;
4729
4730 if (wma_send_vdev_stop_to_fw(wma, add_bss_rsp->vdev_id))
4731 wma_err("Failed to send vdev stop for vdev id %d",
4732 add_bss_rsp->vdev_id);
4733
4734 wma_remove_bss_peer_on_failure(wma, add_bss_rsp->vdev_id);
4735
4736 return wma_vdev_send_start_resp(wma, add_bss_rsp);
4737 }
4738
4739 #ifdef QCA_SUPPORT_CP_STATS
wma_mon_mlme_vdev_start_continue(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4740 QDF_STATUS wma_mon_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme,
4741 uint16_t data_len, void *data)
4742 {
4743 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4744 struct request_info info = {0};
4745 uint8_t interval = 1;
4746 QDF_STATUS status;
4747 int pdev;
4748
4749 if (!wma)
4750 return QDF_STATUS_E_INVAL;
4751
4752 if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev))
4753 mlme_set_chan_switch_in_progress(vdev_mlme->vdev, false);
4754
4755 pdev = target_if_mc_cp_get_mac_id(vdev_mlme);
4756
4757 /* Cancel periodic pdev stats update if running for other mac */
4758 status = wma_cli_set_command(vdev_mlme->vdev->vdev_objmgr.vdev_id,
4759 wmi_pdev_param_pdev_stats_update_period,
4760 0, PDEV_CMD);
4761 if (status != QDF_STATUS_SUCCESS)
4762 pe_err("failed to clear fw stats request = %d", status);
4763
4764 /* send periodic fw stats to get chan noise floor for monitor mode */
4765 info.vdev_id = vdev_mlme->vdev->vdev_objmgr.vdev_id;
4766 info.pdev_id = pdev;
4767 status = tgt_send_mc_cp_stats_req((wlan_vdev_get_psoc(vdev_mlme->vdev)),
4768 TYPE_STATION_STATS,
4769 &info);
4770 if (status != QDF_STATUS_SUCCESS)
4771 pe_err("failed to send fw stats request = %d", status);
4772
4773 status = wma_cli_set2_command(vdev_mlme->vdev->vdev_objmgr.vdev_id,
4774 wmi_pdev_param_pdev_stats_update_period,
4775 interval * 2000, pdev, PDEV_CMD);
4776 if (status != QDF_STATUS_SUCCESS)
4777 pe_err("failed to send fw stats request = %d", status);
4778
4779 lim_process_switch_channel_rsp(wma->mac_context, data);
4780
4781 return QDF_STATUS_SUCCESS;
4782 }
4783 #else
wma_mon_mlme_vdev_start_continue(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4784 QDF_STATUS wma_mon_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme,
4785 uint16_t data_len, void *data)
4786 {
4787 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4788
4789 if (!wma)
4790 return QDF_STATUS_E_INVAL;
4791
4792 if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev))
4793 mlme_set_chan_switch_in_progress(vdev_mlme->vdev, false);
4794
4795 lim_process_switch_channel_rsp(wma->mac_context, data);
4796
4797 return QDF_STATUS_SUCCESS;
4798 }
4799 #endif /* QCA_SUPPORT_CP_STATS */
4800
wma_mon_mlme_vdev_up_send(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4801 QDF_STATUS wma_mon_mlme_vdev_up_send(struct vdev_mlme_obj *vdev_mlme,
4802 uint16_t data_len, void *data)
4803 {
4804 uint8_t vdev_id;
4805 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4806 QDF_STATUS status;
4807 struct wma_txrx_node *iface;
4808
4809 if (!wma)
4810 return QDF_STATUS_E_INVAL;
4811
4812 vdev_id = wlan_vdev_get_id(vdev_mlme->vdev);
4813 iface = &wma->interfaces[vdev_id];
4814 vdev_mlme->proto.sta.assoc_id = 0;
4815
4816 status = vdev_mgr_up_send(vdev_mlme);
4817 if (QDF_IS_STATUS_ERROR(status))
4818 wma_err("Failed to send vdev up cmd: vdev %d", vdev_id);
4819
4820 return status;
4821 }
4822
wma_mon_mlme_vdev_stop_send(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4823 QDF_STATUS wma_mon_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme,
4824 uint16_t data_len, void *data)
4825 {
4826 uint8_t vdev_id;
4827 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4828 QDF_STATUS status;
4829
4830 if (!wma)
4831 return QDF_STATUS_E_INVAL;
4832
4833 vdev_id = wlan_vdev_get_id(vdev_mlme->vdev);
4834
4835 status = wma_send_vdev_stop_to_fw(wma, vdev_id);
4836
4837 if (QDF_IS_STATUS_ERROR(status))
4838 wma_err("Failed to send vdev stop cmd: vdev %d", vdev_id);
4839
4840 wlan_vdev_mlme_sm_deliver_evt(vdev_mlme->vdev,
4841 WLAN_VDEV_SM_EV_MLME_DOWN_REQ,
4842 0,
4843 NULL);
4844
4845 return status;
4846 }
4847
wma_mon_mlme_vdev_down_send(struct vdev_mlme_obj * vdev_mlme,uint16_t data_len,void * data)4848 QDF_STATUS wma_mon_mlme_vdev_down_send(struct vdev_mlme_obj *vdev_mlme,
4849 uint16_t data_len, void *data)
4850 {
4851 uint8_t vdev_id;
4852 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4853 QDF_STATUS status;
4854
4855 if (!wma)
4856 return QDF_STATUS_E_INVAL;
4857
4858 vdev_id = wlan_vdev_get_id(vdev_mlme->vdev);
4859
4860 status = wma_send_vdev_down_to_fw(wma, vdev_id);
4861
4862 if (QDF_IS_STATUS_ERROR(status))
4863 wma_err("Failed to send vdev down cmd: vdev %d", vdev_id);
4864
4865 wlan_vdev_mlme_sm_deliver_evt(vdev_mlme->vdev,
4866 WLAN_VDEV_SM_EV_DOWN_COMPLETE,
4867 0,
4868 NULL);
4869
4870 return status;
4871 }
4872
4873 #ifdef FEATURE_WLM_STATS
wma_wlm_stats_req(int vdev_id,uint32_t bitmask,uint32_t max_size,wma_wlm_stats_cb cb,void * cookie)4874 int wma_wlm_stats_req(int vdev_id, uint32_t bitmask, uint32_t max_size,
4875 wma_wlm_stats_cb cb, void *cookie)
4876 {
4877 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
4878 wmi_unified_t wmi_handle;
4879 wmi_buf_t wmi_buf;
4880 uint32_t buf_len, tlv_tag, tlv_len;
4881 wmi_request_wlm_stats_cmd_fixed_param *cmd;
4882 QDF_STATUS status;
4883
4884 if (!wma_handle)
4885 return -EINVAL;
4886
4887 wmi_handle = wma_handle->wmi_handle;
4888 if (wmi_validate_handle(wmi_handle))
4889 return -EINVAL;
4890
4891 if (!wmi_service_enabled(wmi_handle, wmi_service_wlm_stats_support)) {
4892 wma_err("Feature not supported by firmware");
4893 return -ENOTSUPP;
4894 }
4895
4896 wma_handle->wlm_data.wlm_stats_cookie = cookie;
4897 wma_handle->wlm_data.wlm_stats_callback = cb;
4898 wma_handle->wlm_data.wlm_stats_max_size = max_size;
4899
4900 buf_len = sizeof(*cmd);
4901 wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, buf_len);
4902 if (!wmi_buf)
4903 return -EINVAL;
4904
4905 cmd = (void *)wmi_buf_data(wmi_buf);
4906
4907 tlv_tag = WMITLV_TAG_STRUC_wmi_request_wlm_stats_cmd_fixed_param;
4908 tlv_len =
4909 WMITLV_GET_STRUCT_TLVLEN(wmi_request_wlm_stats_cmd_fixed_param);
4910 WMITLV_SET_HDR(&cmd->tlv_header, tlv_tag, tlv_len);
4911
4912 cmd->vdev_id = vdev_id;
4913 cmd->request_bitmask = bitmask;
4914 status = wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, buf_len,
4915 WMI_REQUEST_WLM_STATS_CMDID);
4916 if (QDF_IS_STATUS_ERROR(status)) {
4917 wmi_buf_free(wmi_buf);
4918 return -EINVAL;
4919 }
4920 /* info logging per test team request */
4921 wma_info("---->sent request for vdev:%d", vdev_id);
4922
4923 return 0;
4924 }
4925
wma_wlm_stats_rsp(void * wma_ctx,uint8_t * event,uint32_t evt_len)4926 int wma_wlm_stats_rsp(void *wma_ctx, uint8_t *event, uint32_t evt_len)
4927 {
4928 WMI_WLM_STATS_EVENTID_param_tlvs *param_tlvs;
4929 wmi_wlm_stats_event_fixed_param *param;
4930 tp_wma_handle wma_handle = wma_ctx;
4931 char *data;
4932 void *cookie;
4933 uint32_t *raw_data;
4934 uint32_t len, buffer_size, raw_data_num, i;
4935
4936 if (wma_validate_handle(wma_handle))
4937 return -EINVAL;
4938
4939 if (!wma_handle->wlm_data.wlm_stats_callback) {
4940 wma_err("No callback registered");
4941 return -EINVAL;
4942 }
4943
4944 param_tlvs = (WMI_WLM_STATS_EVENTID_param_tlvs *)event;
4945 param = param_tlvs->fixed_param;
4946 if (!param) {
4947 wma_err("Fix size param is not present, something is wrong");
4948 return -EINVAL;
4949 }
4950
4951 /* info logging per test team request */
4952 wma_info("---->Received response for vdev:%d", param->vdev_id);
4953
4954 raw_data = param_tlvs->data;
4955 raw_data_num = param_tlvs->num_data;
4956
4957 len = 0;
4958 buffer_size = wma_handle->wlm_data.wlm_stats_max_size;
4959 data = qdf_mem_malloc(buffer_size);
4960 if (!data)
4961 return -ENOMEM;
4962
4963 len += qdf_scnprintf(data + len, buffer_size - len, "\n%x ",
4964 param->request_bitmask);
4965 len += qdf_scnprintf(data + len, buffer_size - len, "%x ",
4966 param->vdev_id);
4967 len += qdf_scnprintf(data + len, buffer_size - len, "%x ",
4968 param->timestamp);
4969 len += qdf_scnprintf(data + len, buffer_size - len, "%x ",
4970 param->req_interval);
4971 if (!raw_data)
4972 goto send_data;
4973
4974 len += qdf_scnprintf(data + len, buffer_size - len, "\ndata:\n");
4975
4976 for (i = 0; i < raw_data_num; i++)
4977 len += qdf_scnprintf(data + len, buffer_size - len, "%x ",
4978 *raw_data++);
4979
4980 send_data:
4981 cookie = wma_handle->wlm_data.wlm_stats_cookie;
4982 wma_handle->wlm_data.wlm_stats_callback(cookie, data);
4983
4984 qdf_mem_free(data);
4985
4986 return 0;
4987 }
4988 #endif /* FEATURE_WLM_STATS */
4989
4990 #ifdef FEATURE_WLAN_DIAG_SUPPORT
wma_send_cold_boot_cal_data(uint8_t * data,wmi_cold_boot_cal_data_fixed_param * event)4991 static QDF_STATUS wma_send_cold_boot_cal_data(uint8_t *data,
4992 wmi_cold_boot_cal_data_fixed_param *event)
4993 {
4994 struct host_log_cold_boot_cal_data_type *log_ptr = NULL;
4995
4996 WLAN_HOST_DIAG_LOG_ALLOC(log_ptr,
4997 struct host_log_cold_boot_cal_data_type,
4998 LOG_WLAN_COLD_BOOT_CAL_DATA_C);
4999
5000 if (!log_ptr)
5001 return QDF_STATUS_E_NOMEM;
5002
5003 log_ptr->version = VERSION_LOG_WLAN_COLD_BOOT_CAL_DATA_C;
5004 log_ptr->cb_cal_data_len = event->data_len;
5005 log_ptr->flags = event->flags;
5006 qdf_mem_copy(log_ptr->cb_cal_data, data, log_ptr->cb_cal_data_len);
5007
5008 WLAN_HOST_DIAG_LOG_REPORT(log_ptr);
5009
5010 return QDF_STATUS_SUCCESS;
5011 }
5012 #else
wma_send_cold_boot_cal_data(uint8_t * data,wmi_cold_boot_cal_data_fixed_param * event)5013 static QDF_STATUS wma_send_cold_boot_cal_data(uint8_t *data,
5014 wmi_cold_boot_cal_data_fixed_param *event)
5015 {
5016 return QDF_STATUS_SUCCESS;
5017 }
5018 #endif
5019
wma_cold_boot_cal_event_handler(void * wma_ctx,uint8_t * event_buff,uint32_t len)5020 int wma_cold_boot_cal_event_handler(void *wma_ctx, uint8_t *event_buff,
5021 uint32_t len)
5022 {
5023 WMI_PDEV_COLD_BOOT_CAL_DATA_EVENTID_param_tlvs *param_buf;
5024 wmi_cold_boot_cal_data_fixed_param *event;
5025 QDF_STATUS status;
5026 tp_wma_handle wma_handle = (tp_wma_handle)wma_ctx;
5027
5028 if (wma_validate_handle(wma_handle))
5029 return -EINVAL;
5030
5031 param_buf =
5032 (WMI_PDEV_COLD_BOOT_CAL_DATA_EVENTID_param_tlvs *)event_buff;
5033 if (!param_buf) {
5034 wma_err("Invalid Cold Boot Cal Event");
5035 return -EINVAL;
5036 }
5037
5038 event = param_buf->fixed_param;
5039 if ((event->data_len > param_buf->num_data) ||
5040 (param_buf->num_data > HOST_LOG_MAX_COLD_BOOT_CAL_DATA_SIZE)) {
5041 wma_err("Excess data_len:%d, num_data:%d", event->data_len,
5042 param_buf->num_data);
5043 return -EINVAL;
5044 }
5045
5046 status = wma_send_cold_boot_cal_data((uint8_t *)param_buf->data, event);
5047 if (status != QDF_STATUS_SUCCESS) {
5048 wma_err("Cold Boot Cal Diag log not sent");
5049 return -ENOMEM;
5050 }
5051
5052 return 0;
5053 }
5054
5055 #ifdef MULTI_CLIENT_LL_SUPPORT
wma_latency_level_event_handler(void * wma_ctx,uint8_t * event_buff,uint32_t len)5056 int wma_latency_level_event_handler(void *wma_ctx, uint8_t *event_buff,
5057 uint32_t len)
5058 {
5059 WMI_VDEV_LATENCY_LEVEL_EVENTID_param_tlvs *param_buf;
5060 struct mac_context *pmac =
5061 (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE);
5062 wmi_vdev_latency_event_fixed_param *event;
5063 struct latency_level_data event_data;
5064 bool multi_client_ll_support, multi_client_ll_caps;
5065
5066 if (!pmac) {
5067 wma_err("NULL mac handle");
5068 return -EINVAL;
5069 }
5070
5071 multi_client_ll_support =
5072 pmac->mlme_cfg->wlm_config.multi_client_ll_support;
5073 multi_client_ll_caps =
5074 wlan_mlme_get_wlm_multi_client_ll_caps(pmac->psoc);
5075
5076 wma_debug("multi client ll INI:%d, caps:%d", multi_client_ll_support,
5077 multi_client_ll_caps);
5078
5079 if ((!multi_client_ll_support) || (!multi_client_ll_caps))
5080 return -EINVAL;
5081
5082 if (!pmac->sme.latency_level_event_handler_cb) {
5083 wma_err("latency level data handler cb is not registered");
5084 return -EINVAL;
5085 }
5086
5087 param_buf = (WMI_VDEV_LATENCY_LEVEL_EVENTID_param_tlvs *)event_buff;
5088 if (!param_buf) {
5089 wma_err("Invalid latency level data Event");
5090 return -EINVAL;
5091 }
5092
5093 event = param_buf->fixed_param;
5094 if (!event) {
5095 wma_err("Invalid fixed param in latency data Event");
5096 return -EINVAL;
5097 }
5098
5099 event_data.vdev_id = event->vdev_id;
5100 event_data.latency_level = event->latency_level;
5101 wma_debug("received event latency level :%d, vdev_id:%d",
5102 event->latency_level, event->vdev_id);
5103 pmac->sme.latency_level_event_handler_cb(&event_data,
5104 event->vdev_id);
5105
5106 return 0;
5107 }
5108 #endif
5109
5110 #ifdef FEATURE_OEM_DATA
wma_oem_event_handler(void * wma_ctx,uint8_t * event_buff,uint32_t len)5111 int wma_oem_event_handler(void *wma_ctx, uint8_t *event_buff, uint32_t len)
5112 {
5113 WMI_OEM_DATA_EVENTID_param_tlvs *param_buf;
5114 struct mac_context *pmac =
5115 (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE);
5116 wmi_oem_data_event_fixed_param *event;
5117 struct oem_data oem_event_data;
5118
5119 if (!pmac) {
5120 wma_err("NULL mac handle");
5121 return -EINVAL;
5122 }
5123
5124 param_buf =
5125 (WMI_OEM_DATA_EVENTID_param_tlvs *)event_buff;
5126 if (!param_buf) {
5127 wma_err("Invalid oem data Event");
5128 return -EINVAL;
5129 }
5130
5131 event = param_buf->fixed_param;
5132 if (!event) {
5133 wma_err("Invalid fixed param in oem data Event");
5134 return -EINVAL;
5135 }
5136
5137 if (event->data_len > param_buf->num_data) {
5138 wma_err("Invalid data len %d num_data %d", event->data_len,
5139 param_buf->num_data);
5140 return -EINVAL;
5141 }
5142
5143 oem_event_data.data_len = event->data_len;
5144 oem_event_data.data = param_buf->data;
5145
5146 if (param_buf->num_file_name) {
5147 oem_event_data.file_name = param_buf->file_name;
5148 oem_event_data.file_name_len = param_buf->num_file_name;
5149 }
5150
5151 if (event->event_cause == WMI_OEM_DATA_EVT_CAUSE_UNSPECIFIED) {
5152 if (pmac->sme.oem_data_event_handler_cb)
5153 pmac->sme.oem_data_event_handler_cb(
5154 &oem_event_data,
5155 pmac->sme.oem_data_vdev_id);
5156 else if (pmac->sme.oem_data_async_event_handler_cb)
5157 pmac->sme.oem_data_async_event_handler_cb(
5158 &oem_event_data);
5159 } else if (event->event_cause == WMI_OEM_DATA_EVT_CAUSE_CMD_REQ) {
5160 if (pmac->sme.oem_data_event_handler_cb)
5161 pmac->sme.oem_data_event_handler_cb(
5162 &oem_event_data,
5163 pmac->sme.oem_data_vdev_id);
5164 } else if (event->event_cause == WMI_OEM_DATA_EVT_CAUSE_ASYNC) {
5165 if (pmac->sme.oem_data_async_event_handler_cb)
5166 pmac->sme.oem_data_async_event_handler_cb(
5167 &oem_event_data);
5168 } else {
5169 return QDF_STATUS_E_FAILURE;
5170 }
5171
5172 return QDF_STATUS_SUCCESS;
5173 }
5174 #endif
5175
5176 #ifdef WLAN_FEATURE_11BE
wma_get_orig_eht_ch_width(void)5177 uint32_t wma_get_orig_eht_ch_width(void)
5178 {
5179 tDot11fIEeht_cap eht_cap;
5180 tp_wma_handle wma;
5181 QDF_STATUS status;
5182
5183 wma = cds_get_context(QDF_MODULE_ID_WMA);
5184 if (qdf_unlikely(!wma)) {
5185 wma_err_rl("wma handle is NULL");
5186 goto vht_ch_width;
5187 }
5188
5189 status = mlme_cfg_get_orig_eht_caps(wma->psoc, &eht_cap);
5190 if (QDF_IS_STATUS_ERROR(status)) {
5191 wma_err_rl("Failed to get eht caps");
5192 goto vht_ch_width;
5193 }
5194
5195 if (eht_cap.support_320mhz_6ghz)
5196 return WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ;
5197
5198 vht_ch_width:
5199 return wma_get_vht_ch_width();
5200 }
5201
wma_get_eht_ch_width(void)5202 uint32_t wma_get_eht_ch_width(void)
5203 {
5204 tDot11fIEeht_cap eht_cap;
5205 tp_wma_handle wma;
5206
5207 wma = cds_get_context(QDF_MODULE_ID_WMA);
5208 if (qdf_unlikely(!wma)) {
5209 wma_err_rl("wma handle is NULL");
5210 goto vht_ch_width;
5211 }
5212
5213 if (QDF_IS_STATUS_ERROR(mlme_cfg_get_eht_caps(wma->psoc, &eht_cap))) {
5214 wma_err_rl("Failed to get eht caps");
5215 goto vht_ch_width;
5216 }
5217
5218 if (eht_cap.support_320mhz_6ghz)
5219 return WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ;
5220
5221 vht_ch_width:
5222 return wma_get_vht_ch_width();
5223 }
5224 #endif
5225