From 956a272de63953be28f48703f3e656bc60c86e7f Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Fri, 28 Apr 2023 10:39:58 +0800
Subject: [PATCH 3006/3010] wifi: mt76: mt7996: add debugfs knob for
 rx_counters

Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
---
 agg-rx.c               |  8 ++++++++
 mac80211.c             | 16 ++++++++++++++--
 mt76.h                 | 15 +++++++++++++++
 mt7996/mac.c           | 18 +++++++++++++++---
 mt7996/mtk_debugfs_i.c | 43 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/agg-rx.c b/agg-rx.c
index 0a089e6..1f4e599 100644
--- a/agg-rx.c
+++ b/agg-rx.c
@@ -34,10 +34,13 @@ mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid,
 			    struct sk_buff_head *frames,
 			    u16 head)
 {
+	struct mt76_phy *phy = mt76_dev_phy(tid->dev, tid->band_idx);
 	int idx;
 
 	while (ieee80211_sn_less(tid->head, head)) {
 		idx = tid->head % tid->size;
+		if (!tid->reorder_buf[idx])
+			phy->rx_stats.rx_agg_miss++;
 		mt76_aggr_release(tid, frames, idx);
 	}
 }
@@ -152,6 +155,7 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
 	struct mt76_wcid *wcid = status->wcid;
 	struct ieee80211_sta *sta;
 	struct mt76_rx_tid *tid;
+	struct mt76_phy *phy;
 	bool sn_less;
 	u16 seqno, head, size, idx;
 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
@@ -187,6 +191,7 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
 	head = tid->head;
 	seqno = status->seqno;
 	size = tid->size;
+	phy = mt76_dev_phy(tid->dev, tid->band_idx);
 	sn_less = ieee80211_sn_less(seqno, head);
 	trace_mt76_rx_aggr_reorder(tid->dev, wcid, head, seqno, sn_less);
 
@@ -199,6 +204,7 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
 
 	if (sn_less) {
 		__skb_unlink(skb, frames);
+		phy->rx_stats.rx_dup_drop++;
 		dev_kfree_skb(skb);
 		goto out;
 	}
@@ -225,6 +231,7 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
 
 	/* Discard if the current slot is already in use */
 	if (tid->reorder_buf[idx]) {
+		phy->rx_stats.rx_dup_drop++;
 		dev_kfree_skb(skb);
 		goto out;
 	}
@@ -256,6 +263,7 @@ int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno,
 	tid->head = ssn;
 	tid->size = size;
 	tid->num = tidno;
+	tid->band_idx = wcid->phy_idx;
 	INIT_DELAYED_WORK(&tid->reorder_work, mt76_rx_aggr_reorder_work);
 	spin_lock_init(&tid->lock);
 
diff --git a/mac80211.c b/mac80211.c
index 5de6471..585526d 100644
--- a/mac80211.c
+++ b/mac80211.c
@@ -725,6 +725,7 @@ static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
 		}
 
 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
+			phy->rx_stats.rx_drop++;
 			dev_kfree_skb(skb);
 			return;
 		}
@@ -1044,10 +1045,16 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
 
 	*sta = wcid_to_sta(mstat.wcid);
 	*hw = mt76_phy_hw(dev, mstat.phy_idx);
+
+	if ((mstat.flag & RX_FLAG_8023) || ieee80211_is_data_qos(hdr->frame_control)) {
+		struct mt76_phy *phy = mt76_dev_phy(dev, mstat.phy_idx);
+
+		phy->rx_stats.rx_mac80211++;
+	}
 }
 
 static void
-mt76_check_ccmp_pn(struct sk_buff *skb)
+mt76_check_ccmp_pn(struct mt76_dev *dev, struct sk_buff *skb)
 {
 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
 	struct mt76_wcid *wcid = status->wcid;
@@ -1094,7 +1101,11 @@ skip_hdr_check:
 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
 		     sizeof(status->iv));
 	if (ret <= 0) {
+		struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
+
+		phy->rx_stats.rx_pn_iv_error++;
 		status->flag |= RX_FLAG_ONLY_MONITOR;
+
 		return;
 	}
 
@@ -1275,7 +1286,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
 	while ((skb = __skb_dequeue(frames)) != NULL) {
 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
 
-		mt76_check_ccmp_pn(skb);
+		mt76_check_ccmp_pn(dev, skb);
 		skb_shinfo(skb)->frag_list = NULL;
 		trace_mt76_rx_complete(dev, (struct mt76_rx_status *)skb->cb, 0);
 		mt76_rx_convert(dev, skb, &hw, &sta);
@@ -1300,6 +1311,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
 	}
 
 	list_for_each_entry_safe(skb, tmp, &list, list) {
+		dev->rx_kernel++;
 		skb_list_del_init(skb);
 		napi_gro_receive(napi, skb);
 	}
diff --git a/mt76.h b/mt76.h
index 2aa152b..b377b4b 100644
--- a/mt76.h
+++ b/mt76.h
@@ -458,6 +458,7 @@ struct mt76_rx_tid {
 	struct rcu_head rcu_head;
 
 	struct mt76_dev *dev;
+	u8 band_idx;
 
 	spinlock_t lock;
 	struct delayed_work reorder_work;
@@ -889,6 +890,19 @@ struct mt76_phy {
 		bool al;
 		u8 pin;
 	} leds;
+
+	struct {
+		u32 rx_mac80211;
+
+		u32 rx_drop;
+		u32 rx_rxd_drop;
+		u32 rx_dup_drop;
+		u32 rx_agg_miss;
+		u32 rx_icv_error;
+		u32 rx_fcs_error;
+		u32 rx_tkip_mic_error;
+		u32 rx_pn_iv_error;
+	} rx_stats;
 };
 
 struct mt76_dev {
@@ -990,6 +1004,7 @@ struct mt76_dev {
 	};
 
 	const char *bin_file_name;
+	u32 rx_kernel;
 };
 
 struct mt76_power_limits {
diff --git a/mt7996/mac.c b/mt7996/mac.c
index 14f4fdd..ed6208c 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -700,8 +700,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
 		return -EINVAL;
 
 	/* ICV error or CCMP/BIP/WPI MIC error */
-	if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)
+	if (rxd1 & MT_RXD1_NORMAL_ICV_ERR) {
+		mphy->rx_stats.rx_icv_error++;
 		status->flag |= RX_FLAG_ONLY_MONITOR;
+	}
 
 	unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
 	idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
@@ -731,11 +733,15 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
 	    !(csum_status & (BIT(0) | BIT(2) | BIT(3))))
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-	if (rxd1 & MT_RXD3_NORMAL_FCS_ERR)
+	if (rxd1 & MT_RXD3_NORMAL_FCS_ERR) {
+		mphy->rx_stats.rx_fcs_error++;
 		status->flag |= RX_FLAG_FAILED_FCS_CRC;
+	}
 
-	if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
+	if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) {
+		mphy->rx_stats.rx_tkip_mic_error++;
 		status->flag |= RX_FLAG_MMIC_ERROR;
+	}
 
 	if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
 	    !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {
@@ -1793,8 +1799,10 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
 			 struct sk_buff *skb, u32 *info)
 {
 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+	struct mt76_phy *phy;
 	__le32 *rxd = (__le32 *)skb->data;
 	__le32 *end = (__le32 *)&skb->data[skb->len];
+	u8 band_idx;
 	enum rx_pkt_type type;
 
 	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
@@ -1834,6 +1842,10 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
 		}
 		fallthrough;
 	default:
+		band_idx = le32_get_bits(rxd[1], MT_RXD1_NORMAL_BAND_IDX);
+		phy = mt76_dev_phy(mdev, band_idx);
+		if (likely(phy))
+			phy->rx_stats.rx_rxd_drop++;
 		dev_kfree_skb(skb);
 		break;
 	}
diff --git a/mt7996/mtk_debugfs_i.c b/mt7996/mtk_debugfs_i.c
index 5a29112..a51edb6 100644
--- a/mt7996/mtk_debugfs_i.c
+++ b/mt7996/mtk_debugfs_i.c
@@ -1737,6 +1737,46 @@ static const struct file_operations fops_muru_fixed_group_rate = {
 	.llseek = default_llseek,
 };
 
+static int mt7996_rx_counters(struct seq_file *s, void *data)
+{
+	struct mt7996_dev *dev = dev_get_drvdata(s->private);
+	u32 rx_mac80211 = 0;
+	int i = 0;
+
+	for (i = 0; i < __MT_MAX_BAND; i++) {
+		struct mt76_phy *phy = mt76_dev_phy(&dev->mt76, i);
+
+		if (!phy)
+			continue;
+
+		seq_printf(s, "\n==========PHY%d==========\n", i);
+
+#define SEQ_PRINT(_str, _rx_param) do {					\
+		seq_printf(s, _str"\n", phy->rx_stats._rx_param);	\
+	} while (0)
+
+		SEQ_PRINT("Rx to mac80211: %u", rx_mac80211);
+		SEQ_PRINT("Rx drop: %u", rx_drop);
+		SEQ_PRINT("Rx drop due to RXD type error: %u", rx_rxd_drop);
+		SEQ_PRINT("Rx duplicated drop: %u", rx_dup_drop);
+		SEQ_PRINT("Rx agg miss: %u", rx_agg_miss);
+		SEQ_PRINT("Rx ICV error: %u", rx_icv_error);
+		SEQ_PRINT("Rx FCS error: %u", rx_fcs_error);
+		SEQ_PRINT("Rx TKIP MIC error: %u", rx_tkip_mic_error);
+		SEQ_PRINT("Rx PN/IV error: %u", rx_pn_iv_error);
+#undef SEQ_PRINT
+
+		rx_mac80211 += phy->rx_stats.rx_mac80211;
+	}
+
+	seq_printf(s, "\n==========SUM==========\n");
+	seq_printf(s, "Rx to kernel: %u\n", dev->mt76.rx_kernel);
+	seq_printf(s, "Rx to mac80211: %u\n", rx_mac80211);
+
+
+	return 0;
+}
+
 int mt7996_mtk_init_debugfs_internal(struct mt7996_phy *phy, struct dentry *dir)
 {
 	struct mt7996_dev *dev = phy->dev;
@@ -1781,6 +1821,9 @@ int mt7996_mtk_init_debugfs_internal(struct mt7996_phy *phy, struct dentry *dir)
 			    &fops_muru_fixed_group_rate);
 	debugfs_create_file("bf_txsnd_info", 0600, dir, phy, &fops_bf_txsnd_info);
 
+	debugfs_create_devm_seqfile(dev->mt76.dev, "rx_counters", dir,
+				    mt7996_rx_counters);
+
 	return 0;
 }
 
-- 
2.18.0

