1 /* 2 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-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 #include <target_if_cfr.h> 21 #include <wlan_tgt_def_config.h> 22 #include <target_type.h> 23 #include <hif_hw_version.h> 24 #include <ol_if_athvar.h> 25 #include <target_if.h> 26 #include <wlan_lmac_if_def.h> 27 #include <wlan_osif_priv.h> 28 #include <init_deinit_lmac.h> 29 #include <wlan_cfr_utils_api.h> 30 #include <target_if_cfr_dbr.h> 31 #ifdef DIRECT_BUF_RX_ENABLE 32 #include <target_if_direct_buf_rx_api.h> 33 #endif 34 35 #ifdef DIRECT_BUF_RX_ENABLE 36 static u_int32_t end_magic = 0xBEAFDEAD; 37 38 /** 39 * dump_lut() - dump all valid lut entries 40 * @pdev: objmgr pdev 41 * 42 * return: none 43 */ 44 static int dump_lut(struct wlan_objmgr_pdev *pdev) 45 { 46 struct pdev_cfr *pdev_cfrobj; 47 struct look_up_table *lut = NULL; 48 int i = 0; 49 50 pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev, 51 WLAN_UMAC_COMP_CFR); 52 if (!pdev_cfrobj) { 53 cfr_err("pdev object for CFR is null"); 54 return -EINVAL; 55 } 56 57 for (i = 0; i < pdev_cfrobj->lut_num; i++) { 58 lut = pdev_cfrobj->lut[i]; 59 cfr_info("idx:%d dbrevnt: %d txevent: %d dbrppdu:0x%x txppdu:0x%x", 60 i, lut->dbr_recv, lut->tx_recv, 61 lut->dbr_ppdu_id, lut->tx_ppdu_id); 62 } 63 64 return 0; 65 } 66 67 /** 68 * dump_dma_hdr() - Dump DMA header populated by uCode 69 * @dma_hdr: pointer to the DMA header 70 * @error: Indicates whether it is an error 71 * 72 * Return: none 73 */ 74 static void dump_dma_hdr(struct whal_cfir_dma_hdr *dma_hdr, int error) 75 { 76 if (!error) { 77 cfr_debug("Tag: 0x%02x Length: %d udone: %d ctype: %d preamble: %d", 78 dma_hdr->tag, dma_hdr->length, dma_hdr->upload_done, 79 dma_hdr->capture_type, dma_hdr->preamble_type); 80 81 cfr_debug("Nss: %d num_chains: %d bw: %d", dma_hdr->nss, 82 dma_hdr->num_chains, dma_hdr->upload_pkt_bw); 83 84 cfr_debug("peervalid: %d peer_id: %d ppdu_id: 0x%04x", 85 dma_hdr->sw_peer_id_valid, dma_hdr->sw_peer_id, 86 dma_hdr->phy_ppdu_id); 87 } else { 88 cfr_err("Tag: 0x%02x Length: %d udone: %d ctype: %d preamble: %d", 89 dma_hdr->tag, dma_hdr->length, dma_hdr->upload_done, 90 dma_hdr->capture_type, dma_hdr->preamble_type); 91 92 cfr_err("Nss: %d num_chains: %d bw: %d", dma_hdr->nss, 93 dma_hdr->num_chains, dma_hdr->upload_pkt_bw); 94 95 cfr_err("peervalid: %d peer_id: %d ppdu_id: 0x%04x", 96 dma_hdr->sw_peer_id_valid, dma_hdr->sw_peer_id, 97 dma_hdr->phy_ppdu_id); 98 } 99 } 100 101 /** 102 * compute_length() - Compute the number of tones based on BW 103 * @dma_hdr: DMA header from uCode 104 * 105 * Return: Computed number of tones based on BW 106 */ 107 static int compute_length(struct whal_cfir_dma_hdr *dma_hdr) 108 { 109 uint8_t bw = dma_hdr->upload_pkt_bw; 110 uint8_t preamble = dma_hdr->preamble_type; 111 112 switch (preamble) { 113 case 0: 114 case 2: 115 switch (bw) { 116 case 0: 117 return TONES_IN_20MHZ; 118 case 1: /* DUP40/VHT40 */ 119 return TONES_IN_40MHZ; 120 case 2: /* DUP80/VHT80 */ 121 return TONES_IN_80MHZ; 122 case 3: /* DUP160/VHT160 */ 123 return TONES_IN_160MHZ; 124 } 125 126 case 1: 127 switch (bw) { 128 case 0: 129 return TONES_IN_20MHZ; 130 case 1: 131 return TONES_IN_40MHZ; 132 } 133 } 134 135 return TONES_INVALID; 136 } 137 138 /** 139 * release_lut_entry() - Clear all params in an LUT entry 140 * @pdev: objmgr PDEV 141 * @lut: pointer to LUT 142 * 143 * Return: status 144 */ 145 static int release_lut_entry(struct wlan_objmgr_pdev *pdev, 146 struct look_up_table *lut) 147 { 148 lut->dbr_recv = false; 149 lut->tx_recv = false; 150 lut->data = NULL; 151 lut->data_len = 0; 152 lut->dbr_ppdu_id = 0; 153 lut->tx_ppdu_id = 0; 154 qdf_mem_zero(&lut->header, sizeof(struct csi_cfr_header)); 155 156 return 0; 157 } 158 159 /** 160 * correlate_and_relay() - Correlate TXRX and DBR events and stream CFR data to 161 * userspace 162 * @pdev: objmgr PDEV 163 * @cookie: Index into lookup table 164 * @lut: pointer to lookup table 165 * @module_id: ID of the event received 166 * 0 - DBR event 167 * 1 - TXRX event 168 * 169 * Return: 170 * - STATUS_ERROR 171 * - STATUS_HOLD 172 * - STATUS_STREAM_AND_RELEASE 173 */ 174 static int correlate_and_relay(struct wlan_objmgr_pdev *pdev, uint32_t cookie, 175 struct look_up_table *lut, uint8_t module_id) 176 { 177 struct pdev_cfr *pdev_cfrobj; 178 int status = STATUS_ERROR; 179 180 if (module_id > 1) { 181 cfr_err("Received request with invalid mod id. Investigate!!"); 182 QDF_ASSERT(0); 183 return status; 184 } 185 186 pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev, 187 WLAN_UMAC_COMP_CFR); 188 189 if (module_id == CORRELATE_TX_EV_MODULE_ID) { 190 pdev_cfrobj->tx_evt_cnt++; 191 lut->tx_recv = true; 192 } else if (module_id == CORRELATE_DBR_MODULE_ID) { 193 pdev_cfrobj->dbr_evt_cnt++; 194 lut->dbr_recv = true; 195 } 196 197 if (lut->dbr_recv && lut->tx_recv) { 198 if (lut->dbr_ppdu_id == lut->tx_ppdu_id) { 199 pdev_cfrobj->release_cnt++; 200 status = STATUS_STREAM_AND_RELEASE; 201 } else { 202 /* 203 * When there is a ppdu id mismatch, discard the other 204 * older event's data and wait hold for new event 205 */ 206 if (module_id == CORRELATE_TX_EV_MODULE_ID) { 207 cfr_debug("Received new tx event for same cookie %u", 208 cookie); 209 lut->dbr_recv = false; 210 lut->data = NULL; 211 lut->data_len = 0; 212 lut->dbr_ppdu_id = 0; 213 qdf_mem_zero(&lut->dbr_address, 214 sizeof(lut->dbr_address)); 215 } else if (module_id == CORRELATE_DBR_MODULE_ID) { 216 cfr_debug("Received new dbr event for same cookie %u", 217 cookie); 218 lut->tx_recv = false; 219 lut->tx_ppdu_id = 0; 220 } 221 222 /* 223 * This is condition can occur if DBR buffer did not get 224 * released, or leaked either by Host/Target. 225 * we may need to add recovery here. 226 * 227 * 1. Stop all captures 228 * 2. Flush/release DBR buffer and LUT 229 * 3. Start capture again 230 */ 231 if ((pdev_cfrobj->dbr_evt_cnt - 232 pdev_cfrobj->release_cnt) >= MAX_LUT_ENTRIES) { 233 cfr_err("cookie = %u dbr_cnt = %llu, release_cnt = %llu", 234 cookie, pdev_cfrobj->dbr_evt_cnt, 235 pdev_cfrobj->release_cnt); 236 dump_lut(pdev); 237 dump_dma_hdr(&lut->dma_hdr, 1); 238 cfr_err("correlation_info1: 0x%08x correlation_info2 0x%08x", 239 lut->tx_address1, lut->tx_address2); 240 } 241 status = STATUS_HOLD; 242 } 243 } else { 244 status = STATUS_HOLD; 245 } 246 247 return status; 248 } 249 250 /** 251 * cfr_dbr_event_handler() - Process DBR event for CFR data DMA completion 252 * @pdev: PDEV object 253 * @payload: pointer to CFR data 254 * 255 * Return: status 256 */ 257 static bool cfr_dbr_event_handler(struct wlan_objmgr_pdev *pdev, 258 struct direct_buf_rx_data *payload) 259 { 260 uint8_t *data = NULL; 261 uint32_t cookie = 0; 262 struct whal_cfir_dma_hdr dma_hdr = {0}; 263 int length = 8, tones = 0, status = 0; 264 struct wlan_objmgr_psoc *psoc; 265 struct pdev_cfr *pdev_cfrobj; 266 struct look_up_table *lut = NULL; 267 struct csi_cfr_header *header = NULL; 268 struct wlan_lmac_if_rx_ops *rx_ops; 269 bool ret = true; 270 271 if ((!pdev) || (!payload)) { 272 cfr_err("pdev or payload is null"); 273 return true; 274 } 275 276 psoc = wlan_pdev_get_psoc(pdev); 277 if (!psoc) { 278 cfr_err("psoc is null"); 279 return true; 280 } 281 282 pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev, 283 WLAN_UMAC_COMP_CFR); 284 if (!pdev_cfrobj) { 285 cfr_err("pdev object for CFR is null"); 286 return true; 287 } 288 289 data = payload->vaddr; 290 cookie = payload->cookie; 291 292 cfr_debug("bufferaddr: 0x%pK cookie: %u", 293 (void *)((uintptr_t)payload->paddr), cookie); 294 qdf_mem_copy(&dma_hdr, &data[0], sizeof(struct whal_cfir_dma_hdr)); 295 296 dump_dma_hdr(&dma_hdr, 0); 297 tones = compute_length(&dma_hdr); 298 if (tones == TONES_INVALID) { 299 cfr_err("Number of tones received is invalid. Investigate!"); 300 return true; 301 } 302 303 length += tones * (dma_hdr.num_chains + 1); 304 305 lut = pdev_cfrobj->lut[cookie]; 306 lut->data = data; 307 lut->data_len = length; 308 lut->dbr_ppdu_id = dma_hdr.phy_ppdu_id; 309 lut->dbr_address = payload->paddr; 310 qdf_mem_copy(&lut->dma_hdr, &dma_hdr, sizeof(struct whal_cfir_dma_hdr)); 311 312 header = &lut->header; 313 header->u.meta_dbr.channel_bw = dma_hdr.upload_pkt_bw; 314 header->u.meta_dbr.length = length; 315 status = correlate_and_relay(pdev, cookie, lut, 316 CORRELATE_DBR_MODULE_ID); 317 if (status == STATUS_STREAM_AND_RELEASE) { 318 /* 319 * Message format 320 * Meta data Header + actual payload + trailer 321 */ 322 rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); 323 if (!rx_ops) { 324 cfr_err("rx_ops is NULL"); 325 return true; 326 } 327 328 status = rx_ops->cfr_rx_ops.cfr_info_send 329 (pdev, &lut->header, 330 sizeof(struct csi_cfr_header), 331 lut->data, lut->data_len, 332 &end_magic, 4); 333 release_lut_entry(pdev, lut); 334 cfr_debug("Data sent to upper layers, released look up table"); 335 ret = true; 336 } else if (status == STATUS_HOLD) { 337 cfr_debug("Tx event not received yet. Buffer is not released"); 338 ret = false; 339 } else { 340 cfr_err("Correlation returned invalid status!!"); 341 ret = true; 342 } 343 344 return ret; 345 } 346 347 /** 348 * dump_cfr_peer_tx_event() - Dump TX completion event 349 * @event: ptr to WMI TX completion event for QOS frames sent during 350 * one-shot capture. 351 * 352 * Return: none 353 */ 354 static void dump_cfr_peer_tx_event(wmi_cfr_peer_tx_event_param *event) 355 { 356 cfr_debug("CFR capture method: %u vdev_id: %u mac: " QDF_MAC_ADDR_FMT, 357 event->capture_method, event->vdev_id, 358 QDF_MAC_ADDR_REF(&event->peer_mac_addr.bytes[0])); 359 360 cfr_debug("Chan: %u bw: %u phymode: %u cfreq1: %u cfrq2: %u nss: %u", 361 event->primary_20mhz_chan, event->bandwidth, 362 event->phy_mode, event->band_center_freq1, 363 event->band_center_freq2, event->spatial_streams); 364 365 cfr_debug("Correlation_info1: 0x%08x Correlation_info2: 0x%08x", 366 event->correlation_info_1, event->correlation_info_2); 367 368 cfr_debug("status: 0x%x ts: %u counter: %u rssi0: 0x%08x", 369 event->status, event->timestamp_us, event->counter, 370 event->chain_rssi[0]); 371 372 cfr_debug("phase0: 0x%04x phase1: 0x%04x phase2: 0x%04x phase3: 0x%04x\n" 373 "phase4: 0x%04x phase5: 0x%04x phase6: 0x%04x phase7: 0x%04x", 374 event->chain_phase[0], event->chain_phase[1], 375 event->chain_phase[2], event->chain_phase[3], 376 event->chain_phase[4], event->chain_phase[5], 377 event->chain_phase[6], event->chain_phase[7]); 378 379 cfr_debug("rtt_cfo_measurement: %d\n", event->cfo_measurement); 380 381 cfr_debug("rx_start_ts: %u\n", event->rx_start_ts); 382 383 cfr_debug("mcs_rate: %u\n", event->mcs_rate); 384 385 cfr_debug("gi_type: %u\n", event->gi_type); 386 387 cfr_debug("agc_gain0: %u agc_gain1: %u agc_gain2: %u agc_gain3: %u\n" 388 "agc_gain4: %u agc_gain5: %u agc_gain6: %u agc_gain7: %u\n", 389 event->agc_gain[0], event->agc_gain[1], 390 event->agc_gain[2], event->agc_gain[3], 391 event->agc_gain[4], event->agc_gain[5], 392 event->agc_gain[6], event->agc_gain[7]); 393 cfr_debug("gain_tbl_idx0: %u gain_tbl_idx1: %u gain_tbl_idx2: %u\n" 394 "gain_tbl_idx3: %u gain_tbl_idx4: %u gain_tbl_idx5: %u\n" 395 "gain_tbl_idx6: %u gain_tbl_idx7: %u\n", 396 event->agc_gain_tbl_index[0], event->agc_gain_tbl_index[1], 397 event->agc_gain_tbl_index[2], event->agc_gain_tbl_index[3], 398 event->agc_gain_tbl_index[4], event->agc_gain_tbl_index[5], 399 event->agc_gain_tbl_index[6], event->agc_gain_tbl_index[7]); 400 } 401 402 /** 403 * prepare_cfr_header_txstatus() - Prepare CFR metadata for TX failures 404 * @tx_evt_param: ptr to WMI TX completion event 405 * @header: pointer to metadata 406 * @target_type: target type 407 * 408 * Return: none 409 */ 410 static 411 void prepare_cfr_header_txstatus(wmi_cfr_peer_tx_event_param *tx_evt_param, 412 struct csi_cfr_header *header, 413 uint32_t target_type) 414 { 415 target_if_cfr_fill_header(header, false, target_type, false); 416 header->u.meta_dbr.status = 0; /* failure */ 417 header->u.meta_dbr.length = 0; 418 qdf_mem_copy(&header->u.meta_dbr.peer_addr[0], 419 &tx_evt_param->peer_mac_addr.bytes[0], QDF_MAC_ADDR_SIZE); 420 } 421 422 /** 423 * target_if_peer_capture_event() - WMI TX completion event for one-shot 424 * capture 425 * @sc: pointer to offload soc object 426 * @data: WMI TX completion event buffer 427 * @datalen: WMI Tx completion event buffer length 428 * 429 * Return: status 430 */ 431 static int 432 target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen) 433 { 434 QDF_STATUS retval = 0; 435 struct wmi_unified *wmi_handle; 436 struct wlan_objmgr_psoc *psoc; 437 struct wlan_objmgr_pdev *pdev; 438 struct wlan_objmgr_vdev *vdev; 439 uint32_t cookie; 440 struct pdev_cfr *pdev_cfrobj; 441 struct look_up_table *lut = NULL; 442 struct csi_cfr_header *header = NULL; 443 struct csi_cfr_header header_error = {0}; 444 wmi_cfr_peer_tx_event_param tx_evt_param = {0}; 445 qdf_dma_addr_t buf_addr = 0, buf_addr_temp = 0; 446 int status; 447 struct wlan_lmac_if_rx_ops *rx_ops; 448 uint32_t target_type; 449 450 psoc = target_if_get_psoc_from_scn_hdl(sc); 451 if (!psoc) { 452 cfr_err("psoc is null"); 453 return -EINVAL; 454 } 455 456 rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); 457 if (!rx_ops) { 458 cfr_err("rx_ops is NULL"); 459 return -EINVAL; 460 } 461 462 retval = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_CFR_ID); 463 if (QDF_IS_STATUS_ERROR(retval)) { 464 cfr_err("unable to get psoc reference"); 465 return -EINVAL; 466 } 467 468 wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc); 469 if (!wmi_handle) { 470 cfr_err("wmi_handle is null"); 471 wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); 472 return -EINVAL; 473 } 474 475 retval = wmi_extract_cfr_peer_tx_event_param(wmi_handle, data, 476 &tx_evt_param); 477 478 if (retval != QDF_STATUS_SUCCESS) { 479 cfr_err("Failed to extract cfr tx event param"); 480 wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); 481 return -EINVAL; 482 } 483 484 dump_cfr_peer_tx_event(&tx_evt_param); 485 486 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, tx_evt_param.vdev_id, 487 WLAN_CFR_ID); 488 if (!vdev) { 489 cfr_err("vdev is null"); 490 wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); 491 return -EINVAL; 492 } 493 494 pdev = wlan_vdev_get_pdev(vdev); 495 if (!pdev) { 496 cfr_err("pdev is null"); 497 wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); 498 wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID); 499 return -EINVAL; 500 } 501 502 retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID); 503 if (retval != QDF_STATUS_SUCCESS) { 504 cfr_err("failed to get pdev reference"); 505 wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); 506 wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID); 507 return -EINVAL; 508 } 509 510 pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev, 511 WLAN_UMAC_COMP_CFR); 512 if (!pdev_cfrobj) { 513 cfr_err("pdev object for CFR is NULL"); 514 status = -EINVAL; 515 goto done; 516 } 517 518 target_type = target_if_cfr_get_target_type(psoc); 519 520 if (tx_evt_param.status & PEER_CFR_CAPTURE_EVT_PS_STATUS_MASK) { 521 cfr_debug("CFR capture failed as peer is in powersave : " QDF_MAC_ADDR_FMT, 522 QDF_MAC_ADDR_REF(&tx_evt_param.peer_mac_addr.bytes[0])); 523 status = -EINVAL; 524 goto relay_failure; 525 } 526 527 if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_STATUS_MASK) == 0) { 528 cfr_debug("CFR capture failed for peer : " QDF_MAC_ADDR_FMT, 529 QDF_MAC_ADDR_REF(&tx_evt_param.peer_mac_addr.bytes[0])); 530 status = -EINVAL; 531 pdev_cfrobj->tx_peer_status_cfr_fail++; 532 goto relay_failure; 533 } 534 535 if (tx_evt_param.status & CFR_TX_EVT_STATUS_MASK) { 536 cfr_debug("TX packet returned status %d for peer: " QDF_MAC_ADDR_FMT, 537 tx_evt_param.status & CFR_TX_EVT_STATUS_MASK, 538 QDF_MAC_ADDR_REF(&tx_evt_param.peer_mac_addr.bytes[0])); 539 status = -EINVAL; 540 pdev_cfrobj->tx_evt_status_cfr_fail++; 541 goto relay_failure; 542 } 543 544 buf_addr_temp = (tx_evt_param.correlation_info_2 & 0x0f); 545 buf_addr = (tx_evt_param.correlation_info_1 | 546 ((uint64_t)buf_addr_temp << 32)); 547 548 if (target_if_dbr_cookie_lookup(pdev, DBR_MODULE_CFR, buf_addr, 549 &cookie, 0)) { 550 cfr_debug("Cookie lookup failure for addr: 0x%pK status: 0x%x", 551 (void *)((uintptr_t)buf_addr), tx_evt_param.status); 552 status = -EINVAL; 553 pdev_cfrobj->tx_dbr_cookie_lookup_fail++; 554 goto done; 555 } 556 557 cfr_debug("buffer address: 0x%pK cookie: %u", 558 (void *)((uintptr_t)buf_addr), cookie); 559 560 lut = pdev_cfrobj->lut[cookie]; 561 lut->tx_ppdu_id = (tx_evt_param.correlation_info_2 >> 16); 562 lut->tx_address1 = tx_evt_param.correlation_info_1; 563 lut->tx_address2 = tx_evt_param.correlation_info_2; 564 header = &lut->header; 565 566 target_if_cfr_fill_header(header, false, target_type, false); 567 568 header->u.meta_dbr.status = (tx_evt_param.status & 569 PEER_CFR_CAPTURE_EVT_STATUS_MASK) ? 570 1 : 0; 571 header->u.meta_dbr.capture_bw = tx_evt_param.bandwidth; 572 header->u.meta_dbr.phy_mode = tx_evt_param.phy_mode; 573 header->u.meta_dbr.prim20_chan = tx_evt_param.primary_20mhz_chan; 574 header->u.meta_dbr.center_freq1 = tx_evt_param.band_center_freq1; 575 header->u.meta_dbr.center_freq2 = tx_evt_param.band_center_freq2; 576 /* Currently CFR data is captured on ACK of a Qos NULL frame. 577 * For 20 MHz, ACK is Legacy and for 40/80/160, ACK is DUP Legacy. 578 */ 579 header->u.meta_dbr.capture_mode = tx_evt_param.bandwidth ? 580 CFR_DUP_LEGACY_ACK : CFR_LEGACY_ACK; 581 header->u.meta_dbr.capture_type = tx_evt_param.capture_method; 582 header->u.meta_dbr.num_rx_chain = wlan_vdev_mlme_get_rxchainmask(vdev); 583 header->u.meta_dbr.sts_count = tx_evt_param.spatial_streams; 584 header->u.meta_dbr.timestamp = tx_evt_param.timestamp_us; 585 header->u.meta_dbr.rx_start_ts = tx_evt_param.rx_start_ts; 586 header->u.meta_dbr.rtt_cfo_measurement = tx_evt_param.cfo_measurement; 587 header->u.meta_dbr.mcs_rate = tx_evt_param.mcs_rate; 588 header->u.meta_dbr.gi_type = tx_evt_param.gi_type; 589 590 qdf_mem_copy(&header->u.meta_dbr.agc_gain[0], 591 &tx_evt_param.agc_gain[0], 592 HOST_MAX_CHAINS * sizeof(tx_evt_param.agc_gain[0])); 593 qdf_mem_copy(&header->u.meta_dbr.peer_addr[0], 594 &tx_evt_param.peer_mac_addr.bytes[0], QDF_MAC_ADDR_SIZE); 595 qdf_mem_copy(&header->u.meta_dbr.chain_rssi[0], 596 &tx_evt_param.chain_rssi[0], 597 HOST_MAX_CHAINS * sizeof(tx_evt_param.chain_rssi[0])); 598 qdf_mem_copy(&header->u.meta_dbr.chain_phase[0], 599 &tx_evt_param.chain_phase[0], 600 HOST_MAX_CHAINS * sizeof(tx_evt_param.chain_phase[0])); 601 qdf_mem_copy(&header->u.meta_dbr.agc_gain_tbl_index[0], 602 &tx_evt_param.agc_gain_tbl_index[0], 603 (HOST_MAX_CHAINS * 604 sizeof(tx_evt_param.agc_gain_tbl_index[0]))); 605 606 status = correlate_and_relay(pdev, cookie, lut, 607 CORRELATE_TX_EV_MODULE_ID); 608 if (status == STATUS_STREAM_AND_RELEASE) { 609 status = rx_ops->cfr_rx_ops.cfr_info_send(pdev, &lut->header, 610 sizeof(struct csi_cfr_header), 611 lut->data, lut->data_len, &end_magic, 4); 612 release_lut_entry(pdev, lut); 613 target_if_dbr_buf_release(pdev, DBR_MODULE_CFR, buf_addr, 614 cookie, 0); 615 cfr_debug("Data sent to upper layers, releasing look up table"); 616 } else if (status == STATUS_HOLD) { 617 cfr_debug("HOLD for buffer address: 0x%pK cookie: %u", 618 (void *)((uintptr_t)buf_addr), cookie); 619 } else { 620 cfr_err("Correlation returned invalid status!!"); 621 status = -EINVAL; 622 goto done; 623 } 624 625 status = 0; 626 goto done; 627 628 relay_failure: 629 prepare_cfr_header_txstatus(&tx_evt_param, &header_error, target_type); 630 rx_ops->cfr_rx_ops.cfr_info_send(pdev, &header_error, 631 sizeof(struct csi_cfr_header), 632 NULL, 0, &end_magic, 4); 633 done: 634 wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); 635 wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID); 636 wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); 637 return status; 638 } 639 #else 640 static int 641 target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen) 642 { 643 return 0; 644 } 645 #endif 646 647 /** 648 * target_if_register_tx_completion_event_handler() - register TX completion 649 * handler 650 * @psoc: pointer to psoc object 651 * 652 * Return: Status 653 */ 654 static QDF_STATUS 655 target_if_register_tx_completion_event_handler(struct wlan_objmgr_psoc *psoc) 656 { 657 /* Register completion handler here */ 658 wmi_unified_t wmi_hdl; 659 QDF_STATUS ret = QDF_STATUS_SUCCESS; 660 661 wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc); 662 if (!wmi_hdl) { 663 cfr_err("Unable to get wmi handle"); 664 return QDF_STATUS_E_NULL_VALUE; 665 } 666 667 ret = wmi_unified_register_event_handler(wmi_hdl, 668 wmi_peer_cfr_capture_event_id, 669 target_if_peer_capture_event, 670 WMI_RX_UMAC_CTX); 671 /* 672 * Event registration is called per pdev 673 * Ignore error if event is already registered. 674 */ 675 if (ret == QDF_STATUS_E_FAILURE) 676 ret = QDF_STATUS_SUCCESS; 677 678 return ret; 679 } 680 681 /** 682 * target_if_unregister_tx_completion_event_handler() - unregister TX 683 * completion handler 684 * @psoc: pointer to psoc object 685 * 686 * Return: Status 687 */ 688 static QDF_STATUS 689 target_if_unregister_tx_completion_event_handler(struct wlan_objmgr_psoc *psoc) 690 { 691 /* Unregister completion handler here */ 692 wmi_unified_t wmi_hdl; 693 QDF_STATUS status = QDF_STATUS_SUCCESS; 694 695 wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc); 696 if (!wmi_hdl) { 697 cfr_err("Unable to get wmi handle"); 698 return QDF_STATUS_E_NULL_VALUE; 699 } 700 701 status = wmi_unified_unregister_event(wmi_hdl, 702 wmi_peer_cfr_capture_event_id); 703 return status; 704 } 705 706 #ifdef DIRECT_BUF_RX_ENABLE 707 /** 708 * target_if_register_to_dbr() - Register to Direct DMA handler 709 * @pdev: pointer to pdev object 710 * 711 * Return: Status 712 */ 713 static QDF_STATUS 714 target_if_register_to_dbr(struct wlan_objmgr_pdev *pdev) 715 { 716 struct wlan_objmgr_psoc *psoc; 717 struct wlan_lmac_if_direct_buf_rx_tx_ops *dbr_tx_ops = NULL; 718 struct dbr_module_config dbr_config; 719 struct wlan_lmac_if_tx_ops *tx_ops; 720 721 psoc = wlan_pdev_get_psoc(pdev); 722 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 723 if (!tx_ops) { 724 cfr_err("tx_ops is NULL"); 725 return QDF_STATUS_E_FAILURE; 726 } 727 728 dbr_tx_ops = &tx_ops->dbr_tx_ops; 729 dbr_config.num_resp_per_event = DBR_NUM_RESP_PER_EVENT_CFR; 730 dbr_config.event_timeout_in_ms = DBR_EVENT_TIMEOUT_IN_MS_CFR; 731 if (dbr_tx_ops->direct_buf_rx_module_register) { 732 return dbr_tx_ops->direct_buf_rx_module_register 733 (pdev, DBR_MODULE_CFR, &dbr_config, 734 cfr_dbr_event_handler); 735 } 736 737 return QDF_STATUS_SUCCESS; 738 } 739 740 /** 741 * target_if_unregister_to_dbr() - Unregister callback for DBR events 742 * @pdev: PDEV object 743 * 744 * Return: status 745 */ 746 static QDF_STATUS 747 target_if_unregister_to_dbr(struct wlan_objmgr_pdev *pdev) 748 { 749 struct wlan_objmgr_psoc *psoc; 750 struct wlan_lmac_if_direct_buf_rx_tx_ops *dbr_tx_ops = NULL; 751 struct wlan_lmac_if_tx_ops *tx_ops; 752 753 psoc = wlan_pdev_get_psoc(pdev); 754 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 755 if (!tx_ops) { 756 cfr_err("tx_ops is NULL"); 757 return QDF_STATUS_E_FAILURE; 758 } 759 760 dbr_tx_ops = &tx_ops->dbr_tx_ops; 761 if (dbr_tx_ops->direct_buf_rx_module_unregister) { 762 return dbr_tx_ops->direct_buf_rx_module_unregister 763 (pdev, DBR_MODULE_CFR); 764 } 765 766 return QDF_STATUS_SUCCESS; 767 } 768 769 #else 770 static QDF_STATUS 771 target_if_cfr_register_to_dbr(struct wlan_objmgr_pdev *pdev) 772 { 773 return QDF_STATUS_SUCCESS; 774 } 775 776 static QDF_STATUS 777 target_if_unregister_to_dbr(struct wlan_objmgr_pdev *pdev) 778 { 779 return QDF_STATUS_SUCCESS; 780 } 781 782 #endif 783 784 QDF_STATUS cfr_dbr_init_pdev(struct wlan_objmgr_psoc *psoc, 785 struct wlan_objmgr_pdev *pdev) 786 { 787 QDF_STATUS status; 788 struct pdev_cfr *pdev_cfrobj; 789 790 pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev, 791 WLAN_UMAC_COMP_CFR); 792 if (!pdev_cfrobj) 793 return QDF_STATUS_E_NULL_VALUE; 794 795 #if DIRECT_BUF_RX_ENABLE 796 status = target_if_register_to_dbr(pdev); 797 if (QDF_STATUS_SUCCESS != status) { 798 cfr_err("Failed to register with dbr"); 799 return QDF_STATUS_E_FAILURE; 800 } 801 #endif 802 803 status = target_if_register_tx_completion_event_handler(psoc); 804 if (QDF_STATUS_SUCCESS != status) { 805 cfr_err("Failed to register with tx event handler"); 806 return QDF_STATUS_E_FAILURE; 807 } 808 809 pdev_cfrobj->cfr_max_sta_count = MAX_CFR_ENABLED_CLIENTS; 810 pdev_cfrobj->subbuf_size = STREAMFS_MAX_SUBBUF_8S; 811 pdev_cfrobj->num_subbufs = STREAMFS_NUM_SUBBUF_8S; 812 813 return status; 814 } 815 816 QDF_STATUS cfr_dbr_deinit_pdev(struct wlan_objmgr_psoc *psoc, 817 struct wlan_objmgr_pdev *pdev) 818 { 819 QDF_STATUS status; 820 struct pdev_cfr *pdev_cfrobj; 821 822 pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev, 823 WLAN_UMAC_COMP_CFR); 824 if (!pdev_cfrobj) 825 return QDF_STATUS_E_NULL_VALUE; 826 827 pdev_cfrobj->cfr_timer_enable = 0; 828 829 status = target_if_unregister_to_dbr(pdev); 830 if (QDF_STATUS_SUCCESS != status) 831 cfr_err("Failed to register with dbr"); 832 833 status = target_if_unregister_tx_completion_event_handler(psoc); 834 return status; 835 } 836