Bladeren bron

qcacmn: per-peer protocol count tracking

Maintain packet counters for each peer based on protocol. Following 3
protocols are supported
* ICMP (IPv4)
* ARP (IPv4)
* EAP

Change-Id: I56dd9bbedd7b6698b7d155a524b242e8cabd76c3
CRs-Fixed: 2604877
Adil Saeed Musthafa 5 jaren geleden
bovenliggende
commit
bbc4de06d7

+ 174 - 0
dp/inc/cdp_txrx_ctrl.h

@@ -284,6 +284,144 @@ cdp_txrx_get_psoc_param(ol_txrx_soc_handle soc,
 	return soc->ops->ctrl_ops->txrx_get_psoc_param(soc, type, val);
 }
 
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+/**
+ * cdp_set_vdev_peer_protocol_count() - set per-peer protocol count tracking
+ *
+ * @soc - pointer to the soc
+ * @vdev - the data virtual device object
+ * @enable - enable per-peer protocol count
+ *
+ * Set per-peer protocol count feature enable
+ *
+ * Return: void
+ */
+static inline
+void cdp_set_vdev_peer_protocol_count(ol_txrx_soc_handle soc, int8_t vdev_id,
+				      bool enable)
+{
+	if (!soc || !soc->ops) {
+		QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG,
+			  "%s: Invalid Instance:", __func__);
+		QDF_BUG(0);
+		return;
+	}
+
+	if (!soc->ops->ctrl_ops ||
+	    !soc->ops->ctrl_ops->txrx_enable_peer_protocol_count)
+		return;
+
+	soc->ops->ctrl_ops->txrx_enable_peer_protocol_count(soc, vdev_id,
+							    enable);
+}
+
+/**
+ * cdp_set_vdev_peer_protocol_drop_mask() - set per-peer protocol drop mask
+ *
+ * @soc - pointer to the soc
+ * @vdev - the data virtual device object
+ * @drop_mask - drop_mask
+ *
+ * Set per-peer protocol drop_mask
+ *
+ * Return - void
+ */
+static inline
+void cdp_set_vdev_peer_protocol_drop_mask(ol_txrx_soc_handle soc,
+					  int8_t vdev_id, int drop_mask)
+{
+	if (!soc || !soc->ops) {
+		QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG,
+			  "%s: Invalid Instance:", __func__);
+		QDF_BUG(0);
+		return;
+	}
+
+	if (!soc->ops->ctrl_ops ||
+	    !soc->ops->ctrl_ops->txrx_set_peer_protocol_drop_mask)
+		return;
+
+	soc->ops->ctrl_ops->txrx_set_peer_protocol_drop_mask(soc, vdev_id,
+							 drop_mask);
+}
+
+/**
+ * cdp_is_vdev_peer_protocol_count_enabled() - whether peer-protocol tracking
+ *                                             enabled
+ *
+ * @soc - pointer to the soc
+ * @vdev - the data virtual device object
+ *
+ * Get whether peer protocol count feature enabled or not
+ *
+ * Return: whether feature enabled or not
+ */
+static inline
+int cdp_is_vdev_peer_protocol_count_enabled(ol_txrx_soc_handle soc,
+					    int8_t vdev_id)
+{
+	if (!soc || !soc->ops) {
+		QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG,
+			  "%s: Invalid Instance:", __func__);
+		QDF_BUG(0);
+		return 0;
+	}
+
+	if (!soc->ops->ctrl_ops ||
+	    !soc->ops->ctrl_ops->txrx_is_peer_protocol_count_enabled)
+		return 0;
+
+	return soc->ops->ctrl_ops->txrx_is_peer_protocol_count_enabled(soc,
+								   vdev_id);
+}
+
+/**
+ * cdp_get_peer_protocol_drop_mask() - get per-peer protocol count drop-mask
+ *
+ * @soc - pointer to the soc
+ * @vdev - the data virtual device object
+ *
+ * Get peer-protocol-count drop-mask
+ *
+ * Return: peer-protocol-count drop-mask
+ */
+static inline
+int cdp_get_peer_protocol_drop_mask(ol_txrx_soc_handle soc, int8_t vdev_id)
+{
+	if (!soc || !soc->ops) {
+		QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG,
+			  "%s: Invalid Instance:", __func__);
+		QDF_BUG(0);
+		return 0;
+	}
+
+	if (!soc->ops->ctrl_ops ||
+	    !soc->ops->ctrl_ops->txrx_get_peer_protocol_drop_mask)
+		return 0;
+
+	return soc->ops->ctrl_ops->txrx_get_peer_protocol_drop_mask(soc,
+								    vdev_id);
+}
+
+/*
+ * Rx-Ingress and Tx-Egress are in the lower level DP layer
+ * Rx-Egress and Tx-ingress are handled in osif layer for DP
+ * So
+ * Rx-Ingress and Tx-Egress definitions are in DP layer
+ * Rx-Egress and Tx-ingress mask definitions are here below
+ */
+#define VDEV_PEER_PROTOCOL_RX_INGRESS_MASK 1
+#define VDEV_PEER_PROTOCOL_TX_INGRESS_MASK 2
+#define VDEV_PEER_PROTOCOL_RX_EGRESS_MASK 4
+#define VDEV_PEER_PROTOCOL_TX_EGRESS_MASK 8
+
+#else
+#define cdp_set_vdev_peer_protocol_count(soc, vdev_id, enable)
+#define cdp_set_vdev_peer_protocol_drop_mask(soc, vdev_id, drop_mask)
+#define cdp_is_vdev_peer_protocol_count_enabled(soc, vdev_id) 0
+#define cdp_get_peer_protocol_drop_mask(soc, vdev_id) 0
+#endif
+
 /**
  * cdp_txrx_set_pdev_param() - set pdev parameter
  * @soc: opaque soc handle
@@ -425,6 +563,42 @@ static inline QDF_STATUS cdp_txrx_get_pdev_param(ol_txrx_soc_handle soc,
 			(soc, pdev_id, type, value);
 }
 
+/**
+ * cdp_txrx_peer_protocol_cnt() - set peer protocol count
+ * @soc: opaque soc handle
+ * @vdev: opaque vdev handle
+ * @nbuf: data packet
+ * @is_egress: whether egress or ingress
+ * @is_rx: whether tx or rx
+ *
+ * Return: void
+ */
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+static inline void
+cdp_txrx_peer_protocol_cnt(ol_txrx_soc_handle soc,
+			   int8_t vdev_id,
+			   qdf_nbuf_t nbuf,
+			   enum vdev_peer_protocol_enter_exit is_egress,
+			   enum vdev_peer_protocol_tx_rx is_rx)
+{
+	if (!soc || !soc->ops) {
+		QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG,
+			  "%s: Invalid Instance:", __func__);
+		QDF_BUG(0);
+		return;
+	}
+
+	if (!soc->ops->ctrl_ops ||
+	    !soc->ops->ctrl_ops->txrx_peer_protocol_cnt)
+		return;
+
+	soc->ops->ctrl_ops->txrx_peer_protocol_cnt(soc, vdev_id, nbuf,
+						   is_egress, is_rx);
+}
+#else
+#define cdp_txrx_peer_protocol_cnt(soc, vdev_id, nbuf, is_egress, is_rx)
+#endif
+
 /**
  * cdp_enable_peer_based_pktlog()- Set flag in peer structure
  *

+ 46 - 1
dp/inc/cdp_txrx_ops.h

@@ -57,6 +57,31 @@ enum cdp_nac_param_cmd {
 	/* IEEE80211_NAC_PARAM_LIST */
 	CDP_NAC_PARAM_LIST,
 };
+
+/**
+ * enum vdev_peer_protocol_enter_exit - whether ingress or egress
+ * @CDP_VDEV_PEER_PROTOCOL_IS_INGRESS: ingress
+ * @CDP_VDEV_PEER_PROTOCOL_IS_EGRESS: egress
+ *
+ * whether ingress or egress
+ */
+enum vdev_peer_protocol_enter_exit {
+	CDP_VDEV_PEER_PROTOCOL_IS_INGRESS,
+	CDP_VDEV_PEER_PROTOCOL_IS_EGRESS
+};
+
+/**
+ * enum vdev_peer_protocol_tx_rx - whether tx or rx
+ * @CDP_VDEV_PEER_PROTOCOL_IS_TX: tx
+ * @CDP_VDEV_PEER_PROTOCOL_IS_RX: rx
+ *
+ * whether tx or rx
+ */
+enum vdev_peer_protocol_tx_rx {
+	CDP_VDEV_PEER_PROTOCOL_IS_TX,
+	CDP_VDEV_PEER_PROTOCOL_IS_RX
+};
+
 /******************************************************************************
  *
  * Control Interface (A Interface)
@@ -617,7 +642,13 @@ struct cdp_ctrl_ops {
 					  cdp_config_param_type *val);
 
 	void * (*txrx_get_pldev)(struct cdp_soc_t *soc, uint8_t pdev_id);
-
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+	void (*txrx_peer_protocol_cnt)(struct cdp_soc_t *soc,
+				       int8_t vdev_id,
+				       qdf_nbuf_t nbuf,
+				       bool is_egress,
+				       bool is_rx);
+#endif
 #ifdef ATH_SUPPORT_NAC_RSSI
 	QDF_STATUS (*txrx_vdev_config_for_nac_rssi)(struct cdp_soc_t *cdp_soc,
 						    uint8_t vdev_id,
@@ -684,6 +715,20 @@ struct cdp_ctrl_ops {
 	QDF_STATUS (*txrx_get_psoc_param)(ol_txrx_soc_handle soc,
 					  enum cdp_psoc_param_type type,
 					  cdp_config_param_type *val);
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+	/*
+	 * Enable per-peer protocol counters
+	 */
+	void (*txrx_enable_peer_protocol_count)(struct cdp_soc_t *soc,
+						int8_t vdev_id, bool enable);
+	void (*txrx_set_peer_protocol_drop_mask)(struct cdp_soc_t *soc,
+						 int8_t vdev_id, int mask);
+	int (*txrx_is_peer_protocol_count_enabled)(struct cdp_soc_t *soc,
+						   int8_t vdev_id);
+	int (*txrx_get_peer_protocol_drop_mask)(struct cdp_soc_t *soc,
+						int8_t vdev_id);
+
+#endif
 };
 
 struct cdp_me_ops {

+ 34 - 0
dp/inc/cdp_txrx_stats_struct.h

@@ -667,6 +667,32 @@ typedef union cdp_peer_stats_buf {
 	uint32_t rx_avg_rssi;
 } cdp_peer_stats_param_t; /* Max union size 16 bytes */
 
+/**
+ * enum cdp_protocol_trace -  Protocols supported by per-peer protocol trace
+ * @CDP_TRACE_ICMP: ICMP packets
+ * @CDP_TRACE_EAP: EAPOL packets
+ * @CDP_TRACE_ARP: ARP packets
+ *
+ * Enumeration of all protocols supported by per-peer protocol trace feature
+ */
+enum cdp_protocol_trace {
+	CDP_TRACE_ICMP,
+	CDP_TRACE_EAP,
+	CDP_TRACE_ARP,
+	CDP_TRACE_MAX
+};
+
+/**
+ * struct protocol_trace_count - type of count on per-peer protocol trace
+ * @egress_cnt: how many packets go out of host driver
+ * @ingress_cnt: how many packets come into the host driver
+ *
+ * Type of count on per-peer protocol trace
+ */
+struct protocol_trace_count {
+	uint16_t egress_cnt;
+	uint16_t ingress_cnt;
+};
 /* struct cdp_tx_stats - tx stats
  * @cdp_pkt_info comp_pkt: Pkt Info for which completions were received
  * @cdp_pkt_info ucast: Unicast Packet Count
@@ -675,6 +701,7 @@ typedef union cdp_peer_stats_buf {
  * @cdp_pkt_info nawds_mcast: NAWDS  Multicast Packet Count
  * @cdp_pkt_info tx_success: Successful Tx Packets
  * @nawds_mcast_drop: NAWDS  Multicast Drop Count
+ * @protocol_trace_cnt: per-peer protocol counter
  * @tx_failed: Total Tx failure
  * @ofdma: Total Packets as ofdma
  * @stbc: Packets in STBC
@@ -749,6 +776,9 @@ struct cdp_tx_stats {
 	struct cdp_pkt_info mcast;
 	struct cdp_pkt_info bcast;
 	struct cdp_pkt_info nawds_mcast;
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+	struct protocol_trace_count protocol_trace_cnt[CDP_TRACE_MAX];
+#endif
 	struct cdp_pkt_info tx_success;
 	uint32_t nawds_mcast_drop;
 	uint32_t tx_failed;
@@ -842,6 +872,7 @@ struct cdp_tx_stats {
  * @pkts: Intra BSS packets received
  * @fail: Intra BSS packets failed
  * @mdns_no_fwd: Intra BSS MDNS packets not forwarded
+ * @protocol_trace_cnt: per-peer protocol counters
  * @mic_err: Rx MIC errors CCMP
  * @decrypt_err: Rx Decryption Errors CRC
  * @fcserr: rx MIC check failed (CCMP)
@@ -905,6 +936,9 @@ struct cdp_rx_stats {
 		struct cdp_pkt_info fail;
 		uint32_t mdns_no_fwd;
 	} intra_bss;
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+	struct protocol_trace_count protocol_trace_cnt[CDP_TRACE_MAX];
+#endif
 
 	struct {
 		uint32_t mic_err;

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

@@ -1599,6 +1599,48 @@ static inline QDF_STATUS dp_peer_stats_notify(struct dp_pdev *pdev,
 }
 
 #endif /* CONFIG_WIN */
+
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+/**
+ * dp_vdev_peer_stats_update_protocol_cnt() - update per-peer protocol counters
+ * @vdev: VDEV DP object
+ * @nbuf: data packet
+ * @peer: Peer DP object
+ * @is_egress: whether egress or ingress
+ * @is_rx: whether rx or tx
+ *
+ * This function updates the per-peer protocol counters
+ * Return: void
+ */
+void dp_vdev_peer_stats_update_protocol_cnt(struct dp_vdev *vdev,
+					    qdf_nbuf_t nbuf,
+					    struct dp_peer *peer,
+					    bool is_egress,
+					    bool is_rx);
+
+/**
+ * dp_vdev_peer_stats_update_protocol_cnt() - update per-peer protocol counters
+ * @soc: SOC DP object
+ * @vdev_id: vdev_id
+ * @nbuf: data packet
+ * @is_egress: whether egress or ingress
+ * @is_rx: whether rx or tx
+ *
+ * This function updates the per-peer protocol counters
+ * Return: void
+ */
+
+void dp_peer_stats_update_protocol_cnt(struct cdp_soc_t *soc,
+				       int8_t vdev_id,
+				       qdf_nbuf_t nbuf,
+				       bool is_egress,
+				       bool is_rx);
+
+#else
+#define dp_vdev_peer_stats_update_protocol_cnt(vdev, nbuf, peer, \
+					       is_egress, is_rx)
+#endif
+
 #ifdef QCA_LL_TX_FLOW_CONTROL_V2
 void dp_tx_dump_flow_pool_info(struct cdp_soc_t *soc_hdl);
 int dp_tx_delete_flow_pool(struct dp_soc *soc, struct dp_tx_desc_pool_s *pool,

+ 62 - 0
dp/wifi3.0/dp_main.c

@@ -6967,6 +6967,57 @@ void dp_peer_set_mesh_rx_filter(struct cdp_vdev *vdev_hdl, uint32_t val)
 }
 #endif
 
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+static void dp_enable_vdev_peer_protocol_count(struct cdp_soc_t *soc,
+					       int8_t vdev_id,
+					       bool enable)
+{
+	struct dp_vdev *vdev;
+
+	vdev = dp_get_vdev_from_soc_vdev_id_wifi3((struct dp_soc *)soc,
+						  vdev_id);
+	dp_info("enable %d vdev_id %d", enable, vdev_id);
+	vdev->peer_protocol_count_track = enable;
+}
+
+static void dp_enable_vdev_peer_protocol_drop_mask(struct cdp_soc_t *soc,
+						   int8_t vdev_id,
+						   int drop_mask)
+{
+	struct dp_vdev *vdev;
+
+	vdev = dp_get_vdev_from_soc_vdev_id_wifi3((struct dp_soc *)soc,
+						  vdev_id);
+	dp_info("drop_mask %d vdev_id %d", drop_mask, vdev_id);
+	vdev->peer_protocol_count_dropmask = drop_mask;
+}
+
+static int dp_is_vdev_peer_protocol_count_enabled(struct cdp_soc_t *soc,
+						  int8_t vdev_id)
+{
+	struct dp_vdev *vdev;
+
+	vdev = dp_get_vdev_from_soc_vdev_id_wifi3((struct dp_soc *)soc,
+						  vdev_id);
+	dp_info("enable %d vdev_id %d", vdev->peer_protocol_count_track,
+		vdev_id);
+	return vdev->peer_protocol_count_track;
+}
+
+static int dp_get_vdev_peer_protocol_drop_mask(struct cdp_soc_t *soc,
+					       int8_t vdev_id)
+{
+	struct dp_vdev *vdev;
+
+	vdev = dp_get_vdev_from_soc_vdev_id_wifi3((struct dp_soc *)soc,
+						  vdev_id);
+	dp_info("drop_mask %d vdev_id %d", vdev->peer_protocol_count_dropmask,
+		vdev_id);
+	return vdev->peer_protocol_count_dropmask;
+}
+
+#endif
+
 bool dp_check_pdev_exists(struct dp_soc *soc, struct dp_pdev *data)
 {
 	uint8_t pdev_count;
@@ -9902,6 +9953,14 @@ static struct cdp_cmn_ops dp_ops_cmn = {
 
 static struct cdp_ctrl_ops dp_ops_ctrl = {
 	.txrx_peer_authorize = dp_peer_authorize,
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+	.txrx_enable_peer_protocol_count = dp_enable_vdev_peer_protocol_count,
+	.txrx_set_peer_protocol_drop_mask =
+		dp_enable_vdev_peer_protocol_drop_mask,
+	.txrx_is_peer_protocol_count_enabled =
+		dp_is_vdev_peer_protocol_count_enabled,
+	.txrx_get_peer_protocol_drop_mask = dp_get_vdev_peer_protocol_drop_mask,
+#endif
 	.txrx_set_vdev_param = dp_set_vdev_param,
 	.txrx_set_psoc_param = dp_set_psoc_param,
 	.txrx_get_psoc_param = dp_get_psoc_param,
@@ -9921,6 +9980,9 @@ static struct cdp_ctrl_ops dp_ops_ctrl = {
 	.txrx_get_pdev_param = dp_get_pdev_param,
 	.txrx_set_peer_param = dp_set_peer_param,
 	.txrx_get_peer_param = dp_get_peer_param,
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+	.txrx_peer_protocol_cnt = dp_peer_stats_update_protocol_cnt,
+#endif
 #ifdef ATH_SUPPORT_NAC_RSSI
 	.txrx_vdev_config_for_nac_rssi = dp_config_for_nac_rssi,
 	.txrx_vdev_get_neighbour_rssi = dp_vdev_get_neighbour_rssi,

+ 25 - 0
dp/wifi3.0/dp_rx.c

@@ -1379,6 +1379,30 @@ static inline void dp_rx_cksum_offload(struct dp_pdev *pdev,
 	}
 }
 
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+#define dp_rx_msdu_stats_update_prot_cnts(vdev_hdl, nbuf, peer) \
+{ \
+	qdf_nbuf_t nbuf_local; \
+	struct dp_peer *peer_local; \
+	struct dp_vdev *vdev_local = vdev_hdl; \
+	do { \
+		if (qdf_likely(!((vdev_local)->peer_protocol_count_track))) \
+			break; \
+		nbuf_local = nbuf; \
+		peer_local = peer; \
+		if (qdf_unlikely(qdf_nbuf_is_frag((nbuf_local)))) \
+			break; \
+		else if (qdf_unlikely(qdf_nbuf_is_raw_frame((nbuf_local)))) \
+			break; \
+		dp_vdev_peer_stats_update_protocol_cnt((vdev_local), \
+						       (nbuf_local), \
+						       (peer_local), 0, 1); \
+	} while (0); \
+}
+#else
+#define dp_rx_msdu_stats_update_prot_cnts(vdev_hdl, nbuf, peer)
+#endif
+
 /**
  * dp_rx_msdu_stats_update() - update per msdu stats.
  * @soc: core txrx main context
@@ -1404,6 +1428,7 @@ static void dp_rx_msdu_stats_update(struct dp_soc *soc,
 	qdf_ether_header_t *eh;
 	uint16_t msdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf);
 
+	dp_rx_msdu_stats_update_prot_cnts(vdev, nbuf, peer);
 	is_not_amsdu = qdf_nbuf_is_rx_chfrag_start(nbuf) &
 			qdf_nbuf_is_rx_chfrag_end(nbuf);
 

+ 2 - 0
dp/wifi3.0/dp_rx_err.c

@@ -821,6 +821,8 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, qdf_nbuf_t nbuf,
 	else
 		qdf_nbuf_pull_head(nbuf, (l2_hdr_offset + RX_PKT_TLVS_LEN));
 
+	dp_vdev_peer_stats_update_protocol_cnt(vdev, nbuf, NULL, 0, 1);
+
 	if (dp_rx_mcast_echo_check(soc, peer, rx_tlv_hdr, nbuf)) {
 		/* this is a looped back MCBC pkt, drop it */
 		DP_STATS_INC_PKT(peer, rx.mec_drop, 1, qdf_nbuf_len(nbuf));

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

@@ -4041,6 +4041,118 @@ void dp_htt_stats_copy_tag(struct dp_pdev *pdev, uint8_t tag_type, uint32_t *tag
 		qdf_mem_copy(dest_ptr, tag_buf, size);
 }
 
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+#ifdef VDEV_PEER_PROTOCOL_COUNT_TESTING
+static QDF_STATUS dp_peer_stats_update_protocol_test_cnt(struct dp_vdev *vdev,
+							 bool is_egress,
+							 bool is_rx)
+{
+	int mask;
+
+	if (is_egress)
+		if (is_rx)
+			mask = VDEV_PEER_PROTOCOL_RX_EGRESS_MASK;
+		else
+			mask = VDEV_PEER_PROTOCOL_TX_EGRESS_MASK;
+	else
+		if (is_rx)
+			mask = VDEV_PEER_PROTOCOL_RX_INGRESS_MASK;
+		else
+			mask = VDEV_PEER_PROTOCOL_TX_INGRESS_MASK;
+
+	if (qdf_unlikely(vdev->peer_protocol_count_dropmask & mask)) {
+		dp_info("drop mask set %x", vdev->peer_protocol_count_dropmask);
+		return QDF_STATUS_SUCCESS;
+	}
+	return QDF_STATUS_E_FAILURE;
+}
+
+#else
+static QDF_STATUS dp_peer_stats_update_protocol_test_cnt(struct dp_vdev *vdev,
+							 bool is_egress,
+							 bool is_rx)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+#endif
+
+void dp_vdev_peer_stats_update_protocol_cnt(struct dp_vdev *vdev,
+					    qdf_nbuf_t nbuf,
+					    struct dp_peer *peer,
+					    bool is_egress,
+					    bool is_rx)
+{
+	struct cdp_peer_stats *peer_stats;
+	struct protocol_trace_count *protocol_trace_cnt;
+	enum cdp_protocol_trace prot;
+	struct dp_soc *soc;
+	struct ether_header *eh;
+	char *mac;
+	bool new_peer_ref = false;
+
+	if (qdf_likely(!vdev->peer_protocol_count_track))
+		return;
+	if (qdf_unlikely(dp_peer_stats_update_protocol_test_cnt(vdev,
+								is_egress,
+								is_rx) ==
+					       QDF_STATUS_SUCCESS))
+		return;
+
+	soc = vdev->pdev->soc;
+	eh = (struct ether_header *)qdf_nbuf_data(nbuf);
+	if (is_rx)
+		mac = eh->ether_shost;
+	else
+		mac = eh->ether_dhost;
+
+	if (!peer) {
+		peer = dp_peer_find_hash_find(soc, mac, 0, vdev->vdev_id);
+		new_peer_ref = true;
+		if (!peer)
+			return;
+	}
+	peer_stats = &peer->stats;
+
+	if (qdf_nbuf_is_icmp_pkt(nbuf) == true)
+		prot = CDP_TRACE_ICMP;
+	else if (qdf_nbuf_is_ipv4_arp_pkt(nbuf) == true)
+		prot = CDP_TRACE_ARP;
+	else if (qdf_nbuf_is_ipv4_eapol_pkt(nbuf) == true)
+		prot = CDP_TRACE_EAP;
+	else
+		goto dp_vdev_peer_stats_update_protocol_cnt_free_peer;
+
+	if (is_rx)
+		protocol_trace_cnt = peer_stats->rx.protocol_trace_cnt;
+	else
+		protocol_trace_cnt = peer_stats->tx.protocol_trace_cnt;
+
+	if (is_egress)
+		protocol_trace_cnt[prot].egress_cnt++;
+	else
+		protocol_trace_cnt[prot].ingress_cnt++;
+dp_vdev_peer_stats_update_protocol_cnt_free_peer:
+	if (new_peer_ref)
+		dp_peer_unref_delete(peer);
+}
+
+void dp_peer_stats_update_protocol_cnt(struct cdp_soc_t *soc,
+				       int8_t vdev_id,
+				       qdf_nbuf_t nbuf,
+				       bool is_egress,
+				       bool is_rx)
+{
+	struct dp_vdev *vdev;
+
+	vdev = dp_get_vdev_from_soc_vdev_id_wifi3((struct dp_soc *)soc,
+						  vdev_id);
+	if (qdf_likely(!vdev->peer_protocol_count_track))
+		return;
+	dp_vdev_peer_stats_update_protocol_cnt(vdev, nbuf, NULL, is_egress,
+					       is_rx);
+}
+#endif
+
 QDF_STATUS dp_peer_stats_notify(struct dp_pdev *dp_pdev, struct dp_peer *peer)
 {
 	struct cdp_interface_peer_stats peer_stats_intf;

+ 26 - 0
dp/wifi3.0/dp_tx.c

@@ -1070,6 +1070,31 @@ static void dp_tx_raw_prepare_unset(struct dp_soc *soc,
 	} while (cur_nbuf);
 }
 
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+#define dp_vdev_peer_stats_update_protocol_cnt_tx(vdev_hdl, nbuf) \
+{ \
+	qdf_nbuf_t nbuf_local; \
+	struct dp_vdev *vdev_local = vdev_hdl; \
+	do { \
+		if (qdf_likely(!((vdev_local)->peer_protocol_count_track))) \
+			break; \
+		nbuf_local = nbuf; \
+		if (qdf_unlikely(((vdev_local)->tx_encap_type) == \
+			 htt_cmn_pkt_type_raw)) \
+			break; \
+		else if (qdf_unlikely(qdf_nbuf_is_nonlinear((nbuf_local)))) \
+			break; \
+		else if (qdf_nbuf_is_tso((nbuf_local))) \
+			break; \
+		dp_vdev_peer_stats_update_protocol_cnt((vdev_local), \
+						       (nbuf_local), \
+						       NULL, 1, 0); \
+	} while (0); \
+}
+#else
+#define dp_vdev_peer_stats_update_protocol_cnt_tx(vdev_hdl, skb)
+#endif
+
 /**
  * dp_tx_hw_enqueue() - Enqueue to TCL HW for transmit
  * @soc: DP Soc Handle
@@ -1181,6 +1206,7 @@ static QDF_STATUS dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev,
 	}
 
 	tx_desc->flags |= DP_TX_DESC_FLAG_QUEUED_TX;
+	dp_vdev_peer_stats_update_protocol_cnt_tx(vdev, tx_desc->nbuf);
 
 	hal_tx_desc_sync(hal_tx_desc_cached, hal_tx_desc);
 	DP_STATS_INC_PKT(vdev, tx_i.processed, 1, length);

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

@@ -1970,6 +1970,21 @@ struct dp_vdev {
 #endif
 	/* Extended data path handle */
 	struct cdp_ext_vdev *vdev_dp_ext_handle;
+#ifdef VDEV_PEER_PROTOCOL_COUNT
+	/*
+	 * Rx-Ingress and Tx-Egress are in the lower level DP layer
+	 * Rx-Egress and Tx-ingress are handled in osif layer for DP
+	 * So
+	 * Rx-Egress and Tx-ingress mask definitions are in OSIF layer
+	 * Rx-Ingress and Tx-Egress definitions are here below
+	 */
+#define VDEV_PEER_PROTOCOL_RX_INGRESS_MASK 1
+#define VDEV_PEER_PROTOCOL_TX_INGRESS_MASK 2
+#define VDEV_PEER_PROTOCOL_RX_EGRESS_MASK 4
+#define VDEV_PEER_PROTOCOL_TX_EGRESS_MASK 8
+	bool peer_protocol_count_track;
+	int peer_protocol_count_dropmask;
+#endif
 };