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 */
dump_lut(struct wlan_objmgr_pdev * pdev)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 */
dump_dma_hdr(struct whal_cfir_dma_hdr * dma_hdr,int error)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 */
compute_length(struct whal_cfir_dma_hdr * dma_hdr)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 */
release_lut_entry(struct wlan_objmgr_pdev * pdev,struct look_up_table * lut)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 */
correlate_and_relay(struct wlan_objmgr_pdev * pdev,uint32_t cookie,struct look_up_table * lut,uint8_t module_id)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 */
cfr_dbr_event_handler(struct wlan_objmgr_pdev * pdev,struct direct_buf_rx_data * payload)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 */
dump_cfr_peer_tx_event(wmi_cfr_peer_tx_event_param * event)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
prepare_cfr_header_txstatus(wmi_cfr_peer_tx_event_param * tx_evt_param,struct csi_cfr_header * header,uint32_t target_type)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
target_if_peer_capture_event(ol_scn_t sc,uint8_t * data,uint32_t datalen)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
target_if_peer_capture_event(ol_scn_t sc,uint8_t * data,uint32_t datalen)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
target_if_register_tx_completion_event_handler(struct wlan_objmgr_psoc * psoc)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
target_if_unregister_tx_completion_event_handler(struct wlan_objmgr_psoc * psoc)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
target_if_register_to_dbr(struct wlan_objmgr_pdev * pdev)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
target_if_unregister_to_dbr(struct wlan_objmgr_pdev * pdev)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
target_if_cfr_register_to_dbr(struct wlan_objmgr_pdev * pdev)771 target_if_cfr_register_to_dbr(struct wlan_objmgr_pdev *pdev)
772 {
773 return QDF_STATUS_SUCCESS;
774 }
775
776 static QDF_STATUS
target_if_unregister_to_dbr(struct wlan_objmgr_pdev * pdev)777 target_if_unregister_to_dbr(struct wlan_objmgr_pdev *pdev)
778 {
779 return QDF_STATUS_SUCCESS;
780 }
781
782 #endif
783
cfr_dbr_init_pdev(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_pdev * pdev)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
cfr_dbr_deinit_pdev(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_pdev * pdev)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