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