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