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