1 /* 2 * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include "osdep.h" 19 #include "wmi.h" 20 #include "wmi_unified_priv.h" 21 #include "wmi_unified_param.h" 22 #include "target_if_cp_stats.h" 23 #include <wlan_cp_stats_public_structs.h> 24 25 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS 26 #ifdef WLAN_SUPPORT_TWT 27 static uint32_t 28 get_stats_req_twt_dialog_id(struct infra_cp_stats_cmd_info *req) 29 { 30 return req->dialog_id; 31 } 32 33 static enum WMI_HOST_GET_STATS_TWT_STATUS 34 wmi_get_converted_twt_get_stats_status(WMI_GET_STATS_TWT_STATUS_T tgt_status) 35 { 36 switch (tgt_status) { 37 case WMI_GET_STATS_TWT_STATUS_OK: 38 return WMI_HOST_GET_STATS_TWT_STATUS_OK; 39 case WMI_GET_STATS_TWT_STATUS_DIALOG_ID_NOT_EXIST: 40 return WMI_HOST_GET_STATS_TWT_STATUS_DIALOG_ID_NOT_EXIST; 41 case WMI_GET_STATS_TWT_STATUS_INVALID_PARAM: 42 return WMI_HOST_GET_STATS_TWT_STATUS_INVALID_PARAM; 43 default: 44 return WMI_HOST_GET_STATS_TWT_STATUS_UNKNOWN_ERROR; 45 } 46 } 47 48 static inline 49 void wmi_extract_ctrl_path_twt_stats_tlv(void *tag_buf, 50 struct twt_infra_cp_stats_event *param) 51 { 52 wmi_ctrl_path_twt_stats_struct *wmi_stats_buf = 53 (wmi_ctrl_path_twt_stats_struct *)tag_buf; 54 55 param->dialog_id = wmi_stats_buf->dialog_id; 56 param->status = wmi_get_converted_twt_get_stats_status(wmi_stats_buf->status); 57 param->num_sp_cycles = wmi_stats_buf->num_sp_cycles; 58 param->avg_sp_dur_us = wmi_stats_buf->avg_sp_dur_us; 59 param->min_sp_dur_us = wmi_stats_buf->min_sp_dur_us; 60 param->max_sp_dur_us = wmi_stats_buf->max_sp_dur_us; 61 param->tx_mpdu_per_sp = wmi_stats_buf->tx_mpdu_per_sp; 62 param->rx_mpdu_per_sp = wmi_stats_buf->rx_mpdu_per_sp; 63 param->tx_bytes_per_sp = wmi_stats_buf->tx_bytes_per_sp; 64 param->rx_bytes_per_sp = wmi_stats_buf->rx_bytes_per_sp; 65 66 wmi_debug("dialog_id = %u status = %u", wmi_stats_buf->dialog_id, 67 wmi_stats_buf->status); 68 wmi_debug("num_sp_cycles = %u avg_sp_dur_us = 0x%x, \ 69 min_sp_dur_us = 0x%x, max_sp_dur_us = 0x%x", 70 wmi_stats_buf->num_sp_cycles, wmi_stats_buf->avg_sp_dur_us, 71 wmi_stats_buf->min_sp_dur_us, wmi_stats_buf->max_sp_dur_us); 72 wmi_debug("tx_mpdu_per_sp 0x%x, rx_mpdu_per_sp = 0x%x, \ 73 tx_bytes_per_sp = 0x%x, rx_bytes_per_sp = 0x%x", 74 wmi_stats_buf->tx_mpdu_per_sp, wmi_stats_buf->rx_mpdu_per_sp, 75 wmi_stats_buf->tx_bytes_per_sp, 76 wmi_stats_buf->rx_bytes_per_sp); 77 } 78 79 static void wmi_twt_extract_stats_struct(void *tag_buf, 80 struct infra_cp_stats_event *params) 81 { 82 struct twt_infra_cp_stats_event *twt_params; 83 84 twt_params = params->twt_infra_cp_stats + 85 params->num_twt_infra_cp_stats; 86 87 wmi_debug("TWT stats struct found - num_twt_cp_stats %d", 88 params->num_twt_infra_cp_stats); 89 90 params->num_twt_infra_cp_stats++; 91 wmi_extract_ctrl_path_twt_stats_tlv(tag_buf, twt_params); 92 } 93 #else 94 static inline 95 uint32_t get_stats_req_twt_dialog_id(struct infra_cp_stats_cmd_info *req) 96 { 97 return 0; 98 } 99 100 static void wmi_twt_extract_stats_struct(void *tag_buf, 101 struct infra_cp_stats_event *params) 102 { 103 } 104 #endif /* WLAN_SUPPORT_TWT */ 105 106 /* 107 * wmi_stats_extract_tag_struct: function to extract tag structs 108 * @tag_type: tag type that is to be printed 109 * @tag_buf: pointer to the tag structure 110 * @params: buffer to hold parameters extracted from response event 111 * 112 * Return: None 113 */ 114 static void wmi_stats_extract_tag_struct(uint32_t tag_type, void *tag_buf, 115 struct infra_cp_stats_event *params) 116 { 117 wmi_debug("tag_type %d", tag_type); 118 119 switch (tag_type) { 120 case WMITLV_TAG_STRUC_wmi_ctrl_path_pdev_stats_struct: 121 break; 122 123 case WMITLV_TAG_STRUC_wmi_ctrl_path_mem_stats_struct: 124 break; 125 126 case WMITLV_TAG_STRUC_wmi_ctrl_path_twt_stats_struct: 127 wmi_twt_extract_stats_struct(tag_buf, params); 128 break; 129 130 default: 131 break; 132 } 133 } 134 135 /* 136 * wmi_stats_handler: parse the wmi event and fill the stats values 137 * @buff: Buffer containing wmi event 138 * @len: length of event buffer 139 * @params: buffer to hold parameters extracted from response event 140 * 141 * Return: QDF_STATUS_SUCCESS on success, else other qdf error values 142 */ 143 QDF_STATUS wmi_stats_handler(void *buff, int32_t len, 144 struct infra_cp_stats_event *params) 145 { 146 WMI_CTRL_PATH_STATS_EVENTID_param_tlvs *param_buf; 147 wmi_ctrl_path_stats_event_fixed_param *ev; 148 uint8_t *buf_ptr = (uint8_t *)buff; 149 uint32_t curr_tlv_tag; 150 uint32_t curr_tlv_len; 151 uint8_t *tag_start_ptr; 152 153 param_buf = (WMI_CTRL_PATH_STATS_EVENTID_param_tlvs *)buff; 154 if (!param_buf) { 155 wmi_err_rl("param_buf is NULL"); 156 return QDF_STATUS_E_FAILURE; 157 } 158 ev = (wmi_ctrl_path_stats_event_fixed_param *)param_buf->fixed_param; 159 160 curr_tlv_tag = WMITLV_GET_TLVTAG(ev->tlv_header); 161 curr_tlv_len = WMITLV_GET_TLVLEN(ev->tlv_header); 162 buf_ptr = (uint8_t *)param_buf->fixed_param; 163 wmi_debug("Fixed param more %d req_id %d status %d", ev->more, 164 ev->request_id, ev->status); 165 params->request_id = ev->request_id; 166 params->status = ev->status; 167 168 /* buffer should point to next TLV in event */ 169 buf_ptr += (curr_tlv_len + WMI_TLV_HDR_SIZE); 170 len -= (curr_tlv_len + WMI_TLV_HDR_SIZE); 171 172 curr_tlv_tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr)); 173 curr_tlv_len = WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)); 174 175 wmi_debug("curr_tlv_len %d curr_tlv_tag %d rem_len %d", len, 176 curr_tlv_len, curr_tlv_tag); 177 178 while ((len >= curr_tlv_len) && 179 (curr_tlv_tag >= WMITLV_TAG_FIRST_ARRAY_ENUM)) { 180 if (curr_tlv_tag == WMITLV_TAG_ARRAY_STRUC) { 181 /* Move to next WMITLV_TAG_ARRAY_STRUC */ 182 buf_ptr += WMI_TLV_HDR_SIZE; 183 len -= WMI_TLV_HDR_SIZE; 184 if (len <= 0) 185 break; 186 } 187 curr_tlv_tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr)); 188 curr_tlv_len = WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)); 189 190 wmi_debug("curr_tlv_len %d curr_tlv_tag %d rem_len %d", 191 len, curr_tlv_len, curr_tlv_tag); 192 if (curr_tlv_len) { 193 /* point to the tag inside WMITLV_TAG_ARRAY_STRUC */ 194 tag_start_ptr = buf_ptr + WMI_TLV_HDR_SIZE; 195 curr_tlv_tag = WMITLV_GET_TLVTAG( 196 WMITLV_GET_HDR(tag_start_ptr)); 197 wmi_stats_extract_tag_struct(curr_tlv_tag, 198 (void *)tag_start_ptr, 199 params); 200 } 201 /* Move to next tag */ 202 buf_ptr += curr_tlv_len + WMI_TLV_HDR_SIZE; 203 len -= (curr_tlv_len + WMI_TLV_HDR_SIZE); 204 205 if (len <= 0) 206 break; 207 } 208 209 return QDF_STATUS_SUCCESS; 210 } 211 212 /** 213 * extract_infra_cp_stats_tlv - api to extract stats information from 214 * event buffer 215 * @wmi_handle: wmi handle 216 * @evt_buf: event buffer 217 * @evt_buf_len: length of the event buffer 218 * @params: buffer to populate more flag 219 * 220 * Return: QDF_STATUS_SUCCESS on success, else other qdf error values 221 */ 222 QDF_STATUS 223 extract_infra_cp_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, 224 uint32_t evt_buf_len, 225 struct infra_cp_stats_event *params) 226 { 227 wmi_stats_handler(evt_buf, evt_buf_len, params); 228 return QDF_STATUS_SUCCESS; 229 } 230 231 /** 232 * prepare_infra_cp_stats_buf() - Allocate and prepate wmi cmd request buffer 233 * @wmi_handle: wmi handle 234 * @stats_req: Request parameters to be filled in wmi cmd request buffer 235 * @req_buf_len: length of the output wmi cmd buffer allocated 236 * 237 * Return: Valid wmi buffer pointer on success and NULL pointer for failure 238 */ 239 static wmi_buf_t 240 prepare_infra_cp_stats_buf(wmi_unified_t wmi_handle, 241 struct infra_cp_stats_cmd_info *stats_req, 242 uint32_t *req_buf_len) 243 { 244 wmi_request_ctrl_path_stats_cmd_fixed_param *cmd_fixed_param; 245 uint32_t index; 246 wmi_buf_t req_buf; 247 uint8_t *buf_ptr; 248 uint32_t *pdev_id_array; 249 uint32_t *vdev_id_array; 250 uint8_t *mac_addr_array; 251 uint32_t *dialog_id_array; 252 uint32_t num_pdev_ids = stats_req->num_pdev_ids; 253 uint32_t num_vdev_ids = stats_req->num_vdev_ids; 254 uint32_t num_mac_addr_list = stats_req->num_mac_addr_list; 255 uint32_t num_dialog_ids = INFRA_CP_STATS_MAX_REQ_TWT_DIALOG_ID; 256 257 /* Calculate total buffer length */ 258 *req_buf_len = (sizeof(wmi_request_ctrl_path_stats_cmd_fixed_param) + 259 WMI_TLV_HDR_SIZE + (sizeof(A_UINT32) * (num_pdev_ids)) + 260 WMI_TLV_HDR_SIZE + sizeof(A_UINT32) * (num_vdev_ids) + 261 WMI_TLV_HDR_SIZE + 262 sizeof(wmi_mac_addr) * (num_mac_addr_list) + 263 WMI_TLV_HDR_SIZE + 264 (sizeof(A_UINT32) * (num_dialog_ids))); 265 req_buf = wmi_buf_alloc(wmi_handle, *req_buf_len); 266 if (!req_buf) 267 return NULL; 268 269 cmd_fixed_param = (wmi_request_ctrl_path_stats_cmd_fixed_param *) 270 wmi_buf_data(req_buf); 271 272 /*Set TLV header*/ 273 WMITLV_SET_HDR(&cmd_fixed_param->tlv_header, 274 WMITLV_TAG_STRUC_wmi_request_ctrl_path_stats_cmd_fixed_param, 275 WMITLV_GET_STRUCT_TLVLEN( 276 wmi_request_ctrl_path_stats_cmd_fixed_param)); 277 278 index = get_infra_cp_stats_id(stats_req->stats_id); 279 cmd_fixed_param->stats_id_mask = (1 << index); 280 281 cmd_fixed_param->request_id = stats_req->action; 282 cmd_fixed_param->action = get_infra_cp_stats_action(stats_req->action); 283 284 buf_ptr = (uint8_t *)cmd_fixed_param; 285 /* Setting tlv header for pdev id arrays*/ 286 buf_ptr = buf_ptr + sizeof(*cmd_fixed_param); 287 pdev_id_array = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); 288 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 289 sizeof(A_UINT32) * num_pdev_ids); 290 291 /* Setting tlv header for vdev id arrays*/ 292 buf_ptr = buf_ptr + WMI_TLV_HDR_SIZE + 293 (sizeof(A_UINT32) * num_pdev_ids); 294 vdev_id_array = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); 295 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 296 sizeof(A_UINT32) * num_vdev_ids); 297 298 /* Setting tlv header for mac addr arrays*/ 299 buf_ptr = buf_ptr + WMI_TLV_HDR_SIZE + 300 (sizeof(A_UINT32) * num_vdev_ids); 301 mac_addr_array = buf_ptr + WMI_TLV_HDR_SIZE; 302 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, 303 sizeof(wmi_mac_addr) * num_mac_addr_list); 304 305 /* Setting tlv header for dialog id arrays*/ 306 buf_ptr = buf_ptr + WMI_TLV_HDR_SIZE + 307 sizeof(wmi_mac_addr) * num_mac_addr_list; 308 dialog_id_array = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); 309 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 310 sizeof(A_UINT32) * num_dialog_ids); 311 312 for (index = 0; index < num_pdev_ids; index++) 313 pdev_id_array[index] = stats_req->pdev_id[index]; 314 315 for (index = 0; index < num_vdev_ids; index++) 316 vdev_id_array[index] = stats_req->vdev_id[index]; 317 318 for (index = 0; index < num_mac_addr_list; index++) { 319 qdf_mem_copy(mac_addr_array, stats_req->peer_mac_addr[index], 320 QDF_MAC_ADDR_SIZE); 321 mac_addr_array += QDF_MAC_ADDR_SIZE; 322 } 323 324 dialog_id_array[0] = get_stats_req_twt_dialog_id(stats_req); 325 326 wmi_debug("stats_id_mask 0x%x action 0x%x dialog_id %d", 327 cmd_fixed_param->stats_id_mask, cmd_fixed_param->action, 328 dialog_id_array[0]); 329 wmi_debug("num_pdev_ids %d num_vdev_ids %d num_dialog_ids %d \ 330 num_mac_addr %d", num_pdev_ids, num_vdev_ids, 331 num_dialog_ids, num_mac_addr_list); 332 333 return req_buf; 334 } 335 336 /** 337 * send_infra_cp_stats_request_cmd_tlv() - Prepare and send infra_cp_stats 338 * wmi cmd to firmware 339 * @wmi_handle: wmi handle 340 * @param: Pointer to request structure 341 * 342 * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes 343 * on failure 344 */ 345 static QDF_STATUS 346 send_infra_cp_stats_request_cmd_tlv(wmi_unified_t wmi_handle, 347 struct infra_cp_stats_cmd_info *param) 348 { 349 uint32_t len; 350 wmi_buf_t buf; 351 QDF_STATUS status; 352 353 buf = prepare_infra_cp_stats_buf(wmi_handle, param, &len); 354 if (!buf) 355 return QDF_STATUS_E_NOMEM; 356 357 wmi_debug("buf_len %d", len); 358 359 wmi_mtrace(WMI_REQUEST_CTRL_PATH_STATS_CMDID, NO_SESSION, 0); 360 status = wmi_unified_cmd_send(wmi_handle, buf, 361 len, WMI_REQUEST_CTRL_PATH_STATS_CMDID); 362 363 if (QDF_IS_STATUS_ERROR(status)) { 364 wmi_buf_free(buf); 365 return QDF_STATUS_E_FAILURE; 366 } 367 368 return QDF_STATUS_SUCCESS; 369 } 370 #else 371 static inline QDF_STATUS 372 send_infra_cp_stats_request_cmd_tlv(wmi_unified_t wmi_handle, 373 struct infra_cp_stats_cmd_info *param) 374 { 375 return QDF_STATUS_SUCCESS; 376 } 377 #endif 378 379 #ifdef QCA_WIFI_EMULATION 380 static QDF_STATUS 381 send_stats_request_cmd_tlv(wmi_unified_t wmi_handle, 382 uint8_t macaddr[QDF_MAC_ADDR_SIZE], 383 struct stats_request_params *param) 384 { 385 return QDF_STATUS_SUCCESS; 386 } 387 #else 388 /** 389 * send_stats_request_cmd_tlv() - WMI request stats function 390 * @param wmi_handle: handle to WMI. 391 * @param macaddr: MAC address 392 * @param param: pointer to hold stats request parameter 393 * 394 * Return: 0 on success and -ve on failure. 395 */ 396 static QDF_STATUS 397 send_stats_request_cmd_tlv(wmi_unified_t wmi_handle, 398 uint8_t macaddr[QDF_MAC_ADDR_SIZE], 399 struct stats_request_params *param) 400 { 401 int32_t ret; 402 wmi_request_stats_cmd_fixed_param *cmd; 403 wmi_buf_t buf; 404 uint16_t len = sizeof(wmi_request_stats_cmd_fixed_param); 405 bool is_qmi_send_support; 406 407 buf = wmi_buf_alloc(wmi_handle, len); 408 if (!buf) 409 return QDF_STATUS_E_NOMEM; 410 411 cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf); 412 WMITLV_SET_HDR(&cmd->tlv_header, 413 WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, 414 WMITLV_GET_STRUCT_TLVLEN 415 (wmi_request_stats_cmd_fixed_param)); 416 cmd->stats_id = param->stats_id; 417 cmd->vdev_id = param->vdev_id; 418 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 419 wmi_handle, 420 param->pdev_id); 421 is_qmi_send_support = param->is_qmi_send_support; 422 423 WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); 424 425 wmi_debug("STATS REQ STATS_ID:%d VDEV_ID:%d PDEV_ID:%d, is_qmi_send_support %d", 426 cmd->stats_id, cmd->vdev_id, cmd->pdev_id, 427 is_qmi_send_support); 428 429 wmi_mtrace(WMI_REQUEST_STATS_CMDID, cmd->vdev_id, 0); 430 ret = wmi_unified_cmd_send_pm_chk(wmi_handle, buf, len, 431 WMI_REQUEST_STATS_CMDID, 432 is_qmi_send_support); 433 434 if (ret) { 435 wmi_err("Failed to send stats request to fw =%d", ret); 436 wmi_buf_free(buf); 437 } 438 439 return qdf_status_from_os_return(ret); 440 } 441 #endif 442 443 #ifdef WLAN_FEATURE_BIG_DATA_STATS 444 /** 445 * send_big_data_stats_request_cmd_tlv () - send big data stats cmd 446 * @wmi_handle: wmi handle 447 * @param : pointer to command request param 448 * 449 * Return: QDF_STATUS_SUCCESS for success or error code 450 */ 451 static QDF_STATUS 452 send_big_data_stats_request_cmd_tlv(wmi_unified_t wmi_handle, 453 struct stats_request_params *param) 454 { 455 int32_t ret = 0; 456 wmi_vdev_get_big_data_p2_cmd_fixed_param *cmd; 457 wmi_buf_t buf; 458 uint16_t len = sizeof(wmi_vdev_get_big_data_p2_cmd_fixed_param); 459 460 buf = wmi_buf_alloc(wmi_handle, len); 461 if (!buf) 462 return QDF_STATUS_E_NOMEM; 463 464 cmd = (wmi_vdev_get_big_data_p2_cmd_fixed_param *)wmi_buf_data(buf); 465 WMITLV_SET_HDR( 466 &cmd->tlv_header, 467 WMITLV_TAG_STRUC_wmi_vdev_get_big_data_p2_cmd_fixed_param, 468 WMITLV_GET_STRUCT_TLVLEN 469 (wmi_vdev_get_big_data_p2_cmd_fixed_param)); 470 471 cmd->vdev_id = param->vdev_id; 472 473 wmi_debug("STATS VDEV_ID:%d -->", cmd->vdev_id); 474 475 wmi_mtrace(WMI_VDEV_GET_BIG_DATA_P2_CMDID, cmd->vdev_id, 0); 476 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 477 WMI_VDEV_GET_BIG_DATA_P2_CMDID); 478 479 if (ret) { 480 wmi_err("Failed to send big data stats request to fw =%d", ret); 481 wmi_buf_free(buf); 482 } 483 484 return qdf_status_from_os_return(ret); 485 } 486 #endif 487 488 /** 489 * extract_all_stats_counts_tlv() - extract all stats count from event 490 * @param wmi_handle: wmi handle 491 * @param evt_buf: pointer to event buffer 492 * @param stats_param: Pointer to hold stats count 493 * 494 * Return: QDF_STATUS_SUCCESS for success or error code 495 */ 496 static QDF_STATUS 497 extract_all_stats_counts_tlv(wmi_unified_t wmi_handle, void *evt_buf, 498 wmi_host_stats_event *stats_param) 499 { 500 wmi_stats_event_fixed_param *ev; 501 wmi_per_chain_rssi_stats *rssi_event; 502 WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; 503 uint64_t min_data_len; 504 uint32_t i; 505 506 qdf_mem_zero(stats_param, sizeof(*stats_param)); 507 param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf; 508 ev = (wmi_stats_event_fixed_param *) param_buf->fixed_param; 509 rssi_event = param_buf->chain_stats; 510 if (!ev) { 511 wmi_err("event fixed param NULL"); 512 return QDF_STATUS_E_FAILURE; 513 } 514 515 if (param_buf->num_data > WMI_SVC_MSG_MAX_SIZE - sizeof(*ev)) { 516 wmi_err("num_data : %u is invalid", param_buf->num_data); 517 return QDF_STATUS_E_FAULT; 518 } 519 520 for (i = 1; i <= WMI_REQUEST_VDEV_EXTD_STAT; i = i << 1) { 521 switch (ev->stats_id & i) { 522 case WMI_REQUEST_PEER_STAT: 523 stats_param->stats_id |= WMI_HOST_REQUEST_PEER_STAT; 524 break; 525 526 case WMI_REQUEST_AP_STAT: 527 stats_param->stats_id |= WMI_HOST_REQUEST_AP_STAT; 528 break; 529 530 case WMI_REQUEST_PDEV_STAT: 531 stats_param->stats_id |= WMI_HOST_REQUEST_PDEV_STAT; 532 break; 533 534 case WMI_REQUEST_VDEV_STAT: 535 stats_param->stats_id |= WMI_HOST_REQUEST_VDEV_STAT; 536 break; 537 538 case WMI_REQUEST_BCNFLT_STAT: 539 stats_param->stats_id |= WMI_HOST_REQUEST_BCNFLT_STAT; 540 break; 541 542 case WMI_REQUEST_VDEV_RATE_STAT: 543 stats_param->stats_id |= 544 WMI_HOST_REQUEST_VDEV_RATE_STAT; 545 break; 546 547 case WMI_REQUEST_BCN_STAT: 548 stats_param->stats_id |= WMI_HOST_REQUEST_BCN_STAT; 549 break; 550 case WMI_REQUEST_PEER_EXTD_STAT: 551 stats_param->stats_id |= WMI_REQUEST_PEER_EXTD_STAT; 552 break; 553 554 case WMI_REQUEST_PEER_EXTD2_STAT: 555 stats_param->stats_id |= 556 WMI_HOST_REQUEST_PEER_ADV_STATS; 557 break; 558 559 case WMI_REQUEST_PMF_BCN_PROTECT_STAT: 560 stats_param->stats_id |= 561 WMI_HOST_REQUEST_PMF_BCN_PROTECT_STAT; 562 break; 563 564 case WMI_REQUEST_VDEV_EXTD_STAT: 565 stats_param->stats_id |= 566 WMI_HOST_REQUEST_VDEV_PRB_FILS_STAT; 567 break; 568 } 569 } 570 571 /* ev->num_*_stats may cause uint32_t overflow, so use uint64_t 572 * to save total length calculated 573 */ 574 min_data_len = 575 (((uint64_t)ev->num_pdev_stats) * sizeof(wmi_pdev_stats)) + 576 (((uint64_t)ev->num_vdev_stats) * sizeof(wmi_vdev_stats)) + 577 (((uint64_t)ev->num_peer_stats) * sizeof(wmi_peer_stats)) + 578 (((uint64_t)ev->num_bcnflt_stats) * 579 sizeof(wmi_bcnfilter_stats_t)) + 580 (((uint64_t)ev->num_chan_stats) * sizeof(wmi_chan_stats)) + 581 (((uint64_t)ev->num_mib_stats) * sizeof(wmi_mib_stats)) + 582 (((uint64_t)ev->num_bcn_stats) * sizeof(wmi_bcn_stats)) + 583 (((uint64_t)ev->num_peer_extd_stats) * 584 sizeof(wmi_peer_extd_stats)) + 585 (((uint64_t)ev->num_mib_extd_stats) * 586 sizeof(wmi_mib_extd_stats)); 587 if (param_buf->num_data != min_data_len) { 588 wmi_err("data len: %u isn't same as calculated: %llu", 589 param_buf->num_data, min_data_len); 590 return QDF_STATUS_E_FAULT; 591 } 592 593 stats_param->last_event = ev->last_event; 594 stats_param->num_pdev_stats = ev->num_pdev_stats; 595 stats_param->num_pdev_ext_stats = 0; 596 stats_param->num_vdev_stats = ev->num_vdev_stats; 597 stats_param->num_peer_stats = ev->num_peer_stats; 598 stats_param->num_peer_extd_stats = ev->num_peer_extd_stats; 599 stats_param->num_bcnflt_stats = ev->num_bcnflt_stats; 600 stats_param->num_chan_stats = ev->num_chan_stats; 601 stats_param->num_mib_stats = ev->num_mib_stats; 602 stats_param->num_mib_extd_stats = ev->num_mib_extd_stats; 603 stats_param->num_bcn_stats = ev->num_bcn_stats; 604 stats_param->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( 605 wmi_handle, 606 ev->pdev_id); 607 608 /* if chain_stats is not populated */ 609 if (!param_buf->chain_stats || !param_buf->num_chain_stats) 610 return QDF_STATUS_SUCCESS; 611 612 if (WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats != 613 WMITLV_GET_TLVTAG(rssi_event->tlv_header)) 614 return QDF_STATUS_SUCCESS; 615 616 if (WMITLV_GET_STRUCT_TLVLEN(wmi_per_chain_rssi_stats) != 617 WMITLV_GET_TLVLEN(rssi_event->tlv_header)) 618 return QDF_STATUS_SUCCESS; 619 620 if (rssi_event->num_per_chain_rssi_stats >= 621 WMITLV_GET_TLVLEN(rssi_event->tlv_header)) { 622 wmi_err("num_per_chain_rssi_stats:%u is out of bounds", 623 rssi_event->num_per_chain_rssi_stats); 624 return QDF_STATUS_E_INVAL; 625 } 626 stats_param->num_rssi_stats = rssi_event->num_per_chain_rssi_stats; 627 628 if (param_buf->vdev_extd_stats) 629 stats_param->num_vdev_extd_stats = 630 param_buf->num_vdev_extd_stats; 631 632 /* if peer_adv_stats is not populated */ 633 if (param_buf->num_peer_extd2_stats) 634 stats_param->num_peer_adv_stats = 635 param_buf->num_peer_extd2_stats; 636 637 return QDF_STATUS_SUCCESS; 638 } 639 640 /** 641 * extract_pdev_tx_stats() - extract pdev tx stats from event 642 */ 643 static void extract_pdev_tx_stats(wmi_host_dbg_tx_stats *tx, 644 struct wlan_dbg_tx_stats *tx_stats) 645 { 646 /* Tx Stats */ 647 tx->comp_queued = tx_stats->comp_queued; 648 tx->comp_delivered = tx_stats->comp_delivered; 649 tx->msdu_enqued = tx_stats->msdu_enqued; 650 tx->mpdu_enqued = tx_stats->mpdu_enqued; 651 tx->wmm_drop = tx_stats->wmm_drop; 652 tx->local_enqued = tx_stats->local_enqued; 653 tx->local_freed = tx_stats->local_freed; 654 tx->hw_queued = tx_stats->hw_queued; 655 tx->hw_reaped = tx_stats->hw_reaped; 656 tx->underrun = tx_stats->underrun; 657 tx->tx_abort = tx_stats->tx_abort; 658 tx->mpdus_requed = tx_stats->mpdus_requed; 659 tx->data_rc = tx_stats->data_rc; 660 tx->self_triggers = tx_stats->self_triggers; 661 tx->sw_retry_failure = tx_stats->sw_retry_failure; 662 tx->illgl_rate_phy_err = tx_stats->illgl_rate_phy_err; 663 tx->pdev_cont_xretry = tx_stats->pdev_cont_xretry; 664 tx->pdev_tx_timeout = tx_stats->pdev_tx_timeout; 665 tx->pdev_resets = tx_stats->pdev_resets; 666 tx->stateless_tid_alloc_failure = tx_stats->stateless_tid_alloc_failure; 667 tx->phy_underrun = tx_stats->phy_underrun; 668 tx->txop_ovf = tx_stats->txop_ovf; 669 670 return; 671 } 672 673 674 /** 675 * extract_pdev_rx_stats() - extract pdev rx stats from event 676 */ 677 static void extract_pdev_rx_stats(wmi_host_dbg_rx_stats *rx, 678 struct wlan_dbg_rx_stats *rx_stats) 679 { 680 /* Rx Stats */ 681 rx->mid_ppdu_route_change = rx_stats->mid_ppdu_route_change; 682 rx->status_rcvd = rx_stats->status_rcvd; 683 rx->r0_frags = rx_stats->r0_frags; 684 rx->r1_frags = rx_stats->r1_frags; 685 rx->r2_frags = rx_stats->r2_frags; 686 /* Only TLV */ 687 rx->r3_frags = 0; 688 rx->htt_msdus = rx_stats->htt_msdus; 689 rx->htt_mpdus = rx_stats->htt_mpdus; 690 rx->loc_msdus = rx_stats->loc_msdus; 691 rx->loc_mpdus = rx_stats->loc_mpdus; 692 rx->oversize_amsdu = rx_stats->oversize_amsdu; 693 rx->phy_errs = rx_stats->phy_errs; 694 rx->phy_err_drop = rx_stats->phy_err_drop; 695 rx->mpdu_errs = rx_stats->mpdu_errs; 696 697 return; 698 } 699 700 /** 701 * extract_pdev_stats_tlv() - extract pdev stats from event 702 * @param wmi_handle: wmi handle 703 * @param evt_buf: pointer to event buffer 704 * @param index: Index into pdev stats 705 * @param pdev_stats: Pointer to hold pdev stats 706 * 707 * Return: QDF_STATUS_SUCCESS for success or error code 708 */ 709 static QDF_STATUS 710 extract_pdev_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, uint32_t index, 711 wmi_host_pdev_stats *pdev_stats) 712 { 713 WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; 714 wmi_stats_event_fixed_param *ev_param; 715 uint8_t *data; 716 717 param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf; 718 ev_param = (wmi_stats_event_fixed_param *) param_buf->fixed_param; 719 pdev_stats->pdev_id = 720 wmi_handle->ops->convert_pdev_id_target_to_host(wmi_handle, 721 ev_param->pdev_id); 722 723 data = param_buf->data; 724 725 if (index < ev_param->num_pdev_stats) { 726 wmi_pdev_stats *ev = (wmi_pdev_stats *) ((data) + 727 (index * sizeof(wmi_pdev_stats))); 728 729 pdev_stats->chan_nf = ev->chan_nf; 730 pdev_stats->tx_frame_count = ev->tx_frame_count; 731 pdev_stats->rx_frame_count = ev->rx_frame_count; 732 pdev_stats->rx_clear_count = ev->rx_clear_count; 733 pdev_stats->cycle_count = ev->cycle_count; 734 pdev_stats->phy_err_count = ev->phy_err_count; 735 pdev_stats->chan_tx_pwr = ev->chan_tx_pwr; 736 737 extract_pdev_tx_stats(&(pdev_stats->pdev_stats.tx), 738 &(ev->pdev_stats.tx)); 739 extract_pdev_rx_stats(&(pdev_stats->pdev_stats.rx), 740 &(ev->pdev_stats.rx)); 741 } 742 743 return QDF_STATUS_SUCCESS; 744 } 745 746 /** 747 * extract_vdev_stats_tlv() - extract vdev stats from event 748 * @param wmi_handle: wmi handle 749 * @param evt_buf: pointer to event buffer 750 * @param index: Index into vdev stats 751 * @param vdev_stats: Pointer to hold vdev stats 752 * 753 * Return: QDF_STATUS_SUCCESS for success or error code 754 */ 755 static QDF_STATUS extract_vdev_stats_tlv(wmi_unified_t wmi_handle, 756 void *evt_buf, uint32_t index, wmi_host_vdev_stats *vdev_stats) 757 { 758 WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; 759 wmi_stats_event_fixed_param *ev_param; 760 uint8_t *data; 761 762 param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf; 763 ev_param = (wmi_stats_event_fixed_param *) param_buf->fixed_param; 764 data = (uint8_t *) param_buf->data; 765 766 if (index < ev_param->num_vdev_stats) { 767 wmi_vdev_stats *ev = (wmi_vdev_stats *) ((data) + 768 ((ev_param->num_pdev_stats) * 769 sizeof(wmi_pdev_stats)) + 770 (index * sizeof(wmi_vdev_stats))); 771 772 vdev_stats->vdev_id = ev->vdev_id; 773 vdev_stats->vdev_snr.bcn_snr = ev->vdev_snr.bcn_snr; 774 vdev_stats->vdev_snr.dat_snr = ev->vdev_snr.dat_snr; 775 776 OS_MEMCPY(vdev_stats->tx_frm_cnt, ev->tx_frm_cnt, 777 sizeof(ev->tx_frm_cnt)); 778 vdev_stats->rx_frm_cnt = ev->rx_frm_cnt; 779 OS_MEMCPY(vdev_stats->multiple_retry_cnt, 780 ev->multiple_retry_cnt, 781 sizeof(ev->multiple_retry_cnt)); 782 OS_MEMCPY(vdev_stats->fail_cnt, ev->fail_cnt, 783 sizeof(ev->fail_cnt)); 784 vdev_stats->rts_fail_cnt = ev->rts_fail_cnt; 785 vdev_stats->rts_succ_cnt = ev->rts_succ_cnt; 786 vdev_stats->rx_err_cnt = ev->rx_err_cnt; 787 vdev_stats->rx_discard_cnt = ev->rx_discard_cnt; 788 vdev_stats->ack_fail_cnt = ev->ack_fail_cnt; 789 OS_MEMCPY(vdev_stats->tx_rate_history, ev->tx_rate_history, 790 sizeof(ev->tx_rate_history)); 791 OS_MEMCPY(vdev_stats->bcn_rssi_history, ev->bcn_rssi_history, 792 sizeof(ev->bcn_rssi_history)); 793 794 } 795 796 return QDF_STATUS_SUCCESS; 797 } 798 799 /** 800 * extract_peer_stats_tlv() - extract peer stats from event 801 * @param wmi_handle: wmi handle 802 * @param evt_buf: pointer to event buffer 803 * @param index: Index into peer stats 804 * @param peer_stats: Pointer to hold peer stats 805 * 806 * Return: QDF_STATUS_SUCCESS for success or error code 807 */ 808 static QDF_STATUS 809 extract_peer_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, uint32_t index, 810 wmi_host_peer_stats *peer_stats) 811 { 812 WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; 813 wmi_stats_event_fixed_param *ev_param; 814 uint8_t *data; 815 816 param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf; 817 ev_param = (wmi_stats_event_fixed_param *) param_buf->fixed_param; 818 data = (uint8_t *) param_buf->data; 819 820 if (index < ev_param->num_peer_stats) { 821 wmi_peer_stats *ev = (wmi_peer_stats *) ((data) + 822 ((ev_param->num_pdev_stats) * sizeof(wmi_pdev_stats)) + 823 ((ev_param->num_vdev_stats) * sizeof(wmi_vdev_stats)) + 824 (index * sizeof(wmi_peer_stats))); 825 826 OS_MEMSET(peer_stats, 0, sizeof(wmi_host_peer_stats)); 827 828 OS_MEMCPY(&(peer_stats->peer_macaddr), 829 &(ev->peer_macaddr), sizeof(wmi_mac_addr)); 830 831 peer_stats->peer_rssi = ev->peer_rssi; 832 peer_stats->peer_tx_rate = ev->peer_tx_rate; 833 peer_stats->peer_rx_rate = ev->peer_rx_rate; 834 } 835 836 return QDF_STATUS_SUCCESS; 837 } 838 839 /** 840 * extract_peer_extd_stats_tlv() - extract extended peer stats from event 841 * @param wmi_handle: wmi handle 842 * @param evt_buf: pointer to event buffer 843 * @param index: Index into extended peer stats 844 * @param peer_extd_stats: Pointer to hold extended peer stats 845 * 846 * Return: QDF_STATUS_SUCCESS for success or error code 847 */ 848 static QDF_STATUS 849 extract_peer_extd_stats_tlv(wmi_unified_t wmi_handle, 850 void *evt_buf, uint32_t index, 851 wmi_host_peer_extd_stats *peer_extd_stats) 852 { 853 WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; 854 wmi_stats_event_fixed_param *ev_param; 855 uint8_t *data; 856 857 param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *)evt_buf; 858 ev_param = (wmi_stats_event_fixed_param *)param_buf->fixed_param; 859 data = (uint8_t *)param_buf->data; 860 if (!data) 861 return QDF_STATUS_E_FAILURE; 862 863 if (index < ev_param->num_peer_extd_stats) { 864 wmi_peer_extd_stats *ev = (wmi_peer_extd_stats *) (data + 865 (ev_param->num_pdev_stats * sizeof(wmi_pdev_stats)) + 866 (ev_param->num_vdev_stats * sizeof(wmi_vdev_stats)) + 867 (ev_param->num_peer_stats * sizeof(wmi_peer_stats)) + 868 (ev_param->num_bcnflt_stats * 869 sizeof(wmi_bcnfilter_stats_t)) + 870 (ev_param->num_chan_stats * sizeof(wmi_chan_stats)) + 871 (ev_param->num_mib_stats * sizeof(wmi_mib_stats)) + 872 (ev_param->num_bcn_stats * sizeof(wmi_bcn_stats)) + 873 (index * sizeof(wmi_peer_extd_stats))); 874 875 qdf_mem_zero(peer_extd_stats, sizeof(wmi_host_peer_extd_stats)); 876 qdf_mem_copy(&peer_extd_stats->peer_macaddr, &ev->peer_macaddr, 877 sizeof(wmi_mac_addr)); 878 879 peer_extd_stats->rx_mc_bc_cnt = ev->rx_mc_bc_cnt; 880 } 881 882 return QDF_STATUS_SUCCESS; 883 884 } 885 886 /** 887 * extract_pmf_bcn_protect_stats_tlv() - extract pmf bcn stats from event 888 * @wmi_handle: wmi handle 889 * @evt_buf: pointer to event buffer 890 * @pmf_bcn_stats: Pointer to hold pmf bcn protect stats 891 * 892 * Return: QDF_STATUS_SUCCESS for success or error code 893 */ 894 895 static QDF_STATUS 896 extract_pmf_bcn_protect_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, 897 wmi_host_pmf_bcn_protect_stats *pmf_bcn_stats) 898 { 899 WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; 900 wmi_stats_event_fixed_param *ev_param; 901 902 param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *)evt_buf; 903 if (!param_buf) 904 return QDF_STATUS_E_FAILURE; 905 906 ev_param = (wmi_stats_event_fixed_param *)param_buf->fixed_param; 907 908 if ((ev_param->stats_id & WMI_REQUEST_PMF_BCN_PROTECT_STAT) && 909 param_buf->pmf_bcn_protect_stats) { 910 pmf_bcn_stats->igtk_mic_fail_cnt = 911 param_buf->pmf_bcn_protect_stats->igtk_mic_fail_cnt; 912 pmf_bcn_stats->igtk_replay_cnt = 913 param_buf->pmf_bcn_protect_stats->igtk_replay_cnt; 914 pmf_bcn_stats->bcn_mic_fail_cnt = 915 param_buf->pmf_bcn_protect_stats->bcn_mic_fail_cnt; 916 pmf_bcn_stats->bcn_replay_cnt = 917 param_buf->pmf_bcn_protect_stats->bcn_replay_cnt; 918 } 919 920 return QDF_STATUS_SUCCESS; 921 } 922 923 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS 924 static void wmi_infra_cp_stats_ops_attach_tlv(struct wmi_ops *ops) 925 { 926 ops->send_infra_cp_stats_request_cmd = 927 send_infra_cp_stats_request_cmd_tlv; 928 } 929 #else 930 static void wmi_infra_cp_stats_ops_attach_tlv(struct wmi_ops *ops) 931 { 932 } 933 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ 934 935 #ifdef WLAN_FEATURE_SON 936 /** 937 * extract_inst_rssi_stats_resp_tlv() - extract inst rssi stats from event 938 * @wmi_handle: wmi handle 939 * @evt_buf: pointer to event buffer 940 * @inst_rssi_resp: Pointer to hold inst rssi response 941 * 942 * @Return: QDF_STATUS_SUCCESS for success or error code 943 */ 944 static QDF_STATUS 945 extract_inst_rssi_stats_resp_tlv(wmi_unified_t wmi_handle, void *evt_buf, 946 struct wmi_host_inst_rssi_stats_resp *inst_rssi_resp) 947 { 948 WMI_INST_RSSI_STATS_EVENTID_param_tlvs *param_buf; 949 wmi_inst_rssi_stats_resp_fixed_param *event; 950 951 param_buf = (WMI_INST_RSSI_STATS_EVENTID_param_tlvs *)evt_buf; 952 event = (wmi_inst_rssi_stats_resp_fixed_param *)param_buf->fixed_param; 953 954 inst_rssi_resp->inst_rssi = event->iRSSI; 955 WMI_CHAR_ARRAY_TO_MAC_ADDR(inst_rssi_resp->peer_macaddr.bytes, 956 &event->peer_macaddr); 957 inst_rssi_resp->vdev_id = event->vdev_id; 958 959 return QDF_STATUS_SUCCESS; 960 } 961 962 static void 963 wmi_inst_rssi_stats_ops_attach_tlv(struct wmi_ops *ops) 964 { 965 ops->extract_inst_rssi_stats_resp = extract_inst_rssi_stats_resp_tlv; 966 } 967 #else 968 static void 969 wmi_inst_rssi_stats_ops_attach_tlv(struct wmi_ops *ops) 970 { 971 } 972 #endif 973 974 void wmi_cp_stats_attach_tlv(wmi_unified_t wmi_handle) 975 { 976 struct wmi_ops *ops = wmi_handle->ops; 977 978 ops->send_stats_request_cmd = send_stats_request_cmd_tlv; 979 #ifdef WLAN_FEATURE_BIG_DATA_STATS 980 ops->send_big_data_stats_request_cmd = 981 send_big_data_stats_request_cmd_tlv; 982 #endif 983 ops->extract_all_stats_count = extract_all_stats_counts_tlv; 984 ops->extract_pdev_stats = extract_pdev_stats_tlv; 985 ops->extract_vdev_stats = extract_vdev_stats_tlv; 986 ops->extract_peer_stats = extract_peer_stats_tlv; 987 ops->extract_peer_extd_stats = extract_peer_extd_stats_tlv; 988 wmi_infra_cp_stats_ops_attach_tlv(ops); 989 ops->extract_pmf_bcn_protect_stats = extract_pmf_bcn_protect_stats_tlv, 990 wmi_inst_rssi_stats_ops_attach_tlv(ops); 991 992 wmi_mc_cp_stats_attach_tlv(wmi_handle); 993 } 994