blob: ac5bfb1b00cda9e259bee5122c79c385f5c4ee1c [file] [log] [blame]
From 999021989ad387b46c8ff4ffed43cc0017322c5e Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Wed, 11 Jan 2023 10:56:27 +0800
Subject: [PATCH 2006/2011] wifi: mt76: add debugfs knob to show packet error
rate
Get tx count and tx failed from mcu command
---
mt76.h | 2 +
mt76_connac_mcu.h | 1 +
mt7915/mcu.c | 108 +++++++++++++++++++++++++++++++++++++++++++
mt7915/mcu.h | 21 ++++++++-
mt7915/mt7915.h | 1 +
mt7915/mtk_debugfs.c | 62 +++++++++++++++++++++++++
6 files changed, 194 insertions(+), 1 deletion(-)
diff --git a/mt76.h b/mt76.h
index 968bf08..3032cdd 100644
--- a/mt76.h
+++ b/mt76.h
@@ -297,8 +297,10 @@ struct mt76_sta_stats {
u64 tx_bytes;
/* WED TX */
u32 tx_packets; /* unit: MSDU */
+ u32 tx_mpdu_cnt;
u32 tx_retries;
u32 tx_failed;
+ u32 tx_failed_wm;
/* WED RX */
u64 rx_bytes;
u32 rx_packets;
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
index 9ad1883..2d6e610 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -1173,6 +1173,7 @@ enum {
MCU_EXT_CMD_EDCA_UPDATE = 0x27,
MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A,
MCU_EXT_CMD_THERMAL_CTRL = 0x2c,
+ MCU_EXT_CMD_GET_TX_STAT = 0x30,
MCU_EXT_CMD_WTBL_UPDATE = 0x32,
MCU_EXT_CMD_SET_DRR_CTRL = 0x36,
MCU_EXT_CMD_SET_FEATURE_CTRL = 0x38,
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
index b2b5c76..d4b0617 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -4233,6 +4233,114 @@ int mt7915_mcu_get_tx_rate(struct mt7915_phy *phy, u16 wcidx)
return mt7915_mcu_get_tx_rate_v2(phy, wcidx);
}
+static int mt7915_mcu_get_tx_stat_v1(struct mt7915_phy *phy,
+ u16 wlan_idx)
+{
+#define to_wcid(hi, lo) (hi << 8 | lo)
+ struct mt7915_dev *dev = phy->dev;
+ struct mt76_phy *mphy = phy->mt76;
+ struct mt7915_mcu_tx_stat_v1 *res;
+ struct mt76_wcid *wcid;
+ struct sk_buff *skb;
+ struct {
+ __le32 category;
+ u8 wlan_idx_lo;
+ u8 band;
+ u8 wlan_idx_hi;
+ u8 __rsv[5];
+ } __packed req = {
+ .category = cpu_to_le32(MCU_GET_TX_STAT_CNT),
+ .band = mphy->band_idx,
+ .wlan_idx_lo = to_wcid_lo(wlan_idx),
+ .wlan_idx_hi = to_wcid_hi(wlan_idx),
+ };
+ int ret;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(GET_TX_STAT),
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ res = (struct mt7915_mcu_tx_stat_v1 *)skb->data;
+
+ if (to_wcid(res->wlan_idx_hi, res->wlan_idx_lo) != wlan_idx) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rcu_read_lock();
+
+ wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
+ if (wcid) {
+ wcid->stats.tx_mpdu_cnt += le32_to_cpu(res->tx_cnt);
+ wcid->stats.tx_failed_wm += le32_to_cpu(res->tx_failed);
+ } else {
+ ret = -EINVAL;
+ }
+
+ rcu_read_unlock();
+out:
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
+static int mt7915_mcu_get_tx_stat_v2(struct mt7915_phy *phy,
+ u16 wlan_idx)
+{
+ struct mt7915_dev *dev = phy->dev;
+ struct mt76_phy *mphy = phy->mt76;
+ struct mt7915_mcu_tx_stat_v2 *res;
+ struct mt76_wcid *wcid;
+ struct sk_buff *skb;
+ struct {
+ u8 category;
+ u8 band;
+ __le16 wcid;
+ } __packed req = {
+ .category = MCU_GET_TX_STAT_CNT,
+ .band = mphy->band_idx,
+ .wcid = cpu_to_le16(wlan_idx),
+ };
+ int ret;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(GET_TX_STAT),
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ res = (struct mt7915_mcu_tx_stat_v2 *)skb->data;
+
+ if (le16_to_cpu(res->wlan_idx) != wlan_idx) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rcu_read_lock();
+
+ wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
+ if (wcid) {
+ wcid->stats.tx_mpdu_cnt += le32_to_cpu(res->tx_cnt);
+ wcid->stats.tx_failed_wm += le32_to_cpu(res->tx_failed);
+ } else {
+ ret = -EINVAL;
+ }
+
+ rcu_read_unlock();
+out:
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
+int mt7915_get_tx_stat(struct mt7915_phy *phy, u16 wlan_idx)
+{
+ if (is_mt7915(&phy->dev->mt76))
+ return mt7915_mcu_get_tx_stat_v1(phy, wlan_idx);
+
+ return mt7915_mcu_get_tx_stat_v2(phy, wlan_idx);
+}
+
int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct cfg80211_he_bss_color *he_bss_color)
{
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
index 825bb7d..12c98c5 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -791,7 +791,8 @@ mt7915_get_power_bound(struct mt7915_phy *phy, s8 txpower)
}
enum {
- MCU_GET_TX_RATE = 4
+ MCU_GET_TX_RATE = 4,
+ MCU_GET_TX_STAT_CNT = 8
};
#ifdef CONFIG_MTK_VENDOR
@@ -1070,6 +1071,24 @@ struct mt7915_muru {
/* DL&UL User config */
#define MURU_USER_CNT BIT(4)
+struct mt7915_mcu_tx_stat_v1 {
+ u8 wlan_idx_lo;
+ u8 band_idx;
+ u8 wlan_idx_hi;
+ u8 __rsv1[29];
+ __le32 tx_cnt;
+ __le32 tx_failed;
+ u8 __rsv2[26];
+};
+
+struct mt7915_mcu_tx_stat_v2 {
+ u8 __rsv1[4];
+ __le16 wlan_idx;
+ u8 __rsv2[2];
+ __le32 tx_cnt;
+ __le32 tx_failed;
+};
+
enum {
CAPI_SU,
CAPI_MU,
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
index c1f3a0a..d47abcf 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
@@ -677,6 +677,7 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,
struct cfg80211_chan_def *chandef);
int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wcid);
+int mt7915_get_tx_stat(struct mt7915_phy *phy, u16 wlan_idx);
int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set);
int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl);
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
index 928bb50..4defc17 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
@@ -3795,6 +3795,66 @@ mt7915_sr_enable_set(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_sr_enable, NULL,
mt7915_sr_enable_set, "%llx\n");
+static int mt7915_reset_counter(void *data, u64 val)
+{
+ struct mt7915_phy *phy = data;
+ struct mt7915_dev *dev = phy->dev;
+ struct mt76_wcid *wcid;
+
+ /* Clear the firmware counters */
+ mt7915_mcu_wed_wa_tx_stats(dev, dev->wlan_idx);
+ mt7915_get_tx_stat(phy, dev->wlan_idx);
+
+ rcu_read_lock();
+ wcid = rcu_dereference(dev->mt76.wcid[dev->wlan_idx]);
+ if (!wcid)
+ return -EINVAL;
+
+ memset(&wcid->stats, 0, sizeof(struct mt76_sta_stats));
+
+ rcu_read_unlock();
+
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_reset_counter, NULL,
+ mt7915_reset_counter, "%lld\n");
+
+static int
+mt7915_per_read(struct seq_file *s, void *data)
+{
+ struct mt7915_dev *dev = dev_get_drvdata(s->private);
+ struct mt76_sta_stats *stats;
+ struct mt76_wcid *wcid;
+ int ret;
+ u8 phy_idx;
+
+ if (!dev->mt76.wcid[dev->wlan_idx])
+ return -EINVAL;
+
+ phy_idx = dev->mt76.wcid[dev->wlan_idx]->phy_idx;
+
+ ret = mt7915_get_tx_stat(dev->mt76.phys[phy_idx]->priv, dev->wlan_idx);
+ if (ret)
+ return ret;
+
+ rcu_read_lock();
+ wcid = rcu_dereference(dev->mt76.wcid[dev->wlan_idx]);
+ if (!wcid)
+ return -EINVAL;
+
+ stats = &wcid->stats;
+
+ seq_printf(s, "sta %d, tx_mpdu_cnt = %u, tx_failed = %u, PER = %u.%u%%\n", dev->wlan_idx,
+ stats->tx_mpdu_cnt, stats->tx_failed_wm,
+ stats->tx_mpdu_cnt ? stats->tx_failed_wm * 1000 / stats->tx_mpdu_cnt / 10 : 0,
+ stats->tx_mpdu_cnt ? stats->tx_failed_wm * 1000 / stats->tx_mpdu_cnt % 10 : 0);
+
+ rcu_read_unlock();
+
+ return 0;
+}
+
int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir)
{
struct mt7915_dev *dev = phy->dev;
@@ -3886,6 +3946,8 @@ int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir)
debugfs_create_file("sw_aci", 0600, dir, dev,
&fops_sw_aci);
debugfs_create_file("sr_enable", 0200, dir, phy, &fops_sr_enable);
+ debugfs_create_file("reset_counter", 0200, dir, dev, &fops_reset_counter);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "per", dir, mt7915_per_read);
return 0;
}
#endif
--
2.18.0