Prechádzať zdrojové kódy

qca-wifi: CFR: Implementation of CFR for QCA6018 platforms

Channel Frequency Response(CFR) captures FFT bins corresponding to a PPDU
received and this is relayed to user space application along with
additional information about the PPDU gathered in the host. Usecases of
this feature include location sensing, motion detection.

Change-Id: If0da492bc1fcc0fc2b6e42339c56f9a54ee813f7
CRs-Fixed: 2541307
Padma Raghunathan 5 rokov pred
rodič
commit
5df9a9481d

+ 13 - 0
target_if/cfr/inc/target_if_cfr.h

@@ -28,6 +28,19 @@
 #define PEER_CFR_CAPTURE_ENABLE   1
 #define PEER_CFR_CAPTURE_DISABLE  0
 
+#define PEER_CFR_CAPTURE_EVT_STATUS_MASK 0x80000000
+#define PEER_CFR_CAPTURE_EVT_PS_STATUS_MASK 0x40000000
+#define CFR_TX_EVT_STATUS_MASK           0x00000003
+
+/* Status codes used by correlate and relay function */
+#define STATUS_STREAM_AND_RELEASE 0
+#define STATUS_HOLD               1
+#define STATUS_ERROR             -1
+
+/* Module IDs using corrlation function */
+#define CORRELATE_DBR_MODULE_ID   0
+#define CORRELATE_TX_EV_MODULE_ID 1 /* HKV2 */
+#define CORRELATE_TXRX_EV_MODULE_ID 1 /* Cypress */
 
 /**
  * target_if_cfr_init_pdev() - Inits cfr pdev and registers necessary handlers.

+ 326 - 0
target_if/cfr/inc/target_if_cfr_6018.h

@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TARGET_IF_CFR_6018_H_
+#define _TARGET_IF_CFR_6018_H_
+
+#ifdef WLAN_ENH_CFR_ENABLE
+/*
+ * Memory requirements :
+ *
+ *  1. DMA header :
+ *
+ * Legacy DMA header(QCA8074V2) : 2 words (length = 8 bytes)
+ * Enhanced DMA header(QCA6018) : Upto 16 words depending on no. of MU users
+ *                       in UL-MU-PPDU (Max length = 64 bytes)
+ *
+ * Fixed 4 words for whal_cfir_enhanced_hdr + freeze TLV
+ *                                          + uplink_user_info TLV (MAX 4)
+ *
+ * mu_rx_num_users -> No. of words in CFR DMA header
+ * 0 -> 12  =  4 + 7(freeze TLV) + 1(for 64-bit alignment)
+ * 1 -> 12  =  4 + 7(freeze TLV) + 1(user1)
+ * 2 -> 14  =  4 + 7(freeze TLV) + 2(users 1,2) + 1(for 64-bit alignment)
+ * 3 -> 14  =  4 + 7(freeze TLV) + 3(users 1,2,3)
+ * 4 -> 16  =  4 + 7(freeze TLV) + 4(users 1,2,3,4) + 1(for 64-bit alignment)
+ *
+ *
+ * 2. CFR data size for max BW/Nss/Nrx
+ *
+ *	Cypress : Max BW = 80 MHz
+ *			 NSS = 2
+ *			 Nrx = 2
+ *			 Size of one tone = 4 bytes
+ *
+ *		a. RTT-H - 2048 bytes
+ *
+ *		b. Debug-H (MIMO CFR) - 16016 bytes
+ *
+ *		c. RTT-H + CIR - 10240 bytes = 2048(RTT-H) + 8192(CIR)
+ */
+
+/* Max 4 users in MU case */
+#define CYP_CFR_MU_USERS 4
+
+#define CYP_MAX_HEADER_LENGTH_WORDS 16
+
+/* Max(2048, 16016, 10240) */
+#define CYP_MAX_DATA_LENGTH_BYTES 16016
+
+/* in ms */
+#define LUT_AGE_TIMER 3000
+#define LUT_AGE_THRESHOLD 3000
+#define NUM_LUT_ENTRIES 136
+
+/* Max size :
+ * 16173 = 93 bytes(csi header) + 64 bytes(cfr header) + 16016 bytes(cfr
+ * payload)
+ */
+#define STREAMFS_MAX_SUBBUF_CYP 16173
+
+#define STREAMFS_NUM_SUBBUF_CYP 255
+
+/*
+ * @tag: ucode fills this with 0xBA
+ *
+ * @length: length of CFR header in words (32-bit)
+ *
+ * @upload_done: ucode sets this to 1 to indicate DMA completion
+ *
+ * @capture_type:
+ *
+ *			0 - None
+ *			1 - RTT-H (Nss = 1, Nrx)
+ *			2 - Debug-H (Nss, Nrx)
+ *			3 - Reserved
+ *			5 - RTT-H + CIR(Nss, Nrx)
+ *
+ * @preamble_type:
+ *
+ *			0 - Legacy
+ *			1 - HT
+ *			2 - VHT
+ *			3 - HE
+ *
+ * @nss:
+ *
+ *			0 - 1-stream
+ *			1 - 2-stream
+ *			..	..
+ *			7 - 8-stream
+ *
+ *@num_chains:
+ *
+ *			0 - 1-chain
+ *			1 - 2-chain
+ *			..  ..
+ *			7 - 8-chain
+ *
+ *@upload_bw_pkt:
+ *
+ *			0 - 20 MHz
+ *			1 - 40 MHz
+ *			2 - 80 MHz
+ *			3 - 160 MHz
+ *
+ * @sw_peer_id_valid: Indicates whether sw_peer_id field is valid or not,
+ * sent from MAC to PHY via the MACRX_FREEZE_CAPTURE_CHANNEL TLV
+ *
+ * @sw_peer_id: Indicates peer id based on AST search, sent from MAC to PHY
+ * via the MACRX_FREEZE_CAPTURE_CHANNEL TLV
+ *
+ * @phy_ppdu_id: sent from PHY to MAC, copied to MACRX_FREEZE_CAPTURE_CHANNEL
+ * TLV
+ *
+ * @total_bytes: Total size of CFR payload (FFT bins)
+ *
+ * @header_version:
+ *
+ *			1 - HKV2/Hastings
+ *			2 - Cypress
+ *
+ * @target_id:
+ *
+ *			1 - Hastings
+ *			2 - Cypress
+ *			3 - Hastings Prime
+ *			4 - Pine
+ *
+ * @cfr_fmt:
+ *
+ *			0 - raw (32-bit format)
+ *			1 - compressed (24-bit format)
+ *
+ * @mu_rx_data_incl: Indicates whether CFR header contains UL-MU-MIMO info
+ *
+ * @freeze_data_incl: Indicates whether CFR header contains
+ * MACRX_FREEZE_CAPTURE_CHANNEL TLV
+ *
+ * @decimation_factor: FFT bins decimation
+ * @mu_rx_num_users: Number of users in UL-MU-PPDU
+ */
+struct whal_cfir_enhanced_hdr {
+	uint16_t tag              :  8,
+		 length           :  6,
+		 rsvd1            :  2;
+
+	uint16_t upload_done        :  1,
+		 capture_type       :  3,
+		 preamble_type      :  2,
+		 nss                :  3,
+		 num_chains         :  3,
+		 upload_pkt_bw      :  3,
+		 sw_peer_id_valid   :  1;
+
+	uint16_t sw_peer_id         : 16;
+
+	uint16_t phy_ppdu_id        : 16;
+
+	uint16_t total_bytes;
+
+	uint16_t header_version  :4,
+		 target_id       :4,
+		 cfr_fmt         :1,
+		 rsvd2           :1,
+		 mu_rx_data_incl :1,
+		 freeze_data_incl:1,
+		 rsvd3           :4;
+
+	uint16_t mu_rx_num_users   :8,
+		 decimation_factor :4,
+		 rsvd4		   :4;
+
+	uint16_t rsvd5;
+};
+
+struct macrx_freeze_capture_channel {
+	uint16_t freeze                          :  1, //[0]
+		 capture_reason                  :  3, //[3:1]
+		 packet_type                     :  2, //[5:4]
+		 packet_sub_type                 :  4, //[9:6]
+		 reserved                        :  5, //[14:10]
+		 sw_peer_id_valid                :  1; //[15]
+	uint16_t sw_peer_id                      : 16; //[15:0]
+	uint16_t phy_ppdu_id                     : 16; //[15:0]
+	uint16_t packet_ta_lower_16              : 16; //[15:0]
+	uint16_t packet_ta_mid_16                : 16; //[15:0]
+	uint16_t packet_ta_upper_16              : 16; //[15:0]
+	uint16_t packet_ra_lower_16              : 16; //[15:0]
+	uint16_t packet_ra_mid_16                : 16; //[15:0]
+	uint16_t packet_ra_upper_16              : 16; //[15:0]
+	uint16_t tsf_timestamp_15_0              : 16; //[15:0]
+	uint16_t tsf_timestamp_31_16             : 16; //[15:0]
+	uint16_t tsf_timestamp_47_32             : 16; //[15:0]
+	uint16_t tsf_timestamp_63_48             : 16; //[15:0]
+	uint16_t user_index                      :  6, //[5:0]
+		 directed                        :  1, //[6]
+		 reserved_13                     :  9; //[15:7]
+};
+
+struct uplink_user_setup_info {
+	uint32_t bw_info_valid                   :  1, //[0]
+		 uplink_receive_type             :  2, //[2:1]
+		 reserved_0a                     :  1, //[3]
+		 uplink_11ax_mcs                 :  4, //[7:4]
+		 ru_width                        :  7, //[14:8]
+		 reserved_0b                     :  1, //[15]
+		 nss                             :  3, //[18:16]
+		 stream_offset                   :  3, //[21:19]
+		 sta_dcm                         :  1, //[22]
+		 sta_coding                      :  1, //[23]
+		 ru_start_index                  :  7, //[30:24]
+		 reserved_0c                     :  1; //[31]
+};
+
+/**
+ * cfr_6018_init_pdev() - Inits cfr pdev and registers necessary handlers.
+ * @psoc: pointer to psoc object
+ * @pdev: pointer to pdev object
+ *
+ * Return: Registration status for necessary handlers
+ */
+QDF_STATUS cfr_6018_init_pdev(
+		struct wlan_objmgr_psoc *psoc,
+		struct wlan_objmgr_pdev *pdev);
+
+/**
+ * cfr_6018_deinit_pdev() - De-inits corresponding pdev and handlers.
+ * @psoc: pointer to psoc object
+ * @pdev: pointer to pdev object
+ *
+ * Return: De-registration status for necessary handlers
+ */
+QDF_STATUS cfr_6018_deinit_pdev(
+		struct wlan_objmgr_psoc *psoc,
+		struct wlan_objmgr_pdev *pdev);
+
+/**
+ * target_if_cfr_start_lut_age_timer() - Start timer to flush aged-out LUT
+ * entries
+ * @pdev: pointer to pdev object
+ *
+ * Return: Success/Failure status
+ */
+QDF_STATUS target_if_cfr_start_lut_age_timer(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * target_if_cfr_stop_lut_age_timer() - Stop timer to flush aged-out LUT
+ * entries
+ * @pdev: pointer to pdev object
+ *
+ * Return: Success/Failure status
+ */
+QDF_STATUS target_if_cfr_stop_lut_age_timer(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * target_if_cfr_dump_lut_enh() - Dump all valid LUT entries
+ * @pdev: objmgr PDEV
+ *
+ * Return: none
+ */
+void target_if_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * target_if_cfr_config_rcc() - Start repetitive channel capture
+ * @pdev: pointer to pdev object
+ * @rcc_param: rcc configurations
+ *
+ * Return: Success/Failure status
+ */
+QDF_STATUS target_if_cfr_config_rcc(struct wlan_objmgr_pdev *pdev,
+				    struct cfr_rcc_param *rcc_param);
+
+/**
+ *  target_if_cfr_default_ta_ra_config() - Configure default values to all
+ *  params(BW/NSS/TA/RA) in TA_RA mode
+ * @rcc_param: rcc configurations
+ * @allvalid: Indicates whether all TA_RA params are valid or not.
+ *            It could be either 0 or 1.
+ *            1: should be sent to FW during CFR initialization
+ *            0: should be set, after a successful commit session.
+ * @reset_cfg: This bitmap is being used to determine which groups'
+ *            parameters are needed to be reset to its default state.
+ */
+void target_if_cfr_default_ta_ra_config(struct cfr_rcc_param *rcc_param,
+					bool allvalid, uint16_t reset_cfg);
+
+/**
+ * target_if_cfr_rx_tlv_process() - Process PPDU status TLVs and store info in
+ * lookup table
+ * @pdev: PDEV object
+ * @nbuf: ppdu info
+ *
+ * Return: none
+ */
+void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf);
+#else
+static QDF_STATUS cfr_6018_init_pdev(
+		struct wlan_objmgr_psoc *psoc,
+		struct wlan_objmgr_pdev *pdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS cfr_6018_deinit_pdev(
+		struct wlan_objmgr_psoc *psoc,
+		struct wlan_objmgr_pdev *pdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+#endif

+ 0 - 12
target_if/cfr/inc/target_if_cfr_8074v2.h

@@ -21,9 +21,6 @@
 
 #define STREAMFS_MAX_SUBBUF_8S 8500
 #define STREAMFS_NUM_SUBBUF_8S 255
-#define PEER_CFR_CAPTURE_EVT_STATUS_MASK 0x80000000
-#define PEER_CFR_CAPTURE_EVT_PS_STATUS_MASK 0x40000000
-#define CFR_TX_EVT_STATUS_MASK           0x00000003
 
 /* Values used for computing number of tones */
 #define TONES_IN_20MHZ  256
@@ -32,15 +29,6 @@
 #define TONES_IN_160MHZ 2048 /* 160 MHz isn't supported yet */
 #define TONES_INVALID   0
 
-/* Status codes used by correlate and relay function */
-#define STATUS_STREAM_AND_RELEASE 0
-#define STATUS_HOLD               1
-#define STATUS_ERROR             -1
-
-/* Module IDs using corrlation function */
-#define CORRELATE_DBR_MODULE_ID   0
-#define CORRELATE_TX_EV_MODULE_ID 1
-
 /**
  * cfr_8074v2_init_pdev() - Inits cfr pdev and registers necessary handlers.
  * @psoc: pointer to psoc object

+ 8 - 1
target_if/cfr/src/target_if_cfr.c

@@ -29,6 +29,7 @@
 #include <wlan_cfr_utils_api.h>
 #include <wlan_objmgr_pdev_obj.h>
 #include <target_if_cfr_8074v2.h>
+#include <target_if_cfr_6018.h>
 
 int target_if_cfr_stop_capture(struct wlan_objmgr_pdev *pdev,
 			       struct wlan_objmgr_peer *peer)
@@ -66,7 +67,8 @@ int target_if_cfr_stop_capture(struct wlan_objmgr_pdev *pdev,
 		return -EINVAL;
 	}
 	cfr_err("CFR capture stats for this capture:");
-	cfr_err("DBR event count = %u, Tx event count = %u Release count = %u",
+	cfr_err("DBR event count = %llu, Tx event count = %llu "
+		"Release count = %llu",
 		pdev_cfrobj->dbr_evt_cnt, pdev_cfrobj->tx_evt_cnt,
 		pdev_cfrobj->release_cnt);
 
@@ -199,6 +201,9 @@ int target_if_cfr_init_pdev(struct wlan_objmgr_psoc *psoc,
 		pa->is_cfr_capable = cfr_sc->is_cfr_capable;
 
 		return cfr_wifi2_0_init_pdev(psoc, pdev);
+	} else if (target_type == TARGET_TYPE_QCA6018) {
+		pa->is_cfr_capable = cfr_sc->is_cfr_capable;
+		return cfr_6018_init_pdev(psoc, pdev);
 	} else
 		return QDF_STATUS_E_NOSUPPORT;
 }
@@ -217,6 +222,8 @@ int target_if_cfr_deinit_pdev(struct wlan_objmgr_psoc *psoc,
 		   (target_type == TARGET_TYPE_QCA9888)) {
 
 		return cfr_wifi2_0_deinit_pdev(psoc, pdev);
+	} else if (target_type == TARGET_TYPE_QCA6018) {
+		return cfr_6018_deinit_pdev(psoc, pdev);
 	} else
 		return QDF_STATUS_E_NOSUPPORT;
 }

+ 1653 - 0
target_if/cfr/src/target_if_cfr_6018.c

@@ -0,0 +1,1653 @@
+/*
+ * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <target_if_cfr.h>
+#include <wlan_tgt_def_config.h>
+#include <target_type.h>
+#include <hif_hw_version.h>
+#include <ol_if_athvar.h>
+#include <target_if.h>
+#include <wlan_lmac_if_def.h>
+#include <wlan_osif_priv.h>
+#include <wlan_mlme_dispatcher.h>
+#include <init_deinit_lmac.h>
+#include <wlan_cfr_utils_api.h>
+#ifdef DIRECT_BUF_RX_ENABLE
+#include <target_if_direct_buf_rx_api.h>
+#endif
+#include <target_if_cfr_6018.h>
+#include "cdp_txrx_ctrl.h"
+
+static u_int32_t end_magic = 0xBEAFDEAD;
+/**
+ * get_lut_entry() - Retrieve LUT entry using cookie number
+ * @pcfr: PDEV CFR object
+ * @offset: cookie number
+ *
+ * Return: look up table entry
+ */
+static struct look_up_table *get_lut_entry(struct pdev_cfr *pcfr,
+					   int offset)
+{
+	if (offset > NUM_LUT_ENTRIES) {
+		cfr_err("Invalid offset\n");
+		return NULL;
+	}
+	return &pcfr->lut[offset];
+}
+
+/**
+ * release_lut_entry_enh() - Clear all params in an LUT entry
+ * @pdev: objmgr PDEV
+ * @lut: pointer to LUT
+ *
+ * Return: status
+ */
+int release_lut_entry_enh(struct wlan_objmgr_pdev *pdev,
+			  struct look_up_table *lut)
+{
+	lut->dbr_recv = false;
+	lut->tx_recv = false;
+	lut->data = NULL;
+	lut->data_len = 0;
+	lut->dbr_ppdu_id = 0;
+	lut->tx_ppdu_id = 0;
+	lut->dbr_tstamp = 0;
+	lut->txrx_tstamp = 0;
+	lut->tx_address1 = 0;
+	lut->tx_address2 = 0;
+	lut->dbr_address = 0;
+	qdf_mem_zero(&lut->header, sizeof(struct csi_cfr_header));
+
+	return 0;
+}
+
+/**
+ * target_if_cfr_dump_lut_enh() - dump all valid lut entries
+ * @pdev: objmgr pdev
+ *
+ * return: none
+ */
+void target_if_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev)
+{
+	struct pdev_cfr *pcfr;
+	struct look_up_table *lut = NULL;
+	int i = 0;
+	uint64_t diff;
+	QDF_STATUS retval = 0;
+
+	retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID);
+	if (retval != QDF_STATUS_SUCCESS) {
+		cfr_err("failed to get pdev reference");
+		return;
+	}
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+	if (!pcfr) {
+		cfr_err("pdev object for CFR is null");
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+		return;
+	}
+
+	for (i = 0; i < NUM_LUT_ENTRIES; i++) {
+		lut = get_lut_entry(pcfr, i);
+		if (!lut)
+			continue;
+		if (lut->dbr_recv ^ lut->tx_recv) {
+			diff = (lut->dbr_tstamp > lut->txrx_tstamp) ?
+				(lut->dbr_tstamp - lut->txrx_tstamp) :
+				(lut->txrx_tstamp - lut->dbr_tstamp);
+			cfr_info("idx:%d dbrevnt: %d txrxevent: %d "
+				 "dbrppdu:0x%x txrxppdu:0x%x dbr_tstamp: %llu "
+				 "txrx_tstamp: %llu diff: %llu\n",
+				 i, lut->dbr_recv, lut->tx_recv,
+				 lut->dbr_ppdu_id, lut->tx_ppdu_id,
+				 lut->dbr_tstamp, lut->txrx_tstamp, diff);
+		}
+
+	}
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+}
+
+/**
+ * cfr_free_pending_dbr_events() - Flush all pending DBR events. This is useful
+ * in cases where for RXTLV drops in host monitor status ring is huge.
+ * @pdev: objmgr pdev
+ *
+ * return: none
+ */
+void cfr_free_pending_dbr_events(struct wlan_objmgr_pdev *pdev)
+{
+	struct pdev_cfr *pcfr;
+	struct look_up_table *lut = NULL;
+	int i = 0;
+	QDF_STATUS retval = 0;
+
+	retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID);
+	if (retval != QDF_STATUS_SUCCESS) {
+		cfr_err("failed to get pdev reference");
+		return;
+	}
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+	if (!pcfr) {
+		cfr_err("pdev object for CFR is null");
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+		return;
+	}
+
+	for (i = 0; i < NUM_LUT_ENTRIES; i++) {
+		lut = get_lut_entry(pcfr, i);
+		if (!lut)
+			continue;
+
+		if (lut->dbr_recv && !lut->tx_recv) {
+			target_if_dbr_buf_release(pdev, DBR_MODULE_CFR,
+						  lut->dbr_address,
+						  i, 0);
+			pcfr->flush_dbr_cnt++;
+			release_lut_entry_enh(pdev, lut);
+		}
+	}
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+}
+
+/**
+ * cfr_free_all_lut_entries() - Flush all pending DBR and TXRX events.
+ * @pdev: objmgr pdev
+ *
+ * return: none
+ */
+void cfr_free_all_lut_entries(struct wlan_objmgr_pdev *pdev)
+{
+	struct pdev_cfr *pcfr;
+	struct look_up_table *lut = NULL;
+	int i = 0;
+	QDF_STATUS retval = 0;
+	qdf_dma_addr_t buf_addr = 0, buf_addr_temp = 0;
+
+	retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID);
+	if (retval != QDF_STATUS_SUCCESS) {
+		cfr_err("failed to get pdev reference");
+		return;
+	}
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+	if (!pcfr) {
+		cfr_err("pdev object for CFR is null");
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+		return;
+	}
+
+	for (i = 0; i < NUM_LUT_ENTRIES; i++) {
+		lut = get_lut_entry(pcfr, i);
+		if (!lut)
+			continue;
+
+		if (lut->dbr_recv && !lut->tx_recv) {
+			target_if_dbr_buf_release(pdev, DBR_MODULE_CFR,
+						  lut->dbr_address,
+						  i, 0);
+			pcfr->flush_all_dbr_cnt++;
+			release_lut_entry_enh(pdev, lut);
+		} else if (lut->tx_recv && !lut->dbr_recv) {
+			buf_addr_temp = (lut->tx_address2 & 0x0f);
+			buf_addr = (lut->tx_address1
+				    | ((uint64_t)buf_addr_temp << 32));
+			target_if_dbr_buf_release(pdev,
+						  DBR_MODULE_CFR,
+						  buf_addr,
+						  i, 0);
+			pcfr->flush_all_txrx_cnt++;
+			release_lut_entry_enh(pdev, lut);
+		}
+	}
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+}
+
+/**
+ * dump_freeze_tlv() - Dump freeze TLV sent in enhanced DMA header
+ * @freeze_tlv: Freeze TLV sent from MAC to PHY
+ * @cookie: Index into lookup table
+ *
+ * Return: none
+ */
+void dump_freeze_tlv(void *freeze_tlv, uint32_t cookie)
+{
+	struct macrx_freeze_capture_channel *freeze =
+		(struct macrx_freeze_capture_channel *)freeze_tlv;
+
+	cfr_debug("<DBRCOMP><FREEZE><%u>\n"
+		  "freeze: %d capture_reason: %d packet_type: 0x%x\n"
+		  "packet_subtype: 0x%x sw_peer_id_valid: %d sw_peer_id: %d\n"
+		  "phy_ppdu_id: 0x%04x packet_ta_upper_16: 0x%04x\n"
+		  "packet_ta_mid_16: 0x%04x packet_ta_lower_16: 0x%04x\n"
+		  "packet_ra_upper_16: 0x%04x packet_ra_mid_16: 0x%04x\n"
+		  "packet_ra_lower_16: 0x%04x tsf_timestamp_63_48: 0x%04x\n"
+		  "tsf_timestamp_47_32: 0x%04x tsf_timestamp_31_16: 0x%04x\n"
+		  "tsf_timestamp_15_0: 0x%04x user_index: %d directed: %d\n",
+		  cookie,
+		  freeze->freeze,
+		  freeze->capture_reason,
+		  freeze->packet_type,
+		  freeze->packet_sub_type,
+		  freeze->sw_peer_id_valid,
+		  freeze->sw_peer_id,
+		  freeze->phy_ppdu_id,
+		  freeze->packet_ta_upper_16,
+		  freeze->packet_ta_mid_16,
+		  freeze->packet_ta_lower_16,
+		  freeze->packet_ra_upper_16,
+		  freeze->packet_ra_mid_16,
+		  freeze->packet_ra_lower_16,
+		  freeze->tsf_timestamp_63_48,
+		  freeze->tsf_timestamp_47_32,
+		  freeze->tsf_timestamp_31_16,
+		  freeze->tsf_timestamp_15_0,
+		  freeze->user_index,
+		  freeze->directed);
+}
+
+/**
+ * dump_mu_rx_info() - Dump MU info in enhanced DMA header
+ * @mu_rx_user_info: MU info sent by ucode
+ * @mu_rx_num_users: Number of MU users in UL-MU-PPDU
+ * @cookie: Index into lookup table
+ *
+ * Return: none
+ */
+void dump_mu_rx_info(void *mu_rx_user_info, uint8_t mu_rx_num_users,
+		     uint32_t cookie)
+{
+	uint8_t i;
+	struct uplink_user_setup_info *ul_mu_user_info =
+		(struct uplink_user_setup_info *) mu_rx_user_info;
+
+	for (i = 0 ; i < mu_rx_num_users; i++) {
+		cfr_debug("<DBRCOMP><MU><%u>\n"
+			  "<user_id:%d>\n"
+			  "bw_info_valid = %d\n"
+			  "uplink_receive_type = %d\n"
+			  "uplink_11ax_mcs = %d\n"
+			  "ru_width = %d\n"
+			  "nss = %d\n"
+			  "stream_offset = %d\n"
+			  "sta_dcm = %d\n"
+			  "sta_coding = %d\n"
+			  "ru_start_index = %d\n",
+			  cookie,
+			  i,
+			  ul_mu_user_info->bw_info_valid,
+			  ul_mu_user_info->uplink_receive_type,
+			  ul_mu_user_info->uplink_11ax_mcs,
+			  ul_mu_user_info->ru_width,
+			  ul_mu_user_info->nss,
+			  ul_mu_user_info->stream_offset,
+			  ul_mu_user_info->sta_dcm,
+			  ul_mu_user_info->sta_coding,
+			  ul_mu_user_info->ru_start_index);
+		ul_mu_user_info += sizeof(struct uplink_user_setup_info);
+	}
+}
+
+void dump_metadata(struct csi_cfr_header *header, uint32_t cookie)
+{
+	uint8_t user_id, chain_id;
+	struct cfr_metadata_version_3 *meta = &header->u.meta_v3;
+	uint8_t *usermac = NULL;
+
+	cfr_debug("<METADATA><%u>\n"
+		  "start_magic_num = %d\n"
+		  "vendorid = %d\n"
+		  "cfr_metadata_version = %d\n"
+		  "cfr_data_version = %d\n"
+		  "chip_type = %d\n"
+		  "platform_type = %d\n"
+		  "status = %d\n"
+		  "capture_bw = %d\n"
+		  "channel_bw = %d\n"
+		  "phy_mode = %d\n"
+		  "prim20_chan = %d\n"
+		  "center_freq1 = %d\n"
+		  "center_freq2 = %d\n"
+		  "ack_capture_mode = %d\n"
+		  "cfr_capture_type = %d\n"
+		  "sts_count = %d\n"
+		  "num_rx_chain = %d\n"
+		  "timestamp = %d\n"
+		  "length = %d\n"
+		  "is_mu_ppdu = %d\n"
+		  "num_users = %d\n",
+		cookie,
+		header->start_magic_num,
+		header->vendorid,
+		header->cfr_metadata_version,
+		header->cfr_data_version,
+		header->chip_type,
+		header->pltform_type,
+		meta->status,
+		meta->capture_bw,
+		meta->channel_bw,
+		meta->phy_mode,
+		meta->prim20_chan,
+		meta->center_freq1,
+		meta->center_freq2,
+		meta->capture_mode,
+		meta->capture_type,
+		meta->sts_count,
+		meta->num_rx_chain,
+		meta->timestamp,
+		meta->length,
+		meta->is_mu_ppdu,
+		meta->num_mu_users);
+
+	if (meta->is_mu_ppdu) {
+		for (user_id = 0; user_id < meta->num_mu_users; user_id++) {
+			usermac = meta->peer_addr.mu_peer_addr[user_id];
+			cfr_debug("peermac[%d]: %s\n",
+				  user_id,
+				  ether_sprintf(usermac));
+		}
+	} else {
+		cfr_debug("peermac: %s\n",
+			  ether_sprintf(meta->peer_addr.su_peer_addr));
+	}
+
+	for (chain_id = 0; chain_id < HOST_MAX_CHAINS; chain_id++) {
+		cfr_debug("chain_rssi[%d] = %d\n",
+			  chain_id,
+			  meta->chain_rssi[chain_id]);
+	}
+
+	for (chain_id = 0; chain_id < HOST_MAX_CHAINS; chain_id++) {
+		cfr_debug("chain_phase[%d] = %d\n",
+			  chain_id,
+			  meta->chain_phase[chain_id]);
+	}
+}
+/**
+ * dump_enh_dma_hdr() - Dump enhanced DMA header populated by ucode
+ * @dma_hdr: pointer to enhanced DMA header
+ * @freeze_tlv: pointer to MACRX_FREEZE_CAPTURE_CHANNEL TLV
+ * @mu_rx_user_info: UPLINK_USER_SETUP_INFO TLV
+ * @header: pointer to metadata passed to userspace
+ * @error: Indicates whether it is an error
+ * @cookie: Index into lookup table
+ *
+ * Return: none
+ */
+void dump_enh_dma_hdr(struct whal_cfir_enhanced_hdr *dma_hdr,
+		      void *freeze_tlv,
+		      void *mu_rx_user_info,
+		      struct csi_cfr_header *header,
+		      int error,
+		      uint32_t cookie)
+{
+	if (!error) {
+		cfr_debug("<DBRCOMP><%u>\n"
+			  "Tag: 0x%02x Length: %d udone: %d\n"
+			  "ctype: %d preamble: %d Nss: %d\n"
+			  "num_chains: %d bw: %d peervalid: %d\n"
+			  "peer_id: %d ppdu_id: 0x%04x total_bytes: %d\n"
+			  "header_version: %d target_id: %d cfr_fmt: %d\n"
+			  "mu_rx_data_incl: %d freeze_data_incl: %d\n"
+			  "mu_rx_num_users: %d decimation_factor: %d\n",
+			  cookie,
+			  dma_hdr->tag,
+			  dma_hdr->length,
+			  dma_hdr->upload_done,
+			  dma_hdr->capture_type,
+			  dma_hdr->preamble_type,
+			  dma_hdr->nss,
+			  dma_hdr->num_chains,
+			  dma_hdr->upload_pkt_bw,
+			  dma_hdr->sw_peer_id_valid,
+			  dma_hdr->sw_peer_id,
+			  dma_hdr->phy_ppdu_id,
+			  dma_hdr->total_bytes,
+			  dma_hdr->header_version,
+			  dma_hdr->target_id,
+			  dma_hdr->cfr_fmt,
+			  dma_hdr->mu_rx_data_incl,
+			  dma_hdr->freeze_data_incl,
+			  dma_hdr->mu_rx_num_users,
+			  dma_hdr->decimation_factor);
+
+		if (dma_hdr->freeze_data_incl)
+			dump_freeze_tlv(freeze_tlv, cookie);
+
+		if (dma_hdr->mu_rx_data_incl)
+			dump_mu_rx_info(mu_rx_user_info,
+					dma_hdr->mu_rx_num_users,
+					cookie);
+	} else {
+		cfr_err("<DBRCOMP><%u>\n"
+			"Tag: 0x%02x Length: %d udone: %d\n"
+			"ctype: %d preamble: %d Nss: %d\n"
+			"num_chains: %d bw: %d peervalid: %d\n"
+			"peer_id: %d ppdu_id: 0x%04x total_bytes: %d\n"
+			"header_version: %d target_id: %d cfr_fmt: %d\n"
+			"mu_rx_data_incl: %d freeze_data_incl: %d\n"
+			"mu_rx_num_users: %d decimation_factor: %d\n",
+			cookie,
+			dma_hdr->tag,
+			dma_hdr->length,
+			dma_hdr->upload_done,
+			dma_hdr->capture_type,
+			dma_hdr->preamble_type,
+			dma_hdr->nss,
+			dma_hdr->num_chains,
+			dma_hdr->upload_pkt_bw,
+			dma_hdr->sw_peer_id_valid,
+			dma_hdr->sw_peer_id,
+			dma_hdr->phy_ppdu_id,
+			dma_hdr->total_bytes,
+			dma_hdr->header_version,
+			dma_hdr->target_id,
+			dma_hdr->cfr_fmt,
+			dma_hdr->mu_rx_data_incl,
+			dma_hdr->freeze_data_incl,
+			dma_hdr->mu_rx_num_users,
+			dma_hdr->decimation_factor);
+	}
+}
+
+
+/**
+ * extract_peer_mac_from_freeze_tlv() - extract macaddr from freeze tlv
+ * @freeze_tlv: Freeze TLV sent from MAC to PHY
+ * @peermac: macaddr of the peer
+ *
+ * Return: none
+ */
+void extract_peer_mac_from_freeze_tlv(void *freeze_tlv, uint8_t *peermac)
+{
+	struct macrx_freeze_capture_channel *freeze =
+		(struct macrx_freeze_capture_channel *)freeze_tlv;
+
+	if (freeze->sw_peer_id_valid) {
+		peermac[0] = freeze->packet_ta_lower_16 & 0x00FF;
+		peermac[1] = (freeze->packet_ta_lower_16 & 0xFF00) >> 8;
+		peermac[2] = freeze->packet_ta_mid_16 & 0x00FF;
+		peermac[3] = (freeze->packet_ta_mid_16 & 0xFF00) >> 8;
+		peermac[4] = freeze->packet_ta_upper_16 & 0x00FF;
+		peermac[5] = (freeze->packet_ta_upper_16 & 0xFF00) >> 8;
+	}
+}
+
+/**
+ * check_dma_length() - Sanity check DMA header and payload length
+ * @dma_hdr: pointer to enhanced DMA header
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS check_dma_length(struct look_up_table *lut)
+{
+	if (lut->header_length <= CYP_MAX_HEADER_LENGTH_WORDS &&
+	    lut->payload_length <= CYP_MAX_DATA_LENGTH_BYTES) {
+		return QDF_STATUS_SUCCESS;
+	} else {
+		return QDF_STATUS_E_FAILURE;
+	}
+}
+
+/**
+ * correlate_and_relay_enh() - Correlate TXRX and DBR events and stream CFR
+ * data to userspace
+ * @pdev: objmgr PDEV
+ * @cookie: Index into lookup table
+ * @lut: pointer to lookup table
+ * @module_id: ID of the event received
+ *  0 - DBR event
+ *  1 - TXRX event
+ *
+ * Return:
+ *	- STATUS_ERROR
+ *	- STATUS_HOLD
+ *	- STATUS_STREAM_AND_RELEASE
+ */
+int correlate_and_relay_enh(struct wlan_objmgr_pdev *pdev, uint32_t cookie,
+			    struct look_up_table *lut, uint8_t module_id)
+{
+	struct pdev_cfr *pcfr;
+	uint64_t diff;
+	int status = STATUS_ERROR;
+
+	if (module_id > 1) {
+		cfr_err("Received request with invalid mod id. Investigate!!");
+		QDF_ASSERT(0);
+		status = STATUS_ERROR;
+		goto done;
+	}
+
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+
+	if (module_id == CORRELATE_TXRX_EV_MODULE_ID) {
+		lut->tx_recv = true;
+	} else if (module_id == CORRELATE_DBR_MODULE_ID) {
+		pcfr->dbr_evt_cnt++;
+		lut->dbr_recv = true;
+	}
+
+	if ((lut->dbr_recv == true) && (lut->tx_recv == true)) {
+		if (lut->dbr_ppdu_id == lut->tx_ppdu_id) {
+
+			if (lut->dbr_tstamp > lut->txrx_tstamp) {
+				diff = lut->dbr_tstamp - lut->txrx_tstamp;
+				cfr_debug("<CORRELATE><%u>: "
+					  "TXRX evt -> DBR evt"
+					  "(delay = %llu ms)\n", cookie, diff);
+			} else if (lut->txrx_tstamp > lut->dbr_tstamp) {
+				diff = lut->txrx_tstamp - lut->dbr_tstamp;
+				cfr_debug("<CORRELATE><%u>: "
+					  "DBR evt -> TXRX evt"
+					  "(delay = %llu ms)\n", cookie, diff);
+			}
+
+			/*
+			 * Flush pending dbr events, if newer PPDU TLV is
+			 * received
+			 */
+			cfr_free_pending_dbr_events(pdev);
+
+			if (check_dma_length(lut) == QDF_STATUS_SUCCESS) {
+				pcfr->release_cnt++;
+				cfr_debug("<CORRELATE><%u>:Stream and release "
+					  "CFR data for "
+					  "ppdu_id:0x%04x\n", cookie,
+					  lut->tx_ppdu_id);
+				status = STATUS_STREAM_AND_RELEASE;
+				goto done;
+			} else {
+				pcfr->invalid_dma_length_cnt++;
+				cfr_err("<CORRELATE><%u>:CFR buffers "
+					"received with invalid length "
+					"length : ppdu_id:0x%04x\n",
+					cookie, lut->tx_ppdu_id);
+				/*
+				 * Assert here as length exceeding the allowed
+				 * limit would anyway manifest as random crash
+				 */
+				QDF_ASSERT(0);
+				status = STATUS_ERROR;
+				goto done;
+			}
+		} else {
+			/*
+			 * When there is a ppdu id mismatch, discard the TXRX
+			 * event since multiple PPDUs are likely to have same
+			 * dma addr, due to ucode aborts
+			 */
+			if (module_id == CORRELATE_TXRX_EV_MODULE_ID) {
+				cfr_debug("Received new tx event for same "
+					  "cookie %u",
+					  cookie);
+				lut->dbr_recv = false;
+				lut->data = NULL;
+				lut->data_len = 0;
+				lut->dbr_ppdu_id = 0;
+				qdf_mem_zero(&lut->dbr_address,
+					     sizeof(lut->dbr_address));
+				pcfr->clear_dbr_event++;
+			} else if (module_id == CORRELATE_DBR_MODULE_ID) {
+				cfr_debug("Received new dbr event for same "
+					  "cookie %u",
+					  cookie);
+				lut->tx_recv = false;
+				lut->tx_ppdu_id = 0;
+				pcfr->clear_txrx_event++;
+			}
+			status = STATUS_HOLD;
+		}
+	} else {
+		status = STATUS_HOLD;
+	}
+done:
+	return status;
+}
+
+/**
+ * target_if_cfr_rx_tlv_process() - Process PPDU status TLVs and store info in
+ * lookup table
+ * @pdev_obj: PDEV object
+ * @nbuf: ppdu info
+ *
+ * Return: none
+ */
+void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
+{
+	struct cdp_rx_indication_ppdu *cdp_rx_ppdu;
+	struct cdp_rx_stats_ppdu_user *rx_stats_peruser;
+	struct cdp_rx_ppdu_cfr_info *cfr_info;
+	qdf_dma_addr_t buf_addr = 0, buf_addr_temp = 0;
+	struct pdev_cfr *pcfr;
+	struct look_up_table *lut = NULL;
+	struct csi_cfr_header *header = NULL;
+	uint32_t cookie;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_channel *bss_chan;
+	enum wlan_phymode ch_phymode;
+	enum phy_ch_width ch_width;
+	uint16_t ch_freq;
+	uint32_t ch_cfreq1;
+	uint32_t ch_cfreq2;
+	uint8_t rx_chainmask;
+	struct wlan_objmgr_vdev *vdev = NULL;
+	int i, status = 0;
+	QDF_STATUS retval = 0;
+	struct wlan_lmac_if_cfr_rx_ops *cfr_rx_ops = NULL;
+	struct cfr_metadata_version_3 *meta = NULL;
+
+	if (qdf_unlikely(!pdev)) {
+		cfr_err("pdev is null\n");
+		qdf_nbuf_free(nbuf);
+		return;
+	}
+
+	retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID);
+	if (qdf_unlikely(retval != QDF_STATUS_SUCCESS)) {
+		cfr_err("failed to get pdev reference");
+		qdf_nbuf_free(nbuf);
+		return;
+	}
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+	if (qdf_unlikely(!pcfr)) {
+		cfr_err("pdev object for CFR is NULL");
+		goto done;
+	}
+
+	cdp_rx_ppdu = (struct cdp_rx_indication_ppdu *)qdf_nbuf_data(nbuf);
+	cfr_info = &cdp_rx_ppdu->cfr_info;
+	if (cfr_info->bb_captured_timeout) {
+		pcfr->bb_captured_timeout_cnt++;
+		pcfr->bb_captured_reason_cnt[cfr_info->bb_captured_reason]++;
+		goto done;
+	}
+
+
+	if (cfr_info->bb_captured_channel) {
+		pcfr->bb_captured_channel_cnt++;
+		pcfr->bb_captured_reason_cnt[cfr_info->bb_captured_reason]++;
+	} else {
+		goto done; /* HW registers have not captured FFT bins */
+	}
+
+	if (cfr_info->rx_location_info_valid) {
+		pcfr->rx_loc_info_valid_cnt++;
+	} else {
+		goto done;
+	}
+
+	pcfr->chan_capture_status[cfr_info->chan_capture_status]++;
+
+	if (cfr_info->chan_capture_status != CAPTURE_ACTIVE) {
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+		qdf_nbuf_free(nbuf);
+		return;
+	}
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (qdf_unlikely(!psoc)) {
+		cfr_err("psoc is null\n");
+		goto done;
+	}
+
+	cfr_rx_ops = &psoc->soc_cb.rx_ops.cfr_rx_ops;
+	buf_addr_temp = cfr_info->rtt_che_buffer_pointer_high8;
+	buf_addr = (cfr_info->rtt_che_buffer_pointer_low32 |
+		    ((uint64_t)buf_addr_temp << 32));
+
+
+	if (target_if_dbr_cookie_lookup(pdev, DBR_MODULE_CFR, buf_addr,
+					&cookie, 0)) {
+		cfr_debug("Cookie lookup failure for addr: 0x%pK",
+			  (void *)((uintptr_t)buf_addr));
+		goto done;
+	}
+
+	cfr_debug("<RXTLV><%u>:buffer address: 0x%pK \n"
+		  "<WIFIRX_PPDU_START_E> ppdu_id: 0x%04x\n"
+		  "<WIFIRXPCU_PPDU_END_INFO_E> BB_CAPTURED_CHANNEL = %d\n"
+		  "<WIFIPHYRX_PKT_END_E> RX_LOCATION_INFO_VALID = %d\n"
+		  "<WIFIPHYRX_PKT_END_E> RTT_CHE_BUFFER_POINTER_LOW32 = %x\n"
+		  "<WIFIPHYRX_PKT_END_E> RTT_CHE_BUFFER_POINTER_HIGH8 = %x\n"
+		  "<WIFIPHYRX_PKT_END_E> CHAN_CAPTURE_STATUS = %d\n",
+		  cookie,
+		  (void *)((uintptr_t)buf_addr),
+		  cdp_rx_ppdu->ppdu_id,
+		  cfr_info->bb_captured_channel,
+		  cfr_info->rx_location_info_valid,
+		  cfr_info->rtt_che_buffer_pointer_low32,
+		  cfr_info->rtt_che_buffer_pointer_high8,
+		  cfr_info->chan_capture_status);
+
+	lut = get_lut_entry(pcfr, cookie);
+	if (qdf_unlikely(!lut)) {
+		cfr_err("lut is NULL");
+		goto done;
+	}
+
+	vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_CFR_ID);
+	if (qdf_unlikely(!vdev)) {
+		cfr_err("vdev is null\n");
+		goto done;
+	}
+
+	bss_chan = wlan_vdev_mlme_get_bss_chan(vdev);
+	ch_freq = bss_chan->ch_freq;
+	ch_cfreq1 = bss_chan->ch_cfreq1;
+	ch_cfreq2 = bss_chan->ch_cfreq2;
+	ch_phymode = bss_chan->ch_phymode;
+	ch_width = bss_chan->ch_width;
+	rx_chainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID);
+
+	pcfr->rx_tlv_evt_cnt++;
+	lut->tx_ppdu_id = cdp_rx_ppdu->ppdu_id;
+	lut->tx_address1 = cfr_info->rtt_che_buffer_pointer_low32;
+	lut->tx_address2 = cfr_info->rtt_che_buffer_pointer_high8;
+	lut->txrx_tstamp = qdf_ktime_to_ms(qdf_ktime_get());
+	header = &lut->header;
+	meta = &header->u.meta_v3;
+
+	header->start_magic_num        = 0xDEADBEAF;
+	header->vendorid               = 0x8cfdf0;
+	header->cfr_metadata_version   = CFR_META_VERSION_3;
+	header->cfr_data_version       = CFR_DATA_VERSION_1;
+	header->chip_type              = CFR_CAPTURE_RADIO_CYP;
+	header->pltform_type           = CFR_PLATFORM_TYPE_ARM;
+	header->Reserved               = 0;
+
+	meta->status       = 1;
+	meta->capture_bw   = ch_width;
+	meta->phy_mode = ch_phymode;
+	meta->prim20_chan  = ch_freq;
+	meta->center_freq1 = ch_cfreq1;
+	meta->center_freq2 = ch_cfreq2;
+	meta->capture_mode = 0;
+	meta->num_rx_chain = rx_chainmask;
+
+	meta->timestamp = cdp_rx_ppdu->timestamp;
+	meta->is_mu_ppdu = (cdp_rx_ppdu->u.ppdu_type == CDP_RX_TYPE_SU) ? 0 : 1;
+	meta->num_mu_users = (meta->is_mu_ppdu) ? (cdp_rx_ppdu->num_users) : 0;
+
+	if (meta->num_mu_users > CYP_CFR_MU_USERS)
+		meta->num_mu_users = CYP_CFR_MU_USERS;
+
+	for (i = 0; i < MAX_CHAIN; i++)
+		meta->chain_rssi[i] = cdp_rx_ppdu->per_chain_rssi[i];
+
+	if (cdp_rx_ppdu->u.ppdu_type == CDP_RX_TYPE_SU) {
+		qdf_mem_copy(meta->peer_addr.su_peer_addr,
+			     cdp_rx_ppdu->mac_addr,
+			     QDF_MAC_ADDR_SIZE);
+	} else {
+		for (i = 0 ; i < meta->num_mu_users; i++) {
+			rx_stats_peruser = &cdp_rx_ppdu->user[i];
+			qdf_mem_copy(meta->peer_addr.mu_peer_addr[i],
+				     rx_stats_peruser->mac_addr,
+				     QDF_MAC_ADDR_SIZE);
+		}
+	}
+	status = correlate_and_relay_enh(pdev, cookie, lut,
+					 CORRELATE_TXRX_EV_MODULE_ID);
+	if (status == STATUS_STREAM_AND_RELEASE) {
+		if (cfr_rx_ops->cfr_info_send)
+			status = cfr_rx_ops->cfr_info_send(pdev,
+							   &lut->header,
+							   sizeof(struct
+							   csi_cfr_header),
+							   lut->data,
+							   lut->data_len,
+							   &end_magic, 4);
+		dump_metadata(header, cookie);
+		release_lut_entry_enh(pdev, lut);
+		target_if_dbr_buf_release(pdev, DBR_MODULE_CFR, buf_addr,
+					  cookie, 0);
+		cfr_debug("Data sent to upper layers, release look up table");
+	} else if (status == STATUS_HOLD) {
+		cfr_debug("HOLD for buffer address: 0x%pK cookie: %u",
+			  (void *)((uintptr_t)buf_addr), cookie);
+	} else {
+		cfr_err("Correlation returned invalid status!!");
+	}
+done:
+	qdf_nbuf_free(nbuf);
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+}
+
+/**
+ * freeze_reason_to_capture_type() - Convert capture type enum in freeze tlv
+ * to the cfr type enum shared with userspace
+ * @freeze_tlv: pointer to MACRX_FREEZE_CAPTURE_CHANNEL TLV
+ *
+ * Return: cfr type enum
+ */
+uint8_t freeze_reason_to_capture_type(void *freeze_tlv)
+{
+	struct macrx_freeze_capture_channel *freeze =
+		(struct macrx_freeze_capture_channel *)freeze_tlv;
+
+	switch (freeze->capture_reason) {
+	case FREEZE_REASON_TM:
+		return CFR_TYPE_METHOD_TM;
+	case FREEZE_REASON_FTM:
+		return CFR_TYPE_METHOD_FTM;
+	case FREEZE_REASON_TA_RA_TYPE_FILTER:
+		return CFR_TYPE_METHOD_TA_RA_TYPE_FILTER;
+	case FREEZE_REASON_NDPA_NDP:
+		return CFR_TYPE_METHOD_NDPA_NDP;
+	case FREEZE_REASON_ALL_PACKET:
+		return CFR_TYPE_METHOD_ALL_PACKET;
+	case FREEZE_REASON_ACK_RESP_TO_TM_FTM:
+		return CFR_TYPE_METHOD_ACK_RESP_TO_TM_FTM;
+	default:
+		return CFR_TYPE_METHOD_AUTO;
+	}
+	return CFR_TYPE_METHOD_AUTO;
+}
+
+#ifdef DIRECT_BUF_RX_ENABLE
+/**
+ * enh_cfr_dbr_event_handler() - Process DBR event for CFR data DMA completion
+ * @pdev: PDEV object
+ * @payload: pointer to CFR data
+ *
+ * Return: status
+ */
+bool enh_cfr_dbr_event_handler(struct wlan_objmgr_pdev *pdev,
+			       struct direct_buf_rx_data *payload)
+{
+	uint8_t *data = NULL;
+	uint32_t cookie = 0;
+	struct whal_cfir_enhanced_hdr dma_hdr = {0};
+	int  length, status = 0;
+	struct wlan_objmgr_psoc *psoc;
+	struct pdev_cfr *pcfr;
+	struct look_up_table *lut = NULL;
+	struct csi_cfr_header *header = NULL;
+	void *mu_rx_user_info = NULL, *freeze_tlv = NULL;
+	uint8_t capture_type;
+	uint8_t *peer_macaddr = NULL;
+	struct wlan_lmac_if_cfr_rx_ops *cfr_rx_ops = NULL;
+	struct cfr_metadata_version_3 *meta = NULL;
+
+	if ((!pdev) || (!payload)) {
+		cfr_err("pdev or payload is null");
+		return true;
+	}
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		cfr_err("psoc is null");
+		return true;
+	}
+
+	cfr_rx_ops = &psoc->soc_cb.rx_ops.cfr_rx_ops;
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+	if (!pcfr) {
+		cfr_err("pdev object for CFR is null");
+		return true;
+	}
+
+	data = payload->vaddr;
+	cookie = payload->cookie;
+
+	cfr_debug("<DBRCOMP><%u>:bufferaddr: 0x%pK cookie: %u\n", cookie,
+		  (void *)((uintptr_t)payload->paddr), cookie);
+
+	qdf_mem_copy(&dma_hdr, &data[0],
+		     sizeof(struct whal_cfir_enhanced_hdr));
+
+	if (dma_hdr.freeze_data_incl) {
+		freeze_tlv = data + sizeof(struct whal_cfir_enhanced_hdr);
+		capture_type = freeze_reason_to_capture_type(freeze_tlv);
+	}
+
+	if (dma_hdr.mu_rx_data_incl) {
+		mu_rx_user_info = data +
+			sizeof(struct whal_cfir_enhanced_hdr) +
+			(dma_hdr.freeze_data_incl ?
+			 sizeof(struct macrx_freeze_capture_channel) : 0);
+	}
+
+
+	length  = dma_hdr.length * 4;
+	length += dma_hdr.total_bytes; /* size of cfr data */
+
+	lut = get_lut_entry(pcfr, cookie);
+	if (!lut) {
+		cfr_err("lut is NULL");
+		return true;
+	}
+
+	lut->data = data;
+	lut->data_len = length;
+	lut->dbr_ppdu_id = dma_hdr.phy_ppdu_id;
+	lut->dbr_address = payload->paddr;
+	lut->dbr_tstamp = qdf_ktime_to_ms(qdf_ktime_get());
+	lut->header_length = dma_hdr.length;
+	lut->payload_length = dma_hdr.total_bytes;
+	qdf_mem_copy(&lut->dma_hdr, &dma_hdr,
+		     sizeof(struct whal_cfir_dma_hdr));
+
+	header = &lut->header;
+	meta = &header->u.meta_v3;
+	meta->channel_bw = dma_hdr.upload_pkt_bw;
+	meta->length = length;
+	/* For Tx based captures, capture type is sent from FW */
+	if (capture_type != CFR_TYPE_METHOD_ACK_RESP_TO_TM_FTM) {
+		meta->capture_type = capture_type;
+		meta->sts_count = (dma_hdr.nss + 1);
+		if (!dma_hdr.mu_rx_data_incl) {
+			/* extract peer addr from freeze tlv */
+			peer_macaddr =
+				meta->peer_addr.su_peer_addr;
+			extract_peer_mac_from_freeze_tlv(freeze_tlv,
+							 peer_macaddr);
+		}
+	}
+
+	dump_enh_dma_hdr(&dma_hdr, freeze_tlv, mu_rx_user_info,
+			 header, 0, cookie);
+	status = correlate_and_relay_enh(pdev, cookie, lut,
+					 CORRELATE_DBR_MODULE_ID);
+	if (status == STATUS_STREAM_AND_RELEASE) {
+		/*
+		 * Message format
+		 *  Meta data Header + actual payload + trailer
+		 */
+		if (cfr_rx_ops->cfr_info_send)
+			status = cfr_rx_ops->cfr_info_send(pdev,
+							   &lut->header,
+							   sizeof(struct
+							   csi_cfr_header),
+							   lut->data,
+							   lut->data_len,
+							   &end_magic, 4);
+		dump_metadata(header, cookie);
+		release_lut_entry_enh(pdev, lut);
+		cfr_debug("Data sent to upper layers, released look up table");
+		status = true;
+	} else if (status == STATUS_HOLD) {
+		cfr_debug("TxRx event not received yet. "
+			  "Buffer is not released");
+		status = false;
+	} else {
+		cfr_err("Correlation returned invalid status!!");
+		status = true;
+	}
+
+	return status;
+}
+
+/**
+ * target_if_register_to_dbr_enh() - Initialize DBR ring and register callback
+ * for DBR events
+ * @pdev: PDEV object
+ *
+ * Return: status
+ */
+QDF_STATUS
+target_if_register_to_dbr_enh(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_lmac_if_direct_buf_rx_tx_ops *dbr_tx_ops = NULL;
+	struct dbr_module_config dbr_config;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	dbr_tx_ops = &psoc->soc_cb.tx_ops.dbr_tx_ops;
+	dbr_config.num_resp_per_event = DBR_NUM_RESP_PER_EVENT_CFR;
+	dbr_config.event_timeout_in_ms = DBR_EVENT_TIMEOUT_IN_MS_CFR;
+	if (dbr_tx_ops->direct_buf_rx_module_register) {
+		return dbr_tx_ops->direct_buf_rx_module_register
+			(pdev, DBR_MODULE_CFR, &dbr_config,
+			 enh_cfr_dbr_event_handler);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * target_if_unregister_to_dbr_enh() - Unregister callback for DBR events
+ * @pdev: PDEV object
+ *
+ * Return: status
+ */
+QDF_STATUS
+target_if_unregister_to_dbr_enh(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_lmac_if_direct_buf_rx_tx_ops *dbr_tx_ops = NULL;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	dbr_tx_ops = &psoc->soc_cb.tx_ops.dbr_tx_ops;
+	if (dbr_tx_ops->direct_buf_rx_module_register) {
+		return dbr_tx_ops->direct_buf_rx_module_unregister
+			(pdev, DBR_MODULE_CFR);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * dump_cfr_peer_tx_event_enh() - Dump TX completion event
+ * @event: ptr to WMI TX completion event for QOS frames sent during
+ * one-shot capture
+ * @cookie: Index into lookup table
+ *
+ * Return: none
+ */
+void dump_cfr_peer_tx_event_enh(wmi_cfr_peer_tx_event_param *event,
+				uint32_t cookie)
+{
+	cfr_debug("<TXCOMP><%u>CFR capture method: %d vdev_id: %d mac: %s\n",
+		  cookie,
+		  event->capture_method, event->vdev_id,
+		  ether_sprintf(&event->peer_mac_addr.bytes[0]));
+
+	cfr_debug("<TXCOMP><%u>Chan: %d bw: %d phymode: %d cfreq1: %d cfrq2: %d "
+		  "nss: %d\n",
+		  cookie,
+		  event->primary_20mhz_chan, event->bandwidth,
+		  event->phy_mode, event->band_center_freq1,
+		  event->band_center_freq2, event->spatial_streams);
+
+	cfr_debug("<TXCOMP><%u>Correlation_info1: 0x%08x "
+		  "Correlation_info2: 0x%08x\n",
+		  cookie,
+		  event->correlation_info_1, event->correlation_info_2);
+
+	cfr_debug("<TXCOMP><%u>status: 0x%x ts: %d counter: %d rssi0: 0x%08x\n",
+		  cookie,
+		  event->status, event->timestamp_us, event->counter,
+		  event->chain_rssi[0]);
+}
+
+#ifdef DIRECT_BUF_RX_ENABLE
+/**
+ * enh_prepare_cfr_header_txstatus() - Prepare CFR metadata for TX failures
+ * @tx_evt_param: ptr to WMI TX completion event
+ * @header: pointer to metadata
+ *
+ * Return: none
+ */
+static void enh_prepare_cfr_header_txstatus(wmi_cfr_peer_tx_event_param
+					    *tx_evt_param,
+					    struct csi_cfr_header *header)
+{
+	header->start_magic_num        = 0xDEADBEAF;
+	header->vendorid               = 0x8cfdf0;
+	header->cfr_metadata_version   = CFR_META_VERSION_3;
+	header->cfr_data_version       = CFR_DATA_VERSION_1;
+	header->chip_type              = CFR_CAPTURE_RADIO_CYP;
+	header->pltform_type           = CFR_PLATFORM_TYPE_ARM;
+	header->Reserved               = 0;
+	header->u.meta_v3.status       = 0; /* failure */
+	header->u.meta_v3.length       = 0;
+
+	qdf_mem_copy(&header->u.meta_v2.peer_addr[0],
+		     &tx_evt_param->peer_mac_addr.bytes[0], QDF_MAC_ADDR_SIZE);
+
+}
+
+/**
+ * target_if_peer_capture_event() - WMI TX completion event for one-shot
+ * capture
+ * @sc: pointer to offload soc object
+ * @data: WMI TX completion event buffer
+ * @datalen: WMI Tx completion event buffer length
+ *
+ * Return: status
+ */
+static int
+target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
+{
+	QDF_STATUS retval = 0;
+	ol_ath_soc_softc_t *scn = (ol_ath_soc_softc_t *)sc;
+	struct wmi_unified *wmi_handle;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_vdev *vdev;
+	uint32_t cookie;
+	struct pdev_cfr *pcfr;
+	struct look_up_table *lut = NULL;
+	struct csi_cfr_header *header = NULL;
+	struct csi_cfr_header header_error = {0};
+	wmi_cfr_peer_tx_event_param tx_evt_param = {0};
+	qdf_dma_addr_t buf_addr = 0, buf_addr_temp = 0;
+	int status;
+	struct wlan_channel *bss_chan;
+	struct wlan_lmac_if_cfr_rx_ops *cfr_rx_ops = NULL;
+
+	psoc = scn->psoc_obj;
+	if (!psoc) {
+		cfr_err("psoc is null");
+		return -EINVAL;
+	}
+
+	cfr_rx_ops = &psoc->soc_cb.rx_ops.cfr_rx_ops;
+
+	retval = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_CFR_ID);
+	if (QDF_IS_STATUS_ERROR(retval)) {
+		cfr_err("unable to get psoc reference");
+		return -EINVAL;
+	}
+
+	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
+	if (!wmi_handle) {
+		cfr_err("wmi_handle is null");
+		wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
+		return -EINVAL;
+	}
+
+
+	retval = wmi_extract_cfr_peer_tx_event_param(wmi_handle, data,
+						     &tx_evt_param);
+
+	if (retval != QDF_STATUS_SUCCESS) {
+		cfr_err("Failed to extract cfr tx event param");
+		wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
+		return -EINVAL;
+	}
+
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, tx_evt_param.vdev_id,
+						    WLAN_CFR_ID);
+	if (!vdev) {
+		cfr_err("vdev is null");
+		wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
+		return -EINVAL;
+	}
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		cfr_err("pdev is null");
+		wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID);
+		return -EINVAL;
+	}
+
+	retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID);
+	if (retval != QDF_STATUS_SUCCESS) {
+		cfr_err("failed to get pdev reference");
+		wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID);
+		return -EINVAL;
+	}
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+	if (!pcfr) {
+		cfr_err("pdev object for CFR is NULL");
+		retval = -EINVAL;
+		goto end;
+	}
+
+	if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_PS_STATUS_MASK) == 1) {
+		cfr_err("CFR capture failed as peer is in powersave : %s",
+			  ether_sprintf(&tx_evt_param.peer_mac_addr.bytes[0]));
+
+		enh_prepare_cfr_header_txstatus(&tx_evt_param, &header_error);
+		if (cfr_rx_ops->cfr_info_send)
+			cfr_rx_ops->cfr_info_send(pdev,
+						  &header_error,
+						  sizeof(struct
+							 csi_cfr_header),
+						  NULL, 0, &end_magic, 4);
+
+		retval = -EINVAL;
+		goto end;
+	}
+
+	if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_STATUS_MASK) == 0) {
+		cfr_debug("CFR capture failed for peer : %s",
+			  ether_sprintf(&tx_evt_param.peer_mac_addr.bytes[0]));
+		retval = -EINVAL;
+		goto end;
+	}
+
+	if (tx_evt_param.status & CFR_TX_EVT_STATUS_MASK) {
+		cfr_debug("TX packet returned status %d for peer: %s",
+			  tx_evt_param.status & CFR_TX_EVT_STATUS_MASK,
+			  ether_sprintf(&tx_evt_param.peer_mac_addr.bytes[0]));
+		retval = -EINVAL;
+		goto end;
+	}
+
+	buf_addr_temp = (tx_evt_param.correlation_info_2 & 0x0f);
+	buf_addr = (tx_evt_param.correlation_info_1 |
+		    ((uint64_t)buf_addr_temp << 32));
+
+	if (target_if_dbr_cookie_lookup(pdev, DBR_MODULE_CFR, buf_addr,
+					&cookie, 0)) {
+		cfr_debug("Cookie lookup failure for addr: 0x%pK status: 0x%x",
+			  (void *)((uintptr_t)buf_addr), tx_evt_param.status);
+		retval = -EINVAL;
+		goto end;
+	}
+
+	cfr_debug("buffer address: 0x%pK cookie: %u",
+		  (void *)((uintptr_t)buf_addr), cookie);
+
+	dump_cfr_peer_tx_event_enh(&tx_evt_param, cookie);
+
+	lut = get_lut_entry(pcfr, cookie);
+	if (!lut) {
+		cfr_err("lut is NULL\n");
+		retval = -EINVAL;
+		goto end;
+	}
+
+	pcfr->tx_evt_cnt++;
+
+	lut->tx_ppdu_id = (tx_evt_param.correlation_info_2 >> 16);
+	lut->tx_address1 = tx_evt_param.correlation_info_1;
+	lut->tx_address2 = tx_evt_param.correlation_info_2;
+	lut->txrx_tstamp = qdf_ktime_to_ms(qdf_ktime_get());
+
+	header = &lut->header;
+	header->start_magic_num        = 0xDEADBEAF;
+	header->vendorid               = 0x8cfdf0;
+	header->cfr_metadata_version   = CFR_META_VERSION_3;
+	header->cfr_data_version       = CFR_DATA_VERSION_1;
+	header->chip_type              = CFR_CAPTURE_RADIO_CYP;
+	header->pltform_type           = CFR_PLATFORM_TYPE_ARM;
+	header->Reserved               = 0;
+	header->u.meta_v3.status       = (tx_evt_param.status &
+					  PEER_CFR_CAPTURE_EVT_STATUS_MASK) ?
+					  1 : 0;
+	header->u.meta_v3.capture_bw   = tx_evt_param.bandwidth;
+
+	bss_chan = wlan_vdev_mlme_get_bss_chan(vdev);
+	header->u.meta_v3.phy_mode     = bss_chan->ch_phymode;
+
+	header->u.meta_v3.prim20_chan  = tx_evt_param.primary_20mhz_chan;
+	header->u.meta_v3.center_freq1 = tx_evt_param.band_center_freq1;
+	header->u.meta_v3.center_freq2 = tx_evt_param.band_center_freq2;
+
+	/* Currently CFR data is captured on ACK of a Qos NULL frame.
+	 * For 20 MHz, ACK is Legacy and for 40/80/160, ACK is DUP Legacy.
+	 */
+	header->u.meta_v3.capture_mode = tx_evt_param.bandwidth ?
+		CFR_DUP_LEGACY_ACK : CFR_LEGACY_ACK;
+	header->u.meta_v3.capture_type = tx_evt_param.capture_method;
+	header->u.meta_v3.num_rx_chain = wlan_vdev_mlme_get_rxchainmask(vdev);
+	header->u.meta_v3.sts_count    = tx_evt_param.spatial_streams;
+	header->u.meta_v3.timestamp    = tx_evt_param.timestamp_us;
+
+	qdf_mem_copy(&header->u.meta_v3.peer_addr.su_peer_addr[0],
+		     &tx_evt_param.peer_mac_addr.bytes[0], QDF_MAC_ADDR_SIZE);
+	qdf_mem_copy(&header->u.meta_v3.chain_rssi[0],
+		     &tx_evt_param.chain_rssi[0],
+		     HOST_MAX_CHAINS * sizeof(tx_evt_param.chain_rssi[0]));
+	qdf_mem_copy(&header->u.meta_v3.chain_phase[0],
+		     &tx_evt_param.chain_phase[0],
+		     HOST_MAX_CHAINS * sizeof(tx_evt_param.chain_phase[0]));
+
+	status = correlate_and_relay_enh(pdev, cookie, lut,
+					 CORRELATE_TXRX_EV_MODULE_ID);
+	if (status == STATUS_STREAM_AND_RELEASE) {
+		if (cfr_rx_ops->cfr_info_send)
+			status = cfr_rx_ops->cfr_info_send(pdev,
+							   &lut->header,
+							   sizeof(
+							   struct
+							   csi_cfr_header),
+							   lut->data,
+							   lut->data_len,
+							   &end_magic, 4);
+		dump_metadata(header, cookie);
+		release_lut_entry_enh(pdev, lut);
+		target_if_dbr_buf_release(pdev, DBR_MODULE_CFR, buf_addr,
+					  cookie, 0);
+		cfr_debug("Data sent to upper layers, "
+			  "releasing look up table");
+	} else if (status == STATUS_HOLD) {
+		cfr_debug("HOLD for buffer address: 0x%pK cookie: %u",
+			  (void *)((uintptr_t)buf_addr), cookie);
+	} else {
+		cfr_err("Correlation returned invalid status!!");
+		retval = -EINVAL;
+		goto end;
+	}
+
+end:
+
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID);
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return retval;
+}
+#else
+static int
+target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
+{
+	return 0;
+}
+#endif
+
+/**
+ * target_if_register_tx_completion_enh_event_handler() - Register callback for
+ * WMI TX completion event
+ * @psoc: PSOC object
+ *
+ * Return: Success/Failure status
+ */
+int
+target_if_register_tx_completion_enh_event_handler(struct wlan_objmgr_psoc
+						   *psoc)
+{
+	/* Register completion handler here */
+	wmi_unified_t wmi_hdl;
+	int ret = 0;
+
+	wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_hdl) {
+		cfr_err("Unable to get wmi handle");
+		return -EINVAL;
+	}
+
+	ret = wmi_unified_register_event_handler(wmi_hdl,
+						 wmi_peer_cfr_capture_event_id,
+						 target_if_peer_capture_event,
+						 WMI_RX_UMAC_CTX);
+	/*
+	 * Event registration is called per pdev
+	 * Ignore erorr if event is alreday registred.
+	 */
+	if (ret == QDF_STATUS_E_FAILURE)
+		ret = QDF_STATUS_SUCCESS;
+
+	return ret;
+}
+
+/**
+ * target_if_unregister_tx_completion_enh_event_handler() - Unregister callback
+ * for WMI TX completion event
+ * @psoc: PSOC object
+ *
+ * Return: Success/Failure status
+ */
+int
+target_if_unregister_tx_completion_enh_event_handler(struct wlan_objmgr_psoc
+						     *psoc)
+{
+	/* Unregister completion handler here */
+	wmi_unified_t wmi_hdl;
+	int status = 0;
+
+	wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_hdl) {
+		cfr_err("Unable to get wmi handle");
+		return -EINVAL;
+	}
+
+	status = wmi_unified_unregister_event(wmi_hdl,
+					      wmi_peer_cfr_capture_event_id);
+	return status;
+}
+
+/**
+ * lut_ageout_timer_task() - Timer to flush pending TXRX/DBR events
+ *
+ * Return: none
+ */
+static os_timer_func(lut_ageout_timer_task)
+{
+	int i = 0;
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	struct look_up_table *lut = NULL;
+	uint64_t diff, cur_tstamp;
+	qdf_dma_addr_t buf_addr = 0, buf_addr_temp = 0;
+
+	OS_GET_TIMER_ARG(pcfr, struct pdev_cfr*);
+
+	if (!pcfr) {
+		cfr_err("pdev object for CFR is null");
+		return;
+	}
+
+	pdev = pcfr->pdev_obj;
+	if (!pdev) {
+		cfr_err("pdev is null");
+		return;
+	}
+
+	if (wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID)
+	    != QDF_STATUS_SUCCESS) {
+		cfr_err("failed to get pdev reference");
+		return;
+	}
+
+	for (i = 0; i < NUM_LUT_ENTRIES; i++) {
+		lut = get_lut_entry(pcfr, i);
+		if (!lut)
+			continue;
+
+		cur_tstamp = qdf_ktime_to_ms(qdf_ktime_get());
+
+		if (lut->dbr_recv && !lut->tx_recv) {
+			diff = cur_tstamp - lut->dbr_tstamp;
+			if (diff > LUT_AGE_THRESHOLD) {
+				cfr_err("<%d>TXRX event not received for "
+					"%llu ms, release lut entry : "
+					"dma_addr = 0x%pK\n", i, diff,
+					(void *)((uintptr_t)lut->dbr_address));
+				target_if_dbr_buf_release(pdev, DBR_MODULE_CFR,
+							  lut->dbr_address,
+							  i, 0);
+				pcfr->flush_timeout_dbr_cnt++;
+				release_lut_entry_enh(pdev, lut);
+			}
+		} else if (lut->tx_recv && !lut->dbr_recv) {
+			diff = cur_tstamp - lut->txrx_tstamp;
+			if (diff > LUT_AGE_THRESHOLD) {
+				buf_addr_temp = (lut->tx_address2 & 0x0f);
+				buf_addr = (lut->tx_address1
+					    | ((uint64_t)buf_addr_temp << 32));
+				cfr_err("<%d>DBR event not received for "
+					"%llu ms, release lut entry : "
+					"dma_addr = 0x%pK\n", i, diff,
+					(void *)((uintptr_t)buf_addr));
+				target_if_dbr_buf_release(pdev,
+							  DBR_MODULE_CFR,
+							  buf_addr,
+							  i, 0);
+				pcfr->flush_timeout_txrx_cnt++;
+				release_lut_entry_enh(pdev, lut);
+			}
+		}
+	}
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+}
+
+/**
+ * target_if_cfr_start_lut_age_timer() - Start timer to flush aged-out LUT
+ * entries
+ * @pdev: pointer to pdev object
+ *
+ * Return: Success/Failure status
+ */
+QDF_STATUS target_if_cfr_start_lut_age_timer(struct wlan_objmgr_pdev *pdev)
+{
+	struct pdev_cfr *pcfr;
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+
+	qdf_timer_mod(&pcfr->lut_age_timer, LUT_AGE_TIMER);
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * target_if_cfr_stop_lut_age_timer() - Stop timer to flush aged-out LUT
+ * entries
+ * @pdev: pointer to pdev object
+ *
+ * Return: Success/Failure status
+ */
+QDF_STATUS target_if_cfr_stop_lut_age_timer(struct wlan_objmgr_pdev *pdev)
+{
+	struct pdev_cfr *pcfr;
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+
+	qdf_timer_stop(&pcfr->lut_age_timer);
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * cfr_6018_init_pdev() - Inits cfr pdev and registers necessary handlers.
+ * @psoc: pointer to psoc object
+ * @pdev: pointer to pdev object
+ *
+ * Return: Registration status for necessary handlers
+ */
+QDF_STATUS cfr_6018_init_pdev(struct wlan_objmgr_psoc *psoc,
+			      struct wlan_objmgr_pdev *pdev)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct pdev_cfr *pcfr;
+
+	if (!pdev) {
+		cfr_err("PDEV is NULL!");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+	if (!pcfr) {
+		cfr_err("pcfr is NULL!");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+#if DIRECT_BUF_RX_ENABLE
+	status = target_if_register_to_dbr_enh(pdev);
+	if (status != QDF_STATUS_SUCCESS) {
+		cfr_err("Failed to register with dbr");
+		return status;
+	}
+#endif
+
+	status = target_if_register_tx_completion_enh_event_handler(psoc);
+	if (status != QDF_STATUS_SUCCESS) {
+		cfr_err("Failed to register with tx event handler");
+		return status;
+	}
+
+	pcfr->cfr_max_sta_count = MAX_CFR_ENABLED_CLIENTS;
+	pcfr->subbuf_size = STREAMFS_MAX_SUBBUF_CYP;
+	pcfr->num_subbufs = STREAMFS_NUM_SUBBUF_CYP;
+
+	if (!pcfr->lut_timer_init) {
+		qdf_timer_init(NULL,
+			       &(pcfr->lut_age_timer),
+			       lut_ageout_timer_task, (void *)pcfr,
+			       QDF_TIMER_TYPE_WAKE_APPS);
+		pcfr->lut_timer_init = 1;
+	}
+
+	pcfr->cfr_data_subscriber = (wdi_event_subscribe *)
+		qdf_mem_malloc(sizeof(wdi_event_subscribe));
+	if (!pcfr->cfr_data_subscriber) {
+		cfr_err("Failed to alloc cfr_data_subscriber object\n");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+
+	return status;
+}
+
+/**
+ * cfr_6018_deinit_pdev() - De-inits corresponding pdev and handlers.
+ * @psoc: pointer to psoc object
+ * @pdev: pointer to pdev object
+ *
+ * Return: De-registration status for necessary handlers
+ */
+QDF_STATUS cfr_6018_deinit_pdev(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_pdev *pdev)
+{
+	int status;
+	struct pdev_cfr *pcfr;
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+	if (!pcfr) {
+		cfr_err("pcfr is NULL");
+		return -EINVAL;
+	}
+
+	if (pcfr->lut_timer_init) {
+		qdf_timer_free(&(pcfr->lut_age_timer));
+		pcfr->lut_timer_init = 0;
+	}
+
+	pcfr->tx_evt_cnt = 0;
+	pcfr->dbr_evt_cnt = 0;
+	pcfr->release_cnt = 0;
+	pcfr->rx_tlv_evt_cnt = 0;
+	pcfr->flush_dbr_cnt = 0;
+	pcfr->flush_all_dbr_cnt = 0;
+	pcfr->flush_all_txrx_cnt = 0;
+	pcfr->flush_timeout_dbr_cnt = 0;
+	pcfr->flush_timeout_txrx_cnt = 0;
+	pcfr->invalid_dma_length_cnt = 0;
+	pcfr->clear_dbr_event = 0;
+	pcfr->clear_txrx_event = 0;
+	pcfr->bb_captured_channel_cnt = 0;
+	pcfr->bb_captured_timeout_cnt = 0;
+	pcfr->rx_loc_info_valid_cnt = 0;
+	qdf_mem_zero(&pcfr->chan_capture_status,
+		     sizeof(uint64_t) * NUM_CHAN_CAPTURE_STATUS);
+	qdf_mem_zero(&pcfr->bb_captured_reason_cnt,
+		     sizeof(uint64_t) * NUM_CHAN_CAPTURE_REASON);
+
+#ifdef DIRECT_BUF_RX_ENABLE
+	status = target_if_unregister_to_dbr_enh(pdev);
+	if (status != QDF_STATUS_SUCCESS)
+		cfr_err("Failed to register with dbr");
+#endif
+
+	status = target_if_unregister_tx_completion_enh_event_handler(psoc);
+	if (status != QDF_STATUS_SUCCESS)
+		cfr_err("Failed to register with dbr");
+
+	if (pcfr->cfr_data_subscriber) {
+		qdf_mem_free(pcfr->cfr_data_subscriber);
+		pcfr->cfr_data_subscriber = NULL;
+	}
+
+
+	return status;
+}

+ 148 - 3
umac/cfr/dispatcher/inc/wlan_cfr_utils_api.h

@@ -21,6 +21,9 @@
 
 #include <wlan_objmgr_cmn.h>
 #include <qal_streamfs.h>
+#ifdef WLAN_ENH_CFR_ENABLE
+#include <qdf_timer.h>
+#endif
 
 #define cfr_alert(format, args...) \
 		QDF_TRACE_FATAL(QDF_MODULE_ID_CFR, format, ## args)
@@ -40,11 +43,17 @@
 #define DBR_EVENT_TIMEOUT_IN_MS_CFR 1
 #define DBR_NUM_RESP_PER_EVENT_CFR 1
 #define MAX_CFR_ENABLED_CLIENTS 10
+#ifdef WLAN_ENH_CFR_ENABLE
+#define MAX_CFR_MU_USERS 4
+#define NUM_CHAN_CAPTURE_STATUS 4
+#define NUM_CHAN_CAPTURE_REASON 6
+#endif
 
 enum cfrmetaversion {
 	CFR_META_VERSION_NONE,
 	CFR_META_VERSION_1,
 	CFR_META_VERSION_2,
+	CFR_META_VERSION_3,
 	CFR_META_VERSION_MAX = 0xFF,
 };
 
@@ -76,6 +85,7 @@ enum cfrradiotype {
 	CFR_CAPTURE_RADIO_DAKOTA,
 	CFR_CAPTURE_RADIO_BESRA,
 	CFR_CAPTURE_RADIO_HKV2,
+	CFR_CAPTURE_RADIO_CYP,
 	CFR_CAPTURE_RADIO_MAX = 0xFF,
 };
 
@@ -87,6 +97,41 @@ enum ack_capture_mode {
 	CFR_INVALID_ACK, /*Always keep this at last*/
 };
 
+/* Similar to WMI_PEER_CFR_CAPTURE_METHOD used in one-shot capture */
+enum cfr_capture_type {
+	CFR_TYPE_METHOD_NULL_FRAME = 0,
+	CFR_TYPE_METHOD_NULL_FRAME_WITH_PHASE = 1,
+	CFR_TYPE_METHOD_PROBE_RESP = 2,
+	CFR_TYPE_METHOD_TM = 3,
+	CFR_TYPE_METHOD_FTM = 4,
+	CFR_TYPE_METHOD_ACK_RESP_TO_TM_FTM = 5,
+	CFR_TYPE_METHOD_TA_RA_TYPE_FILTER = 6,
+	CFR_TYPE_METHOD_NDPA_NDP = 7,
+	CFR_TYPE_METHOD_ALL_PACKET = 8,
+	/* Add new capture methods before this line */
+	CFR_TYPE_METHOD_LAST_VALID,
+	CFR_TYPE_METHOD_AUTO = 0xff,
+	CFR_TYPE_METHOD_MAX,
+};
+
+enum mac_freeze_capture_reason {
+	FREEZE_REASON_TM = 0,
+	FREEZE_REASON_FTM = 1,
+	FREEZE_REASON_ACK_RESP_TO_TM_FTM = 2,
+	FREEZE_REASON_TA_RA_TYPE_FILTER = 3,
+	FREEZE_REASON_NDPA_NDP = 4,
+	FREEZE_REASON_ALL_PACKET = 5,
+	FREEZE_REASON_MAX,
+};
+
+enum chan_capture_status {
+	CAPTURE_IDLE = 0,
+	CAPTURE_BUSY,
+	CAPTURE_ACTIVE,
+	CAPTURE_NO_BUFFER,
+	CAPTURE_MAX,
+};
+
 struct cfr_metadata_version_1 {
 	u_int8_t    peer_addr[QDF_MAC_ADDR_SIZE];
 	u_int8_t    status;
@@ -125,6 +170,32 @@ struct cfr_metadata_version_2 {
 	u_int16_t   chain_phase[HOST_MAX_CHAINS];
 } __attribute__ ((__packed__));
 
+#ifdef WLAN_ENH_CFR_ENABLE
+struct cfr_metadata_version_3 {
+	u_int8_t    status;
+	u_int8_t    capture_bw;
+	u_int8_t    channel_bw;
+	u_int8_t    phy_mode;
+	u_int16_t   prim20_chan;
+	u_int16_t   center_freq1;
+	u_int16_t   center_freq2;
+	u_int8_t    capture_mode; /* ack_capture_mode */
+	u_int8_t    capture_type; /* cfr_capture_type */
+	u_int8_t    sts_count;
+	u_int8_t    num_rx_chain;
+	u_int32_t   timestamp;
+	u_int32_t   length;
+	u_int8_t    is_mu_ppdu;
+	u_int8_t    num_mu_users;
+	union {
+		u_int8_t    su_peer_addr[QDF_MAC_ADDR_SIZE];
+		u_int8_t    mu_peer_addr[MAX_CFR_MU_USERS][QDF_MAC_ADDR_SIZE];
+	} peer_addr;
+	u_int32_t   chain_rssi[HOST_MAX_CHAINS];
+	u_int16_t   chain_phase[HOST_MAX_CHAINS];
+} __attribute__ ((__packed__));
+#endif
+
 struct csi_cfr_header {
 	u_int32_t   start_magic_num;
 	u_int32_t   vendorid;
@@ -137,6 +208,9 @@ struct csi_cfr_header {
 	union {
 		struct cfr_metadata_version_1 meta_v1;
 		struct cfr_metadata_version_2 meta_v2;
+#ifdef WLAN_ENH_CFR_ENABLE
+		struct cfr_metadata_version_3 meta_v3;
+#endif
 	} u;
 } __attribute__ ((__packed__));
 
@@ -206,6 +280,28 @@ struct whal_cfir_dma_hdr {
 
 #define MAX_LUT_ENTRIES 140 /* For HKv2 136 is max */
 
+/**
+ * struct look_up_table - Placeholder for 2 asynchronous events (DBR and
+ * TXRX event)
+ * dbr_recv: Indicates whether WMI for DBR completion is received or not
+ * tx_recv: Indicates whether WMI for TX completion (or) WDI event for RX
+ * status is received or not
+ * data: pointer to CFR data that ucode DMAs to host memory
+ * data_len: length of CFR data DMAed by ucode
+ * dbr_ppdu_id: PPDU id retrieved from DBR completion WMI event
+ * tx_ppdu_id: PPDU id retrieved from WMI TX completion event (or) PPDU status
+ * TLV
+ * dbr_address: Physical address of the CFR data dump retrieved from DBR
+ * completion WMI event
+ * tx_address1: Physical address of the CFR data from TX/RX event
+ * tx_address2: Physical address of the CFR data from TX/RX event
+ * csi_cfr_header: CFR header constructed by host
+ * whal_cfir_enhanced_hdr: CFR header constructed by ucode
+ * tx_tstamp: Timestamp when TX/RX event was received
+ * dbr_tstamp: Timestamp when DBR completion event was received
+ * header_length: Length of header DMAed by ucode in words
+ * payload_length: Length of CFR payload
+ */
 struct look_up_table {
 	bool dbr_recv;
 	bool tx_recv;
@@ -218,6 +314,10 @@ struct look_up_table {
 	uint32_t tx_address2; /* capture len */
 	struct csi_cfr_header header;
 	struct whal_cfir_dma_hdr dma_hdr;
+	uint64_t txrx_tstamp;
+	uint64_t dbr_tstamp;
+	uint32_t header_length;
+	uint32_t payload_length;
 };
 
 struct unassoc_pool_entry {
@@ -231,6 +331,30 @@ struct unassoc_pool_entry {
  * pdev_obj: pointer to pdev object
  * is_cfr_capable: flag to determine if cfr is enabled or not
  * cfr_timer_enable: flag to enable/disable timer
+ * rx_tlv_evt_cnt: Number of CFR WDI events from datapath
+ * lut_age_timer: Timer to flush pending TXRX/DBR events in lookup table
+ * lut_timer_init: flag to determine if lut_age_timer is initialized or not
+ * cfr_data_subscriber: CFR WDI subscriber object
+ * bb_captured_channel_cnt: No. of PPDUs for which MAC sent Freeze TLV to PHY
+ * bb_captured_timeout_cnt: No. of PPDUs for which CFR filter criteria matched
+ * but MAC did not send Freeze TLV to PHY as time exceeded freeze tlv delay
+ * count threshold
+ * rx_loc_info_valid_cnt: No. of PPDUs for which PHY could find a valid buffer
+   in ucode IPC ring
+ * chan_capture_status[]: capture status counters
+ *	[0] - No. of PPDUs with capture status CAPTURE_IDLE
+ *	[1] - No. of PPDUs with capture status CAPTURE_BUSY
+ *	[2] - No. of PPDUs with capture status CAPTURE_ACTIVE
+ *	[3] - No. of PPDUs with capture status CAPTURE_NO_BUFFER
+ * bb_captured_reason_cnt[]: capture reason counters
+ *	[0] - No. PPDUs filtered due to freeze_reason_TM
+ *	[1] - No. PPDUs filtered due to freeze_reason_FTM
+ *	[2] - No. PPDUs filtered due to freeze_reason_ACK_resp_to_TM_FTM
+ *	[3] - No. PPDUs filtered due to freeze_reason_TA_RA_TYPE_FILTER
+ *	[4] - No. PPDUs filtered due to freeze_reason_NDPA_NDP
+ *	[5] - No. PPDUs filtered due to freeze_reason_ALL_PACKET
+ * release_err_cnt: No. of lookup table entries freed due to invalid CFR data
+ * length
  */
 /*
  * To be extended if we get more capbality info
@@ -250,9 +374,30 @@ struct pdev_cfr {
 	struct look_up_table lut[MAX_LUT_ENTRIES];
 	uint32_t dbr_buf_size;
 	uint32_t dbr_num_bufs;
-	uint32_t tx_evt_cnt;
-	uint32_t dbr_evt_cnt;
-	uint32_t release_cnt;
+	uint64_t tx_evt_cnt;
+	uint64_t dbr_evt_cnt;
+	uint64_t release_cnt;
+#ifdef WLAN_ENH_CFR_ENABLE
+	struct cfr_rcc_param rcc_param;
+	struct ta_ra_cfr_cfg global[MAX_TA_RA_ENTRIES];
+	uint64_t rx_tlv_evt_cnt;
+	qdf_timer_t lut_age_timer;
+	uint8_t lut_timer_init;
+	void *cfr_data_subscriber;
+	uint64_t bb_captured_channel_cnt;
+	uint64_t bb_captured_timeout_cnt;
+	uint64_t rx_loc_info_valid_cnt;
+	uint64_t chan_capture_status[CAPTURE_MAX];
+	uint64_t bb_captured_reason_cnt[FREEZE_REASON_MAX];
+	uint64_t flush_dbr_cnt;
+	uint64_t flush_all_dbr_cnt;
+	uint64_t flush_all_txrx_cnt;
+	uint64_t invalid_dma_length_cnt;
+	uint64_t flush_timeout_dbr_cnt;
+	uint64_t flush_timeout_txrx_cnt;
+	uint64_t clear_dbr_event;
+	uint64_t clear_txrx_event;
+#endif
 	struct unassoc_pool_entry unassoc_pool[MAX_CFR_ENABLED_CLIENTS];
 };