xref: /wlan-dirver/qca-wifi-host-cmn/target_if/cfr/src/target_if_cfr_dbr.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
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