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