xref: /wlan-dirver/qca-wifi-host-cmn/target_if/cfr/src/target_if_cfr_dbr.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #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  *
407  * Return: none
408  */
409 static
410 void prepare_cfr_header_txstatus(wmi_cfr_peer_tx_event_param *tx_evt_param,
411 				 struct csi_cfr_header *header,
412 				 uint32_t target_type)
413 {
414 	target_if_cfr_fill_header(header, false, target_type, false);
415 	header->u.meta_dbr.status = 0; /* failure */
416 	header->u.meta_dbr.length = 0;
417 	qdf_mem_copy(&header->u.meta_dbr.peer_addr[0],
418 		     &tx_evt_param->peer_mac_addr.bytes[0], QDF_MAC_ADDR_SIZE);
419 }
420 
421 /**
422  * target_if_peer_capture_event() - WMI TX completion event for one-shot
423  * capture
424  * @sc: pointer to offload soc object
425  * @data: WMI TX completion event buffer
426  * @datalen: WMI Tx completion event buffer length
427  *
428  * Return: status
429  */
430 static int
431 target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
432 {
433 	QDF_STATUS retval = 0;
434 	struct wmi_unified *wmi_handle;
435 	struct wlan_objmgr_psoc *psoc;
436 	struct wlan_objmgr_pdev *pdev;
437 	struct wlan_objmgr_vdev *vdev;
438 	uint32_t cookie;
439 	struct pdev_cfr *pdev_cfrobj;
440 	struct look_up_table *lut = NULL;
441 	struct csi_cfr_header *header = NULL;
442 	struct csi_cfr_header header_error = {0};
443 	wmi_cfr_peer_tx_event_param tx_evt_param = {0};
444 	qdf_dma_addr_t buf_addr = 0, buf_addr_temp = 0;
445 	int status;
446 	struct wlan_lmac_if_rx_ops *rx_ops;
447 	uint32_t target_type;
448 
449 	psoc = target_if_get_psoc_from_scn_hdl(sc);
450 	if (!psoc) {
451 		cfr_err("psoc is null");
452 		return -EINVAL;
453 	}
454 
455 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
456 	if (!rx_ops) {
457 		cfr_err("rx_ops is NULL");
458 		return -EINVAL;
459 	}
460 
461 	retval = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_CFR_ID);
462 	if (QDF_IS_STATUS_ERROR(retval)) {
463 		cfr_err("unable to get psoc reference");
464 		return -EINVAL;
465 	}
466 
467 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
468 	if (!wmi_handle) {
469 		cfr_err("wmi_handle is null");
470 		wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
471 		return -EINVAL;
472 	}
473 
474 	retval = wmi_extract_cfr_peer_tx_event_param(wmi_handle, data,
475 						     &tx_evt_param);
476 
477 	if (retval != QDF_STATUS_SUCCESS) {
478 		cfr_err("Failed to extract cfr tx event param");
479 		wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
480 		return -EINVAL;
481 	}
482 
483 	dump_cfr_peer_tx_event(&tx_evt_param);
484 
485 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, tx_evt_param.vdev_id,
486 						    WLAN_CFR_ID);
487 	if (!vdev) {
488 		cfr_err("vdev is null");
489 		wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
490 		return -EINVAL;
491 	}
492 
493 	pdev = wlan_vdev_get_pdev(vdev);
494 	if (!pdev) {
495 		cfr_err("pdev is null");
496 		wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
497 		wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID);
498 		return -EINVAL;
499 	}
500 
501 	retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID);
502 	if (retval != QDF_STATUS_SUCCESS) {
503 		cfr_err("failed to get pdev reference");
504 		wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
505 		wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID);
506 		return -EINVAL;
507 	}
508 
509 	pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
510 							    WLAN_UMAC_COMP_CFR);
511 	if (!pdev_cfrobj) {
512 		cfr_err("pdev object for CFR is NULL");
513 		status = -EINVAL;
514 		goto done;
515 	}
516 
517 	target_type = target_if_cfr_get_target_type(psoc);
518 
519 	if (tx_evt_param.status & PEER_CFR_CAPTURE_EVT_PS_STATUS_MASK) {
520 		cfr_debug("CFR capture failed as peer is in powersave : " QDF_MAC_ADDR_FMT,
521 			  QDF_MAC_ADDR_REF(&tx_evt_param.peer_mac_addr.bytes[0]));
522 		status = -EINVAL;
523 		goto relay_failure;
524 	}
525 
526 	if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_STATUS_MASK) == 0) {
527 		cfr_debug("CFR capture failed for peer : " QDF_MAC_ADDR_FMT,
528 			  QDF_MAC_ADDR_REF(&tx_evt_param.peer_mac_addr.bytes[0]));
529 		status = -EINVAL;
530 		pdev_cfrobj->tx_peer_status_cfr_fail++;
531 		goto relay_failure;
532 	}
533 
534 	if (tx_evt_param.status & CFR_TX_EVT_STATUS_MASK) {
535 		cfr_debug("TX packet returned status %d for peer: " QDF_MAC_ADDR_FMT,
536 			  tx_evt_param.status & CFR_TX_EVT_STATUS_MASK,
537 			  QDF_MAC_ADDR_REF(&tx_evt_param.peer_mac_addr.bytes[0]));
538 		status = -EINVAL;
539 		pdev_cfrobj->tx_evt_status_cfr_fail++;
540 		goto relay_failure;
541 	}
542 
543 	buf_addr_temp = (tx_evt_param.correlation_info_2 & 0x0f);
544 	buf_addr = (tx_evt_param.correlation_info_1 |
545 		    ((uint64_t)buf_addr_temp << 32));
546 
547 	if (target_if_dbr_cookie_lookup(pdev, DBR_MODULE_CFR, buf_addr,
548 					&cookie, 0)) {
549 		cfr_debug("Cookie lookup failure for addr: 0x%pK status: 0x%x",
550 			  (void *)((uintptr_t)buf_addr), tx_evt_param.status);
551 		status = -EINVAL;
552 		pdev_cfrobj->tx_dbr_cookie_lookup_fail++;
553 		goto done;
554 	}
555 
556 	cfr_debug("buffer address: 0x%pK cookie: %u",
557 		  (void *)((uintptr_t)buf_addr), cookie);
558 
559 	lut = pdev_cfrobj->lut[cookie];
560 	lut->tx_ppdu_id = (tx_evt_param.correlation_info_2 >> 16);
561 	lut->tx_address1 = tx_evt_param.correlation_info_1;
562 	lut->tx_address2 = tx_evt_param.correlation_info_2;
563 	header = &lut->header;
564 
565 	target_if_cfr_fill_header(header, false, target_type, false);
566 
567 	header->u.meta_dbr.status        = (tx_evt_param.status &
568 					    PEER_CFR_CAPTURE_EVT_STATUS_MASK) ?
569 					    1 : 0;
570 	header->u.meta_dbr.capture_bw    = tx_evt_param.bandwidth;
571 	header->u.meta_dbr.phy_mode      = tx_evt_param.phy_mode;
572 	header->u.meta_dbr.prim20_chan   = tx_evt_param.primary_20mhz_chan;
573 	header->u.meta_dbr.center_freq1  = tx_evt_param.band_center_freq1;
574 	header->u.meta_dbr.center_freq2  = tx_evt_param.band_center_freq2;
575 	/* Currently CFR data is captured on ACK of a Qos NULL frame.
576 	 * For 20 MHz, ACK is Legacy and for 40/80/160, ACK is DUP Legacy.
577 	 */
578 	header->u.meta_dbr.capture_mode  = tx_evt_param.bandwidth ?
579 					   CFR_DUP_LEGACY_ACK : CFR_LEGACY_ACK;
580 	header->u.meta_dbr.capture_type  = tx_evt_param.capture_method;
581 	header->u.meta_dbr.num_rx_chain  = wlan_vdev_mlme_get_rxchainmask(vdev);
582 	header->u.meta_dbr.sts_count     = tx_evt_param.spatial_streams;
583 	header->u.meta_dbr.timestamp     = tx_evt_param.timestamp_us;
584 	header->u.meta_dbr.rx_start_ts   = tx_evt_param.rx_start_ts;
585 	header->u.meta_dbr.rtt_cfo_measurement = tx_evt_param.cfo_measurement;
586 	header->u.meta_dbr.mcs_rate      = tx_evt_param.mcs_rate;
587 	header->u.meta_dbr.gi_type       = tx_evt_param.gi_type;
588 
589 	qdf_mem_copy(&header->u.meta_dbr.agc_gain[0],
590 		     &tx_evt_param.agc_gain[0],
591 		     HOST_MAX_CHAINS * sizeof(tx_evt_param.agc_gain[0]));
592 	qdf_mem_copy(&header->u.meta_dbr.peer_addr[0],
593 		     &tx_evt_param.peer_mac_addr.bytes[0], QDF_MAC_ADDR_SIZE);
594 	qdf_mem_copy(&header->u.meta_dbr.chain_rssi[0],
595 		     &tx_evt_param.chain_rssi[0],
596 		     HOST_MAX_CHAINS * sizeof(tx_evt_param.chain_rssi[0]));
597 	qdf_mem_copy(&header->u.meta_dbr.chain_phase[0],
598 		     &tx_evt_param.chain_phase[0],
599 		     HOST_MAX_CHAINS * sizeof(tx_evt_param.chain_phase[0]));
600 	qdf_mem_copy(&header->u.meta_dbr.agc_gain_tbl_index[0],
601 		     &tx_evt_param.agc_gain_tbl_index[0],
602 		     (HOST_MAX_CHAINS *
603 		      sizeof(tx_evt_param.agc_gain_tbl_index[0])));
604 
605 	status = correlate_and_relay(pdev, cookie, lut,
606 				     CORRELATE_TX_EV_MODULE_ID);
607 	if (status == STATUS_STREAM_AND_RELEASE) {
608 		status = rx_ops->cfr_rx_ops.cfr_info_send(pdev, &lut->header,
609 				sizeof(struct csi_cfr_header),
610 				lut->data, lut->data_len, &end_magic, 4);
611 		release_lut_entry(pdev, lut);
612 		target_if_dbr_buf_release(pdev, DBR_MODULE_CFR, buf_addr,
613 					  cookie, 0);
614 		cfr_debug("Data sent to upper layers, releasing look up table");
615 	} else if (status == STATUS_HOLD) {
616 		cfr_debug("HOLD for buffer address: 0x%pK cookie: %u",
617 			  (void *)((uintptr_t)buf_addr), cookie);
618 	} else {
619 		cfr_err("Correlation returned invalid status!!");
620 		status = -EINVAL;
621 		goto done;
622 	}
623 
624 	status = 0;
625 	goto done;
626 
627 relay_failure:
628 	prepare_cfr_header_txstatus(&tx_evt_param, &header_error, target_type);
629 	rx_ops->cfr_rx_ops.cfr_info_send(pdev, &header_error,
630 					 sizeof(struct csi_cfr_header),
631 					 NULL, 0, &end_magic, 4);
632 done:
633 	wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
634 	wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID);
635 	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
636 	return status;
637 }
638 #else
639 static int
640 target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
641 {
642 	return 0;
643 }
644 #endif
645 
646 /**
647  * target_if_register_tx_completion_event_handler()
648  * register TX completion handler
649  * @pdev: pointer to pdev object
650  *
651  * Return: Status
652  */
653 static QDF_STATUS
654 target_if_register_tx_completion_event_handler(struct wlan_objmgr_psoc *psoc)
655 {
656 	/* Register completion handler here */
657 	wmi_unified_t wmi_hdl;
658 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
659 
660 	wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc);
661 	if (!wmi_hdl) {
662 		cfr_err("Unable to get wmi handle");
663 		return QDF_STATUS_E_NULL_VALUE;
664 	}
665 
666 	ret = wmi_unified_register_event_handler(wmi_hdl,
667 						 wmi_peer_cfr_capture_event_id,
668 						 target_if_peer_capture_event,
669 						 WMI_RX_UMAC_CTX);
670 	/*
671 	 * Event registration is called per pdev
672 	 * Ignore error if event is already registered.
673 	 */
674 	if (ret == QDF_STATUS_E_FAILURE)
675 		ret = QDF_STATUS_SUCCESS;
676 
677 	return ret;
678 }
679 
680 /**
681  * target_if_unregister_tx_completion_event_handler
682  * unregister TX completion handler
683  * @pdev: pointer to pdev object
684  *
685  * Return: Status
686  */
687 static QDF_STATUS
688 target_if_unregister_tx_completion_event_handler(struct wlan_objmgr_psoc *psoc)
689 {
690 	/* Unregister completion handler here */
691 	wmi_unified_t wmi_hdl;
692 	QDF_STATUS status = QDF_STATUS_SUCCESS;
693 
694 	wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc);
695 	if (!wmi_hdl) {
696 		cfr_err("Unable to get wmi handle");
697 		return QDF_STATUS_E_NULL_VALUE;
698 	}
699 
700 	status = wmi_unified_unregister_event(wmi_hdl,
701 					      wmi_peer_cfr_capture_event_id);
702 	return status;
703 }
704 
705 #ifdef DIRECT_BUF_RX_ENABLE
706 /**
707  * target_if_register_to_dbr() - Register to Direct DMA handler
708  * @pdev: pointer to pdev object
709  *
710  * Return: Status
711  */
712 static QDF_STATUS
713 target_if_register_to_dbr(struct wlan_objmgr_pdev *pdev)
714 {
715 	struct wlan_objmgr_psoc *psoc;
716 	struct wlan_lmac_if_direct_buf_rx_tx_ops *dbr_tx_ops = NULL;
717 	struct dbr_module_config dbr_config;
718 	struct wlan_lmac_if_tx_ops *tx_ops;
719 
720 	psoc = wlan_pdev_get_psoc(pdev);
721 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
722 	if (!tx_ops) {
723 		cfr_err("tx_ops is NULL");
724 		return QDF_STATUS_E_FAILURE;
725 	}
726 
727 	dbr_tx_ops = &tx_ops->dbr_tx_ops;
728 	dbr_config.num_resp_per_event = DBR_NUM_RESP_PER_EVENT_CFR;
729 	dbr_config.event_timeout_in_ms = DBR_EVENT_TIMEOUT_IN_MS_CFR;
730 	if (dbr_tx_ops->direct_buf_rx_module_register) {
731 		return dbr_tx_ops->direct_buf_rx_module_register
732 			(pdev, DBR_MODULE_CFR, &dbr_config,
733 			 cfr_dbr_event_handler);
734 	}
735 
736 	return QDF_STATUS_SUCCESS;
737 }
738 
739 /**
740  * target_if_unregister_to_dbr() - Unregister callback for DBR events
741  * @pdev: PDEV object
742  *
743  * Return: status
744  */
745 static QDF_STATUS
746 target_if_unregister_to_dbr(struct wlan_objmgr_pdev *pdev)
747 {
748 	struct wlan_objmgr_psoc *psoc;
749 	struct wlan_lmac_if_direct_buf_rx_tx_ops *dbr_tx_ops = NULL;
750 	struct wlan_lmac_if_tx_ops *tx_ops;
751 
752 	psoc = wlan_pdev_get_psoc(pdev);
753 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
754 	if (!tx_ops) {
755 		cfr_err("tx_ops is NULL");
756 		return QDF_STATUS_E_FAILURE;
757 	}
758 
759 	dbr_tx_ops = &tx_ops->dbr_tx_ops;
760 	if (dbr_tx_ops->direct_buf_rx_module_unregister) {
761 		return dbr_tx_ops->direct_buf_rx_module_unregister
762 			(pdev, DBR_MODULE_CFR);
763 	}
764 
765 	return QDF_STATUS_SUCCESS;
766 }
767 
768 #else
769 static QDF_STATUS
770 target_if_cfr_register_to_dbr(struct wlan_objmgr_pdev *pdev)
771 {
772 	return QDF_STATUS_SUCCESS;
773 }
774 
775 static QDF_STATUS
776 target_if_unregister_to_dbr(struct wlan_objmgr_pdev *pdev)
777 {
778 	return QDF_STATUS_SUCCESS;
779 }
780 
781 #endif
782 
783 QDF_STATUS cfr_dbr_init_pdev(struct wlan_objmgr_psoc *psoc,
784 			     struct wlan_objmgr_pdev *pdev)
785 {
786 	QDF_STATUS status;
787 	struct pdev_cfr *pdev_cfrobj;
788 
789 	pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
790 							    WLAN_UMAC_COMP_CFR);
791 	if (!pdev_cfrobj)
792 		return QDF_STATUS_E_NULL_VALUE;
793 
794 #if DIRECT_BUF_RX_ENABLE
795 	status = target_if_register_to_dbr(pdev);
796 	if (QDF_STATUS_SUCCESS != status) {
797 		cfr_err("Failed to register with dbr");
798 		return QDF_STATUS_E_FAILURE;
799 	}
800 #endif
801 
802 	status = target_if_register_tx_completion_event_handler(psoc);
803 	if (QDF_STATUS_SUCCESS != status) {
804 		cfr_err("Failed to register with tx event handler");
805 		return QDF_STATUS_E_FAILURE;
806 	}
807 
808 	pdev_cfrobj->cfr_max_sta_count = MAX_CFR_ENABLED_CLIENTS;
809 	pdev_cfrobj->subbuf_size = STREAMFS_MAX_SUBBUF_8S;
810 	pdev_cfrobj->num_subbufs = STREAMFS_NUM_SUBBUF_8S;
811 
812 	return status;
813 }
814 
815 QDF_STATUS cfr_dbr_deinit_pdev(struct wlan_objmgr_psoc *psoc,
816 			       struct wlan_objmgr_pdev *pdev)
817 {
818 	QDF_STATUS status;
819 	struct pdev_cfr *pdev_cfrobj;
820 
821 	pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
822 							    WLAN_UMAC_COMP_CFR);
823 	if (!pdev_cfrobj)
824 		return QDF_STATUS_E_NULL_VALUE;
825 
826 	pdev_cfrobj->cfr_timer_enable = 0;
827 
828 	status = target_if_unregister_to_dbr(pdev);
829 	if (QDF_STATUS_SUCCESS != status)
830 		cfr_err("Failed to register with dbr");
831 
832 	status = target_if_unregister_tx_completion_event_handler(psoc);
833 	return status;
834 }
835