| From 3a498fb75b2f609a41019f844873496117b1fff6 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] 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 6c488bd1..cbd63695 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 1257dfa1..cfdee7c1 100644 |
| --- a/mt76_connac_mcu.h |
| +++ b/mt76_connac_mcu.h |
| @@ -1162,6 +1162,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 74728252..07a4b085 100644 |
| --- a/mt7915/mcu.c |
| +++ b/mt7915/mcu.c |
| @@ -4214,6 +4214,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 82b0847d..d6849797 100644 |
| --- a/mt7915/mcu.h |
| +++ b/mt7915/mcu.h |
| @@ -790,7 +790,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 |
| @@ -1069,6 +1070,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 0153e5fe..85c5c95c 100644 |
| --- a/mt7915/mt7915.h |
| +++ b/mt7915/mt7915.h |
| @@ -661,6 +661,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 3eeb921f..da33578c 100644 |
| --- a/mt7915/mtk_debugfs.c |
| +++ b/mt7915/mtk_debugfs.c |
| @@ -3790,6 +3790,66 @@ mt7915_sw_aci_set(void *data, u64 val) |
| DEFINE_DEBUGFS_ATTRIBUTE(fops_sw_aci, NULL, |
| mt7915_sw_aci_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; |
| @@ -3880,6 +3940,8 @@ int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir) |
| mt7915_show_eeprom_mode); |
| debugfs_create_file("sw_aci", 0600, dir, dev, |
| &fops_sw_aci); |
| + 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 |
| |