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