qcacmn: CFR: Copy hal ppdu info to cdp ppdu structure

CFR information extracted from PPDU status TLVs is already stored in
HAL ppdu structure. Extract the same and copy it to CDP ppdu structure.
This is delivered to subscribers through a WDI event, similar to PPDU
stats.

Change-Id: I4315626c7f79f85b75b8d1b9e1e5caf8d65abed9
CRs-Fixed: 2593416
diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h
index 4877e9a..0fd0083 100644
--- a/dp/inc/cdp_txrx_cmn_struct.h
+++ b/dp/inc/cdp_txrx_cmn_struct.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2020 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
@@ -1905,6 +1905,9 @@
 	uint32_t nf;
 	uint8_t  per_chain_rssi[MAX_CHAIN];
 	uint8_t is_mcast_bcast;
+#if defined(WLAN_CFR_ENABLE) && defined(WLAN_ENH_CFR_ENABLE)
+	struct cdp_rx_ppdu_cfr_info cfr_info;
+#endif
 };
 
 /**
diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h
index 289df96..0d29335 100644
--- a/dp/inc/cdp_txrx_stats_struct.h
+++ b/dp/inc/cdp_txrx_stats_struct.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 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
@@ -296,6 +296,65 @@
 	uint32_t stats[TIDQ_STATS_MAX];
 };
 
+#if defined(WLAN_CFR_ENABLE) && defined(WLAN_ENH_CFR_ENABLE)
+/**
+ * struct cdp_rx_ppdu_cfr_info - struct for storing ppdu info extracted from HW
+ * TLVs, this will be used for CFR correlation
+ *
+ * @bb_captured_channel : Set by RXPCU when MACRX_FREEZE_CAPTURE_CHANNEL TLV is
+ * sent to PHY, SW checks it to correlate current PPDU TLVs with uploaded
+ * channel information.
+ *
+ * @bb_captured_timeout : Set by RxPCU to indicate channel capture condition is
+ * met, but MACRX_FREEZE_CAPTURE_CHANNEL is not sent to PHY due to AST delay,
+ * which means the rx_frame_falling edge to FREEZE TLV ready time exceeds
+ * the threshold time defined by RXPCU register FREEZE_TLV_DELAY_CNT_THRESH.
+ * Bb_captured_reason is still valid in this case.
+ *
+ * @bb_captured_reason : Copy capture_reason of MACRX_FREEZE_CAPTURE_CHANNEL
+ * TLV to here for FW usage. Valid when bb_captured_channel or
+ * bb_captured_timeout is set.
+ * <enum 0 freeze_reason_TM>
+ * <enum 1 freeze_reason_FTM>
+ * <enum 2 freeze_reason_ACK_resp_to_TM_FTM>
+ * <enum 3 freeze_reason_TA_RA_TYPE_FILTER>
+ * <enum 4 freeze_reason_NDPA_NDP>
+ * <enum 5 freeze_reason_ALL_PACKET>
+ * <legal 0-5>
+ *
+ * @rx_location_info_valid: Indicates whether CFR DMA address in the PPDU TLV
+ * is valid
+ * <enum 0 rx_location_info_is_not_valid>
+ * <enum 1 rx_location_info_is_valid>
+ * <legal all>
+ *
+ * @chan_capture_status : capture status reported by ucode
+ * a. CAPTURE_IDLE: FW has disabled "REPETITIVE_CHE_CAPTURE_CTRL"
+ * b. CAPTURE_BUSY: previous PPDU’s channel capture upload DMA ongoing. (Note
+ * that this upload is triggered after receiving freeze_channel_capture TLV
+ * after last PPDU is rx)
+ * c. CAPTURE_ACTIVE: channel capture is enabled and no previous channel
+ * capture ongoing
+ * d. CAPTURE_NO_BUFFER: next buffer in IPC ring not available
+ *
+ * @rtt_che_buffer_pointer_high8 : The high 8 bits of the 40 bits pointer to
+ * external RTT channel information buffer
+ *
+ * @rtt_che_buffer_pointer_low32 : The low 32 bits of the 40 bits pointer to
+ * external RTT channel information buffer
+ *
+ */
+
+struct cdp_rx_ppdu_cfr_info {
+	bool bb_captured_channel;
+	bool bb_captured_timeout;
+	uint8_t bb_captured_reason;
+	bool rx_location_info_valid;
+	uint8_t chan_capture_status;
+	uint8_t rtt_che_buffer_pointer_high8;
+	uint32_t rtt_che_buffer_pointer_low32;
+};
+#endif
 /*
  * struct cdp_rx_su_evm_info: Rx evm info
  * @number_of_symbols: number of symbols
diff --git a/dp/wifi3.0/dp_rx_mon_status.c b/dp/wifi3.0/dp_rx_mon_status.c
index c4c0b86..50a3909 100644
--- a/dp/wifi3.0/dp_rx_mon_status.c
+++ b/dp/wifi3.0/dp_rx_mon_status.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020 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
@@ -899,6 +899,203 @@
 	return 0;
 }
 
+#if defined(WLAN_CFR_ENABLE) && defined(WLAN_ENH_CFR_ENABLE)
+/*
+ * dp_rx_mon_handle_cfr_mu_info() - Gather macaddr and ast_index of peer(s) in
+ * the PPDU received, this will be used for correlation of CFR data captured
+ * for an UL-MU-PPDU
+ * @pdev: pdev ctx
+ * @ppdu_info: pointer to ppdu info structure populated from ppdu status TLVs
+ * @ppdu_nbuf: qdf nbuf abstraction for linux skb
+ *
+ * Return: none
+ */
+static inline void
+dp_rx_mon_handle_cfr_mu_info(struct dp_pdev *pdev,
+			     struct hal_rx_ppdu_info *ppdu_info,
+			     qdf_nbuf_t ppdu_nbuf)
+{
+	struct dp_peer *peer;
+	struct dp_soc *soc = pdev->soc;
+	struct dp_ast_entry *ast_entry;
+	struct cdp_rx_indication_ppdu *cdp_rx_ppdu;
+	struct mon_rx_user_status *rx_user_status;
+	struct cdp_rx_stats_ppdu_user *rx_stats_peruser;
+	uint32_t num_users;
+	int user_id;
+	uint32_t ast_index;
+
+	if (!ppdu_info->cfr_info.bb_captured_channel)
+		return;
+
+	cdp_rx_ppdu = (struct cdp_rx_indication_ppdu *)ppdu_nbuf->data;
+
+	qdf_spin_lock_bh(&soc->ast_lock);
+
+	num_users = ppdu_info->com_info.num_users;
+	for (user_id = 0; user_id < num_users; user_id++) {
+		if (user_id > OFDMA_NUM_USERS) {
+			qdf_spin_unlock_bh(&soc->ast_lock);
+			return;
+		}
+
+		rx_user_status =  &ppdu_info->rx_user_status[user_id];
+		rx_stats_peruser = &cdp_rx_ppdu->user[user_id];
+		ast_index = rx_user_status->ast_index;
+
+		if (ast_index >= wlan_cfg_get_max_ast_idx(soc->wlan_cfg_ctx)) {
+			rx_stats_peruser->peer_id = HTT_INVALID_PEER;
+			continue;
+		}
+
+		ast_entry = soc->ast_table[ast_index];
+		if (!ast_entry) {
+			rx_stats_peruser->peer_id = HTT_INVALID_PEER;
+			continue;
+		}
+
+		peer = ast_entry->peer;
+		if (!peer || peer->peer_ids[0] == HTT_INVALID_PEER) {
+			rx_stats_peruser->peer_id = HTT_INVALID_PEER;
+			continue;
+		}
+
+		qdf_mem_copy(rx_stats_peruser->mac_addr,
+			     peer->mac_addr.raw, QDF_MAC_ADDR_SIZE);
+	}
+
+	qdf_spin_unlock_bh(&soc->ast_lock);
+}
+
+/*
+ * dp_rx_mon_populate_cfr_ppdu_info() - Populate cdp ppdu info from hal ppdu
+ * info
+ * @pdev: pdev ctx
+ * @ppdu_info: ppdu info structure from ppdu ring
+ * @ppdu_nbuf: qdf nbuf abstraction for linux skb
+ *
+ * Return: none
+ */
+static inline void
+dp_rx_mon_populate_cfr_ppdu_info(struct dp_pdev *pdev,
+				 struct hal_rx_ppdu_info *ppdu_info,
+				 qdf_nbuf_t ppdu_nbuf)
+{
+	struct cdp_rx_indication_ppdu *cdp_rx_ppdu;
+	int chain;
+
+	cdp_rx_ppdu = (struct cdp_rx_indication_ppdu *)ppdu_nbuf->data;
+	cdp_rx_ppdu->ppdu_id = ppdu_info->com_info.ppdu_id;
+	cdp_rx_ppdu->timestamp = ppdu_info->rx_status.tsft;
+	cdp_rx_ppdu->u.ppdu_type = ppdu_info->rx_status.reception_type;
+	cdp_rx_ppdu->num_users = ppdu_info->com_info.num_users;
+
+	for (chain = 0; chain < MAX_CHAIN; chain++)
+		cdp_rx_ppdu->per_chain_rssi[chain] =
+			ppdu_info->rx_status.rssi[chain];
+	dp_rx_mon_handle_cfr_mu_info(pdev, ppdu_info, ppdu_nbuf);
+}
+
+/*
+ * dp_rx_mon_populate_cfr_info() - Populate cdp ppdu info from hal cfr info
+ * @pdev: pdev ctx
+ * @ppdu_info: ppdu info structure from ppdu ring
+ * @ppdu_nbuf: qdf nbuf abstraction for linux skb
+ *
+ * Return: none
+ */
+static inline void
+dp_rx_mon_populate_cfr_info(struct dp_pdev *pdev,
+			    struct hal_rx_ppdu_info *ppdu_info,
+			    qdf_nbuf_t ppdu_nbuf)
+{
+	struct cdp_rx_indication_ppdu *cdp_rx_ppdu;
+	struct cdp_rx_ppdu_cfr_info *cfr_info;
+
+	if (qdf_unlikely(!pdev->cfr_rcc_mode))
+		return;
+
+	cdp_rx_ppdu = (struct cdp_rx_indication_ppdu *)ppdu_nbuf->data;
+	cfr_info = &cdp_rx_ppdu->cfr_info;
+
+	cfr_info->bb_captured_channel
+		= ppdu_info->cfr_info.bb_captured_channel;
+	cfr_info->bb_captured_timeout
+		= ppdu_info->cfr_info.bb_captured_timeout;
+	cfr_info->bb_captured_reason
+		= ppdu_info->cfr_info.bb_captured_reason;
+	cfr_info->rx_location_info_valid
+		= ppdu_info->cfr_info.rx_location_info_valid;
+	cfr_info->chan_capture_status
+		= ppdu_info->cfr_info.chan_capture_status;
+	cfr_info->rtt_che_buffer_pointer_high8
+		= ppdu_info->cfr_info.rtt_che_buffer_pointer_high8;
+	cfr_info->rtt_che_buffer_pointer_low32
+		= ppdu_info->cfr_info.rtt_che_buffer_pointer_low32;
+}
+
+/*
+ * dp_rx_handle_cfr() - Gather cfr info from hal ppdu info
+ * @soc: core txrx main context
+ * @pdev: pdev ctx
+ * @ppdu_info: ppdu info structure from ppdu ring
+ *
+ * Return: none
+ */
+static inline void
+dp_rx_handle_cfr(struct dp_soc *soc, struct dp_pdev *pdev,
+		 struct hal_rx_ppdu_info *ppdu_info)
+{
+	qdf_nbuf_t ppdu_nbuf;
+
+	if (!ppdu_info->cfr_info.bb_captured_channel &&
+	    !ppdu_info->cfr_info.bb_captured_timeout)
+		return;
+
+	ppdu_nbuf = qdf_nbuf_alloc(soc->osdev,
+				   sizeof(struct cdp_rx_indication_ppdu),
+				   0,
+				   0,
+				   FALSE);
+	if (ppdu_nbuf) {
+		dp_rx_mon_populate_cfr_info(pdev, ppdu_info, ppdu_nbuf);
+		dp_rx_mon_populate_cfr_ppdu_info(pdev, ppdu_info, ppdu_nbuf);
+		qdf_nbuf_put_tail(ppdu_nbuf,
+				  sizeof(struct cdp_rx_indication_ppdu));
+		dp_wdi_event_handler(WDI_EVENT_RX_PPDU_DESC, soc,
+				     ppdu_nbuf, HTT_INVALID_PEER,
+				     WDI_NO_VAL, pdev->pdev_id);
+	}
+}
+#else
+static inline void
+dp_rx_mon_handle_cfr_mu_info(struct dp_pdev *pdev,
+			     struct hal_rx_ppdu_info *ppdu_info,
+			     qdf_nbuf_t ppdu_nbuf)
+{
+}
+
+static inline void
+dp_rx_mon_populate_cfr_ppdu_info(struct dp_pdev *pdev,
+				 struct hal_rx_ppdu_info *ppdu_info,
+				 qdf_nbuf_t ppdu_nbuf)
+{
+}
+
+static inline void
+dp_rx_mon_populate_cfr_info(struct dp_pdev *pdev,
+			    struct hal_rx_ppdu_info *ppdu_info,
+			    qdf_nbuf_t ppdu_nbuf)
+{
+}
+
+static inline void
+dp_rx_handle_cfr(struct dp_soc *soc, struct dp_pdev *pdev,
+		 struct hal_rx_ppdu_info *ppdu_info)
+{
+}
+#endif
+
 /**
 * dp_rx_handle_ppdu_stats() - Allocate and deliver ppdu stats to cdp layer
 * @soc: core txrx main context
@@ -918,6 +1115,8 @@
 	/*
 	 * Do not allocate if fcs error,
 	 * ast idx invalid / fctl invalid
+	 *
+	 * In CFR RCC mode - PPDU status TLVs of error pkts are also needed
 	 */
 	if (ppdu_info->com_info.mpdu_cnt_fcs_ok == 0)
 		return;
@@ -946,10 +1145,11 @@
 	/* need not generate wdi event when mcopy and
 	 * enhanced stats are not enabled
 	 */
-	if (!pdev->mcopy_mode && !pdev->enhanced_stats_en)
+	if (!pdev->mcopy_mode && !pdev->enhanced_stats_en &&
+	    !pdev->cfr_rcc_mode)
 		return;
 
-	if (!pdev->mcopy_mode) {
+	if (!pdev->mcopy_mode && !pdev->cfr_rcc_mode) {
 		if (!ppdu_info->rx_status.frame_control_info_valid)
 			return;
 
@@ -960,6 +1160,7 @@
 			sizeof(struct cdp_rx_indication_ppdu), 0, 0, FALSE);
 	if (ppdu_nbuf) {
 		dp_rx_populate_cdp_indication_ppdu(pdev, ppdu_info, ppdu_nbuf);
+		dp_rx_mon_populate_cfr_info(pdev, ppdu_info, ppdu_nbuf);
 		qdf_nbuf_put_tail(ppdu_nbuf,
 				sizeof(struct cdp_rx_indication_ppdu));
 		cdp_rx_ppdu = (struct cdp_rx_indication_ppdu *)ppdu_nbuf->data;
@@ -970,7 +1171,7 @@
 					     soc, ppdu_nbuf,
 					     cdp_rx_ppdu->peer_id,
 					     WDI_NO_VAL, pdev->pdev_id);
-		} else if (pdev->mcopy_mode) {
+		} else if (pdev->mcopy_mode || pdev->cfr_rcc_mode) {
 			dp_wdi_event_handler(WDI_EVENT_RX_PPDU_DESC, soc,
 					ppdu_nbuf, HTT_INVALID_PEER,
 					WDI_NO_VAL, pdev->pdev_id);
@@ -1240,6 +1441,8 @@
 			if (pdev->enhanced_stats_en ||
 			    pdev->mcopy_mode || pdev->neighbour_peers_added)
 				dp_rx_handle_ppdu_stats(soc, pdev, ppdu_info);
+			else if (pdev->cfr_rcc_mode)
+				dp_rx_handle_cfr(soc, pdev, ppdu_info);
 
 			pdev->mon_ppdu_status = DP_PPDU_STATUS_DONE;
 			dp_rx_mon_dest_process(soc, mac_id, quota);