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