1 /* 2 * Copyright (c) 2018, 2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: target_if_cp_stats.c 22 * 23 * This file provide definition for APIs registered through lmac Tx Ops 24 */ 25 26 #include <qdf_mem.h> 27 #include <qdf_status.h> 28 #include <target_if_cp_stats.h> 29 #include <wmi_unified_priv.h> 30 #include <wmi_unified_param.h> 31 #include <target_if.h> 32 #include <wlan_tgt_def_config.h> 33 #include <wmi_unified_api.h> 34 #include <wlan_osif_priv.h> 35 #include <wlan_cp_stats_utils_api.h> 36 #include <wlan_objmgr_peer_obj.h> 37 #ifdef WLAN_FEATURE_MIB_STATS 38 #include <wlan_cp_stats_mc_defs.h> 39 #endif 40 #include "cp_stats/core/src/wlan_cp_stats_defs.h" 41 #include "cdp_txrx_cmn_struct.h" 42 #include "cdp_txrx_ctrl.h" 43 #include "cp_stats/core/src/wlan_cp_stats_comp_handler.h" 44 45 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS 46 47 uint32_t get_infra_cp_stats_id(enum infra_cp_stats_id type) 48 { 49 switch (type) { 50 case TYPE_REQ_CTRL_PATH_PDEV_TX_STAT: 51 return WMI_REQUEST_CTRL_PATH_PDEV_TX_STAT; 52 case TYPE_REQ_CTRL_PATH_VDEV_EXTD_STAT: 53 return WMI_REQUEST_CTRL_PATH_VDEV_EXTD_STAT; 54 case TYPE_REQ_CTRL_PATH_MEM_STAT: 55 return WMI_REQUEST_CTRL_PATH_MEM_STAT; 56 case TYPE_REQ_CTRL_PATH_TWT_STAT: 57 return WMI_REQUEST_CTRL_PATH_TWT_STAT; 58 case TYPE_REQ_CTRL_PATH_BMISS_STAT: 59 return WMI_REQUEST_CTRL_PATH_BMISS_STAT; 60 default: 61 return -EINVAL; 62 } 63 } 64 65 uint32_t get_infra_cp_stats_action(enum infra_cp_stats_action action) 66 { 67 switch (action) { 68 case ACTION_REQ_CTRL_PATH_STAT_GET: 69 return WMI_REQUEST_CTRL_PATH_STAT_GET; 70 case ACTION_REQ_CTRL_PATH_STAT_RESET: 71 return WMI_REQUEST_CTRL_PATH_STAT_RESET; 72 case ACTION_REQ_CTRL_PATH_STAT_START: 73 return WMI_REQUEST_CTRL_PATH_STAT_START; 74 case ACTION_REQ_CTRL_PATH_STAT_STOP: 75 return WMI_REQUEST_CTRL_PATH_STAT_STOP; 76 default: 77 return -EINVAL; 78 } 79 } 80 81 #ifdef WLAN_SUPPORT_TWT 82 /** 83 * target_if_infra_cp_stats_twt_event_free() - Free event buffer 84 * @ev: pointer to infra cp stats event structure 85 * 86 * Return: None 87 */ 88 static 89 void target_if_infra_cp_stats_twt_event_free(struct infra_cp_stats_event *ev) 90 { 91 qdf_mem_free(ev->twt_infra_cp_stats); 92 ev->twt_infra_cp_stats = NULL; 93 } 94 95 /** 96 * target_if_infra_cp_stats_twt_event_alloc() - Allocate event buffer for TWT 97 * parameters 98 * @ev: pointer to infra cp stats event structure 99 * 100 * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes on 101 * failure 102 */ 103 static QDF_STATUS 104 target_if_infra_cp_stats_twt_event_alloc(struct infra_cp_stats_event *ev) 105 { 106 ev->twt_infra_cp_stats = 107 qdf_mem_malloc(sizeof(*ev->twt_infra_cp_stats) * 108 INFRA_CP_STATS_MAX_RESP_TWT_DIALOG_ID); 109 if (!ev->twt_infra_cp_stats) { 110 cp_stats_err("mem alloc failed for ev.twt_infra_cp_stats"); 111 return QDF_STATUS_E_NOMEM; 112 } 113 114 return QDF_STATUS_SUCCESS; 115 } 116 117 #else 118 static inline 119 void target_if_infra_cp_stats_twt_event_free(struct infra_cp_stats_event *ev) 120 { 121 } 122 123 static inline QDF_STATUS 124 target_if_infra_cp_stats_twt_event_alloc(struct infra_cp_stats_event *ev) 125 { 126 return QDF_STATUS_SUCCESS; 127 } 128 129 static inline 130 void target_if_infra_cp_stats_free_stats_event(struct infra_cp_stats_event *ev) 131 { 132 } 133 #endif /* WLAN_SUPPORT_TWT */ 134 135 #ifdef CONFIG_WLAN_BMISS 136 137 /** 138 * target_if_infra_cp_stats_bmiss_event_free() - Free event buffer 139 * @ev: pointer to infra cp stats event structure 140 * 141 * Return: None 142 */ 143 static 144 void target_if_infra_cp_stats_bmiss_event_free(struct infra_cp_stats_event *ev) 145 { 146 qdf_mem_free(ev->bmiss_infra_cp_stats); 147 ev->bmiss_infra_cp_stats = NULL; 148 } 149 150 /** 151 * target_if_infra_cp_stats_bmiss_event_alloc() - Allocate buffer for bmiss 152 * parameters 153 * @ev: pointer to infra cp stats event structure 154 * 155 * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes on 156 * failure 157 */ 158 static QDF_STATUS 159 target_if_infra_cp_stats_bmiss_event_alloc(struct infra_cp_stats_event *ev) 160 { 161 ev->bmiss_infra_cp_stats = 162 qdf_mem_malloc(sizeof(*ev->bmiss_infra_cp_stats)); 163 if (!ev->bmiss_infra_cp_stats) { 164 cp_stats_err("mem alloc failed for ev.bmiss_infra_cp_stats"); 165 return QDF_STATUS_E_NOMEM; 166 } 167 168 return QDF_STATUS_SUCCESS; 169 } 170 #else 171 172 static inline 173 void target_if_infra_cp_stats_bmiss_event_free(struct infra_cp_stats_event *ev) 174 { 175 } 176 177 static inline QDF_STATUS 178 target_if_infra_cp_stats_bmiss_event_alloc(struct infra_cp_stats_event *ev) 179 { 180 return QDF_STATUS_SUCCESS; 181 } 182 #endif /* CONFIG_WLAN_BMISS */ 183 184 /** 185 * target_if_infra_cp_stats_event_free() - Free event buffer 186 * @ev: pointer to infra cp stats event structure 187 * 188 * Return : None 189 */ 190 static 191 void target_if_infra_cp_stats_event_free(struct infra_cp_stats_event *ev) 192 { 193 target_if_infra_cp_stats_twt_event_free(ev); 194 target_if_infra_cp_stats_bmiss_event_free(ev); 195 } 196 197 /** 198 * target_if_infra_cp_stats_event_alloc() - Allocate buffer for event 199 * parameters 200 * @ev: pointer to infra cp stats event structure 201 * 202 * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes on 203 * failure 204 */ 205 static QDF_STATUS 206 target_if_infra_cp_stats_event_alloc(struct infra_cp_stats_event *ev) 207 { 208 QDF_STATUS status; 209 210 status = target_if_infra_cp_stats_twt_event_alloc(ev); 211 if (status) 212 return QDF_STATUS_E_NOMEM; 213 214 status = target_if_infra_cp_stats_bmiss_event_alloc(ev); 215 if (status) 216 return QDF_STATUS_E_NOMEM; 217 218 return QDF_STATUS_SUCCESS; 219 } 220 221 /** 222 * target_if_extract_infra_cp_stats_event() - Extract data from stats event 223 * @wmi_hdl: WMI Handle 224 * @data: pointer to event data buffer from firmware 225 * @data_len: length of the data buffer 226 * @ev: pointer of output structure to be filled with extracted values 227 * 228 * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes 229 * on failure 230 */ 231 static QDF_STATUS 232 target_if_extract_infra_cp_stats_event(struct wmi_unified *wmi_hdl, 233 uint8_t *data, uint32_t data_len, 234 struct infra_cp_stats_event *ev) 235 { 236 QDF_STATUS status; 237 uint32_t more_flag = 0; 238 239 status = wmi_unified_extract_cp_stats_more_pending(wmi_hdl, data, 240 &more_flag); 241 242 status = wmi_unified_extract_infra_cp_stats(wmi_hdl, data, 243 data_len, ev); 244 245 cp_stats_debug("request_id %d", ev->request_id); 246 247 return QDF_STATUS_SUCCESS; 248 } 249 250 /** 251 * target_if_infra_cp_stats_event_handler() - Handle 252 * wmi_pdev_cp_fwstats_eventid 253 * @scn: opaque scn handle 254 * @data: event buffer received from fw 255 * @datalen: length of event buffer 256 * 257 * Return: 0 for success or non zero error codes for failure 258 */ 259 static 260 int target_if_infra_cp_stats_event_handler(ol_scn_t scn, uint8_t *data, 261 uint32_t datalen) 262 { 263 QDF_STATUS status; 264 struct infra_cp_stats_event ev = {0}; 265 struct wlan_objmgr_psoc *psoc; 266 struct wmi_unified *wmi_handle; 267 struct wlan_lmac_if_cp_stats_rx_ops *rx_ops; 268 269 cp_stats_debug("Enter"); 270 271 if (!scn || !data) { 272 cp_stats_err("scn: 0x%pK, data: 0x%pK", scn, data); 273 return -EINVAL; 274 } 275 276 psoc = target_if_get_psoc_from_scn_hdl(scn); 277 if (!psoc) { 278 cp_stats_err("null psoc"); 279 return -EINVAL; 280 } 281 282 rx_ops = target_if_cp_stats_get_rx_ops(psoc); 283 if (!rx_ops || !rx_ops->process_stats_event) { 284 cp_stats_err("callback not registered"); 285 return -EINVAL; 286 } 287 288 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 289 if (!wmi_handle) { 290 cp_stats_err("wmi_handle is null"); 291 return -EINVAL; 292 } 293 status = target_if_infra_cp_stats_event_alloc(&ev); 294 if (QDF_IS_STATUS_ERROR(status)) { 295 cp_stats_err("Alloc event mem failed"); 296 goto end; 297 } 298 299 status = target_if_extract_infra_cp_stats_event(wmi_handle, data, 300 datalen, &ev); 301 if (QDF_IS_STATUS_ERROR(status)) { 302 cp_stats_err("extract event failed"); 303 goto end; 304 } 305 306 status = rx_ops->process_infra_stats_event(psoc, &ev); 307 308 end: 309 target_if_infra_cp_stats_event_free(&ev); 310 return qdf_status_to_os_return(status); 311 } 312 #else 313 static 314 int target_if_infra_cp_stats_event_handler(ol_scn_t scn, uint8_t *data, 315 uint32_t datalen) 316 { 317 return 0; 318 } 319 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ 320 321 #if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) 322 static int 323 target_if_twt_session_params_event_handler(ol_scn_t scn, 324 uint8_t *evt_buf, 325 uint32_t evt_data_len) 326 { 327 struct wlan_objmgr_psoc *psoc; 328 struct wlan_objmgr_peer *peer_obj; 329 struct wmi_unified *wmi_hdl; 330 struct twt_session_stats_info twt_params; 331 struct twt_session_stats_event_param params = {0}; 332 struct peer_cp_stats *peer_cp_stats; 333 int i; 334 QDF_STATUS status; 335 uint32_t ev; 336 cdp_config_param_type val = {0}; 337 ol_txrx_soc_handle soc_txrx_handle; 338 struct wlan_lmac_if_rx_ops *rx_ops; 339 340 TARGET_IF_ENTER(); 341 342 if (!scn || !evt_buf) { 343 target_if_err("scn: 0x%pK, evt_buf: 0x%pK", scn, evt_buf); 344 return -EINVAL; 345 } 346 347 psoc = target_if_get_psoc_from_scn_hdl(scn); 348 if (!psoc) { 349 target_if_err("psoc object is null!"); 350 return -EINVAL; 351 } 352 353 soc_txrx_handle = wlan_psoc_get_dp_handle(psoc); 354 if (!soc_txrx_handle) 355 return -EINVAL; 356 357 wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc); 358 if (!wmi_hdl) { 359 target_if_err("wmi_handle is null!"); 360 return -EINVAL; 361 } 362 363 rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); 364 if (!rx_ops) { 365 target_if_err("No valid twt session stats rx ops"); 366 return -EINVAL; 367 } 368 369 status = wmi_extract_twt_session_stats_event(wmi_hdl, evt_buf, ¶ms); 370 if (QDF_IS_STATUS_ERROR(status)) { 371 target_if_err("Could not extract twt session stats event"); 372 return qdf_status_to_os_return(status); 373 } 374 375 if (params.num_sessions > WLAN_MAX_TWT_SESSIONS_PER_PEER) { 376 target_if_err("Number of twt sessions exceeded, num:%d max:%d", 377 params.num_sessions, WLAN_MAX_TWT_SESSIONS_PER_PEER); 378 return -EINVAL; 379 } 380 381 for (i = 0; i < params.num_sessions; i++) { 382 status = wmi_extract_twt_session_stats_data(wmi_hdl, evt_buf, 383 ¶ms, 384 &twt_params, i); 385 386 if (QDF_IS_STATUS_ERROR(status)) { 387 target_if_err("Unable to extract twt params for idx %d", 388 i); 389 return -EINVAL; 390 } 391 peer_obj = wlan_objmgr_get_peer_by_mac(psoc, 392 twt_params.peer_mac.bytes, 393 WLAN_CP_STATS_ID); 394 if (!peer_obj) { 395 target_if_err("peer obj not found for "QDF_MAC_ADDR_FMT, 396 QDF_MAC_ADDR_REF(twt_params.peer_mac.bytes)); 397 continue; 398 } 399 400 ev = twt_params.event_type; 401 if (ev == HOST_TWT_SESSION_SETUP) 402 val.cdp_peer_param_in_twt = 1; 403 else if (ev == HOST_TWT_SESSION_TEARDOWN) 404 val.cdp_peer_param_in_twt = 0; 405 406 cdp_txrx_set_peer_param(soc_txrx_handle, twt_params.vdev_id, 407 twt_params.peer_mac.bytes, 408 CDP_CONFIG_IN_TWT, val); 409 410 peer_cp_stats = wlan_cp_stats_get_peer_stats_obj(peer_obj); 411 if (!peer_cp_stats) { 412 target_if_err("peer_cp_stats is null"); 413 continue; 414 } 415 416 wlan_cp_stats_peer_obj_lock(peer_cp_stats); 417 418 rx_ops->cp_stats_rx_ops.twt_get_session_param_resp(psoc, 419 &twt_params); 420 421 wlan_cp_stats_peer_obj_unlock(peer_cp_stats); 422 wlan_objmgr_peer_release_ref(peer_obj, WLAN_CP_STATS_ID); 423 } 424 return 0; 425 } 426 427 static QDF_STATUS 428 target_if_cp_stats_register_twt_session_event(struct wmi_unified *wmi_handle) 429 { 430 QDF_STATUS ret_val; 431 432 ret_val = wmi_unified_register_event_handler(wmi_handle, 433 wmi_twt_session_stats_event_id, 434 target_if_twt_session_params_event_handler, 435 WMI_RX_WORK_CTX); 436 437 return ret_val; 438 } 439 440 static void 441 target_if_cp_stats_unregister_twt_session_event(struct wmi_unified *wmi_handle) 442 { 443 wmi_unified_unregister_event_handler(wmi_handle, 444 wmi_twt_session_stats_event_id); 445 } 446 #else 447 static QDF_STATUS 448 target_if_cp_stats_register_twt_session_event(struct wmi_unified *wmi_handle) 449 { 450 return QDF_STATUS_SUCCESS; 451 } 452 453 static void 454 target_if_cp_stats_unregister_twt_session_event(struct wmi_unified *wmi_handle) 455 { 456 } 457 #endif /* WLAN_SUPPORT_TWT && WLAN_TWT_CONV_SUPPORTED*/ 458 459 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS 460 static QDF_STATUS 461 target_if_cp_stats_infra_register_event_handler(struct wlan_objmgr_psoc *psoc, 462 struct wmi_unified *wmi_handle) 463 { 464 QDF_STATUS ret_val; 465 466 if (!psoc) { 467 cp_stats_err("PSOC is NULL!"); 468 return QDF_STATUS_E_INVAL; 469 } 470 471 if (!wmi_handle) { 472 cp_stats_err("wmi_handle is null"); 473 return QDF_STATUS_E_INVAL; 474 } 475 476 ret_val = wmi_unified_register_event_handler(wmi_handle, 477 wmi_pdev_cp_fwstats_eventid, 478 target_if_infra_cp_stats_event_handler, 479 WMI_RX_WORK_CTX); 480 if (QDF_IS_STATUS_ERROR(ret_val)) { 481 cp_stats_err("Failed to register for pdev_cp_fwstats_event"); 482 return ret_val; 483 } 484 485 return QDF_STATUS_SUCCESS; 486 } 487 #else 488 static QDF_STATUS 489 target_if_cp_stats_infra_register_event_handler(struct wlan_objmgr_psoc *psoc, 490 struct wmi_unified *wmi_handle) 491 { 492 return QDF_STATUS_SUCCESS; 493 } 494 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ 495 496 static QDF_STATUS 497 target_if_cp_stats_register_event_handler(struct wlan_objmgr_psoc *psoc) 498 { 499 struct wmi_unified *wmi_handle; 500 QDF_STATUS ret_val; 501 502 if (!psoc) { 503 cp_stats_err("PSOC is NULL!"); 504 return QDF_STATUS_E_INVAL; 505 } 506 507 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 508 if (!wmi_handle) { 509 cp_stats_err("wmi_handle is null"); 510 return QDF_STATUS_E_INVAL; 511 } 512 513 ret_val = target_if_cp_stats_infra_register_event_handler(psoc, 514 wmi_handle); 515 if (QDF_IS_STATUS_ERROR(ret_val)) { 516 cp_stats_err("Failed to register for pdev_cp_fwstats_event"); 517 return ret_val; 518 } 519 520 ret_val = target_if_cp_stats_register_twt_session_event(wmi_handle); 521 if (QDF_IS_STATUS_ERROR(ret_val)) { 522 cp_stats_err("Failed to register twt session stats event"); 523 return ret_val; 524 } 525 526 return QDF_STATUS_SUCCESS; 527 } 528 529 static QDF_STATUS 530 target_if_cp_stats_unregister_event_handler(struct wlan_objmgr_psoc *psoc) 531 { 532 struct wmi_unified *wmi_handle; 533 534 if (!psoc) { 535 cp_stats_err("PSOC is NULL!"); 536 return QDF_STATUS_E_INVAL; 537 } 538 539 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 540 if (!wmi_handle) { 541 cp_stats_err("wmi_handle is null"); 542 return QDF_STATUS_E_INVAL; 543 } 544 545 wmi_unified_unregister_event_handler(wmi_handle, 546 wmi_pdev_cp_fwstats_eventid); 547 target_if_cp_stats_unregister_twt_session_event(wmi_handle); 548 return QDF_STATUS_SUCCESS; 549 } 550 551 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS 552 /** 553 * target_if_infra_cp_stats_req() - API to send stats request to wmi 554 * @psoc: pointer to psoc object 555 * @req: pointer to object containing stats request parameters 556 * 557 * Return: QDF_STATUS_SUCCESS on success, else other qdf error values 558 */ 559 static 560 QDF_STATUS target_if_infra_cp_stats_req(struct wlan_objmgr_psoc *psoc, 561 struct infra_cp_stats_cmd_info *req) 562 563 { 564 struct wmi_unified *wmi_handle; 565 566 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 567 if (!wmi_handle) { 568 cp_stats_err("wmi_handle is null."); 569 return QDF_STATUS_E_NULL_VALUE; 570 } 571 572 return wmi_unified_infra_cp_stats_request_send(wmi_handle, req); 573 } 574 575 static void target_if_register_infra_cp_stats_txops( 576 struct wlan_lmac_if_cp_stats_tx_ops *tx_ops) 577 { 578 tx_ops->send_req_infra_cp_stats = target_if_infra_cp_stats_req; 579 } 580 #else 581 static void target_if_register_infra_cp_stats_txops( 582 struct wlan_lmac_if_cp_stats_tx_ops *tx_ops) 583 { 584 } 585 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ 586 587 QDF_STATUS 588 target_if_cp_stats_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 589 { 590 struct wlan_lmac_if_cp_stats_tx_ops *cp_stats_tx_ops; 591 592 if (!tx_ops) { 593 cp_stats_err("lmac tx ops is NULL!"); 594 return QDF_STATUS_E_INVAL; 595 } 596 597 cp_stats_tx_ops = &tx_ops->cp_stats_tx_ops; 598 if (!cp_stats_tx_ops) { 599 cp_stats_err("lmac tx ops is NULL!"); 600 return QDF_STATUS_E_FAILURE; 601 } 602 target_if_register_infra_cp_stats_txops(cp_stats_tx_ops); 603 604 cp_stats_tx_ops->cp_stats_attach = 605 target_if_cp_stats_register_event_handler; 606 cp_stats_tx_ops->cp_stats_detach = 607 target_if_cp_stats_unregister_event_handler; 608 cp_stats_tx_ops->cp_stats_legacy_attach = 609 target_if_cp_stats_register_legacy_event_handler; 610 cp_stats_tx_ops->cp_stats_legacy_detach = 611 target_if_cp_stats_unregister_legacy_event_handler; 612 return QDF_STATUS_SUCCESS; 613 } 614 615