Browse Source

qcacmn: Add CFR feature support

Add CFR feature support for WIN and MCL.

Change-Id: I135409c00df953ad7ae4e570418403b11ebc1bc7
CRs-Fixed: 2639069
Padma Raghunathan 5 years ago
parent
commit
9946d36d19

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

@@ -0,0 +1,167 @@
+/*
+ * 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_H_
+#define _TARGET_IF_CFR_H_
+
+#include <wlan_objmgr_cmn.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_peer_obj.h>
+
+#include "wmi_unified_cfr_api.h"
+#include "wmi_unified_param.h"
+#include "wmi_unified_cfr_param.h"
+#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
+/*
+ * HKV2 - Tx completion event for one-shot capture
+ * Cypress - Tx completion event for one-shot capture (or) RXTLV event for RCC
+ */
+#define CORRELATE_TX_EV_MODULE_ID 1
+
+/**
+ * target_if_cfr_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
+ */
+int target_if_cfr_init_pdev(struct wlan_objmgr_psoc *psoc,
+			    struct wlan_objmgr_pdev *pdev);
+
+/**
+ * target_if_cfr_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
+ */
+int target_if_cfr_deinit_pdev(struct wlan_objmgr_psoc *psoc,
+			      struct wlan_objmgr_pdev *pdev);
+
+/**
+ * target_if_cfr_tx_ops_register() - Registers tx ops for cfr module
+ * @tx_ops - pointer to tx_ops structure.
+ */
+void target_if_cfr_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops);
+
+/**
+ * target_if_cfr_enable_cfr_timer() - Enables cfr timer
+ * @pdev: pointer to pdev object
+ * @cfr_timer: Amount of time this timer has to run
+ *
+ * Return: status of timer
+ */
+int target_if_cfr_enable_cfr_timer(struct wlan_objmgr_pdev *pdev,
+				   uint32_t cfr_timer);
+
+/**
+ * target_if_cfr_pdev_set_param() - Function to set params for cfr config
+ * @pdev: pointer to pdev object
+ * @param_id: param id which has to be set
+ * @param_value: value of param being set
+ *
+ * Return: success/failure of setting param
+ */
+int target_if_cfr_pdev_set_param(struct wlan_objmgr_pdev *pdev,
+				 uint32_t param_id, uint32_t param_value);
+/**
+ * target_if_cfr_start_capture() - Function to start cfr capture for a peer
+ * @pdev: pointer to pdev object
+ * @peer: pointer to peer object
+ * @cfr_params: capture parameters for this peer
+ *
+ * Return: success/failure status of start capture
+ */
+int target_if_cfr_start_capture(struct wlan_objmgr_pdev *pdev,
+				struct wlan_objmgr_peer *peer,
+				struct cfr_capture_params *cfr_params);
+/**
+ * target_if_cfr_stop_capture() - Function to stop cfr capture for a peer
+ * @pdev: pointer to pdev object
+ * @peer: pointer to peer object
+ *
+ * Return: success/failure status of stop capture
+ */
+int target_if_cfr_stop_capture(struct wlan_objmgr_pdev *pdev,
+			       struct wlan_objmgr_peer *peer);
+
+/**
+ * target_if_cfr_get_target_type() - Function to get target type
+ * @psoc: pointer to psoc object
+ *
+ * Return: target type of target
+ */
+int target_if_cfr_get_target_type(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_cfr_set_cfr_support() - Function to set cfr support
+ * @psoc: pointer to psoc object
+ * @value: value to be set
+ */
+void target_if_cfr_set_cfr_support(struct wlan_objmgr_psoc *psoc,
+				   uint8_t value);
+
+/**
+ * target_if_cfr_info_send() - Function to send cfr info to upper layers
+ * @pdev: pointer to pdev object
+ * @head: pointer to cfr info head
+ * @hlen: head len
+ * @data: pointer to cfr info data
+ * @dlen: data len
+ * @tail: pointer to cfr info tail
+ * @tlen: tail len
+ */
+void target_if_cfr_info_send(struct wlan_objmgr_pdev *pdev, void *head,
+			     size_t hlen, void *data, size_t dlen, void *tail,
+			     size_t tlen);
+
+/**
+ * cfr_wifi2_0_init_pdev() - Function to init legacy pdev
+ * @psoc: pointer to psoc object
+ * @pdev: pointer to pdev object
+ *
+ * Return: success/failure status of init
+ */
+QDF_STATUS cfr_wifi2_0_init_pdev(struct wlan_objmgr_psoc *psoc,
+				 struct wlan_objmgr_pdev *pdev);
+
+/**
+ * cfr_wifi2_0_deinit_pdev() - Function to deinit legacy pdev
+ * @psoc: pointer to psoc object
+ * @pdev: pointer to pdev object
+ *
+ * Return: success/failure status of deinit
+ */
+QDF_STATUS cfr_wifi2_0_deinit_pdev(struct wlan_objmgr_psoc *psoc,
+				   struct wlan_objmgr_pdev *pdev);
+#endif

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

@@ -0,0 +1,335 @@
+/*
+ * 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
+
+/* payload_len = Max(2048, 16016, 10240) = 16064 (64-bit alignment) */
+#define CYP_MAX_DATA_LENGTH_BYTES 16064
+
+/* 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: None
+ */
+void 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: None
+ */
+void 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);
+
+/**
+ * target_if_cfr_update_global_cfg() - Update global config after a successful
+ * commit
+ * @pdev: pointer to pdev object
+ *
+ * Return: None
+ */
+void target_if_cfr_update_global_cfg(struct wlan_objmgr_pdev *pdev);
+#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

+ 362 - 0
target_if/cfr/src/target_if_cfr.c

@@ -0,0 +1,362 @@
+/*
+ * 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>
+#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)
+{
+	struct peer_cfr *pe;
+	struct peer_cfr_params param = {0};
+	struct wmi_unified *pdev_wmi_handle = NULL;
+	struct wlan_objmgr_vdev *vdev = {0};
+	struct pdev_cfr *pdev_cfrobj;
+	int retv = 0;
+
+	pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR);
+	if (pe == NULL)
+		return -EINVAL;
+
+	pdev_wmi_handle = lmac_get_pdev_wmi_handle(pdev);
+	vdev = wlan_peer_get_vdev(peer);
+
+	qdf_mem_set(&param, sizeof(param), 0);
+
+	param.request = PEER_CFR_CAPTURE_DISABLE;
+	param.macaddr = wlan_peer_get_macaddr(peer);
+	param.vdev_id = wlan_vdev_get_id(vdev);
+
+	param.periodicity = pe->period;
+	param.bandwidth = pe->bandwidth;
+	param.capture_method = pe->capture_method;
+
+	retv = wmi_unified_send_peer_cfr_capture_cmd(pdev_wmi_handle, &param);
+
+	pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+							    WLAN_UMAC_COMP_CFR);
+	if (!pdev_cfrobj) {
+		cfr_err("pdev object for CFR is null");
+		return -EINVAL;
+	}
+	cfr_err("CFR capture stats for this capture:");
+	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);
+
+	pdev_cfrobj->dbr_evt_cnt = 0;
+	pdev_cfrobj->tx_evt_cnt  = 0;
+	pdev_cfrobj->release_cnt = 0;
+
+	return retv;
+}
+
+int target_if_cfr_start_capture(struct wlan_objmgr_pdev *pdev,
+				struct wlan_objmgr_peer *peer,
+				struct cfr_capture_params *cfr_params)
+{
+	struct peer_cfr_params param = {0};
+	struct wmi_unified *pdev_wmi_handle = NULL;
+	struct wlan_objmgr_vdev *vdev;
+	int retv = 0;
+
+	pdev_wmi_handle = lmac_get_pdev_wmi_handle(pdev);
+	vdev = wlan_peer_get_vdev(peer);
+	qdf_mem_set(&param, sizeof(param), 0);
+
+	param.request = PEER_CFR_CAPTURE_ENABLE;
+	param.macaddr = wlan_peer_get_macaddr(peer);
+	param.vdev_id = wlan_vdev_get_id(vdev);
+
+	param.periodicity = cfr_params->period;
+	param.bandwidth = cfr_params->bandwidth;
+	param.capture_method = cfr_params->method;
+
+	retv = wmi_unified_send_peer_cfr_capture_cmd(pdev_wmi_handle, &param);
+	return retv;
+}
+
+int target_if_cfr_pdev_set_param(struct wlan_objmgr_pdev *pdev,
+				 uint32_t param_id, uint32_t param_value)
+{
+	struct pdev_params pparam;
+	uint32_t pdev_id;
+
+	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
+	if (pdev_id < 0)
+		return -EINVAL;
+
+	qdf_mem_set(&pparam, sizeof(pparam), 0);
+	pparam.param_id = param_id;
+	pparam.param_value = param_value;
+
+	return wmi_unified_pdev_param_send(lmac_get_pdev_wmi_handle(pdev),
+					   &pparam, pdev_id);
+}
+
+int target_if_cfr_enable_cfr_timer(struct wlan_objmgr_pdev *pdev,
+				   uint32_t cfr_timer)
+{
+	struct pdev_cfr *pa;
+	int retval;
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+	if (pa == NULL)
+		return QDF_STATUS_E_FAILURE;
+
+	if (!cfr_timer) {
+	     /* disable periodic cfr capture */
+		retval =
+	target_if_cfr_pdev_set_param(pdev,
+				     wmi_pdev_param_per_peer_prd_cfr_enable,
+				     WMI_HOST_PEER_CFR_TIMER_DISABLE);
+
+		if (retval == QDF_STATUS_SUCCESS)
+			pa->cfr_timer_enable = 0;
+	} else {
+	    /* enable periodic cfr capture (default base timer is 10ms ) */
+		retval =
+	target_if_cfr_pdev_set_param(pdev,
+				     wmi_pdev_param_per_peer_prd_cfr_enable,
+				     WMI_HOST_PEER_CFR_TIMER_ENABLE);
+
+		if (retval == QDF_STATUS_SUCCESS)
+			pa->cfr_timer_enable = 1;
+	}
+
+	return retval;
+}
+
+int target_if_cfr_get_target_type(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t target_type = 0;
+	struct wlan_lmac_if_target_tx_ops *target_type_tx_ops;
+
+	target_type_tx_ops = &psoc->soc_cb.tx_ops.target_tx_ops;
+
+	if (target_type_tx_ops->tgt_get_tgt_type)
+		target_type = target_type_tx_ops->tgt_get_tgt_type(psoc);
+
+	return target_type;
+}
+
+int target_if_cfr_init_pdev(struct wlan_objmgr_psoc *psoc,
+			    struct wlan_objmgr_pdev *pdev)
+{
+	uint32_t target_type;
+	struct pdev_cfr *pa;
+	struct psoc_cfr *cfr_sc;
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+	if (pa == NULL)
+		return QDF_STATUS_E_FAILURE;
+
+	/* Reset unassociated entries for every init */
+	qdf_mem_zero(&pa->unassoc_pool[0], MAX_CFR_ENABLED_CLIENTS *
+		     sizeof(struct unassoc_pool_entry));
+
+	cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+						       WLAN_UMAC_COMP_CFR);
+
+	if (cfr_sc == NULL)
+		return QDF_STATUS_E_FAILURE;
+
+	target_type = target_if_cfr_get_target_type(psoc);
+
+	if (target_type == TARGET_TYPE_QCA8074V2) {
+		pa->is_cfr_capable = cfr_sc->is_cfr_capable;
+		return cfr_8074v2_init_pdev(psoc, pdev);
+	} else if ((target_type == TARGET_TYPE_IPQ4019) ||
+		   (target_type == TARGET_TYPE_QCA9984) ||
+		   (target_type == TARGET_TYPE_QCA9888)) {
+
+		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;
+}
+
+int target_if_cfr_deinit_pdev(struct wlan_objmgr_psoc *psoc,
+			      struct wlan_objmgr_pdev *pdev)
+{
+	uint32_t target_type;
+
+	target_type = target_if_cfr_get_target_type(psoc);
+
+	if (target_type == TARGET_TYPE_QCA8074V2) {
+		return cfr_8074v2_deinit_pdev(psoc, pdev);
+	} else if ((target_type == TARGET_TYPE_IPQ4019) ||
+		   (target_type == TARGET_TYPE_QCA9984) ||
+		   (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;
+}
+
+#ifdef WLAN_ENH_CFR_ENABLE
+QDF_STATUS target_if_cfr_config_rcc(struct wlan_objmgr_pdev *pdev,
+				    struct cfr_rcc_param *rcc_info)
+{
+	QDF_STATUS status;
+	struct wmi_unified *pdev_wmi_handle = NULL;
+
+	pdev_wmi_handle = lmac_get_pdev_wmi_handle(pdev);
+	if (!pdev_wmi_handle) {
+		cfr_err("pdev_wmi_handle is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	rcc_info->pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
+	rcc_info->num_grp_tlvs =
+		count_set_bits(rcc_info->modified_in_curr_session);
+
+	status = wmi_unified_send_cfr_rcc_cmd(pdev_wmi_handle, rcc_info);
+	return status;
+}
+
+void target_if_cfr_default_ta_ra_config(struct cfr_rcc_param *rcc_info,
+					bool allvalid, uint16_t reset_cfg)
+{
+	struct ta_ra_cfr_cfg *curr_cfg = NULL;
+	int grp_id;
+
+	uint8_t def_mac[QDF_MAC_ADDR_SIZE] = {0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF};
+	uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0, 0, 0, 0, 0, 0};
+
+	for (grp_id = 0; grp_id < MAX_TA_RA_ENTRIES; grp_id++) {
+		if (qdf_test_bit(grp_id, (unsigned long *)&reset_cfg)) {
+			curr_cfg = &rcc_info->curr[grp_id];
+			qdf_mem_copy(curr_cfg->tx_addr,
+				     def_mac, QDF_MAC_ADDR_SIZE);
+			qdf_mem_copy(curr_cfg->tx_addr_mask,
+				     null_mac, QDF_MAC_ADDR_SIZE);
+			qdf_mem_copy(curr_cfg->rx_addr,
+				     def_mac, QDF_MAC_ADDR_SIZE);
+			qdf_mem_copy(curr_cfg->rx_addr_mask,
+				     null_mac, QDF_MAC_ADDR_SIZE);
+			curr_cfg->bw = 0xf;
+			curr_cfg->nss = 0xff;
+			curr_cfg->mgmt_subtype_filter = 0xffff;
+			curr_cfg->ctrl_subtype_filter = 0xffff;
+			curr_cfg->data_subtype_filter = 0xffff;
+			if (!allvalid) {
+				curr_cfg->valid_ta = 0;
+				curr_cfg->valid_ta_mask = 0;
+				curr_cfg->valid_ra = 0;
+				curr_cfg->valid_ra_mask = 0;
+				curr_cfg->valid_bw_mask = 0;
+				curr_cfg->valid_nss_mask = 0;
+				curr_cfg->valid_mgmt_subtype = 0;
+				curr_cfg->valid_ctrl_subtype = 0;
+				curr_cfg->valid_data_subtype = 0;
+			} else {
+				curr_cfg->valid_ta = 1;
+				curr_cfg->valid_ta_mask = 1;
+				curr_cfg->valid_ra = 1;
+				curr_cfg->valid_ra_mask = 1;
+				curr_cfg->valid_bw_mask = 1;
+				curr_cfg->valid_nss_mask = 1;
+				curr_cfg->valid_mgmt_subtype = 1;
+				curr_cfg->valid_ctrl_subtype = 1;
+				curr_cfg->valid_data_subtype = 1;
+			}
+		}
+	}
+}
+#endif
+
+#ifdef WLAN_ENH_CFR_ENABLE
+void target_if_enh_cfr_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+	tx_ops->cfr_tx_ops.cfr_config_rcc =
+		target_if_cfr_config_rcc;
+	tx_ops->cfr_tx_ops.cfr_start_lut_timer =
+		target_if_cfr_start_lut_age_timer;
+	tx_ops->cfr_tx_ops.cfr_stop_lut_timer =
+		target_if_cfr_stop_lut_age_timer;
+	tx_ops->cfr_tx_ops.cfr_default_ta_ra_cfg =
+		target_if_cfr_default_ta_ra_config;
+	tx_ops->cfr_tx_ops.cfr_dump_lut_enh =
+		target_if_cfr_dump_lut_enh;
+	tx_ops->cfr_tx_ops.cfr_rx_tlv_process =
+		target_if_cfr_rx_tlv_process;
+	tx_ops->cfr_tx_ops.cfr_update_global_cfg =
+		target_if_cfr_update_global_cfg;
+}
+#else
+void target_if_enh_cfr_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+}
+#endif
+
+void target_if_cfr_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+	tx_ops->cfr_tx_ops.cfr_init_pdev =
+		target_if_cfr_init_pdev;
+	tx_ops->cfr_tx_ops.cfr_deinit_pdev =
+		target_if_cfr_deinit_pdev;
+	tx_ops->cfr_tx_ops.cfr_enable_cfr_timer =
+		target_if_cfr_enable_cfr_timer;
+	tx_ops->cfr_tx_ops.cfr_start_capture =
+		target_if_cfr_start_capture;
+	tx_ops->cfr_tx_ops.cfr_stop_capture =
+		target_if_cfr_stop_capture;
+	target_if_enh_cfr_tx_ops(tx_ops);
+}
+
+void target_if_cfr_set_cfr_support(struct wlan_objmgr_psoc *psoc,
+				   uint8_t value)
+{
+	if (psoc->soc_cb.rx_ops.cfr_rx_ops.cfr_support_set)
+		psoc->soc_cb.rx_ops.cfr_rx_ops.cfr_support_set(psoc, value);
+}
+
+void target_if_cfr_info_send(struct wlan_objmgr_pdev *pdev, void *head,
+			     size_t hlen, void *data, size_t dlen, void *tail,
+			     size_t tlen)
+{
+	struct wlan_objmgr_psoc *psoc;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+
+	if (psoc->soc_cb.rx_ops.cfr_rx_ops.cfr_info_send)
+		psoc->soc_cb.rx_ops.cfr_rx_ops.cfr_info_send(pdev, head, hlen,
+							     data, dlen, tail,
+							     tlen);
+}

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

@@ -0,0 +1,1618 @@
+/*
+ * 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_err("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 &&
+		    (lut->dbr_tstamp < pcfr->last_success_tstamp)) {
+			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);
+}
+
+/**
+ * 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 = 0x%x\n"
+		  "vendorid = 0x%x\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 = 0x%x\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;
+
+	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_TX_EV_MODULE_ID) {
+		if (lut->tx_recv)
+			pcfr->cfr_dma_aborts++;
+		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) {
+
+			pcfr->last_success_tstamp = lut->dbr_tstamp;
+			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 "
+					"header_length_words = %d "
+					"cfr_payload_length_bytes = %d "
+					"ppdu_id:0x%04x\n",
+					cookie,
+					lut->header_length,
+					lut->payload_length,
+					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
+			 */
+			cfr_debug("Received new dbr event for same "
+				  "cookie %u",
+				  cookie);
+			lut->tx_recv = false;
+			lut->tx_ppdu_id = 0;
+			pcfr->clear_txrx_event++;
+			pcfr->cfr_dma_aborts++;
+			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_extn = 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;
+	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_channel)
+		goto done;
+
+	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_extn = cfr_info->rtt_che_buffer_pointer_high8 & 0xF;
+	buf_addr = (cfr_info->rtt_che_buffer_pointer_low32 |
+		    ((uint64_t)buf_addr_extn << 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_debug("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;
+	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   = cdp_rx_ppdu->u.bw;
+	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_TX_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_unregister) {
+		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++;
+	pcfr->total_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_TX_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;
+
+	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;
+	}
+
+	cur_tstamp = qdf_ktime_to_ms(qdf_ktime_get());
+
+	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 = cur_tstamp - lut->dbr_tstamp;
+			if (diff > LUT_AGE_THRESHOLD) {
+				cfr_debug("<%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);
+			}
+		}
+	}
+
+	if (pcfr->lut_timer_init)
+		qdf_timer_mod(&pcfr->lut_age_timer, LUT_AGE_TIMER);
+	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: None
+ */
+void 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);
+	if (pcfr->lut_timer_init)
+		qdf_timer_mod(&pcfr->lut_age_timer, LUT_AGE_TIMER);
+}
+
+/**
+ * target_if_cfr_stop_lut_age_timer() - Stop timer to flush aged-out LUT
+ * entries
+ * @pdev: pointer to pdev object
+ *
+ * Return: None
+ */
+void 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);
+	if (pcfr->lut_timer_init)
+		qdf_timer_stop(&pcfr->lut_age_timer);
+}
+
+/**
+ * target_if_cfr_update_global_cfg() - Update global config after a successful
+ * commit
+ * @pdev: pointer to pdev object
+ *
+ * Return: None
+ */
+void target_if_cfr_update_global_cfg(struct wlan_objmgr_pdev *pdev)
+{
+	int grp_id;
+	struct pdev_cfr *pcfr;
+	struct ta_ra_cfr_cfg *curr_cfg = NULL;
+	struct ta_ra_cfr_cfg *glbl_cfg = NULL;
+	unsigned long *modified_in_this_session;
+
+	pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+						     WLAN_UMAC_COMP_CFR);
+	modified_in_this_session =
+		(unsigned long *)&pcfr->rcc_param.modified_in_curr_session;
+
+	for (grp_id = 0; grp_id < MAX_TA_RA_ENTRIES; grp_id++) {
+		if (qdf_test_bit(grp_id, modified_in_this_session)) {
+			/* Populating global config based on user's input */
+			glbl_cfg = &pcfr->global[grp_id];
+			curr_cfg = &pcfr->rcc_param.curr[grp_id];
+
+			if (curr_cfg->valid_ta)
+				qdf_mem_copy(glbl_cfg->tx_addr,
+					     curr_cfg->tx_addr,
+					     QDF_MAC_ADDR_SIZE);
+
+			if (curr_cfg->valid_ra)
+				qdf_mem_copy(glbl_cfg->rx_addr,
+					     curr_cfg->rx_addr,
+					     QDF_MAC_ADDR_SIZE);
+
+			if (curr_cfg->valid_ta_mask)
+				qdf_mem_copy(glbl_cfg->tx_addr_mask,
+					     curr_cfg->tx_addr_mask,
+					     QDF_MAC_ADDR_SIZE);
+
+			if (curr_cfg->valid_ra_mask)
+				qdf_mem_copy(glbl_cfg->rx_addr_mask,
+					     curr_cfg->rx_addr_mask,
+					     QDF_MAC_ADDR_SIZE);
+
+			if (curr_cfg->valid_bw_mask)
+				glbl_cfg->bw = curr_cfg->bw;
+
+			if (curr_cfg->valid_nss_mask)
+				glbl_cfg->nss = curr_cfg->nss;
+
+			if (curr_cfg->valid_mgmt_subtype)
+				glbl_cfg->mgmt_subtype_filter =
+					curr_cfg->mgmt_subtype_filter;
+
+			if (curr_cfg->valid_ctrl_subtype)
+				glbl_cfg->ctrl_subtype_filter =
+					curr_cfg->ctrl_subtype_filter;
+
+			if (curr_cfg->valid_data_subtype)
+				glbl_cfg->data_subtype_filter =
+					curr_cfg->data_subtype_filter;
+		}
+	}
+}
+
+/**
+ * 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->is_cfr_rcc_capable = 1;
+	pcfr->rcc_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
+	pcfr->rcc_param.modified_in_curr_session = MAX_RESET_CFG_ENTRY;
+	pcfr->rcc_param.num_grp_tlvs = MAX_TA_RA_ENTRIES;
+
+	target_if_cfr_default_ta_ra_config(&pcfr->rcc_param,
+					   true, MAX_RESET_CFG_ENTRY);
+
+	status = target_if_cfr_config_rcc(pdev, &pcfr->rcc_param);
+	if (status == QDF_STATUS_SUCCESS) {
+		/* Update global configuration */
+		target_if_cfr_update_global_cfg(pdev);
+	} else {
+		cfr_err("Sending WMI to configure default has failed\n");
+		return status;
+	}
+
+	pcfr->rcc_param.modified_in_curr_session = 0;
+
+	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;
+	}
+
+	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_stop(&pcfr->lut_age_timer);
+		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->total_tx_evt_cnt = 0;
+	pcfr->rx_tlv_evt_cnt = 0;
+	pcfr->flush_dbr_cnt = 0;
+	pcfr->flush_timeout_dbr_cnt = 0;
+	pcfr->invalid_dma_length_cnt = 0;
+	pcfr->clear_txrx_event = 0;
+	pcfr->cfr_dma_aborts = 0;
+	qdf_mem_zero(&pcfr->rcc_param, sizeof(struct cfr_rcc_param));
+	qdf_mem_zero(&pcfr->global, (sizeof(struct ta_ra_cfr_cfg) *
+				     MAX_TA_RA_ENTRIES));
+
+#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");
+
+	return status;
+}

+ 133 - 0
umac/cfr/core/inc/cfr_defs_i.h

@@ -0,0 +1,133 @@
+/*
+ * 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 _CFR_DEFS_I_H_
+#define _CFR_DEFS_I_H_
+
+#include <wlan_objmgr_cmn.h>
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_peer_obj.h>
+#include <qdf_list.h>
+#include <qdf_timer.h>
+#include <qdf_util.h>
+#include <qdf_types.h>
+#include <wlan_cfr_utils_api.h>
+
+/**
+ * wlan_cfr_psoc_obj_create_handler() - psoc object create handler for cfr
+ * @psoc - pointer to psoc object
+ * @args - void pointer in case it needs arguments
+ *
+ * Return: status of object creation
+ */
+QDF_STATUS
+wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg);
+
+/**
+ * wlan_cfr_psoc_obj_destroy_handler() - psoc object destroy handler for cfr
+ * @psoc - pointer to psoc object
+ * @args - void pointer in case it needs arguments
+ *
+ * Return: status of destroy object
+ */
+QDF_STATUS
+wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, void *arg);
+
+/**
+ * wlan_cfr_pdev_obj_create_handler() - pdev object create handler for cfr
+ * @pdev - pointer to pdev object
+ * @args - void pointer in case it needs arguments
+ *
+ * Return: status of object creation
+ */
+QDF_STATUS
+wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg);
+
+/**
+ * wlan_cfr_pdev_obj_destroy_handler() - pdev object destroy handler for cfr
+ * @pdev - pointer to pdev object
+ * @args - void pointer in case it needs arguments
+ *
+ * Return: status of destroy object
+ */
+QDF_STATUS
+wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg);
+
+/**
+ * wlan_cfr_peer_obj_create_handler() - peer object create handler for cfr
+ * @peer - pointer to peer object
+ * @args - void pointer in case it needs arguments
+ *
+ * Return: status of object creation
+ */
+QDF_STATUS
+wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg);
+
+/**
+ * wlan_cfr_peer_obj_destroy_handler() - peer object destroy handler for cfr
+ * @peer - pointer to peer object
+ * @args - void pointer in case it needs arguments
+ *
+ * Return: status ofi destry object
+ */
+QDF_STATUS
+wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg);
+
+/**
+ * cfr_streamfs_init() - stream filesystem init
+ * @pdev - pointer to pdev object
+ *
+ * Return: status of fs init
+ */
+QDF_STATUS
+cfr_streamfs_init(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * cfr_streamfs_remove() - stream filesystem remove
+ * @pdev - pointer to pdev object
+ *
+ * Return: status of fs remove
+ */
+QDF_STATUS
+cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * cfr_streamfs_write() - write to stream filesystem
+ * @pa - pointer to pdev_cfr object
+ * @write_data - Pointer to data
+ * @write_len - data len
+ *
+ * Return: status of fs write
+ */
+QDF_STATUS
+cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data,
+		   size_t write_len);
+
+/**
+ * cfr_streamfs_flush() - flush the write to streamfs
+ * @pa - pointer to pdev_cfr object
+ *
+ * Return: status of fs flush
+ */
+QDF_STATUS
+cfr_streamfs_flush(struct pdev_cfr *pa);
+
+#endif

+ 323 - 0
umac/cfr/core/src/cfr_common.c

@@ -0,0 +1,323 @@
+/*
+ * 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 <cfr_defs_i.h>
+#include <qdf_types.h>
+#include <osif_private.h>
+#include <ol_if_athvar.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_peer_obj.h>
+#include <wlan_cfr_tgt_api.h>
+#include <qal_streamfs.h>
+#include <relay.h>
+#include <debugfs.h>
+#include <target_if.h>
+
+QDF_STATUS
+wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg)
+{
+	struct psoc_cfr *cfr_sc = NULL;
+
+	cfr_sc = (struct psoc_cfr *)qdf_mem_malloc(sizeof(struct psoc_cfr));
+	if (NULL == cfr_sc) {
+		cfr_err("Failed to allocate cfr_ctx object\n");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	qdf_mem_zero(cfr_sc, sizeof(struct psoc_cfr));
+	cfr_sc->psoc_obj = psoc;
+
+	wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_CFR,
+					      (void *)cfr_sc,
+					      QDF_STATUS_SUCCESS);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, void *arg)
+{
+	struct psoc_cfr *cfr_sc = NULL;
+
+	cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+						       WLAN_UMAC_COMP_CFR);
+	if (NULL != cfr_sc) {
+		wlan_objmgr_psoc_component_obj_detach(psoc, WLAN_UMAC_COMP_CFR,
+						      (void *)cfr_sc);
+		qdf_mem_free(cfr_sc);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg)
+{
+	struct pdev_cfr *pa = NULL;
+
+	if (NULL == pdev) {
+		cfr_err("PDEV is NULL\n");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pa = (struct pdev_cfr *)qdf_mem_malloc(sizeof(struct pdev_cfr));
+	if (NULL == pa) {
+		cfr_err("Failed to allocate pdev_cfr object\n");
+		return QDF_STATUS_E_NOMEM;
+	}
+	qdf_mem_zero(pa, sizeof(struct pdev_cfr));
+	pa->pdev_obj = pdev;
+
+	wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_CFR,
+					      (void *)pa, QDF_STATUS_SUCCESS);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg)
+{
+	struct pdev_cfr *pa = NULL;
+
+	if (NULL == pdev) {
+		cfr_err("PDEV is NULL\n");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+	if (NULL != pa) {
+		wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_CFR,
+						      (void *)pa);
+		qdf_mem_free(pa);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg)
+{
+	struct peer_cfr *pe = NULL;
+
+	if (NULL == peer) {
+		cfr_err("PEER is NULL\n");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pe = (struct peer_cfr *)qdf_mem_malloc(sizeof(struct peer_cfr));
+	if (NULL == pe) {
+		cfr_err("Failed to allocate peer_cfr object\n");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pe->peer_obj = peer;
+
+	/* Remaining will be populated when we give CFR capture command */
+	wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_CFR,
+					      (void *)pe, QDF_STATUS_SUCCESS);
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg)
+{
+	struct peer_cfr *pe = NULL;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	struct pdev_cfr *pa = NULL;
+
+	if (NULL == peer) {
+		cfr_err("PEER is NULL\n");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	vdev = wlan_peer_get_vdev(peer);
+	if (vdev)
+		pdev = wlan_vdev_get_pdev(vdev);
+
+	if (pdev)
+		pa = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+							   WLAN_UMAC_COMP_CFR);
+
+	pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR);
+
+	if (pa && pe) {
+		if (pe->period && pe->request)
+			pa->cfr_current_sta_count--;
+	}
+
+	if (NULL != pe) {
+		wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_CFR,
+						      (void *)pe);
+		qdf_mem_free(pe);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * create_buf_file_handler() - Create streamfs buffer file
+ *  @filename: base name of files to create, NULL for buffering only
+ *  @parent: dentry of parent directory, NULL for root directory
+ *  @mode: filemode
+ *  @rchan_buf: streamfs channel buf
+ *
+ *  Returns dentry if successful, NULL otherwise.
+ */
+static struct dentry *create_buf_file_handler(const char *filename,
+					      struct dentry *parent,
+					      umode_t mode,
+					      struct rchan_buf *buf,
+					      int *is_global)
+{
+	struct qal_dentry_t *buf_file;
+	*is_global = 1;
+	buf_file = qal_streamfs_create_file(filename, mode,
+					(struct qal_dentry_t *)parent,
+					(struct qal_streamfs_chan_buf *)buf);
+
+	if (!buf_file) {
+		cfr_err("Chan buffer creation failed\n");
+		return NULL;
+	}
+
+	return (struct dentry *)buf_file;
+}
+
+/**
+ * remove_buf_file_handler() - Remove streamfs buffer file
+ *  @dentry:dentry
+ */
+static int remove_buf_file_handler(struct dentry *dentry)
+{
+	qal_streamfs_remove_file((struct qal_dentry_t *)dentry);
+
+	return 0;
+}
+
+static struct rchan_callbacks cfr_streamfs_cb = {
+	.create_buf_file = create_buf_file_handler,
+	.remove_buf_file = remove_buf_file_handler,
+};
+
+QDF_STATUS cfr_streamfs_init(struct wlan_objmgr_pdev *pdev)
+{
+	struct pdev_cfr *pa = NULL;
+	char folder[32];
+	struct net_device *pdev_netdev;
+	struct ol_ath_softc_net80211 *scn;
+	struct target_pdev_info *tgt_hdl;
+
+	if (pdev == NULL) {
+		cfr_err("PDEV is NULL\n");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	tgt_hdl = wlan_pdev_get_tgt_if_handle(pdev);
+
+	if (!tgt_hdl) {
+		cfr_err("target_pdev_info is NULL\n");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	scn = target_pdev_get_feature_ptr(tgt_hdl);
+	pdev_netdev = scn->netdev;
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+
+	if (pa == NULL) {
+		cfr_err("pdev_cfr is NULL\n");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!pa->is_cfr_capable) {
+		cfr_err("CFR IS NOT SUPPORTED\n");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	snprintf(folder, sizeof(folder), "cfr%s", pdev_netdev->name);
+
+	pa->dir_ptr = qal_streamfs_create_dir((const char *)folder, NULL);
+
+	if (!pa->dir_ptr) {
+		cfr_err("Directory create failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pa->chan_ptr = qal_streamfs_open("cfr_dump", pa->dir_ptr,
+			pa->subbuf_size, pa->num_subbufs,
+			(struct qal_streamfs_chan_callbacks *)&cfr_streamfs_cb,
+			NULL);
+
+	if (!pa->chan_ptr) {
+		cfr_err("Chan create failed");
+		qal_streamfs_remove_dir_recursive(pa->dir_ptr);
+		pa->dir_ptr = NULL;
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev)
+{
+	struct pdev_cfr *pa = NULL;
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+	if (pa) {
+		if (pa->chan_ptr) {
+			qal_streamfs_close(pa->chan_ptr);
+			pa->chan_ptr = NULL;
+		}
+
+		if (pa->dir_ptr) {
+			qal_streamfs_remove_dir_recursive(pa->dir_ptr);
+			pa->dir_ptr = NULL;
+		}
+
+	} else
+		return QDF_STATUS_E_FAILURE;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data,
+			      size_t write_len)
+{
+	if (pa->chan_ptr) {
+
+	/* write to channel buffer */
+		qal_streamfs_write(pa->chan_ptr, (const void *)write_data,
+				write_len);
+	} else
+		return QDF_STATUS_E_FAILURE;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS cfr_streamfs_flush(struct pdev_cfr *pa)
+{
+	if (pa->chan_ptr) {
+
+	/* Flush the data write to channel buffer */
+		qal_streamfs_flush(pa->chan_ptr);
+	} else
+		return QDF_STATUS_E_FAILURE;
+
+	return QDF_STATUS_SUCCESS;
+}

+ 169 - 0
umac/cfr/dispatcher/inc/wlan_cfr_tgt_api.h

@@ -0,0 +1,169 @@
+/*
+ * 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 _WLAN_CFR_TGT_API_H_
+#define _WLAN_CFR_TGT_API_H_
+
+#include <wlan_objmgr_peer_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_cmn.h>
+#include <qdf_types.h>
+
+/* tgt layer has APIs in application, to access functions in target
+ * through tx_ops.
+ */
+
+/**
+ * tgt_cfr_init_pdev() - API that registers CFR to handlers.
+ * @pdev: pointer to pdev_object
+ *
+ * Return: success/failure of init
+ */
+int tgt_cfr_init_pdev(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * tgt_cfr_deinit_pdev() - API that de-registers CFR to handlers.
+ * @pdev: pointer to pdev_object
+ *
+ * Return: success/failure of de-init
+ */
+int tgt_cfr_deinit_pdev(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * tgt_cfr_get_target_type() - API to determine target type.
+ * @psoc: pointer to psoc_object
+ *
+ * Return: enum value of target type
+ */
+int tgt_cfr_get_target_type(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * tgt_cfr_start_capture() - API to start cfr capture on a peer.
+ * @pdev: pointer to pdev_object
+ * @peer: pointer to peer_object
+ * @cfr_params: pointer to config cfr_params
+ *
+ * Return: success/failure of start capture
+ */
+int tgt_cfr_start_capture(struct wlan_objmgr_pdev *pdev,
+			  struct wlan_objmgr_peer *peer,
+			  struct cfr_capture_params *cfr_params);
+
+/**
+ * tgt_cfr_stop_capture() - API to stop cfr capture on a peer.
+ * @pdev: pointer to pdev_object
+ * @peer: pointer to peer_object
+ *
+ * Return: success/failure of stop capture
+ */
+int tgt_cfr_stop_capture(struct wlan_objmgr_pdev *pdev,
+			 struct wlan_objmgr_peer *peer);
+
+/**
+ * tgt_cfr_enable_cfr_timer() - API to enable cfr timer
+ * @pdev: pointer to pdev_object
+ * @cfr_timer: Amount of time this timer has to run. If 0, it disables timer.
+ *
+ * Return: success/failure of timer enable
+ */
+int
+tgt_cfr_enable_cfr_timer(struct wlan_objmgr_pdev *pdev, uint32_t cfr_timer);
+
+/**
+ * tgt_cfr_support_set() - API to set cfr support
+ * @psoc: pointer to psoc_object
+ * @value: value to be set
+ */
+void tgt_cfr_support_set(struct wlan_objmgr_psoc *psoc, uint32_t value);
+
+/**
+ * tgt_cfr_info_send() - API to send cfr info
+ * @pdev: pointer to pdev_object
+ * @head: pointer to cfr info head
+ * @hlen: head len
+ * @data: pointer to cfr info data
+ * @dlen: data len
+ * @tail: pointer to cfr info tail
+ * @tlen: tail len
+ *
+ * Return: success/failure of cfr info send
+ */
+uint32_t tgt_cfr_info_send(struct wlan_objmgr_pdev *pdev, void *head,
+			   size_t hlen, void *data, size_t dlen, void *tail,
+			   size_t tlen);
+
+#ifdef WLAN_ENH_CFR_ENABLE
+/**
+ * tgt_cfr_config_rcc() - API to set RCC
+ * @pdev: pointer to pdev_object
+ * @rcc_param: rcc configurations
+ *
+ * Return: succcess / failure
+ */
+QDF_STATUS tgt_cfr_config_rcc(struct wlan_objmgr_pdev *pdev,
+			      struct cfr_rcc_param *rcc_param);
+
+/**
+ * tgt_cfr_start_lut_age_timer() - API to start timer to flush aged out LUT
+ * entries
+ * @pdev: pointer to pdev_object
+ *
+ * Return: None
+ */
+void tgt_cfr_start_lut_age_timer(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * tgt_cfr_stop_lut_age_timer() - API to stop timer to flush aged out LUT
+ * entries
+ * @pdev: pointer to pdev_object
+ *
+ * Return: None
+ */
+void tgt_cfr_stop_lut_age_timer(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * tgt_cfr_default_ta_ra_cfg() - API to configure default values in TA_RA mode
+ * entries
+ * @pdev: pointer to pdev_object
+ *
+ * Return: none
+ */
+void tgt_cfr_default_ta_ra_cfg(struct wlan_objmgr_pdev *pdev,
+			       struct cfr_rcc_param *rcc_param,
+			       bool allvalid, uint16_t reset_cfg);
+
+/**
+ * tgt_cfr_dump_lut_enh() - Print all LUT entries
+ * @pdev: pointer to pdev_object
+ */
+void tgt_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * tgt_cfr_rx_tlv_process() - Process PPDU status TLVs
+ * @pdev_obj: pointer to pdev_object
+ * @nbuf: pointer to cdp_rx_indication_ppdu
+ */
+void tgt_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf);
+
+/**
+ * tgt_cfr_update_global_cfg() - Update global config after successful commit
+ * @pdev: pointer to pdev_object
+ */
+void tgt_cfr_update_global_cfg(struct wlan_objmgr_pdev *pdev);
+#endif
+#endif

+ 267 - 0
umac/cfr/dispatcher/inc/wlan_cfr_ucfg_api.h

@@ -0,0 +1,267 @@
+/*
+ * 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 _WLAN_CFR_UCFG_API_H_
+#define _WLAN_CFR_UCFG_API_H_
+
+#include <wlan_objmgr_peer_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <ieee80211_ioctl.h>
+
+#define MAX_CFR_PRD        (10*60*1000)        /* 10 minutes */
+
+/**
+ * ucfg_cfr_start_capture() - function to start cfr capture for connected client
+ * @pdev: pointer to pdev object
+ * @peer: pointer to peer object
+ * @cfr_params: config params to cfr capture
+ *
+ * Return: status of start capture.
+ */
+int ucfg_cfr_start_capture(struct wlan_objmgr_pdev *pdev,
+			   struct wlan_objmgr_peer *peer,
+			   struct cfr_capture_params *cfr_params);
+
+/**
+ * ucfg_cfr_stop_capture() - function to stop cfr capture for connected client
+ * @pdev: pointer to pdev object
+ * @peer: pointer to peer object
+ *
+ * Return: status of stop capture.
+ */
+int ucfg_cfr_stop_capture(struct wlan_objmgr_pdev *pdev,
+			  struct wlan_objmgr_peer *peer);
+
+/**
+ * ucfg_cfr_start_capture_probe_req() - function to start cfr capture for
+ *					unassociated clients
+ * @pdev: pointer to pdev object
+ * @unassoc_mac: mac address of un-associated client
+ * @cfr_params: config params to cfr capture
+ *
+ * Return: status of start capture.
+ */
+int ucfg_cfr_start_capture_probe_req(struct wlan_objmgr_pdev *pdev,
+				     struct qdf_mac_addr *unassoc_mac,
+				     struct cfr_capture_params *params);
+
+/**
+ * ucfg_cfr_stop_capture_probe_req() - function to stop cfr capture for
+ *				       unassociated cleints
+ * @pdev: pointer to pdev object
+ * @unassoc_mac: mac address of un-associated client
+ *
+ * Return: status of stop capture.
+ */
+int ucfg_cfr_stop_capture_probe_req(struct wlan_objmgr_pdev *pdev,
+				    struct qdf_mac_addr *unassoc_mac);
+
+/**
+ * ucfg_cfr_list_peers() - Lists total number of peers with cfr capture enabled
+ * @pdev: pointer to pdev object
+ *
+ * Return: number of peers with cfr capture enabled
+ */
+int ucfg_cfr_list_peers(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * ucfg_cfr_set_timer() - function to enable cfr timer
+ * @pdev: pointer to pdev object
+ * @value: value to be set
+ *
+ * Return: status of timer enable
+ */
+int ucfg_cfr_set_timer(struct wlan_objmgr_pdev *pdev, uint32_t value);
+
+/**
+ * ucfg_cfr_get_timer() - function to get cfr_timer_enable
+ * @pdev: pointer to pdev object
+ *
+ * Return: value of cfr_timer_enable
+ */
+int ucfg_cfr_get_timer(struct wlan_objmgr_pdev *pdev);
+
+#ifdef WLAN_ENH_CFR_ENABLE
+/* Channel capture recipe filters */
+enum capture_type {
+	RCC_DIRECTED_FTM_FILTER,
+	RCC_ALL_FTM_ACK_FILTER,
+	RCC_DIRECTED_NDPA_NDP_FILTER,
+	RCC_NDPA_NDP_ALL_FILTER,
+	RCC_TA_RA_FILTER,
+	RCC_ALL_PACKET_FILTER,
+	RCC_DIS_ALL_MODE,
+};
+
+/**
+ * ucfg_cfr_set_rcc_mode() - function to set RCC mode
+ * @vdev: pointer to vdev object
+ * @mode: capture type passed by user
+ * @value: Enable/Disable capture mode
+ *
+ * Return: status if the mode is set or not
+ */
+QDF_STATUS ucfg_cfr_set_rcc_mode(struct wlan_objmgr_vdev *vdev,
+				 enum capture_type mode, uint8_t value);
+
+/**
+ * ucfg_cfr_get_rcc_enabled() - function to get RCC mode
+ * @vdev: pointer to vdev object
+ *
+ * Return: if the rcc is enabled or not
+ */
+bool ucfg_cfr_get_rcc_enabled(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_cfr_set_tara_config() - function to configure TA/RA address and mask
+ * @vdev: pointer to vdev object
+ * @params: user config
+ *
+ * Return: status
+ */
+QDF_STATUS ucfg_cfr_set_tara_config(struct wlan_objmgr_vdev *vdev,
+				    struct ieee80211_wlanconfig_cfr *params);
+
+/**
+ * ucfg_cfr_set_bw_nss() - function to configure nss and bandwidth
+ * @vdev: pointer to vdev object
+ * @params: user config
+ *
+ * Return: status
+ */
+QDF_STATUS ucfg_cfr_set_bw_nss(struct wlan_objmgr_vdev *vdev,
+			       struct ieee80211_wlanconfig_cfr *params);
+
+/**
+ * ucfg_cfr_set_frame_type_subtype() - function to configure frame type/subtype
+ * @vdev: pointer to vdev object
+ * @params: user config
+ *
+ * Return: status
+ */
+QDF_STATUS
+ucfg_cfr_set_frame_type_subtype(struct wlan_objmgr_vdev *vdev,
+				struct ieee80211_wlanconfig_cfr *params);
+
+/**
+ * ucfg_cfr_set_capture_duration() - function to configure capture duration
+ * @vdev: pointer to vdev object
+ * @params: user config
+ *
+ * Return: status
+ */
+QDF_STATUS
+ucfg_cfr_set_capture_duration(struct wlan_objmgr_vdev *vdev,
+			      struct ieee80211_wlanconfig_cfr *params);
+
+/**
+ * ucfg_cfr_set_capture_interval() - function to configure capture interval
+ * @vdev: pointer to vdev object
+ * @params: user config
+ *
+ * Return: status
+ */
+QDF_STATUS
+ucfg_cfr_set_capture_interval(struct wlan_objmgr_vdev *vdev,
+			      struct ieee80211_wlanconfig_cfr *params);
+
+/**
+ * ucfg_cfr_set_en_bitmap() - function to configure 16-bit bitmap in TA_RA mode
+ * @vdev: pointer to vdev object
+ * @params: user config
+ *
+ * Return: status
+ */
+QDF_STATUS ucfg_cfr_set_en_bitmap(struct wlan_objmgr_vdev *vdev,
+				  struct ieee80211_wlanconfig_cfr *params);
+
+/**
+ * ucfg_cfr_set_reset_bitmap() - function to clear all 9 params for all 16
+ * groups in TA_RA mode
+ * @vdev: pointer to vdev object
+ * @params: user config
+ *
+ * Return: status
+ */
+QDF_STATUS ucfg_cfr_set_reset_bitmap(struct wlan_objmgr_vdev *vdev,
+				     struct ieee80211_wlanconfig_cfr *params);
+
+/**
+ * ucfg_cfr_set_ul_mu_user_mask() - function to configure UL MU user mask
+ * @vdev: pointer to vdev object
+ * @params: user config
+ *
+ * Return: status
+ */
+QDF_STATUS
+ucfg_cfr_set_ul_mu_user_mask(struct wlan_objmgr_vdev *vdev,
+			     struct ieee80211_wlanconfig_cfr *params);
+
+/**
+ * ucfg_cfr_set_freeze_tlv_delay_cnt() - function to configure freeze TLV delay
+ * count threshold
+ * @vdev: pointer to vdev object
+ * @params: user config
+ *
+ * Return: status
+ */
+QDF_STATUS
+ucfg_cfr_set_freeze_tlv_delay_cnt(struct wlan_objmgr_vdev *vdev,
+				  struct ieee80211_wlanconfig_cfr *params);
+
+/**
+ * ucfg_cfr_committed_rcc_config() - function to commit user config
+ * @vdev: pointer to vdev object
+ *
+ * Return: status
+ */
+QDF_STATUS ucfg_cfr_committed_rcc_config(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_cfr_get_cfg() - function to display user config
+ * @vdev: pointer to vdev object
+ *
+ * Return: status
+ */
+QDF_STATUS ucfg_cfr_get_cfg(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_cfr_rcc_dump_dbg_counters() - function to display PPDU counters
+ * @vdev: pointer to vdev object
+ *
+ * Return: status
+ */
+QDF_STATUS ucfg_cfr_rcc_dump_dbg_counters(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_cfr_rcc_clr_dbg_counters() - function to clear CFR PPDU counters
+ * @vdev: pointer to vdev object
+ *
+ * Return: status
+ */
+QDF_STATUS ucfg_cfr_rcc_clr_dbg_counters(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_cfr_rcc_dump_lut() - function to display lookup table
+ * @vdev: pointer to vdev object
+ *
+ * Return: status
+ */
+QDF_STATUS ucfg_cfr_rcc_dump_lut(struct wlan_objmgr_vdev *vdev);
+#endif
+#endif

+ 583 - 0
umac/cfr/dispatcher/inc/wlan_cfr_utils_api.h

@@ -0,0 +1,583 @@
+/*
+ * 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 _WLAN_CFR_UTILS_API_H_
+#define _WLAN_CFR_UTILS_API_H_
+
+#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)
+
+#define cfr_err(format, args...) \
+		QDF_TRACE_ERROR(QDF_MODULE_ID_CFR, format, ## args)
+
+#define cfr_warn(format, args...) \
+		QDF_TRACE_WARN(QDF_MODULE_ID_CFR, format, ## args)
+
+#define cfr_info(format, args...) \
+		QDF_TRACE_INFO(QDF_MODULE_ID_CFR, format, ## args)
+
+#define cfr_debug(format, args...) \
+		QDF_TRACE_DEBUG(QDF_MODULE_ID_CFR, format, ## args)
+
+#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
+#define MAX_TA_RA_ENTRIES 16
+#define MAX_RESET_CFG_ENTRY 0xFFFF
+#endif
+
+enum cfrmetaversion {
+	CFR_META_VERSION_NONE,
+	CFR_META_VERSION_1,
+	CFR_META_VERSION_2,
+	CFR_META_VERSION_3,
+	CFR_META_VERSION_MAX = 0xFF,
+};
+
+enum cfrdataversion {
+	CFR_DATA_VERSION_NONE,
+	CFR_DATA_VERSION_1,
+	CFR_DATA_VERSION_MAX = 0xFF,
+};
+
+enum cfrplatformtype {
+	CFR_PLATFORM_TYPE_NONE,
+	CFR_PLATFORM_TYPE_MIPS,
+	CFR_PLATFORM_TYPE_ARM,
+	CFR_PLATFFORM_TYPE_MAX = 0xFF,
+};
+
+enum cfrradiotype {
+	CFR_CAPTURE_RADIO_NONE,
+	CFR_CAPTURE_RADIO_OSPREY,
+	CFR_CAPTURE_RADIO_PEAKCOCK,
+	CFR_CAPTURE_RADIO_SCORPION,
+	CFR_CAPTURE_RADIO_HONEYBEE,
+	CFR_CAPTURE_RADIO_DRAGONFLY,
+	CFR_CAPTURE_RADIO_JET,
+	CFR_CAPTURE_RADIO_PEREGRINE = 17,
+	CFR_CAPTURE_RADIO_SWIFT,
+	CFR_CAPTURE_RADIO_BEELINER,
+	CFR_CAPTURE_RADIO_CASCADE,
+	CFR_CAPTURE_RADIO_DAKOTA,
+	CFR_CAPTURE_RADIO_BESRA,
+	CFR_CAPTURE_RADIO_HKV2,
+	CFR_CAPTURE_RADIO_CYP,
+	CFR_CAPTURE_RADIO_MAX = 0xFF,
+};
+
+enum ack_capture_mode {
+	CFR_LEGACY_ACK     = 0,
+	CFR_DUP_LEGACY_ACK = 1,
+	CFR_HT_ACK         = 2,
+	CFR_VHT_ACK        = 3,
+	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,
+};
+
+struct cfr_metadata_version_1 {
+	u_int8_t    peer_addr[QDF_MAC_ADDR_SIZE];
+	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;
+	u_int8_t    capture_type;
+	u_int8_t    sts_count;
+	u_int8_t    num_rx_chain;
+	u_int32_t   timestamp;
+	u_int32_t   length;
+} __attribute__ ((__packed__));
+
+#define HOST_MAX_CHAINS 8
+
+struct cfr_metadata_version_2 {
+	u_int8_t    peer_addr[QDF_MAC_ADDR_SIZE];
+	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;
+	u_int8_t    capture_type;
+	u_int8_t    sts_count;
+	u_int8_t    num_rx_chain;
+	u_int32_t   timestamp;
+	u_int32_t   length;
+	u_int32_t   chain_rssi[HOST_MAX_CHAINS];
+	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;
+	u_int8_t    cfr_metadata_version;
+	u_int8_t    cfr_data_version;
+	u_int8_t    chip_type;
+	u_int8_t    pltform_type;
+	u_int32_t   Reserved;
+
+	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__));
+
+/**
+ * struct cfr_capture_params - structure to store cfr config param
+ * bandwidth: bandwitdh of capture
+ * period: period of capture
+ * method: enum of method being followed to capture cfr data. 0-QoS null data
+ */
+struct cfr_capture_params {
+	u_int8_t   bandwidth;
+	u_int32_t  period;
+	u_int8_t   method;
+};
+
+/**
+ * struct psoc_cfr - private psoc object for cfr
+ * psoc_obj: pointer to psoc object
+ * is_cfr_capable: flag to determine if cfr is enabled or not
+ */
+struct psoc_cfr {
+	struct wlan_objmgr_psoc *psoc_obj;
+	uint8_t is_cfr_capable;
+};
+
+/**
+ * struct cfr_wmi_host_mem_chunk - wmi mem chunk related
+ * vaddr: pointer to virtual address
+ * paddr: physical address
+ * len: len of the mem chunk allocated
+ * req_id: reqid related to the mem chunk
+ */
+struct cfr_wmi_host_mem_chunk {
+	uint32_t *vaddr;
+	uint32_t paddr;
+	uint32_t len;
+	uint32_t req_id;
+};
+
+struct whal_cfir_dma_hdr {
+	uint16_t
+		// 'BA'
+		tag                 : 8,
+		// '02', length of header in 4 octet units
+		length              : 6,
+		// 00
+		reserved            : 2;
+	uint16_t
+		// [16]
+		upload_done         : 1,
+		// [17:18], 0: invalid, 1: CFR, 2: CIR, 3: DebugH
+		capture_type        : 3,
+		// [19:20], 0: Legacy, 1: HT, 2: VHT, 3: HE
+		preamble_type       : 2,
+		// [21:23], 0: 1-stream, 1: 2-stream, ..., 7: 8-stream
+		nss                 : 3,
+		// [24:27], 0: invalid, 1: 1-chain, 2: 2-chain, etc.
+		num_chains          : 3,
+		// [28:30], 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160 MHz
+		upload_pkt_bw       : 3,    // [31]
+		sw_peer_id_valid    : 1;
+	uint16_t
+		sw_peer_id          : 16;   // [15:0]
+	uint16_t
+		phy_ppdu_id         : 16;   // [15:0]
+};
+
+#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;
+	uint8_t *data; /* capture payload */
+	uint32_t data_len; /* capture len */
+	uint16_t dbr_ppdu_id; /* ppdu id from dbr */
+	uint16_t tx_ppdu_id; /* ppdu id from TX event */
+	qdf_dma_addr_t dbr_address; /* capture len */
+	uint32_t tx_address1; /* capture len */
+	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 {
+	struct qdf_mac_addr mac;
+	struct cfr_capture_params cfr_params;
+	bool is_valid;
+};
+
+#ifdef WLAN_ENH_CFR_ENABLE
+/**
+ * struct ta_ra_cfr_cfg - structure to store configuration of 16 groups in
+ * M_TA_RA mode
+ * filter_group_id: Filter group number for which the below filters needs to be
+ * applied
+ * bw: CFR capture will be done for packets matching the bandwidths specified
+ * within this bitmask
+ * nss: CFR capture will be done for packets matching the Nss specified within
+ * this bitmask
+ * valid_ta: Ta_addr is valid if set
+ * valid_ta_mask: Ta_addr_mask is valid if set
+ * valid_ra: Ra_addr is valid if set
+ * valid_ra_mask: Ra_addr_mask is valid if set
+ * valid_bw_mask: Bandwidth is valid if set
+ * valid_nss_mask: NSS is valid if set
+ * valid_mgmt_subtype: Mgmt_subtype is valid if set
+ * valid_ctrl_subtype: Ctrl_subtype is valid if set
+ * valid_data_subtype: Data_subtype is valid if set
+ * mgmt_subtype_filter: Managments Packets matching the subtype filter
+ * categories will be filtered in by MAC for CFR capture.
+ * ctrl_subtype_filter: Control Packets matching the subtype filter
+ * categories will be filtered in by MAC for CFR capture.
+ * data_subtype_filter: Data Packets matching the subtype filter
+ * categories will be filtered in by MAC for CFR capture.
+ * tx_addr: Packets whose transmitter address matches (tx_addr & tx_addr_mask)
+ * will be filtered in by MAC
+ * tx_addr_mask: Packets whose transmitter address matches (tx_addr &
+ * tx_addr_mask) will be filtered in by MAC
+ * rx_addr: Packets whose receiver address matches (rx_addr & rx_addr_mask)
+ * will be filtered in by MAC
+ * rx_addr_mask: Packets whose receiver address matches (rx_addr &
+ * rx_addr_mask) will be filtered in by MAC
+ */
+struct ta_ra_cfr_cfg {
+	uint8_t filter_group_id;
+	uint16_t bw                          :5,
+		 nss                         :8,
+		 rsvd0                       :3;
+	uint16_t valid_ta                    :1,
+		 valid_ta_mask               :1,
+		 valid_ra                    :1,
+		 valid_ra_mask               :1,
+		 valid_bw_mask               :1,
+		 valid_nss_mask              :1,
+		 valid_mgmt_subtype          :1,
+		 valid_ctrl_subtype          :1,
+		 valid_data_subtype          :1,
+		 rsvd1                       :7;
+	uint16_t mgmt_subtype_filter;
+	uint16_t ctrl_subtype_filter;
+	uint16_t data_subtype_filter;
+	uint8_t tx_addr[QDF_MAC_ADDR_SIZE];
+	uint8_t rx_addr[QDF_MAC_ADDR_SIZE];
+	uint8_t tx_addr_mask[QDF_MAC_ADDR_SIZE];
+	uint8_t rx_addr_mask[QDF_MAC_ADDR_SIZE];
+
+} qdf_packed;
+
+/**
+ * struct cfr_rcc_param - structure to store cfr config param
+ * pdev_id: pdev_id for identifying the MAC
+ * capture_duration: Capture Duration field for which CFR capture has to happen,
+ * in microsecond units
+ * capture_interval: Capture interval field which is time in between
+ * consecutive CFR capture, in microsecond units
+ * ul_mu_user_mask_lower: Bitfields indicates which of the users in the current
+ * UL MU tranmission are enabled for CFR capture.
+ * ul_mu_user_mask_upper: This is contiuation of the above lower mask.
+ * freeze_tlv_delay_cnt_en: Enable Freeze TLV delay counter in MAC
+ * freeze_tlv_delay_cnt_thr: Indicates the number of consecutive Rx packets to
+ * be skipped before CFR capture is enabled again.
+ * filter_group_bitmap: Bitfields set indicates which of the CFR group config is
+ * enabled
+ * m_directed_ftm: Filter Directed FTM ACK frames for CFR capture
+ * m_all_ftm_ack: Filter All FTM ACK frames for CFR capture
+ * m_ndpa_ndp_directed: Filter NDPA NDP Directed Frames for CFR capture
+ * m_ndpa_ndp_all: Filter all NDPA NDP for CFR capture
+ * m_ta_ra_filter: Filter Frames based on TA/RA/Subtype as provided in CFR Group
+ * config
+ * m_all_packet: Filter in All packets for CFR Capture
+ * num_grp_tlvs: Indicates the number of groups in M_TA_RA mode, that have
+ * changes in the current commit session, use to construct WMI group TLV(s)
+ * curr: Placeholder for M_TA_RA group config in current commit session
+ * modified_in_curr_session: Bitmap indicating number of groups in M_TA_RA mode
+ * that have changed in current commit session.
+ */
+struct cfr_rcc_param {
+	uint8_t pdev_id;
+	uint32_t capture_duration;
+	uint32_t capture_interval;
+	uint32_t ul_mu_user_mask_lower;
+	uint32_t ul_mu_user_mask_upper;
+	uint16_t freeze_tlv_delay_cnt_en  :1,
+		 freeze_tlv_delay_cnt_thr :8,
+		 rsvd0 :7;
+	uint16_t filter_group_bitmap;
+	uint8_t m_directed_ftm      : 1,
+		m_all_ftm_ack       : 1,
+		m_ndpa_ndp_directed : 1,
+		m_ndpa_ndp_all      : 1,
+		m_ta_ra_filter      : 1,
+		m_all_packet        : 1,
+		rsvd1               : 2;
+	uint8_t num_grp_tlvs;
+
+	struct ta_ra_cfr_cfg curr[MAX_TA_RA_ENTRIES];
+	uint16_t modified_in_curr_session;
+};
+#endif /* WLAN_ENH_CFR_ENABLE */
+
+/**
+ * struct pdev_cfr - private pdev object for cfr
+ * 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
+ * cfr_mem_chunk: Region of memory used for storing cfr data
+ * cfr_max_sta_count: Maximum stations supported in one-shot capture mode
+ * num_subbufs: No. of sub-buffers used in relayfs
+ * subbuf_size: Size of sub-buffer used in relayfs
+ * chan_ptr: Channel in relayfs
+ * dir_ptr: Parent directory of relayfs file
+ * lut: lookup table used to store asynchronous DBR and TX/RX events for
+ * correlation
+ * dbr_buf_size: Size of DBR completion buffer
+ * dbr_num_bufs: No. of DBR completions
+ * tx_evt_cnt: No. of TX completion events till CFR stop was issued
+ * total_tx_evt_cnt: No. of Tx completion events since wifi was up
+ * dbr_evt_cnt: No. of WMI DBR completion events
+ * release_cnt: No. of CFR data buffers relayed to userspace
+ * rcc_param: Structure to store CFR config for the current commit session
+ * global: Structure to store accumulated CFR config
+ * 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
+ * is_cfr_rcc_capable: Flag to determine if RCC is enabled or not.
+ * flush_dbr_cnt: No. of un-correlated DBR completions flushed when a newer PPDU
+ * is correlated successfully with newer DBR completion
+ * invalid_dma_length_cnt: No. of buffers for which CFR DMA header length (or)
+ * data length was invalid
+ * flush_timeout_dbr_cnt: No. of DBR completion flushed out in ageout logic
+ * clear_txrx_event: No. of PPDU status TLVs over-written in LUT
+ * unassoc_pool: Pool of un-associated clients used when capture method is
+ * CFR_CAPTURE_METHOD_PROBE_RESPONSE
+ * last_success_tstamp: DBR timestamp which indicates that both DBR and TX/RX
+ * events have been received successfully.
+ * cfr_dma_aborts: No. of CFR DMA aborts in ucode
+ */
+/*
+ * To be extended if we get more capbality info
+ * from FW's extended service ready event.
+ */
+struct pdev_cfr {
+	struct wlan_objmgr_pdev *pdev_obj;
+	uint8_t is_cfr_capable;
+	uint8_t cfr_timer_enable;
+	struct cfr_wmi_host_mem_chunk cfr_mem_chunk;
+	uint16_t cfr_max_sta_count;
+	uint16_t cfr_current_sta_count;
+	uint32_t num_subbufs;
+	uint32_t subbuf_size;
+	struct qal_streamfs_chan *chan_ptr;
+	struct qal_dentry_t *dir_ptr;
+	struct look_up_table lut[MAX_LUT_ENTRIES];
+	uint32_t dbr_buf_size;
+	uint32_t dbr_num_bufs;
+	uint64_t tx_evt_cnt;
+	uint64_t total_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;
+	uint8_t is_cfr_rcc_capable;
+	uint64_t flush_dbr_cnt;
+	uint64_t invalid_dma_length_cnt;
+	uint64_t flush_timeout_dbr_cnt;
+	uint64_t clear_txrx_event;
+	uint64_t last_success_tstamp;
+	uint64_t cfr_dma_aborts;
+#endif
+	struct unassoc_pool_entry unassoc_pool[MAX_CFR_ENABLED_CLIENTS];
+};
+
+#define PEER_CFR_CAPTURE_ENABLE   1
+#define PEER_CFR_CAPTURE_DISABLE  0
+/**
+ * struct peer_cfr - private peer object for cfr
+ * peer_obj: pointer to peer_obj
+ * request: Type of request (start/stop)
+ * bandwidth: bandwitdth of capture for this peer
+ * capture_method: enum determining type of cfr data capture.
+ *                 0-Qos null data
+ */
+struct peer_cfr {
+	struct wlan_objmgr_peer *peer_obj;
+	u_int8_t   request;            /* start/stop */
+	u_int8_t   bandwidth;
+	u_int32_t  period;
+	u_int8_t   capture_method;
+};
+
+/**
+ * cfr_initialize_pdev() - cfr initialize pdev
+ * @pdev: Pointer to pdev_obj
+ *
+ * Return: status of cfr pdev init
+ */
+QDF_STATUS cfr_initialize_pdev(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * cfr_deinitialize_pdev() - cfr deinitialize pdev
+ * @pdev: Pointer to pdev_obj
+ *
+ * Return: status of cfr pdev deinit
+ */
+QDF_STATUS cfr_deinitialize_pdev(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * wlan_cfr_init() - Global init for cfr.
+ *
+ * Return: status of global init pass/fail
+ */
+QDF_STATUS wlan_cfr_init(void);
+
+/**
+ * wlan_cfr_deinit() - Global de-init for cfr.
+ *
+ * Return: status of global de-init pass/fail
+ */
+QDF_STATUS wlan_cfr_deinit(void);
+
+/**
+ * wlan_cfr_pdev_open() - pdev_open function for cfr.
+ * @pdev: pointer to pdev object
+ *
+ * Return: status of pdev_open pass/fail
+ */
+QDF_STATUS wlan_cfr_pdev_open(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * wlan_cfr_pdev_close() - pdev_close function for cfr.
+ * @pdev: pointer to pdev object
+ *
+ * Return: status of pdev_close pass/fail
+ */
+QDF_STATUS wlan_cfr_pdev_close(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * count_set_bits() - function to count set bits in a bitmap
+ * @value: input bitmap
+ *
+ * Return: No. of set bits
+ */
+uint8_t count_set_bits(uint32_t value);
+
+#ifdef WLAN_ENH_CFR_ENABLE
+/**
+ * wlan_cfr_rx_tlv_process() - Process PPDU status TLVs and store info in
+ * lookup table
+ * @pdev_obj: PDEV object
+ * @nbuf: ppdu info
+ *
+ * Return: none
+ */
+void wlan_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf);
+#endif
+#endif

+ 287 - 0
umac/cfr/dispatcher/src/wlan_cfr_tgt_api.c

@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+/*
+ * Layer b/w umac and target_if (ol) txops
+ * It contains wrapers for txops
+ */
+
+#include <wlan_cfr_tgt_api.h>
+#include <wlan_cfr_utils_api.h>
+#include <target_type.h>
+#include <cfr_defs_i.h>
+
+uint32_t tgt_cfr_info_send(struct wlan_objmgr_pdev *pdev, void *head,
+			   size_t hlen, void *data, size_t dlen, void *tail,
+			   size_t tlen)
+{
+	struct pdev_cfr *pa;
+	uint32_t status;
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+
+	if (pa == NULL) {
+		cfr_err("pdev_cfr is NULL\n");
+		return -1;
+	}
+
+	if (head)
+		status = cfr_streamfs_write(pa, (const void *)head, hlen);
+
+	if (data)
+		status = cfr_streamfs_write(pa, (const void *)data, dlen);
+
+	if (tail)
+		status = cfr_streamfs_write(pa, (const void *)tail, tlen);
+
+
+	/* finalise the write */
+	status = cfr_streamfs_flush(pa);
+
+	return status;
+}
+
+void tgt_cfr_support_set(struct wlan_objmgr_psoc *psoc, uint32_t value)
+{
+	struct psoc_cfr *cfr_sc;
+
+	if (psoc == NULL)
+		return;
+
+	cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+					WLAN_UMAC_COMP_CFR);
+	if (cfr_sc == NULL)
+		return;
+
+	cfr_sc->is_cfr_capable = !!value;
+	cfr_debug("CFR:%s FW support advert=%d\n", __func__,
+		    cfr_sc->is_cfr_capable);
+}
+
+static inline struct wlan_lmac_if_cfr_tx_ops *
+	wlan_psoc_get_cfr_txops(struct wlan_objmgr_psoc *psoc)
+{
+	return &((psoc->soc_cb.tx_ops.cfr_tx_ops));
+}
+
+int tgt_cfr_get_target_type(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t target_type = 0;
+	struct wlan_lmac_if_target_tx_ops *target_type_tx_ops;
+
+	target_type_tx_ops = &psoc->soc_cb.tx_ops.target_tx_ops;
+
+	if (target_type_tx_ops->tgt_get_tgt_type)
+		target_type = target_type_tx_ops->tgt_get_tgt_type(psoc);
+
+	return target_type;
+}
+
+int tgt_cfr_init_pdev(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	int status = 0;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_init_pdev)
+		status = cfr_tx_ops->cfr_init_pdev(psoc, pdev);
+
+	if (status != 0)
+		cfr_err("Error occurred with exit code %d\n", status);
+
+	return status;
+}
+
+int tgt_cfr_deinit_pdev(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	int status = 0;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_deinit_pdev)
+		status = cfr_tx_ops->cfr_deinit_pdev(psoc, pdev);
+
+	if (status != 0)
+		cfr_err("Error occurred with exit code %d\n", status);
+
+	return status;
+}
+
+int tgt_cfr_start_capture(struct wlan_objmgr_pdev *pdev,
+			  struct wlan_objmgr_peer *peer,
+			  struct cfr_capture_params *cfr_params)
+{
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	int status = 0;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_start_capture)
+		status = cfr_tx_ops->cfr_start_capture(pdev, peer, cfr_params);
+
+	if (status != 0)
+		cfr_err("Error occurred with exit code %d\n", status);
+
+	return status;
+}
+
+int tgt_cfr_stop_capture(struct wlan_objmgr_pdev *pdev,
+			 struct wlan_objmgr_peer *peer)
+{
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	int status = 0;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_stop_capture)
+		status = cfr_tx_ops->cfr_stop_capture(pdev, peer);
+
+	if (status != 0)
+		cfr_err("Error occurred with exit code %d\n", status);
+
+	return status;
+}
+
+int
+tgt_cfr_enable_cfr_timer(struct wlan_objmgr_pdev *pdev, uint32_t cfr_timer)
+{
+	int status = 0;
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_enable_cfr_timer)
+		status = cfr_tx_ops->cfr_enable_cfr_timer(pdev, cfr_timer);
+
+	if (status != 0)
+		cfr_err("Error occurred with exit code %d\n", status);
+
+	return status;
+}
+
+#ifdef WLAN_ENH_CFR_ENABLE
+QDF_STATUS
+tgt_cfr_config_rcc(struct wlan_objmgr_pdev *pdev,
+		   struct cfr_rcc_param *rcc_param)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_config_rcc)
+		status = cfr_tx_ops->cfr_config_rcc(pdev, rcc_param);
+
+	if (status != QDF_STATUS_SUCCESS)
+		cfr_err("Error occurred with exit code %d\n", status);
+
+	return status;
+}
+
+void tgt_cfr_start_lut_age_timer(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	if (!psoc) {
+		cfr_err("Invalid PSOC: Flush LUT Timer cannot be started\n");
+		return;
+	}
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_start_lut_timer)
+		cfr_tx_ops->cfr_start_lut_timer(pdev);
+}
+
+void tgt_cfr_stop_lut_age_timer(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	if (!psoc) {
+		cfr_err("Invalid PSOC: Flush LUT Timer cannot be stopped\n");
+		return;
+	}
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_stop_lut_timer)
+		cfr_tx_ops->cfr_stop_lut_timer(pdev);
+}
+
+void tgt_cfr_default_ta_ra_cfg(struct wlan_objmgr_pdev *pdev,
+			       struct cfr_rcc_param *rcc_param,
+			       bool allvalid, uint16_t reset_cfg)
+{
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_default_ta_ra_cfg)
+		cfr_tx_ops->cfr_default_ta_ra_cfg(rcc_param,
+						 allvalid, reset_cfg);
+}
+
+void tgt_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_dump_lut_enh)
+		cfr_tx_ops->cfr_dump_lut_enh(pdev);
+}
+
+void tgt_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
+{
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_rx_tlv_process)
+		cfr_tx_ops->cfr_rx_tlv_process(pdev, nbuf);
+}
+
+void tgt_cfr_update_global_cfg(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	if (!psoc) {
+		cfr_err("Invalid PSOC:Cannot update global config.\n");
+		return;
+	}
+
+	cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc);
+
+	if (cfr_tx_ops->cfr_update_global_cfg)
+		cfr_tx_ops->cfr_update_global_cfg(pdev);
+}
+#endif

+ 1104 - 0
umac/cfr/dispatcher/src/wlan_cfr_ucfg_api.c

@@ -0,0 +1,1104 @@
+/*
+ * 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 <wlan_cfr_ucfg_api.h>
+#include "../../core/inc/cfr_defs_i.h"
+#include <wlan_cfr_utils_api.h>
+#include <wlan_cfr_tgt_api.h>
+#include <wlan_objmgr_peer_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#ifdef WLAN_ENH_CFR_ENABLE
+#include "cdp_txrx_ctrl.h"
+#endif
+
+int ucfg_cfr_start_capture(struct wlan_objmgr_pdev *pdev,
+			   struct wlan_objmgr_peer *peer,
+			   struct cfr_capture_params *params)
+{
+	int status;
+	struct pdev_cfr *pa;
+	struct peer_cfr *pe;
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+	if (NULL == pa) {
+		cfr_err("PDEV cfr object is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (!(pa->is_cfr_capable)) {
+		qdf_info("cfr is not supported on this chip\n");
+		return -EINVAL;
+	}
+
+	/* Get peer private object */
+	pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR);
+	if (NULL == pe) {
+		cfr_err("PEER cfr object is NULL!\n");
+		return -EINVAL;
+	}
+
+	if ((params->period < 0) || (params->period > MAX_CFR_PRD) ||
+		(params->period % 10)) {
+		cfr_err("Invalid period value: %d\n", params->period);
+		return -EINVAL;
+	}
+
+	if (!(params->period) && (pa->cfr_timer_enable)) {
+		cfr_err("Single shot capture is not allowed during periodic capture\n");
+		return -EINVAL;
+	}
+
+	if ((params->period) && !(pa->cfr_timer_enable)) {
+		cfr_err("Global periodic timer is not enabled, configure global cfr timer\n");
+	}
+
+	if (params->period) {
+		if (pa->cfr_current_sta_count == pa->cfr_max_sta_count) {
+			qdf_info("max periodic cfr clients reached\n");
+			return -EINVAL;
+		}
+		if (!(pe->request))
+			pa->cfr_current_sta_count++;
+	}
+
+	status = tgt_cfr_start_capture(pdev, peer, params);
+
+	if (status == 0) {
+		pe->bandwidth = params->bandwidth;
+		pe->period = params->period;
+		pe->capture_method = params->method;
+		pe->request = PEER_CFR_CAPTURE_ENABLE;
+	} else
+		pa->cfr_current_sta_count--;
+
+	return status;
+}
+
+int ucfg_cfr_start_capture_probe_req(struct wlan_objmgr_pdev *pdev,
+				     struct qdf_mac_addr *unassoc_mac,
+				     struct cfr_capture_params *params)
+{
+	int idx, idx_to_insert = -1;
+	struct pdev_cfr *pa;
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+	if (!pa) {
+		cfr_err("Pdev cfr object is null!");
+		return -EINVAL;
+	}
+
+	if (!(pa->is_cfr_capable)) {
+		cfr_err("CFR is not supported on this chip");
+		return -EINVAL;
+	}
+
+	if (pa->cfr_current_sta_count == pa->cfr_max_sta_count) {
+		cfr_err("max cfr cleint reached");
+		return -EINVAL;
+	}
+
+	for (idx = 0; idx < MAX_CFR_ENABLED_CLIENTS; idx++) {
+		/* Store first invalid entry's index, to add mac entry if not
+		 * already present.
+		 */
+		if (idx_to_insert < 0) {
+			if (pa->unassoc_pool[idx].is_valid != true)
+				idx_to_insert = idx;
+		}
+
+		/* Add new mac entry only if it is not present. If already
+		 * present, update the capture parameters
+		 */
+		if (qdf_mem_cmp(&pa->unassoc_pool[idx].mac, unassoc_mac,
+				sizeof(struct qdf_mac_addr)) == 0) {
+			cfr_info("Node already present. Updating params");
+			qdf_mem_copy(&pa->unassoc_pool[idx].cfr_params,
+				     params,
+				     sizeof(struct cfr_capture_params));
+			pa->unassoc_pool[idx].is_valid = true;
+			return 0;
+		}
+	}
+
+	if (idx_to_insert < 0) {
+		/* All the entries in the table are valid. So we have reached
+		 * max client capacity. To add a new client, capture on one of
+		 * the clients in table has to be stopped.
+		 */
+		cfr_err("Maximum client capacity reached");
+		return -EINVAL;
+	}
+
+	/* If control reaches here, we did not find mac in the table
+	 * and we have atleast one free entry in table.
+	 * Add the entry at index = idx_to_insert
+	 */
+	qdf_mem_copy(&pa->unassoc_pool[idx_to_insert].mac,
+		     unassoc_mac, sizeof(struct qdf_mac_addr));
+	qdf_mem_copy(&pa->unassoc_pool[idx_to_insert].cfr_params,
+		     params, sizeof(struct cfr_capture_params));
+	pa->unassoc_pool[idx_to_insert].is_valid = true;
+	pa->cfr_current_sta_count++;
+
+	return 0;
+}
+
+int ucfg_cfr_stop_capture_probe_req(struct wlan_objmgr_pdev *pdev,
+				    struct qdf_mac_addr *unassoc_mac)
+{
+	struct pdev_cfr *pa;
+	int idx;
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+	if (!pa) {
+		cfr_err("Pdev cfr object is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (!(pa->is_cfr_capable)) {
+		cfr_err("CFR is not supported on this chip\n");
+		return -EINVAL;
+	}
+
+	for (idx = 0; idx < MAX_CFR_ENABLED_CLIENTS; idx++) {
+		/* Remove mac only if it is present */
+		if (qdf_mem_cmp(&pa->unassoc_pool[idx].mac, unassoc_mac,
+				sizeof(struct qdf_mac_addr)) == 0) {
+			qdf_mem_zero(&pa->unassoc_pool[idx],
+				     sizeof(struct unassoc_pool_entry));
+			pa->cfr_current_sta_count--;
+			return 0;
+		}
+	}
+
+	/* If mac was present in pool it would have been deleted in the
+	 * above loop and returned from there.
+	 * If control reached here, mac was not found. So, ignore the request.
+	 */
+	cfr_err("Trying to delete mac not present in pool. Ignoring request.");
+	return 0;
+}
+
+int ucfg_cfr_set_timer(struct wlan_objmgr_pdev *pdev, uint32_t value)
+{
+	struct pdev_cfr *pa;
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+	if (pa == NULL) {
+		cfr_err("PDEV cfr object is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (!(pa->is_cfr_capable)) {
+		qdf_info("cfr is not supported on this chip\n");
+		return -EINVAL;
+	}
+
+	return tgt_cfr_enable_cfr_timer(pdev, value);
+}
+qdf_export_symbol(ucfg_cfr_set_timer);
+
+int ucfg_cfr_get_timer(struct wlan_objmgr_pdev *pdev)
+{
+	struct pdev_cfr *pa;
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+	if (pa == NULL) {
+		cfr_err("PDEV cfr object is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (!(pa->is_cfr_capable)) {
+		qdf_info("cfr is not supported on this chip\n");
+		return -EINVAL;
+	}
+
+	return pa->cfr_timer_enable;
+}
+qdf_export_symbol(ucfg_cfr_get_timer);
+
+int ucfg_cfr_stop_capture(struct wlan_objmgr_pdev *pdev,
+			  struct wlan_objmgr_peer *peer)
+{
+	int status;
+	struct peer_cfr *pe;
+	struct pdev_cfr *pa;
+
+	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
+	if (pa == NULL) {
+		cfr_err("PDEV cfr object is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (!(pa->is_cfr_capable)) {
+		qdf_info("cfr is not supported on this chip\n");
+		return -EINVAL;
+	}
+
+	pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR);
+	if (pe == NULL) {
+		cfr_err("PEER cfr object is NULL!\n");
+		return -EINVAL;
+	}
+
+	if ((pe->period) && (pe->request))
+		status = tgt_cfr_stop_capture(pdev, peer);
+	else {
+		qdf_info("periodic cfr not started for the client\n");
+		return -EINVAL;
+	}
+
+	if (status == 0) {
+		pe->request = PEER_CFR_CAPTURE_DISABLE;
+		pa->cfr_current_sta_count--;
+	}
+
+	return status;
+}
+
+int ucfg_cfr_list_peers(struct wlan_objmgr_pdev *pdev)
+{
+	return 0;
+}
+
+#ifdef WLAN_ENH_CFR_ENABLE
+
+static inline
+QDF_STATUS dev_sanity_check(struct wlan_objmgr_vdev *vdev,
+			    struct wlan_objmgr_pdev **ppdev,
+			    struct pdev_cfr **ppcfr)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!vdev) {
+		cfr_err("vdev is NULL\n");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	*ppdev = wlan_vdev_get_pdev(vdev);
+
+	if (!*ppdev) {
+		cfr_err("pdev is NULL\n");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	status = wlan_objmgr_pdev_try_get_ref(*ppdev, WLAN_CFR_ID);
+	if (status != QDF_STATUS_SUCCESS) {
+		cfr_err("Failed to get pdev reference\n");
+		return status;
+	}
+
+	*ppcfr = wlan_objmgr_pdev_get_comp_private_obj(*ppdev,
+						     WLAN_UMAC_COMP_CFR);
+
+	if (!(*ppcfr)) {
+		cfr_err("pdev object for CFR is null");
+		wlan_objmgr_pdev_release_ref(*ppdev, WLAN_CFR_ID);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	if (!(*ppcfr)->is_cfr_rcc_capable) {
+		cfr_err("cfr is not supported on this chip\n");
+		wlan_objmgr_pdev_release_ref(*ppdev, WLAN_CFR_ID);
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+
+	return status;
+}
+
+/*
+ * This is needed only in case of m_ta_ra_filter mode.
+ * If user wants to reset the group configurations to default values,
+ * then this handler will come into action.
+ *
+ * If user wants to reset the configurations of 0th, 1st and 3rd group,
+ * then the input should be :
+ *
+ *               wlanconfig ath0 cfr reset_cfg 0xb
+ *
+ */
+
+QDF_STATUS ucfg_cfr_set_reset_bitmap(struct wlan_objmgr_vdev *vdev,
+				     struct ieee80211_wlanconfig_cfr *params)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	pcfr->rcc_param.modified_in_curr_session |= params->reset_cfg;
+	tgt_cfr_default_ta_ra_cfg(pdev, &pcfr->rcc_param,
+				  true, params->reset_cfg);
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+/*
+ * This is needed only in case of m_ta_ra_filter mode.
+ * After providing all the group configurations, user should provide
+ * the information about which groups need to be enabled.
+ * Based on that FW will enable the configurations for CFR groups.
+ * If user has to enable only 0th group, then input should be :
+ *
+ *               wlanconfig ath0 cfr en_cfg 0x1
+ *
+ * Enable the bitmap from user provided configuration into cfr_rcc_param.
+ */
+
+QDF_STATUS ucfg_cfr_set_en_bitmap(struct wlan_objmgr_vdev *vdev,
+				  struct ieee80211_wlanconfig_cfr *params)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	pcfr->rcc_param.filter_group_bitmap = params->en_cfg;
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+/*
+ * Copy user provided input for ul_mu_user_mask into cfr_rcc_param.
+ */
+
+QDF_STATUS
+ucfg_cfr_set_ul_mu_user_mask(struct wlan_objmgr_vdev *vdev,
+			     struct ieee80211_wlanconfig_cfr *params)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	pcfr->rcc_param.ul_mu_user_mask_lower = params->ul_mu_user_mask_lower;
+	pcfr->rcc_param.ul_mu_user_mask_upper = params->ul_mu_user_mask_upper;
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+/*
+ * FREEZE_TLV_DELAY_CNT_* registers are used for FREEZE TLV timeout mechanism
+ * in MAC side. In case MAC send FREEZE TLV to PHY too late due to
+ * long AST delay, PHY ucode may not handle it well or it will impact
+ * next frame’s normal processing, then MAC needs to drop FREEZE TLV
+ * sending process after reaching the threshold.
+ *
+ * This handler will copy user provided input for freeze_tlv_delay_cnt
+ * into cfr_rcc_param.
+ */
+
+QDF_STATUS
+ucfg_cfr_set_freeze_tlv_delay_cnt(struct wlan_objmgr_vdev *vdev,
+				  struct ieee80211_wlanconfig_cfr *params)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	pcfr->rcc_param.freeze_tlv_delay_cnt_en =
+		params->freeze_tlv_delay_cnt_en;
+
+	pcfr->rcc_param.freeze_tlv_delay_cnt_thr =
+		params->freeze_tlv_delay_cnt_thr;
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+/*
+ * Set capture interval from the provided configuration into cfr_rcc_param.
+ * All fixed parameters are needed to be stored into cfr_rcc_param.
+ */
+
+QDF_STATUS
+ucfg_cfr_set_capture_interval(struct wlan_objmgr_vdev *vdev,
+			      struct ieee80211_wlanconfig_cfr *params)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	pcfr->rcc_param.capture_interval = params->cap_intvl;
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+/*
+ * Set capture duration from the provided configuration into cfr_rcc_param.
+ * All fixed parameters are needed to be stored into cfr_rcc_param.
+ */
+
+QDF_STATUS
+ucfg_cfr_set_capture_duration(struct wlan_objmgr_vdev *vdev,
+			      struct ieee80211_wlanconfig_cfr *params)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	pcfr->rcc_param.capture_duration = params->cap_dur;
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+/*
+ * Copy user provided group parameters( type/ subtype of mgmt, ctrl, data )
+ * into curr_cfg instance of ta_ra_cfr_cfg.
+ * Set valid mask for the provided configuration.
+ * Set modified_in_this_session for the particular group.
+ */
+
+QDF_STATUS
+ucfg_cfr_set_frame_type_subtype(struct wlan_objmgr_vdev *vdev,
+				struct ieee80211_wlanconfig_cfr *params)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	struct ta_ra_cfr_cfg *curr_cfg = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	/* Populating current config based on user's input */
+	curr_cfg = &pcfr->rcc_param.curr[params->grp_id];
+	curr_cfg->mgmt_subtype_filter = params->expected_mgmt_subtype;
+	curr_cfg->ctrl_subtype_filter = params->expected_ctrl_subtype;
+	curr_cfg->data_subtype_filter = params->expected_data_subtype;
+
+	curr_cfg->valid_mgmt_subtype = 1;
+	curr_cfg->valid_ctrl_subtype = 1;
+	curr_cfg->valid_data_subtype = 1;
+
+	qdf_set_bit(params->grp_id,
+		    (unsigned long *)
+		    &pcfr->rcc_param.modified_in_curr_session);
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+/*
+ * Copy user provided group parameters( BW and NSS )
+ * into curr_cfg instance of ta_ra_cfr_cfg.
+ * Set valid mask for the provided configuration.
+ * Set modified_in_this_session for the particular group.
+ */
+
+QDF_STATUS ucfg_cfr_set_bw_nss(struct wlan_objmgr_vdev *vdev,
+			       struct ieee80211_wlanconfig_cfr *params)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	struct ta_ra_cfr_cfg *curr_cfg = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	/* Populating current config based on user's input */
+	curr_cfg = &pcfr->rcc_param.curr[params->grp_id];
+	curr_cfg->bw = params->bw;
+	curr_cfg->nss = params->nss;
+
+	curr_cfg->valid_bw_mask = 1;
+	curr_cfg->valid_nss_mask = 1;
+
+	qdf_set_bit(params->grp_id,
+		    (unsigned long *)&pcfr->rcc_param.modified_in_curr_session);
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+/*
+ * Copy user provided group parameters( TA, RA, TA_MASK, RA_MASK )
+ * into curr_cfg instance of ta_ra_cfr_cfg.
+ * Set valid mask for the provided configuration.
+ * Set modified_in_this_session for the particular group.
+ */
+
+QDF_STATUS ucfg_cfr_set_tara_config(struct wlan_objmgr_vdev *vdev,
+				    struct ieee80211_wlanconfig_cfr *params)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	struct ta_ra_cfr_cfg *curr_cfg = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	curr_cfg = &pcfr->rcc_param.curr[params->grp_id];
+	qdf_mem_copy(curr_cfg->tx_addr, params->ta, QDF_MAC_ADDR_SIZE);
+	qdf_mem_copy(curr_cfg->rx_addr, params->ra, QDF_MAC_ADDR_SIZE);
+	qdf_mem_copy(curr_cfg->tx_addr_mask,
+		     params->ta_mask, QDF_MAC_ADDR_SIZE);
+	qdf_mem_copy(curr_cfg->rx_addr_mask,
+		     params->ra_mask, QDF_MAC_ADDR_SIZE);
+
+	curr_cfg->valid_ta = 1;
+	curr_cfg->valid_ta_mask = 1;
+	curr_cfg->valid_ra = 1;
+	curr_cfg->valid_ra_mask = 1;
+
+	qdf_set_bit(params->grp_id,
+		    (unsigned long *)
+		    &pcfr->rcc_param.modified_in_curr_session);
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+static bool cfr_is_filter_enabled(struct cfr_rcc_param *rcc_param)
+{
+	if (rcc_param->m_directed_ftm ||
+	    rcc_param->m_all_ftm_ack ||
+	    rcc_param->m_ndpa_ndp_directed ||
+	    rcc_param->m_ndpa_ndp_all ||
+	    rcc_param->m_ta_ra_filter ||
+	    rcc_param->m_all_packet)
+		return true;
+	else
+		return false;
+}
+
+QDF_STATUS ucfg_cfr_get_cfg(struct wlan_objmgr_vdev *vdev)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	struct ta_ra_cfr_cfg *glbl_cfg = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	uint8_t grp_id;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+	if (!cfr_is_filter_enabled(&pcfr->rcc_param)) {
+		cfr_err(" All RCC modes are disabled.\n");
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+		return status;
+	}
+
+	cfr_err("CAPTURE MODE:\n");
+
+	cfr_err("m_directed_ftm is : %s\n",
+		pcfr->rcc_param.m_directed_ftm ?
+		"enabled" : "disabled");
+	cfr_err("m_all_ftm_ack is : %s\n",
+		pcfr->rcc_param.m_all_ftm_ack ?
+		"enabled" : "disabled");
+	cfr_err("m_ndpa_ndp_directed is: %s\n",
+		pcfr->rcc_param.m_ndpa_ndp_directed ?
+		"enabled" : "disabled");
+	cfr_err("m_ndpa_ndp_all is : %s\n",
+		pcfr->rcc_param.m_ndpa_ndp_all ?
+		"enabled" : "disabled");
+	cfr_err("m_ta_ra_filter is : %s\n",
+		pcfr->rcc_param.m_ta_ra_filter ?
+		"enabled" : "disabled");
+	cfr_err("m_all_packet is : %s\n",
+		pcfr->rcc_param.m_all_packet ?
+		"enabled" : "disabled");
+
+	cfr_err("capture duration : %u usec\n",
+		pcfr->rcc_param.capture_duration);
+	cfr_err("capture interval : %u usec\n",
+		pcfr->rcc_param.capture_interval);
+	cfr_err("UL MU User mask lower : %u\n",
+		pcfr->rcc_param.ul_mu_user_mask_lower);
+	cfr_err("UL MU User mask upper : %u\n",
+		pcfr->rcc_param.ul_mu_user_mask_upper);
+	cfr_err("Freeze TLV delay count is : %s\n",
+		pcfr->rcc_param.freeze_tlv_delay_cnt_en ?
+		"enabled" : "disabled");
+	cfr_err("Freeze TLV delay count threshold : %u\n",
+		pcfr->rcc_param.freeze_tlv_delay_cnt_thr);
+	cfr_err("Enabled CFG id bitmap : 0x%x\n",
+		pcfr->rcc_param.filter_group_bitmap);
+	cfr_err(" Modified cfg id bitmap : 0x%x\n",
+		pcfr->rcc_param.modified_in_curr_session);
+
+	cfr_err("TARA_CONFIG details:\n");
+
+	for (grp_id = 0; grp_id < MAX_TA_RA_ENTRIES; grp_id++) {
+		glbl_cfg = &pcfr->global[grp_id];
+
+		cfr_err("Config ID: %d\n", grp_id);
+		cfr_err("Bandwidth :0x%x\n", glbl_cfg->bw);
+		cfr_err("NSS : 0x%x\n", glbl_cfg->nss);
+		cfr_err("valid_ta: %d\n", glbl_cfg->valid_ta);
+		cfr_err("valid_ta_mask: %d\n", glbl_cfg->valid_ta_mask);
+		cfr_err("valid_ra: %d\n", glbl_cfg->valid_ra);
+		cfr_err("valid_ra_mask: %d\n", glbl_cfg->valid_ra_mask);
+		cfr_err("valid_bw_mask: %d\n", glbl_cfg->valid_bw_mask);
+		cfr_err("valid_nss_mask: %d\n", glbl_cfg->valid_nss_mask);
+		cfr_err("valid_mgmt_subtype: %d\n",
+			glbl_cfg->valid_mgmt_subtype);
+		cfr_err("valid_ctrl_subtype: %d\n",
+			glbl_cfg->valid_ctrl_subtype);
+		cfr_err("valid_data_subtype: %d\n",
+			glbl_cfg->valid_data_subtype);
+		cfr_err("Mgmt subtype : 0x%x\n",
+			glbl_cfg->mgmt_subtype_filter);
+		cfr_err("CTRL subtype : 0x%x\n",
+			glbl_cfg->ctrl_subtype_filter);
+		cfr_err("Data subtype : 0x%x\n",
+			glbl_cfg->data_subtype_filter);
+		cfr_err("TX Addr : %s\n",
+			ether_sprintf(glbl_cfg->tx_addr));
+		cfr_err("TX Addr Mask : %s\n",
+			ether_sprintf(glbl_cfg->tx_addr_mask));
+		cfr_err("RX Addr : %s\n",
+			ether_sprintf(glbl_cfg->rx_addr));
+		cfr_err("RX Addr Mask: %s\n",
+			ether_sprintf(glbl_cfg->rx_addr_mask));
+	}
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+static const char *chan_capture_status_to_str(enum chan_capture_status type)
+{
+	switch (type) {
+	case CAPTURE_IDLE:
+		return "CAPTURE_IDLE";
+	case CAPTURE_BUSY:
+		return "CAPTURE_BUSY";
+	case CAPTURE_ACTIVE:
+		return "CAPTURE_ACTIVE";
+	case CAPTURE_NO_BUFFER:
+		return "CAPTURE_NO_BUFFER";
+	default:
+		return "INVALID";
+	}
+}
+
+static const
+char *mac_freeze_reason_to_str(enum mac_freeze_capture_reason type)
+{
+	switch (type) {
+	case FREEZE_REASON_TM:
+		return "FREEZE_REASON_TM";
+	case FREEZE_REASON_FTM:
+		return "FREEZE_REASON_FTM";
+	case FREEZE_REASON_ACK_RESP_TO_TM_FTM:
+		return "FREEZE_REASON_ACK_RESP_TO_TM_FTM";
+	case FREEZE_REASON_TA_RA_TYPE_FILTER:
+		return "FREEZE_REASON_TA_RA_TYPE_FILTER";
+	case FREEZE_REASON_NDPA_NDP:
+		return "FREEZE_REASON_NDPA_NDP";
+	case FREEZE_REASON_ALL_PACKET:
+		return "FREEZE_REASON_ALL_PACKET";
+	default:
+		return "INVALID";
+	}
+}
+
+QDF_STATUS ucfg_cfr_rcc_dump_dbg_counters(struct wlan_objmgr_vdev *vdev)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	struct wlan_objmgr_psoc *psoc = NULL;
+	struct cdp_cfr_rcc_stats *cfr_rcc_stats = NULL;
+	uint8_t stats_cnt;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		cfr_err("psoc is null!");
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	cfr_err("total_tx_evt_cnt = %llu\n",
+		pcfr->total_tx_evt_cnt);
+	cfr_err("dbr_evt_cnt = %llu\n",
+		pcfr->dbr_evt_cnt);
+	cfr_err("rx_tlv_evt_cnt = %llu\n",
+		pcfr->rx_tlv_evt_cnt);
+	cfr_err("release_cnt = %llu\n",
+		pcfr->release_cnt);
+	cfr_err("Error cnt:\n");
+	cfr_err("flush_dbr_cnt = %llu\n",
+		pcfr->flush_dbr_cnt);
+	cfr_err("invalid_dma_length_cnt = %llu\n",
+		pcfr->invalid_dma_length_cnt);
+	cfr_err("flush_timeout_dbr_cnt = %llu\n",
+		pcfr->flush_timeout_dbr_cnt);
+	cfr_err("PPDU id mismatch for same cookie:\n");
+	cfr_err("clear_txrx_event = %llu\n",
+		pcfr->clear_txrx_event);
+	cfr_err("cfr_dma_aborts = %llu\n",
+		pcfr->cfr_dma_aborts);
+
+	cfr_rcc_stats = qdf_mem_malloc(sizeof(struct cdp_cfr_rcc_stats));
+	if (!cfr_rcc_stats) {
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	cdp_get_cfr_dbg_stats(wlan_psoc_get_dp_handle(psoc),
+			      wlan_objmgr_pdev_get_pdev_id(pdev),
+			      cfr_rcc_stats);
+
+	cfr_err("bb_captured_channel_cnt: %llu\n",
+		cfr_rcc_stats->bb_captured_channel_cnt);
+	cfr_err("bb_captured_timeout_cnt: %llu\n",
+		cfr_rcc_stats->bb_captured_timeout_cnt);
+	cfr_err("rx_loc_info_valid_cnt: %llu\n",
+		cfr_rcc_stats->rx_loc_info_valid_cnt);
+
+	cfr_err("Channel capture status:\n");
+	for (stats_cnt = 0; stats_cnt < CAPTURE_MAX; stats_cnt++) {
+		cfr_err("%s = %llu\n",
+			chan_capture_status_to_str(stats_cnt),
+			cfr_rcc_stats->chan_capture_status[stats_cnt]);
+	}
+
+	cfr_err("Freeze reason:\n");
+	for (stats_cnt = 0; stats_cnt < FREEZE_REASON_MAX; stats_cnt++) {
+		cfr_err("%s = %llu\n",
+			mac_freeze_reason_to_str(stats_cnt),
+			cfr_rcc_stats->reason_cnt[stats_cnt]);
+	}
+
+	qdf_mem_free(cfr_rcc_stats);
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+QDF_STATUS ucfg_cfr_rcc_clr_dbg_counters(struct wlan_objmgr_vdev *vdev)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	struct wlan_objmgr_psoc *psoc = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		cfr_err("psoc is null!");
+		wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	cdp_cfr_clr_dbg_stats(wlan_psoc_get_dp_handle(psoc),
+			      wlan_objmgr_pdev_get_pdev_id(pdev));
+
+	pcfr->dbr_evt_cnt = 0;
+	pcfr->release_cnt = 0;
+	pcfr->total_tx_evt_cnt = 0;
+	pcfr->rx_tlv_evt_cnt = 0;
+	pcfr->flush_dbr_cnt = 0;
+	pcfr->flush_timeout_dbr_cnt = 0;
+	pcfr->invalid_dma_length_cnt = 0;
+	pcfr->clear_txrx_event = 0;
+	pcfr->cfr_dma_aborts = 0;
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+QDF_STATUS ucfg_cfr_rcc_dump_lut(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_pdev *pdev = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!vdev) {
+		cfr_err("vdev is NULL\n");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		cfr_err("pdev is NULL\n");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID) !=
+	    QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_INVAL;
+	}
+
+	cfr_err("LUT table:\n");
+	tgt_cfr_dump_lut_enh(pdev);
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+void cfr_set_filter(struct wlan_objmgr_pdev *pdev,
+		    bool enable, struct cdp_monitor_filter *filter_val)
+{
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+	cfr_info("pdev_id=%d\n", wlan_objmgr_pdev_get_pdev_id(pdev));
+
+	cdp_cfr_filter(wlan_psoc_get_dp_handle(psoc),
+		       wlan_objmgr_pdev_get_pdev_id(pdev),
+		       enable,
+		       filter_val);
+}
+
+/*
+ * With the initiation of commit command, this handler will be triggered.
+ *
+ * Starts the procedure of forming the TLVs.
+ * If Host succeeds to send WMI command to FW, after TLV processing, then it
+ * will save the previous CFR configurations into one instance ta_ra_cfr_cfg,
+ * called glbl_cfg and update the current config to default state for the
+ * next commit session.
+ *
+ * Finally, reset the counter (modified_in_this_session) to 0 before moving to
+ * next commit session.
+ *
+ */
+
+QDF_STATUS ucfg_cfr_committed_rcc_config(struct wlan_objmgr_vdev *vdev)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	struct wlan_objmgr_psoc *psoc = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct cdp_monitor_filter filter_val = {0};
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+
+	if (!psoc) {
+		cfr_err("psoc is null!");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	/*
+	 * If capture mode is valid, then Host:
+	 * Subscribes for PPDU status TLVs in monitor status ring.
+	 * Sets filter type to either FP or MO, based on the capture mode.
+	 * Starts the LUT_AGE_TIMER of 1sec.
+	 *
+	 * If capture mode is disabled, then Host:
+	 * unsubscribes for PPDU status TLVs in monitor status ring.
+	 * Sets filter type to 0.
+	 * Stops the LUT_AGE_TIMER.
+	 *
+	 */
+
+	if (cfr_is_filter_enabled(&pcfr->rcc_param)) {
+		if (pcfr->rcc_param.m_all_ftm_ack) {
+			filter_val.mode |= MON_FILTER_PASS |
+					   MON_FILTER_OTHER;
+			filter_val.fp_mgmt |= FILTER_MGMT_ACTION;
+			filter_val.mo_mgmt |= FILTER_MGMT_ACTION;
+		}
+
+		if (pcfr->rcc_param.m_ndpa_ndp_all) {
+			filter_val.mode |= MON_FILTER_PASS |
+					   MON_FILTER_OTHER;
+			filter_val.fp_ctrl |= FILTER_CTRL_VHT_NDP;
+			filter_val.mo_ctrl |= FILTER_CTRL_VHT_NDP;
+		}
+
+		if (pcfr->rcc_param.m_all_packet) {
+			filter_val.mode |= MON_FILTER_PASS |
+					   MON_FILTER_OTHER;
+			filter_val.fp_mgmt |= FILTER_MGMT_ALL;
+			filter_val.mo_mgmt |= FILTER_MGMT_ALL;
+			filter_val.fp_ctrl |= FILTER_CTRL_ALL;
+			filter_val.mo_ctrl |= FILTER_CTRL_ALL;
+			filter_val.fp_data |= FILTER_DATA_ALL;
+			filter_val.mo_data |= FILTER_DATA_ALL;
+		}
+
+		/*
+		 * M_TA_RA in monitor other is as intensive as M_ALL pkt
+		 * Support only FP in M_TA_RA mode
+		 */
+		if (pcfr->rcc_param.m_ta_ra_filter) {
+			filter_val.mode |= MON_FILTER_PASS |
+					   MON_FILTER_OTHER;
+			filter_val.fp_mgmt |= FILTER_MGMT_ALL;
+			filter_val.mo_mgmt |= FILTER_MGMT_ALL;
+			filter_val.fp_ctrl |= FILTER_CTRL_ALL;
+			filter_val.mo_ctrl |= FILTER_CTRL_ALL;
+			filter_val.fp_data |= FILTER_DATA_ALL;
+			filter_val.mo_data |= FILTER_DATA_ALL;
+		}
+
+		if (pcfr->rcc_param.m_directed_ftm) {
+			filter_val.mode |= MON_FILTER_PASS;
+			filter_val.fp_mgmt |= FILTER_MGMT_ACTION;
+		}
+
+		if (pcfr->rcc_param.m_ndpa_ndp_directed) {
+			filter_val.mode |= MON_FILTER_PASS;
+			filter_val.fp_ctrl |= FILTER_CTRL_VHT_NDP;
+		}
+
+		if (!cdp_get_cfr_rcc(wlan_psoc_get_dp_handle(psoc),
+				    wlan_objmgr_pdev_get_pdev_id(pdev)))
+			tgt_cfr_start_lut_age_timer(pdev);
+		cfr_set_filter(pdev, 1, &filter_val);
+	} else {
+		if (cdp_get_cfr_rcc(wlan_psoc_get_dp_handle(psoc),
+				    wlan_objmgr_pdev_get_pdev_id(pdev)))
+			tgt_cfr_stop_lut_age_timer(pdev);
+		cfr_set_filter(pdev, 0, &filter_val);
+	}
+
+	/* Trigger wmi to start the TLV processing. */
+	status = tgt_cfr_config_rcc(pdev, &pcfr->rcc_param);
+	if (status == QDF_STATUS_SUCCESS) {
+		cfr_info("CFR commit done\n");
+		/* Update global config */
+		tgt_cfr_update_global_cfg(pdev);
+
+		/* Bring curr_cfg to default state for next commit session */
+		tgt_cfr_default_ta_ra_cfg(pdev, &pcfr->rcc_param,
+					  false, MAX_RESET_CFG_ENTRY);
+	} else {
+		cfr_err("CFR commit failed\n");
+	}
+
+	pcfr->rcc_param.num_grp_tlvs = 0;
+	pcfr->rcc_param.modified_in_curr_session = 0;
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+/*
+ * This handler is used to enable / disable the capture mode.
+ *
+ */
+QDF_STATUS ucfg_cfr_set_rcc_mode(struct wlan_objmgr_vdev *vdev,
+				 enum capture_type mode, uint8_t value)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	switch (mode) {
+	case RCC_DIRECTED_FTM_FILTER:
+		pcfr->rcc_param.m_directed_ftm = value;
+		break;
+	case RCC_ALL_FTM_ACK_FILTER:
+		pcfr->rcc_param.m_all_ftm_ack = value;
+		break;
+	case RCC_DIRECTED_NDPA_NDP_FILTER:
+		pcfr->rcc_param.m_ndpa_ndp_directed = value;
+		break;
+	case RCC_NDPA_NDP_ALL_FILTER:
+		pcfr->rcc_param.m_ndpa_ndp_all = value;
+		break;
+	case RCC_TA_RA_FILTER:
+		pcfr->rcc_param.m_ta_ra_filter = value;
+		break;
+	case RCC_ALL_PACKET_FILTER:
+		pcfr->rcc_param.m_all_packet = value;
+		break;
+	case RCC_DIS_ALL_MODE:
+		pcfr->rcc_param.m_directed_ftm = value;
+		pcfr->rcc_param.m_all_ftm_ack = value;
+		pcfr->rcc_param.m_ndpa_ndp_directed = value;
+		pcfr->rcc_param.m_ndpa_ndp_all = value;
+		pcfr->rcc_param.m_ta_ra_filter = value;
+		pcfr->rcc_param.m_all_packet = value;
+		break;
+
+	default:
+		break;
+	}
+
+	cfr_debug("<CFR_UMAC> Capture mode set by user: 0x%x\n", value);
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return status;
+}
+
+bool ucfg_cfr_get_rcc_enabled(struct wlan_objmgr_vdev *vdev)
+{
+	struct pdev_cfr *pcfr = NULL;
+	struct wlan_objmgr_pdev *pdev = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	bool rcc_enabled = false;
+
+	status = dev_sanity_check(vdev, &pdev, &pcfr);
+	if (status != QDF_STATUS_SUCCESS)
+		return false;
+
+	rcc_enabled = cfr_is_filter_enabled(&pcfr->rcc_param);
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
+
+	return rcc_enabled;
+}
+#endif

+ 184 - 0
umac/cfr/dispatcher/src/wlan_cfr_utils_api.c

@@ -0,0 +1,184 @@
+/*
+ * 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 <wlan_cfr_utils_api.h>
+#include <wlan_cfr_tgt_api.h>
+#include <qdf_module.h>
+#include "../../core/inc/cfr_defs_i.h"
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+
+QDF_STATUS wlan_cfr_init(void)
+{
+	if (wlan_objmgr_register_psoc_create_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_psoc_obj_create_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (wlan_objmgr_register_psoc_destroy_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_psoc_obj_destroy_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (wlan_objmgr_register_pdev_create_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_pdev_obj_create_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (wlan_objmgr_register_pdev_destroy_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_pdev_obj_destroy_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (wlan_objmgr_register_peer_create_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_peer_obj_create_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (wlan_objmgr_register_peer_destroy_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_peer_obj_destroy_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_cfr_deinit(void)
+{
+	if (wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_psoc_obj_create_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_psoc_obj_destroy_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_pdev_obj_create_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_pdev_obj_destroy_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_peer_obj_create_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (wlan_objmgr_unregister_peer_destroy_handler(WLAN_UMAC_COMP_CFR,
+				wlan_cfr_peer_obj_destroy_handler, NULL)
+				!= QDF_STATUS_SUCCESS) {
+		return QDF_STATUS_E_FAILURE;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_cfr_pdev_open(struct wlan_objmgr_pdev *pdev)
+{
+	int status;
+
+	/* chip specific init */
+	status = tgt_cfr_init_pdev(pdev);
+
+	if (status != QDF_STATUS_SUCCESS) {
+		cfr_err("tgt_cfr_init_pdev failed with %d\n", status);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	/* RealyFS init */
+	status = cfr_streamfs_init(pdev);
+
+	if (status != QDF_STATUS_SUCCESS) {
+		cfr_err("cfr_streamfs_init failed with %d\n", status);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_cfr_pdev_close(struct wlan_objmgr_pdev *pdev)
+{
+	int status = QDF_STATUS_SUCCESS;
+	/*
+	 * DBR does not have close as of now;
+	 * but this is getting added as part for new gerrit
+	 * Once we have that support we will add it.
+	 */
+	status = cfr_streamfs_remove(pdev);
+
+	return status;
+}
+
+QDF_STATUS cfr_initialize_pdev(struct wlan_objmgr_pdev *pdev)
+{
+	int status = QDF_STATUS_SUCCESS;
+
+	/* chip specific init */
+
+	status = tgt_cfr_init_pdev(pdev);
+
+	if (status != QDF_STATUS_SUCCESS)
+		cfr_err("cfr_initialize_pdev status=%d\n", status);
+
+	return status;
+}
+qdf_export_symbol(cfr_initialize_pdev);
+
+QDF_STATUS cfr_deinitialize_pdev(struct wlan_objmgr_pdev *pdev)
+{
+	int status = QDF_STATUS_SUCCESS;
+
+	/* chip specific deinit */
+
+	status = tgt_cfr_deinit_pdev(pdev);
+
+	if (status != QDF_STATUS_SUCCESS)
+		cfr_err("cfr_deinitialize_pdev status=%d\n", status);
+
+	return status;
+}
+qdf_export_symbol(cfr_deinitialize_pdev);
+
+uint8_t count_set_bits(uint32_t value)
+{
+	uint8_t count = 0;
+
+	while (value) {
+		value &= (value - 1);
+		count++;
+	}
+
+	return count;
+}
+
+qdf_export_symbol(count_set_bits);
+
+#ifdef WLAN_ENH_CFR_ENABLE
+void wlan_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
+{
+	tgt_cfr_rx_tlv_process(pdev, nbuf);
+}
+
+qdf_export_symbol(wlan_cfr_rx_tlv_process);
+#endif