瀏覽代碼

qcacmn: Add APIs to enable HTT FW Stats

Adding support to parse stream of HTT TLV's recieved as response
to the HTT EXT stats request message

Change-Id: I44c990a1ed91c2381b89811de33c0717bd24be7d
CRs-Fixed: 1114641
Ishank Jain 8 年之前
父節點
當前提交
6290a3c543

+ 2 - 3
dp/inc/cdp_txrx_cmn.h

@@ -494,17 +494,16 @@ static inline void cdp_flush_cache_rx_queue(ol_txrx_soc_handle soc)
  * cdp_txrx_stats(): function to map to host and firmware statistics
  * @soc: soc handle
  * @vdev: virtual device
- * @req: statistics request handle
  * @stats: statistics option
  *
  * return: status
  */
 static inline
 int cdp_txrx_stats(ol_txrx_soc_handle soc, struct cdp_vdev *vdev,
-		struct ol_txrx_stats_req *req, enum cdp_stats stats)
+		enum cdp_stats stats)
 {
 	if (soc->ops->cmn_drv_ops->txrx_stats)
-		return soc->ops->cmn_drv_ops->txrx_stats(vdev, req, stats);
+		return soc->ops->cmn_drv_ops->txrx_stats(vdev, stats);
 	return 0;
 }
 

+ 7 - 6
dp/inc/cdp_txrx_cmn_struct.h

@@ -130,11 +130,11 @@ enum htt_cmn_dbg_stats_type {
 */
 enum cdp_host_txrx_stats {
 	TXRX_HOST_STATS_INVALID  = -1,
-	TXRX_RX_RATE_STATS  = 0,
-	TXRX_TX_RATE_STATS  = 1,
-	TXRX_TX_HOST_STATS  = 2,
-	TXRX_RX_HOST_STATS  = 3,
-	TXRX_CLEAR_STATS    = 4,
+	TXRX_CLEAR_STATS    = 0,
+	TXRX_RX_RATE_STATS  = 1,
+	TXRX_TX_RATE_STATS  = 2,
+	TXRX_TX_HOST_STATS  = 3,
+	TXRX_RX_HOST_STATS  = 4,
 	TXRX_HOST_STATS_MAX,
 };
 
@@ -517,7 +517,8 @@ enum cdp_stats {
 	CDP_TXRX_STATS_25,
 	CDP_TXRX_STATS_26,
 	CDP_TXRX_STATS_27,
-	CDP_TXRX_MAX_STATS,
+	CDP_TXRX_STATS_HTT_MAX = 256,
+	CDP_TXRX_MAX_STATS = 512,
 };
 
 /* Different Packet Types */

+ 26 - 10
dp/inc/cdp_txrx_host_stats.h

@@ -32,29 +32,36 @@
 #ifndef _CDP_TXRX_HOST_STATS_H_
 #define _CDP_TXRX_HOST_STATS_H_
 #include "cdp_txrx_handle.h"
-/* WIN */
-/* Need to remove the "req" parameter */
-/* Need to rename the function to reflect the functionality "show" / "display"
- * WIN -- to figure out whether to change OSIF to converge (not an immediate AI)
- * */
 /**
  * cdp_host_stats_get: cdp call to get host stats
  * @soc: SOC handle
  * @req: Requirement type
- * @type: Host stat type
  *
  * return: 0 for Success, Failure returns error message
  */
 static inline int cdp_host_stats_get(ol_txrx_soc_handle soc,
-	struct cdp_vdev *vdev,
-	struct ol_txrx_stats_req *req, enum cdp_host_txrx_stats type)
+		struct cdp_vdev *vdev,
+		struct ol_txrx_stats_req *req)
 {
 	if (soc->ops->host_stats_ops->txrx_host_stats_get)
-		return soc->ops->host_stats_ops->txrx_host_stats_get(vdev, req,
-				type);
+		return soc->ops->host_stats_ops->txrx_host_stats_get(vdev, req);
 	return 0;
 }
 
+/**
+ * cdp_host_stats_clr: cdp call to clear host stats
+ * @vdev: vdev handle
+ *
+ * return: void
+ */
+static inline void
+cdp_host_stats_clr(ol_txrx_soc_handle soc, struct cdp_vdev *vdev)
+{
+	if (soc->ops->host_stats_ops->txrx_host_stats_clr)
+		return soc->ops->host_stats_ops->txrx_host_stats_clr(vdev);
+	return;
+}
+
 static inline void
 cdp_host_ce_stats(ol_txrx_soc_handle soc, struct cdp_vdev *vdev)
 {
@@ -213,6 +220,15 @@ cdp_reset_lro_stats(ol_txrx_soc_handle soc, struct cdp_vdev *vdev)
 	return;
 }
 
+static inline void cdp_get_dp_fw_peer_stats(ol_txrx_soc_handle soc,
+		struct cdp_pdev *pdev, uint8_t *mac, uint32_t caps)
+{
+	if (soc->ops->host_stats_ops->get_fw_peer_stats)
+		return soc->ops->host_stats_ops->get_fw_peer_stats
+			(pdev, mac, caps);
+	return;
+}
+
 /**
  * @brief Parse the stats header and get the payload from the message.
  *

+ 8 - 4
dp/inc/cdp_txrx_ops.h

@@ -199,8 +199,7 @@ struct cdp_cmn_ops {
 	void (*set_pdev_dscp_tid_map)(struct cdp_pdev *pdev, uint8_t map_id,
 			uint8_t tos, uint8_t tid);
 
-	A_STATUS(*txrx_stats)(struct cdp_vdev *vdev,
-		struct ol_txrx_stats_req *req, enum cdp_stats stats);
+	int (*txrx_stats)(struct cdp_vdev *vdev, enum cdp_stats stats);
 
 	QDF_STATUS (*display_stats)(void *psoc, uint16_t value);
 
@@ -466,8 +465,9 @@ struct cdp_mon_ops {
 
 struct cdp_host_stats_ops {
 	int (*txrx_host_stats_get)(struct cdp_vdev *vdev,
-			struct ol_txrx_stats_req *req,
-			enum cdp_host_txrx_stats type);
+			struct ol_txrx_stats_req *req);
+
+	void (*txrx_host_stats_clr)(struct cdp_vdev *vdev);
 
 	void (*txrx_host_ce_stats)(struct cdp_vdev *vdev);
 
@@ -530,6 +530,10 @@ struct cdp_host_stats_ops {
 	void
 		(*reset_lro_stats)(struct cdp_vdev *vdev);
 
+	void
+		(*get_fw_peer_stats)(struct cdp_pdev *pdev, uint8_t *addr,
+				uint32_t cap);
+
 };
 
 struct cdp_wds_ops {

+ 310 - 2
dp/wifi3.0/dp_htt.c

@@ -23,12 +23,16 @@
 #include "dp_types.h"
 #include "dp_internal.h"
 #include "dp_rx_mon.h"
+#include "htt_stats.h"
+
+#define HTT_TLV_HDR_LEN HTT_T2H_EXT_STATS_CONF_TLV_HDR_SIZE
 
 #define HTT_HTC_PKT_POOL_INIT_SIZE 64
 
 #define HTT_MSG_BUF_SIZE(msg_bytes) \
 	((msg_bytes) + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING)
 
+#define DP_EXT_MSG_LENGTH 2048
 /*
  * htt_htc_pkt_alloc() - Allocate HTC packet buffer
  * @htt_soc:	HTT SOC handle
@@ -853,6 +857,210 @@ fail0:
 	return QDF_STATUS_E_FAILURE;
 }
 
+/**
+ * dp_process_htt_stat_msg(): Process the list of buffers of HTT EXT stats
+ * @soc: DP SOC handle
+ *
+ * The FW sends the HTT EXT STATS as a stream of T2H messages. Each T2H message
+ * contains sub messages which are identified by a TLV header.
+ * In this function we will process the stream of T2H messages and read all the
+ * TLV contained in the message.
+ *
+ * THe following cases have been taken care of
+ * Case 1: When the tlv_remain_length <= msg_remain_length of HTT MSG buffer
+ *		In this case the buffer will contain multiple tlvs.
+ * Case 2: When the tlv_remain_length > msg_remain_length of HTT MSG buffer.
+ *		Only one tlv will be contained in the HTT message and this tag
+ *		will extend onto the next buffer.
+ * Case 3: When the buffer is the continuation of the previous message
+ * Case 4: tlv length is 0. which will indicate the end of message
+ *
+ * return: void
+ */
+static inline void dp_process_htt_stat_msg(struct dp_soc *soc)
+{
+	htt_tlv_tag_t tlv_type = 0xff;
+	qdf_nbuf_t htt_msg = NULL;
+	uint32_t *msg_word;
+	uint8_t *tlv_buf_head = NULL;
+	uint8_t *tlv_buf_tail = NULL;
+	uint32_t msg_remain_len = 0;
+	uint32_t tlv_remain_len = 0;
+	uint32_t *tlv_start;
+
+	/* Process node in the HTT message queue */
+	while ((htt_msg = qdf_nbuf_queue_remove(&soc->htt_stats_msg)) != NULL) {
+		msg_word = (uint32_t *) qdf_nbuf_data(htt_msg);
+		/* read 5th word */
+		msg_word = msg_word + 4;
+		msg_remain_len = qdf_min(soc->htt_msg_len,
+				(uint32_t)DP_EXT_MSG_LENGTH);
+
+		/* Keep processing the node till node length is 0 */
+		while (msg_remain_len) {
+			/*
+			 * if message is not a continuation of previous message
+			 * read the tlv type and tlv length
+			 */
+			if (!tlv_buf_head) {
+				tlv_type = HTT_STATS_TLV_TAG_GET(
+						*msg_word);
+				tlv_remain_len = HTT_STATS_TLV_LENGTH_GET(
+						*msg_word);
+			}
+
+			if (tlv_remain_len == 0) {
+				msg_remain_len = 0;
+
+				if (tlv_buf_head) {
+					qdf_mem_free(tlv_buf_head);
+					tlv_buf_head = NULL;
+					tlv_buf_tail = NULL;
+				}
+
+				goto error;
+			}
+
+			tlv_remain_len += HTT_TLV_HDR_LEN;
+
+			if ((tlv_remain_len <= msg_remain_len)) {
+				/* Case 3 */
+				if (tlv_buf_head) {
+					qdf_mem_copy(tlv_buf_tail,
+							(uint8_t *)msg_word,
+							tlv_remain_len);
+					tlv_start = (uint32_t *)tlv_buf_head;
+				} else {
+					/* Case 1 */
+					tlv_start = msg_word;
+				}
+
+				dp_htt_stats_print_tag(tlv_type, tlv_start);
+
+				msg_remain_len -= tlv_remain_len;
+
+				msg_word = (uint32_t *)
+					(((uint8_t *)msg_word) +
+					tlv_remain_len);
+
+				tlv_remain_len = 0;
+
+				if (tlv_buf_head) {
+					qdf_mem_free(tlv_buf_head);
+					tlv_buf_head = NULL;
+					tlv_buf_tail = NULL;
+				}
+
+			} else { /* tlv_remain_len > msg_remain_len */
+				/* Case 2 & 3 */
+				if (!tlv_buf_head) {
+					tlv_buf_head = qdf_mem_malloc(
+							tlv_remain_len);
+
+					if (!tlv_buf_head) {
+						QDF_TRACE(QDF_MODULE_ID_TXRX,
+								QDF_TRACE_LEVEL_ERROR,
+								"Alloc failed");
+						goto error;
+					}
+
+					tlv_buf_tail = tlv_buf_head;
+				}
+
+				qdf_mem_copy(tlv_buf_tail, (uint8_t *)msg_word,
+						msg_remain_len);
+				tlv_remain_len -= msg_remain_len;
+				tlv_buf_tail += msg_remain_len;
+				msg_remain_len = 0;
+			}
+		}
+
+		if (soc->htt_msg_len >= DP_EXT_MSG_LENGTH) {
+			soc->htt_msg_len -= DP_EXT_MSG_LENGTH;
+		}
+
+		qdf_nbuf_free(htt_msg);
+	}
+	soc->htt_msg_len = 0;
+	return;
+
+error:
+	qdf_nbuf_free(htt_msg);
+	soc->htt_msg_len = 0;
+	while ((htt_msg = qdf_nbuf_queue_remove(&soc->htt_stats_msg))
+			!= NULL)
+		qdf_nbuf_free(htt_msg);
+}
+
+/**
+ * dp_txrx_fw_stats_handler():Function to process HTT EXT stats
+ * @soc: DP SOC handle
+ * @htt_t2h_msg: HTT message nbuf
+ *
+ * return:void
+ */
+static inline void dp_txrx_fw_stats_handler(struct dp_soc *soc,
+		qdf_nbuf_t htt_t2h_msg)
+{
+	uint32_t length;
+	uint8_t done;
+	qdf_nbuf_t msg_copy;
+	uint32_t *msg_word;
+
+	msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg);
+	msg_word = msg_word + 3;
+	done = 0;
+	length = HTT_T2H_EXT_STATS_CONF_TLV_LENGTH_GET(*msg_word);
+	done = HTT_T2H_EXT_STATS_CONF_TLV_DONE_GET(*msg_word);
+
+	/*
+	 * HTT EXT stats response comes as stream of TLVs which span over
+	 * multiple T2H messages.
+	 * The first message will carry length of the response.
+	 * For rest of the messages length will be zero.
+	 */
+	if (soc->htt_msg_len && length)
+		goto error;
+
+	if (length)
+		soc->htt_msg_len = length;
+
+	/*
+	 * Clone the T2H message buffer and store it in a list to process
+	 * it later.
+	 *
+	 * The original T2H message buffers gets freed in the T2H HTT event
+	 * handler
+	 */
+	msg_copy = qdf_nbuf_clone(htt_t2h_msg);
+
+	if (!msg_copy) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
+				"T2H messge clone failed for HTT EXT STATS");
+		soc->htt_msg_len = 0;
+		goto error;
+	}
+
+	qdf_nbuf_queue_add(&soc->htt_stats_msg, msg_copy);
+
+	/*
+	 * Done bit signifies that this is the last T2H buffer in the stream of
+	 * HTT EXT STATS message
+	 */
+	if (done)
+		dp_process_htt_stat_msg(soc);
+
+	return;
+
+error:
+	while ((msg_copy = qdf_nbuf_queue_remove(&soc->htt_stats_msg))
+			!= NULL) {
+		qdf_nbuf_free(msg_copy);
+	}
+	return;
+
+}
+
 /*
  * htt_soc_attach_target() - SOC level HTT setup
  * @htt_soc:	HTT SOC handle
@@ -1015,8 +1223,11 @@ static void dp_htt_t2h_msg_handler(void *context, HTC_PACKET *pkt)
 			}
 			break;
 		}
-
-
+	case HTT_T2H_MSG_TYPE_EXT_STATS_CONF:
+		{
+			dp_txrx_fw_stats_handler(soc->dp_soc, htt_t2h_msg);
+			break;
+		}
 	default:
 		break;
 	};
@@ -1166,3 +1377,100 @@ htt_soc_detach(void *htt_soc)
 	qdf_mem_free(soc);
 }
 
+/**
+ * dp_h2t_ext_stats_msg_send(): function to contruct HTT message to pass to FW
+ * @pdev: DP PDEV handle
+ * @stats_type_upload_mask: stats type requested by user
+ * @config_param_0: extra configuration parameters
+ * @config_param_1: extra configuration parameters
+ * @config_param_2: extra configuration parameters
+ * @config_param_3: extra configuration parameters
+ *
+ * return: QDF STATUS
+ */
+QDF_STATUS dp_h2t_ext_stats_msg_send(struct dp_pdev *pdev,
+		uint32_t stats_type_upload_mask, uint32_t config_param_0,
+		uint32_t config_param_1, uint32_t config_param_2,
+		uint32_t config_param_3)
+{
+	struct htt_soc *soc = pdev->soc->htt_handle;
+	struct dp_htt_htc_pkt *pkt;
+	qdf_nbuf_t msg;
+	uint32_t *msg_word;
+	uint8_t pdev_mask;
+
+	msg = qdf_nbuf_alloc(
+			soc->osdev,
+			HTT_MSG_BUF_SIZE(HTT_H2T_EXT_STATS_REQ_MSG_SZ),
+			HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE);
+
+	if (!msg)
+		return QDF_STATUS_E_NOMEM;
+
+	/*TODO:Add support for SOC stats
+	 * Bit 0: SOC Stats
+	 * Bit 1: Pdev stats for pdev id 0
+	 * Bit 2: Pdev stats for pdev id 1
+	 * Bit 3: Pdev stats for pdev id 2
+	 */
+	pdev_mask = 1 << (pdev->pdev_id + 1);
+
+	/*
+	 * Set the length of the message.
+	 * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added
+	 * separately during the below call to qdf_nbuf_push_head.
+	 * The contribution from the HTC header is added separately inside HTC.
+	 */
+	if (qdf_nbuf_put_tail(msg, HTT_H2T_EXT_STATS_REQ_MSG_SZ) == NULL) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+				"Failed to expand head for HTT_EXT_STATS");
+		qdf_nbuf_free(msg);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	msg_word = (uint32_t *) qdf_nbuf_data(msg);
+
+	qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING);
+	*msg_word = 0;
+	HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_EXT_STATS_REQ);
+	HTT_H2T_EXT_STATS_REQ_PDEV_MASK_SET(*msg_word, pdev_mask);
+	HTT_H2T_EXT_STATS_REQ_STATS_TYPE_SET(*msg_word, stats_type_upload_mask);
+
+	/* word 1 */
+	msg_word++;
+	*msg_word = 0;
+	HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, config_param_0);
+
+	/* word 2 */
+	msg_word++;
+	*msg_word = 0;
+	HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, config_param_1);
+
+	/* word 3 */
+	msg_word++;
+	*msg_word = 0;
+	HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, config_param_2);
+
+	/* word 4 */
+	msg_word++;
+	*msg_word = 0;
+	HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, config_param_3);
+
+	HTT_H2T_EXT_STATS_REQ_CONFIG_PARAM_SET(*msg_word, 0);
+	pkt = htt_htc_pkt_alloc(soc);
+	if (!pkt) {
+		qdf_nbuf_free(msg);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	pkt->soc_ctxt = NULL; /* not used during send-done callback */
+
+	SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt,
+			dp_htt_h2t_send_complete_free_netbuf,
+			qdf_nbuf_data(msg), qdf_nbuf_len(msg),
+			soc->htc_endpoint,
+			1); /* tag - not relevant here */
+
+	SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg);
+	return htc_send_pkt(soc->htc_soc, &pkt->htc_pkt);
+}

+ 5 - 0
dp/wifi3.0/dp_internal.h

@@ -279,4 +279,9 @@ uint16_t dp_tx_me_send_convert_ucast(struct cdp_vdev *vdev_handle,
 void dp_tx_me_alloc_descriptor(struct cdp_pdev *pdev);
 
 void dp_tx_me_free_descriptor(struct cdp_pdev *pdev);
+QDF_STATUS dp_h2t_ext_stats_msg_send(struct dp_pdev *pdev,
+		uint32_t stats_type_upload_mask, uint32_t config_param_0,
+		uint32_t config_param_1, uint32_t config_param_2,
+		uint32_t config_param_3);
+void dp_htt_stats_print_tag(uint8_t tag_type, uint32_t *tag_buf);
 #endif /* #ifndef _DP_INTERNAL_H_ */

+ 109 - 41
dp/wifi3.0/dp_main.c

@@ -36,12 +36,15 @@
 #include <qdf_util.h>
 #include "dp_peer.h"
 #include "dp_rx_mon.h"
+#include "htt_stats.h"
 
 #define DP_INTR_POLL_TIMER_MS	10
 #define DP_MCS_LENGTH (6*MAX_MCS)
 #define DP_NSS_LENGTH (6*SS_COUNT)
 #define DP_RXDMA_ERR_LENGTH (6*MAX_RXDMA_ERRORS)
 #define DP_REO_ERR_LENGTH (6*REO_ERROR_TYPE_MAX)
+#define DP_CURR_FW_STATS_AVAIL 19
+#define DP_HTT_DBG_EXT_STATS_MAX 256
 
 /**
  * default_dscp_tid_map - Default DSCP-TID mapping
@@ -89,33 +92,31 @@ enum dp_fw_stats {
  * currently supported
  */
 const int dp_stats_mapping_table[][STATS_TYPE_MAX] = {
+	{HTT_DBG_EXT_STATS_RESET, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_PDEV_TX, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_PDEV_RX, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_PDEV_TX_HWQ, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_PDEV_TX_SCHED, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_PDEV_ERROR, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_PDEV_TQM, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_TQM_CMDQ, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_TX_DE_INFO, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_PDEV_TX_RATE, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_PDEV_RX_RATE, TXRX_HOST_STATS_INVALID},
 	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_TX_SELFGEN_INFO, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_TX_MU_HWQ, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_RING_IF_INFO, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_SRNG_INFO, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_SFM_INFO, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_PDEV_TX_MU, TXRX_HOST_STATS_INVALID},
+	{HTT_DBG_EXT_STATS_ACTIVE_PEERS_LIST, TXRX_HOST_STATS_INVALID},
+	/* Last ENUM for HTT FW STATS */
+	{DP_HTT_DBG_EXT_STATS_MAX, TXRX_HOST_STATS_INVALID},
+	{TXRX_FW_STATS_INVALID, TXRX_CLEAR_STATS},
 	{TXRX_FW_STATS_INVALID, TXRX_RX_RATE_STATS},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
 	{TXRX_FW_STATS_INVALID, TXRX_TX_RATE_STATS},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
 	{TXRX_FW_STATS_INVALID, TXRX_TX_HOST_STATS},
-	{TXRX_FW_STATS_INVALID, TXRX_CLEAR_STATS},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
-	{TXRX_FW_STATS_INVALID, TXRX_HOST_STATS_INVALID},
 	{TXRX_FW_STATS_INVALID, TXRX_RX_HOST_STATS},
 };
 
@@ -975,6 +976,7 @@ static int dp_soc_cmn_setup(struct dp_soc *soc)
 	hal_reo_setup(soc->hal_soc, &reo_params);
 
 	qdf_atomic_set(&soc->cmn_init_done, 1);
+	qdf_nbuf_queue_init(&soc->htt_stats_msg);
 	return 0;
 fail1:
 	/*
@@ -3289,27 +3291,28 @@ static inline void dp_print_peer_stats(struct dp_peer *peer)
 /**
  * dp_print_host_stats()- Function to print the stats aggregated at host
  * @vdev_handle: DP_VDEV handle
- * @req: ol_txrx_stats_req
  * @type: host stats type
  *
  * Available Stat types
+ * TXRX_CLEAR_STATS  : Clear the stats
  * TXRX_RX_RATE_STATS: Print Rx Rate Info
  * TXRX_TX_RATE_STATS: Print Tx Rate Info
  * TXRX_TX_HOST_STATS: Print Tx Stats
  * TXRX_RX_HOST_STATS: Print Rx Stats
- * TXRX_CLEAR_STATS  : Clear the stats
  *
  * Return: 0 on success, print error message in case of failure
  */
 static int
-dp_print_host_stats(struct cdp_vdev *vdev_handle, struct ol_txrx_stats_req *req,
-		enum cdp_host_txrx_stats type)
+dp_print_host_stats(struct cdp_vdev *vdev_handle, enum cdp_host_txrx_stats type)
 {
 	struct dp_vdev *vdev = (struct dp_vdev *)vdev_handle;
 	struct dp_pdev *pdev = (struct dp_pdev *)vdev->pdev;
 
 	dp_aggregate_pdev_stats(pdev);
 	switch (type) {
+	case TXRX_CLEAR_STATS:
+		dp_txrx_host_stats_clr(vdev);
+		break;
 	case TXRX_RX_RATE_STATS:
 		dp_print_rx_rates(vdev);
 		break;
@@ -3324,9 +3327,6 @@ dp_print_host_stats(struct cdp_vdev *vdev_handle, struct ol_txrx_stats_req *req,
 		dp_print_pdev_rx_stats(pdev);
 		dp_print_soc_rx_stats(pdev->soc);
 		break;
-	case TXRX_CLEAR_STATS:
-		dp_txrx_host_stats_clr(vdev);
-		break;
 	default:
 		DP_TRACE(FATAL, "Wrong Input For TxRx Host Stats");
 		break;
@@ -3335,23 +3335,65 @@ dp_print_host_stats(struct cdp_vdev *vdev_handle, struct ol_txrx_stats_req *req,
 }
 
 /*
- * dp_get_peer_stats()- function to print peer stats
+ * dp_get_host_peer_stats()- function to print peer stats
  * @pdev_handle: DP_PDEV handle
  * @mac_addr: mac address of the peer
  *
  * Return: void
  */
 static void
-dp_get_peer_stats(struct cdp_pdev *pdev_handle, char *mac_addr)
+dp_get_host_peer_stats(struct cdp_pdev *pdev_handle, char *mac_addr)
 {
 	struct dp_peer *peer;
 	uint8_t local_id;
 	peer = (struct dp_peer *)dp_find_peer_by_addr(pdev_handle, mac_addr,
 			&local_id);
 
-		dp_print_peer_stats(peer);
-		return;
+	dp_print_peer_stats(peer);
+	return;
 }
+
+/*
+ * dp_get_fw_peer_stats()- function to print peer stats
+ * @pdev_handle: DP_PDEV handle
+ * @mac_addr: mac address of the peer
+ * @cap: Type of htt stats requested
+ *
+ * Currently Supporting only MAC ID based requests Only
+ *	1: HTT_PEER_STATS_REQ_MODE_NO_QUERY
+ *	2: HTT_PEER_STATS_REQ_MODE_QUERY_TQM
+ *	3: HTT_PEER_STATS_REQ_MODE_FLUSH_TQM
+ *
+ * Return: void
+ */
+static void
+dp_get_fw_peer_stats(struct cdp_pdev *pdev_handle, uint8_t *mac_addr,
+		uint32_t cap)
+{
+	struct dp_pdev *pdev = (struct dp_pdev *)pdev_handle;
+	uint32_t config_param0 = 0;
+	uint32_t config_param1 = 0;
+	uint32_t config_param2 = 0;
+	uint32_t config_param3 = 0;
+
+	HTT_DBG_EXT_STATS_PEER_INFO_IS_MAC_ADDR_SET(config_param0, 1);
+	config_param0 |= (1 << (cap + 1));
+
+	config_param1 = 0x8f;
+
+	config_param2 |= (mac_addr[0] & 0x000000ff);
+	config_param2 |= ((mac_addr[1] << 8) & 0x0000ff00);
+	config_param2 |= ((mac_addr[2] << 16) & 0x00ff0000);
+	config_param2 |= ((mac_addr[3] << 24) & 0xff000000);
+
+	config_param3 |= (mac_addr[4] & 0x000000ff);
+	config_param3 |= ((mac_addr[5] << 8) & 0x0000ff00);
+
+	dp_h2t_ext_stats_msg_send(pdev, HTT_DBG_EXT_STATS_PEER_INFO,
+			config_param0, config_param1, config_param2,
+			config_param3);
+}
+
 /*
  * dp_set_vdev_param: function to set parameters in vdev
  * @param: parameter type to be set
@@ -3436,16 +3478,35 @@ static void dp_set_pdev_dscp_tid_map_wifi3(struct cdp_pdev *pdev_handle,
 	return;
 }
 
+/**
+ * dp_fw_stats_process(): Process TxRX FW stats request
+ * @vdev_handle: DP VDEV handle
+ * @val: value passed by user
+ *
+ * return: int
+ */
+static int dp_fw_stats_process(struct cdp_vdev *vdev_handle, uint32_t val)
+{
+	struct dp_vdev *vdev = (struct dp_vdev *)vdev_handle;
+	struct dp_pdev *pdev = NULL;
+
+	if (!vdev) {
+		DP_TRACE(NONE, "VDEV not found");
+		return 1;
+	}
+
+	pdev = vdev->pdev;
+	return dp_h2t_ext_stats_msg_send(pdev, val, 0, 0, 0, 0);
+}
+
 /*
  * dp_txrx_stats() - function to map to firmware and host stats
  * @vdev: virtual handle
- * @req: statistics request handle
  * @stats: type of statistics requested
  *
  * Return: integer
  */
-static int dp_txrx_stats(struct cdp_vdev *vdev,
-			struct ol_txrx_stats_req *req, enum cdp_stats stats)
+static int dp_txrx_stats(struct cdp_vdev *vdev, enum cdp_stats stats)
 {
 	int host_stats;
 	int fw_stats;
@@ -3453,6 +3514,12 @@ static int dp_txrx_stats(struct cdp_vdev *vdev,
 	if (stats >= CDP_TXRX_MAX_STATS)
 		return 0;
 
+	/*
+	 * DP_CURR_FW_STATS_AVAIL: no of FW stats currently available
+	 *			has to be updated if new FW HTT stats added
+	 */
+	if (stats > CDP_TXRX_STATS_HTT_MAX)
+		stats = stats + DP_CURR_FW_STATS_AVAIL - DP_HTT_DBG_EXT_STATS_MAX;
 	fw_stats = dp_stats_mapping_table[stats][STATS_FW];
 	host_stats = dp_stats_mapping_table[stats][STATS_HOST];
 
@@ -3460,11 +3527,12 @@ static int dp_txrx_stats(struct cdp_vdev *vdev,
 		 "stats: %u fw_stats_type: %d host_stats_type: %d",
 		  stats, fw_stats, host_stats);
 
-	/* TODO: Firmware Mapping not implemented */
+	if (fw_stats != TXRX_FW_STATS_INVALID)
+		return dp_fw_stats_process(vdev, fw_stats);
 
 	if ((host_stats != TXRX_HOST_STATS_INVALID) &&
 			(host_stats <= TXRX_HOST_STATS_MAX))
-		return dp_print_host_stats(vdev, req, host_stats);
+		return dp_print_host_stats(vdev, host_stats);
 	else
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
 				"Wrong Input for TxRx Stats");
@@ -3751,8 +3819,8 @@ static struct cdp_mon_ops dp_ops_mon = {
 };
 
 static struct cdp_host_stats_ops dp_ops_host_stats = {
-	.txrx_host_stats_get = dp_print_host_stats,
-	.txrx_per_peer_stats = dp_get_peer_stats,
+	.txrx_per_peer_stats = dp_get_host_peer_stats,
+	.get_fw_peer_stats = dp_get_fw_peer_stats,
 	/* TODO */
 };
 

+ 262 - 0
dp/wifi3.0/dp_stats.c

@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2017 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 "qdf_types.h"
+#include "htt_stats.h"
+#include "dp_types.h"
+#include "dp_internal.h"
+
+#define DP_MAX_STRING_LEN 500
+
+/* these values are fixed in the next gerrit */
+#define DP_HTT_DATA_LEN  1
+#define DP_HTT_URRN_STATS_LEN  1
+#define DP_HTT_FLUSH_ERRS_LEN  1
+#define DP_HTT_SIFS_STATUS_LEN  1
+#define DP_HTT_PHY_ERRS_LEN  1
+#define DP_HTT_HW_INTR_NAME_LEN  HTT_STATS_MAX_HW_INTR_NAME_LEN
+#define DP_HTT_HW_MODULE_NAME_LEN  HTT_STATS_MAX_HW_MODULE_NAME_LEN
+#define DP_HTT_COUNTER_NAME_LEN  HTT_MAX_COUNTER_NAME
+#define DP_HTT_PEER_DETAILS_LEN  1
+#define DP_HTT_MU_MIMO_SCH_STATS_TLV_LEN  1
+#define DP_HTT_MU_MIMO_MPDU_STATS_TLV_LEN  1
+#define DP_HTT_DIFS_LATENCY_HIST_LEN  1
+#define DP_HTT_CMD_RESULT_LEN  1
+#define DP_HTT_CMD_STALL_STATUS_LEN  1
+#define DP_HTT_FES_RESULT_LEN  1
+#define DP_HTT_SCHED_CMD_POSTED_LEN  1
+#define DP_HTT_SCHED_CMD_REAPED_LEN  1
+#define DP_HTT_GEN_MPDU_END_REASON_LEN  1
+#define DP_HTT_LIST_MPDU_END_REASON_LEN  1
+#define DP_HTT_LIST_MPDU_CNT_HIST_LEN  1
+#define DP_HTT_LOW_WM_HIT_COUNT_LEN  HTT_STATS_LOW_WM_BINS
+#define DP_HTT_HIGH_WM_HIT_COUNT_LEN  HTT_STATS_HIGH_WM_BINS
+#define DP_HTT_DWORDS_USED_BY_USER_N_LEN  1
+#define DP_HTT_TX_MCS_LEN  HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS
+#define DP_HTT_TX_SU_MCS_LEN  HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS
+#define DP_HTT_TX_MU_MCS_LEN  HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS
+#define DP_HTT_TX_NSS_LEN  HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS
+#define DP_HTT_TX_BW_LEN  HTT_TX_PDEV_STATS_NUM_BW_COUNTERS
+#define DP_HTT_TX_STBC_LEN  HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS
+#define DP_HTT_TX_PREAM_LEN  HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES
+#define DP_HTT_TX_GI_LEN  HTT_TX_PDEV_STATS_NUM_GI_COUNTERS
+#define DP_HTT_TX_DCM_LEN  HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS
+#define DP_HTT_RX_MCS_LEN  HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS
+#define DP_HTT_RX_NSS_LEN  HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS
+#define DP_HTT_RX_DCM_LEN  HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS
+#define DP_HTT_RX_STBC_LEN  HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS
+#define DP_HTT_RX_BW_LEN  HTT_RX_PDEV_STATS_NUM_BW_COUNTERS
+#define DP_HTT_RX_PREAM_LEN  HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES
+#define DP_HTT_RSSI_CHAIN_LEN  HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS
+#define DP_HTT_RX_GI_LEN  HTT_RX_PDEV_STATS_NUM_GI_COUNTERS
+#define DP_HTT_REFILL_RING_EMPTY_CNT_LEN  1
+#define DP_HTT_REFILL_RING_NUM_REFILL_LEN  1
+#define DP_HTT_FW_RING_MGMT_SUBTYPE_LEN  HTT_STATS_SUBTYPE_MAX
+#define DP_HTT_FW_RING_CTRL_SUBTYPE_LEN  HTT_STATS_SUBTYPE_MAX
+#define DP_HTT_FW_RING_MPDU_ERR_LEN  HTT_RX_STATS_RXDMA_MAX_ERR
+#define DP_HTT_FW_MPDU_DROP_LEN  1
+#define DP_HTT_TID_NAME_LEN  MAX_HTT_TID_NAME
+
+/* TODO:Below stat function is for initial testing
+ * Further functions will be added after reviews on the FW side are complete
+ */
+
+/**
+ * dp_print_tx_pdev_stats_cmn_tlv: display htt_tx_pdev_stats_cmn_tlv
+ * @dp_htt_tag:pointer to structure htt_tx_pdev_stats_cmn_tlv
+ *
+ * return:void
+ */
+static inline void dp_print_tx_pdev_stats_cmn_tlv(uint32_t *tag_buf)
+{
+	htt_tx_pdev_stats_cmn_tlv *dp_htt_tag =
+		(htt_tx_pdev_stats_cmn_tlv *)tag_buf;
+
+	DP_TRACE_STATS(NONE, "Pdev Stats:\n");
+	DP_TRACE_STATS(NONE, "mac_id__word = %d",
+			dp_htt_tag->mac_id__word);
+	DP_TRACE_STATS(NONE, "hw_queued = %d",
+			dp_htt_tag->hw_queued);
+	DP_TRACE_STATS(NONE, "hw_reaped = %d",
+			dp_htt_tag->hw_reaped);
+	DP_TRACE_STATS(NONE, "underrun = %d",
+			dp_htt_tag->underrun);
+	DP_TRACE_STATS(NONE, "hw_paused = %d",
+			dp_htt_tag->hw_paused);
+	DP_TRACE_STATS(NONE, "hw_flush = %d",
+			dp_htt_tag->hw_flush);
+	DP_TRACE_STATS(NONE, "hw_filt = %d",
+			dp_htt_tag->hw_filt);
+	DP_TRACE_STATS(NONE, "tx_abort = %d",
+			dp_htt_tag->tx_abort);
+	DP_TRACE_STATS(NONE, "mpdu_requeued = %d",
+			dp_htt_tag->mpdu_requed);
+	DP_TRACE_STATS(NONE, "tx_xretry = %d",
+			dp_htt_tag->tx_xretry);
+	DP_TRACE_STATS(NONE, "data_rc = %d",
+			dp_htt_tag->data_rc);
+	DP_TRACE_STATS(NONE, "mpdu_dropped_xretry = %d",
+			dp_htt_tag->mpdu_dropped_xretry);
+	DP_TRACE_STATS(NONE, "illegal_rate_phy_err = %d",
+			dp_htt_tag->illgl_rate_phy_err);
+	DP_TRACE_STATS(NONE, "cont_xretry = %d",
+			dp_htt_tag->cont_xretry);
+	DP_TRACE_STATS(NONE, "tx_timeout = %d",
+			dp_htt_tag->tx_timeout);
+	DP_TRACE_STATS(NONE, "pdev_resets = %d",
+			dp_htt_tag->pdev_resets);
+	DP_TRACE_STATS(NONE, "phy_underrun = %d",
+			dp_htt_tag->phy_underrun);
+	DP_TRACE_STATS(NONE, "txop_ovf = %d",
+			dp_htt_tag->txop_ovf);
+	DP_TRACE_STATS(NONE, "seq_posted = %d",
+			dp_htt_tag->seq_posted);
+	DP_TRACE_STATS(NONE, "seq_failed_queueing = %d",
+			dp_htt_tag->seq_failed_queueing);
+	DP_TRACE_STATS(NONE, "seq_completed = %d",
+			dp_htt_tag->seq_completed);
+	DP_TRACE_STATS(NONE, "seq_restarted = %d",
+			dp_htt_tag->seq_restarted);
+	DP_TRACE_STATS(NONE, "mu_seq_posted = %d",
+			dp_htt_tag->mu_seq_posted);
+	DP_TRACE_STATS(NONE, "mpdu_count_tqm = %d",
+			dp_htt_tag->mpdu_count_tqm);
+	DP_TRACE_STATS(NONE, "msdu_count_tqm = %d",
+			dp_htt_tag->msdu_count_tqm);
+	DP_TRACE_STATS(NONE, "mpdu_removed_tqm = %d",
+			dp_htt_tag->mpdu_removed_tqm);
+	DP_TRACE_STATS(NONE, "msdu_removed_tqm = %d",
+			dp_htt_tag->msdu_removed_tqm);
+	DP_TRACE_STATS(NONE, "mpdus_sw_flush = %d",
+			dp_htt_tag->mpdus_sw_flush);
+	DP_TRACE_STATS(NONE, "mpdus_hw_filter = %d",
+			dp_htt_tag->mpdus_hw_filter);
+	DP_TRACE_STATS(NONE, "mpdus_truncated = %d",
+			dp_htt_tag->mpdus_truncated);
+	DP_TRACE_STATS(NONE, "mpdus_ack_failed = %d",
+			dp_htt_tag->mpdus_ack_failed);
+	DP_TRACE_STATS(NONE, "mpdus_expired = %d",
+			dp_htt_tag->mpdus_expired);
+	DP_TRACE_STATS(NONE, "mpdus_seq_hw_retry = %d",
+			dp_htt_tag->mpdus_seq_hw_retry);
+	DP_TRACE_STATS(NONE, "ack_tlv_proc = %d",
+			dp_htt_tag->ack_tlv_proc);
+	DP_TRACE_STATS(NONE, "coex_abort_mpdu_cnt_valid = %d",
+			dp_htt_tag->
+			coex_abort_mpdu_cnt_valid);
+	DP_TRACE_STATS(NONE, "coex_abort_mpdu_cnt = %d",
+			dp_htt_tag->coex_abort_mpdu_cnt);
+}
+
+/**
+ * dp_print_tx_pdev_stats_urrn_tlv_v: display htt_tx_pdev_stats_urrn_tlv_v
+ * @tag_buf: buffer containing the tlv
+ *
+ * return:void
+ */
+static inline void dp_print_tx_pdev_stats_urrn_tlv_v(uint32_t *tag_buf)
+{
+	htt_tx_pdev_stats_urrn_tlv_v *dp_htt_tag =
+		(htt_tx_pdev_stats_urrn_tlv_v *)tag_buf;
+	uint8_t i;
+	uint16_t index = 0;
+	char urrn_stats[DP_MAX_STRING_LEN];
+	uint32_t tag_len = (HTT_STATS_TLV_LENGTH_GET(*tag_buf) >> 2);
+
+	tag_len = qdf_min(tag_len, (uint32_t)HTT_TX_PDEV_MAX_URRN_STATS);
+	DP_TRACE_STATS(NONE, "Pdev Underun Stats:\n");
+	for (i = 0; i < tag_len; i++) {
+		index += qdf_snprint(&urrn_stats[index],
+				DP_MAX_STRING_LEN - index, " %d,",
+				dp_htt_tag->urrn_stats[i]);
+	}
+	DP_TRACE_STATS(NONE, "urrn_stats = %s", urrn_stats);
+}
+
+/*
+ * dp_print_tx_pdev_stats_flush_tlv_v: display htt_tx_pdev_stats_flush_tlv_v
+ * @tag_buf: buffer containing the tlv *
+ * return:void
+ */
+static inline void dp_print_tx_pdev_stats_flush_tlv_v(uint32_t *tag_buf)
+{
+	htt_tx_pdev_stats_flush_tlv_v *dp_htt_tag =
+		(htt_tx_pdev_stats_flush_tlv_v *)tag_buf;
+	uint8_t i;
+	uint8_t index = 0;
+	char flush_errs[DP_MAX_STRING_LEN];
+	uint32_t tag_len = (HTT_STATS_TLV_LENGTH_GET(*tag_buf) >> 2);
+
+	tag_len = qdf_min(tag_len,
+			(uint32_t)HTT_TX_PDEV_MAX_FLUSH_REASON_STATS);
+	DP_TRACE_STATS(NONE, "Pdev Flush Stats:\n");
+	for (i = 0; i <  tag_len; i++) {
+		index += qdf_snprint(&flush_errs[index],
+				DP_MAX_STRING_LEN - index, " %d,",
+				dp_htt_tag->flush_errs[i]);
+	}
+	DP_TRACE_STATS(NONE, "flush_errs = %s ", flush_errs);
+}
+
+/*
+ * dp_print_tx_pdev_stats_sifs_tlv_v: display htt_tx_pdev_stats_sifs_tlv_v
+ * @tag_buf: buffer containing the tlv *
+ * return:void
+ */
+static inline void dp_print_tx_pdev_stats_sifs_tlv_v(uint32_t *tag_buf)
+{
+	htt_tx_pdev_stats_sifs_tlv_v *dp_htt_tag =
+		(htt_tx_pdev_stats_sifs_tlv_v *)tag_buf;
+	uint8_t i;
+	uint8_t index = 0;
+	char sifs_status[DP_MAX_STRING_LEN];
+	uint32_t tag_len = (HTT_STATS_TLV_LENGTH_GET(*tag_buf) >> 2);
+
+	tag_len = qdf_min(tag_len, (uint32_t)HTT_TX_PDEV_MAX_SIFS_BURST_STATS);
+	DP_TRACE_STATS(NONE, "Pdev SIFS Stats:\n");
+	for (i = 0; i <  tag_len; i++) {
+		index += qdf_snprint(&sifs_status[index],
+				DP_MAX_STRING_LEN - index, " %d,",
+				dp_htt_tag->sifs_status[i]);
+	}
+	DP_TRACE_STATS(NONE, "sifs_status = %s ", sifs_status);
+}
+
+/**
+ * dp_htt_stats_print_tag: function to select the tag type and
+ * print the corresponding tag structure
+ * @tag_type: tag type that is to be printed
+ * @tag_buf: pointer to the tag structure
+ *
+ * return: void
+ */
+void dp_htt_stats_print_tag(uint8_t tag_type, uint32_t *tag_buf)
+{
+	switch (tag_type) {
+	case HTT_STATS_TX_PDEV_CMN_TAG:
+		dp_print_tx_pdev_stats_cmn_tlv(tag_buf);
+		break;
+	case HTT_STATS_TX_PDEV_UNDERRUN_TAG:
+		dp_print_tx_pdev_stats_urrn_tlv_v(tag_buf);
+		break;
+	case HTT_STATS_TX_PDEV_SIFS_TAG:
+		dp_print_tx_pdev_stats_sifs_tlv_v(tag_buf);
+		break;
+	default:
+		break;
+	}
+}

+ 4 - 0
dp/wifi3.0/dp_types.h

@@ -633,6 +633,10 @@ struct dp_soc {
 	u_int16_t pdev_bs_inact_interval;
 	/* Inactivity timer */
 #endif /* QCA_SUPPORT_SON */
+	/* T2H Ext stats message queue */
+	qdf_nbuf_queue_t htt_stats_msg;
+	/* T2H Ext stats message length */
+	uint32_t htt_msg_len;
 };
 #define MAX_RX_MAC_RINGS 2
 /* Same as NAC_MAX_CLENT */

+ 2 - 2
qdf/linux/src/i_qdf_util.h

@@ -220,8 +220,8 @@ static inline bool __qdf_is_macaddr_equal(struct qdf_mac_addr *mac_addr1,
 /**
  * @brief memory barriers.
  */
-#define __qdf_min(_a, _b) min(a, b)
-#define __qdf_max(_a, _b) max(a, b)
+#define __qdf_min(_a, _b) min(_a, _b)
+#define __qdf_max(_a, _b) max(_a, _b)
 
 #define MEMINFO_KB(x)  ((x) << (PAGE_SHIFT - 10))   /* In kilobytes */