blob: b201ac8bcd33eacfdda3b5f8cb8f3a6cf1d02ccb [file] [log] [blame]
From 980b02284098c3cb3555ae7ec586918c94b6d51d Mon Sep 17 00:00:00 2001
From: Howard Hsu <howard-yh.hsu@mediatek.com>
Date: Mon, 10 Jul 2023 11:47:29 +0800
Subject: [PATCH 1021/1024] wifi: mt76: mt7996: add support spatial reuse debug
commands
This commit adds the following debug commands in debugfs:
1. sr_enable: enable/disable spatial reuse feature. Default is on.
2. sr_enhanced_enable: enable/disable enhanced spatial reuse feature.
Default is on. This feature is mtk proprietary feature.
3. sr_stats: Check the Spatial reuse tx statistics.
4. sr_scene_cond: Check the result of mtk scene detection algorithm. Mtk
scene detection algorithm in firmware may decide whether current
environment can SR Tx or not.
To learn more details of these commands, please check:
https://wiki.mediatek.inc/display/APKB/mt76+Phy+feature+debug+Cheetsheet#mt76PhyfeaturedebugCheetsheet-SpatialReuse
---
mt76_connac_mcu.h | 1 +
mt7996/main.c | 6 +++
mt7996/mcu.c | 5 ++
mt7996/mt7996.h | 6 +++
mt7996/mtk_debugfs.c | 82 ++++++++++++++++++++++++++++++++
mt7996/mtk_mcu.c | 111 +++++++++++++++++++++++++++++++++++++++++++
mt7996/mtk_mcu.h | 56 ++++++++++++++++++++++
7 files changed, 267 insertions(+)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
index 21cae4bf4..1d01b2b89 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -1029,6 +1029,7 @@ enum {
MCU_UNI_EVENT_BSS_BEACON_LOSS = 0x0c,
MCU_UNI_EVENT_SCAN_DONE = 0x0e,
MCU_UNI_EVENT_RDD_REPORT = 0x11,
+ MCU_UNI_EVENT_SR = 0x25,
MCU_UNI_EVENT_ROC = 0x27,
MCU_UNI_EVENT_TX_DONE = 0x2d,
MCU_UNI_EVENT_BF = 0x33,
diff --git a/mt7996/main.c b/mt7996/main.c
index 3ce31786a..bae25ceda 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
@@ -6,6 +6,9 @@
#include "mt7996.h"
#include "mcu.h"
#include "mac.h"
+#ifdef CONFIG_MTK_DEBUG
+#include "mtk_mcu.h"
+#endif
static bool mt7996_dev_running(struct mt7996_dev *dev)
{
@@ -78,6 +81,9 @@ int mt7996_run(struct ieee80211_hw *hw)
goto out;
#ifdef CONFIG_MTK_DEBUG
+ phy->sr_enable = true;
+ phy->enhanced_sr_enable = true;
+
ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
!dev->dbg.sku_disable);
#else
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
index 7c40b8bb6..76788907a 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -617,6 +617,11 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_UNI_EVENT_RDD_REPORT:
mt7996_mcu_rx_radar_detected(dev, skb);
break;
+#ifdef CONFIG_MTK_DEBUG
+ case MCU_UNI_EVENT_SR:
+ mt7996_mcu_rx_sr_event(dev, skb);
+ break;
+#endif
case MCU_UNI_EVENT_THERMAL:
mt7996_mcu_rx_thermal_notify(dev, skb);
break;
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
index eda74f7a9..feb82e440 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -270,6 +270,10 @@ struct mt7996_phy {
spinlock_t amnt_lock;
struct mt7996_air_monitor_ctrl amnt_ctrl;
#endif
+#ifdef CONFIG_MTK_DEBUG
+ bool sr_enable:1;
+ bool enhanced_sr_enable:1;
+#endif
};
struct mt7996_dev {
@@ -700,6 +704,8 @@ enum edcca_bw_id {
#ifdef CONFIG_MTK_DEBUG
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
+int mt7996_mcu_set_sr_enable(struct mt7996_phy *phy, u8 action, u64 val, bool set);
+void mt7996_mcu_rx_sr_event(struct mt7996_dev *dev, struct sk_buff *skb);
#endif
#endif
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
index 82b2785bd..f56ad88df 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
@@ -2589,6 +2589,83 @@ static int mt7996_show_eeprom_mode(struct seq_file *s, void *data)
return 0;
}
+static int
+mt7996_sr_enable_get(void *data, u64 *val)
+{
+ struct mt7996_phy *phy = data;
+
+ *val = phy->sr_enable;
+
+ return 0;
+}
+
+static int
+mt7996_sr_enable_set(void *data, u64 val)
+{
+ struct mt7996_phy *phy = data;
+ int ret;
+
+ if (!!val == phy->sr_enable)
+ return 0;
+
+ ret = mt7996_mcu_set_sr_enable(phy, UNI_CMD_SR_CFG_SR_ENABLE, val, true);
+ if (ret)
+ return ret;
+
+ return mt7996_mcu_set_sr_enable(phy, UNI_CMD_SR_CFG_SR_ENABLE, 0, false);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_sr_enable, mt7996_sr_enable_get,
+ mt7996_sr_enable_set, "%lld\n");
+static int
+mt7996_sr_enhanced_enable_get(void *data, u64 *val)
+{
+ struct mt7996_phy *phy = data;
+
+ *val = phy->enhanced_sr_enable;
+
+ return 0;
+}
+
+static int
+mt7996_sr_enhanced_enable_set(void *data, u64 val)
+{
+ struct mt7996_phy *phy = data;
+ int ret;
+
+ if (!!val == phy->enhanced_sr_enable)
+ return 0;
+
+ ret = mt7996_mcu_set_sr_enable(phy, UNI_CMD_SR_HW_ENHANCE_SR_ENABLE, val, true);
+ if (ret)
+ return ret;
+
+ return mt7996_mcu_set_sr_enable(phy, UNI_CMD_SR_HW_ENHANCE_SR_ENABLE, 0, false);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_sr_enhanced_enable, mt7996_sr_enhanced_enable_get,
+ mt7996_sr_enhanced_enable_set, "%lld\n");
+
+static int
+mt7996_sr_stats_show(struct seq_file *file, void *data)
+{
+ struct mt7996_phy *phy = file->private;
+
+ mt7996_mcu_set_sr_enable(phy, UNI_CMD_SR_HW_IND, 0, false);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(mt7996_sr_stats);
+
+static int
+mt7996_sr_scene_cond_show(struct seq_file *file, void *data)
+{
+ struct mt7996_phy *phy = file->private;
+
+ mt7996_mcu_set_sr_enable(phy, UNI_CMD_SR_SW_SD, 0, false);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(mt7996_sr_scene_cond);
+
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
@@ -2642,6 +2719,11 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_u8("sku_disable", 0600, dir, &dev->dbg.sku_disable);
+ debugfs_create_file("sr_enable", 0600, dir, phy, &fops_sr_enable);
+ debugfs_create_file("sr_enhanced_enable", 0600, dir, phy, &fops_sr_enhanced_enable);
+ debugfs_create_file("sr_stats", 0400, dir, phy, &mt7996_sr_stats_fops);
+ debugfs_create_file("sr_scene_cond", 0400, dir, phy, &mt7996_sr_scene_cond_fops);
+
return 0;
}
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
index 048c53475..3256de7f5 100644
--- a/mt7996/mtk_mcu.c
+++ b/mt7996/mtk_mcu.c
@@ -124,4 +124,115 @@ int mt7996_mcu_edcca_threshold_ctrl(struct mt7996_phy *phy, u8 *value, bool set)
return 0;
}
+int mt7996_mcu_set_sr_enable(struct mt7996_phy *phy, u8 action, u64 val, bool set)
+{
+ struct {
+ u8 band_idx;
+ u8 _rsv[3];
+
+ __le16 tag;
+ __le16 len;
+
+ __le32 val;
+
+ } __packed req = {
+ .band_idx = phy->mt76->band_idx,
+
+ .tag = cpu_to_le16(action),
+ .len = cpu_to_le16(sizeof(req) - 4),
+
+ .val = cpu_to_le32((u32) val),
+ };
+
+ if (set)
+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(SR), &req,
+ sizeof(req), false);
+ else
+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD_QUERY(SR), &req,
+ sizeof(req), false);
+}
+
+void mt7996_mcu_rx_sr_swsd(struct mt7996_dev *dev, struct sk_buff *skb)
+{
+#define SR_SCENE_DETECTION_TIMER_PERIOD_MS 500
+ struct mt7996_mcu_sr_swsd_event *event;
+ static const char * const rules[] = {"1 - NO CONNECTED", "2 - NO CONGESTION",
+ "3 - NO INTERFERENCE", "4 - SR ON"};
+ u8 idx;
+
+ event = (struct mt7996_mcu_sr_swsd_event *)skb->data;
+ idx = event->basic.band_idx;
+
+ dev_info(dev->mt76.dev, "Band index = %u\n", le16_to_cpu(event->basic.band_idx));
+ dev_info(dev->mt76.dev, "Hit Rule = %s\n", rules[event->tlv[idx].rule]);
+ dev_info(dev->mt76.dev, "Timer Period = %d(us)\n"
+ "Congestion Ratio = %d.%1d%%\n",
+ SR_SCENE_DETECTION_TIMER_PERIOD_MS * 1000,
+ le32_to_cpu(event->tlv[idx].total_airtime_ratio) / 10,
+ le32_to_cpu(event->tlv[idx].total_airtime_ratio) % 10);
+ dev_info(dev->mt76.dev,
+ "Total Airtime = %d(us)\n"
+ "ChBusy = %d\n"
+ "SrTx = %d\n"
+ "OBSS = %d\n"
+ "MyTx = %d\n"
+ "MyRx = %d\n"
+ "Interference Ratio = %d.%1d%%\n",
+ le32_to_cpu(event->tlv[idx].total_airtime),
+ le32_to_cpu(event->tlv[idx].channel_busy_time),
+ le32_to_cpu(event->tlv[idx].sr_tx_airtime),
+ le32_to_cpu(event->tlv[idx].obss_airtime),
+ le32_to_cpu(event->tlv[idx].my_tx_airtime),
+ le32_to_cpu(event->tlv[idx].my_rx_airtime),
+ le32_to_cpu(event->tlv[idx].obss_airtime_ratio) / 10,
+ le32_to_cpu(event->tlv[idx].obss_airtime_ratio) % 10);
+}
+
+void mt7996_mcu_rx_sr_hw_indicator(struct mt7996_dev *dev, struct sk_buff *skb)
+{
+ struct mt7996_mcu_sr_hw_ind_event *event;
+
+ event = (struct mt7996_mcu_sr_hw_ind_event *)skb->data;
+
+ dev_info(dev->mt76.dev, "Inter PPDU Count = %u\n",
+ le16_to_cpu(event->inter_bss_ppdu_cnt));
+ dev_info(dev->mt76.dev, "SR Valid Count = %u\n",
+ le16_to_cpu(event->non_srg_valid_cnt));
+ dev_info(dev->mt76.dev, "SR Tx Count = %u\n",
+ le32_to_cpu(event->sr_ampdu_mpdu_cnt));
+ dev_info(dev->mt76.dev, "SR Tx Acked Count = %u\n",
+ le32_to_cpu(event->sr_ampdu_mpdu_acked_cnt));
+}
+
+void mt7996_mcu_rx_sr_event(struct mt7996_dev *dev, struct sk_buff *skb)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt7996_phy *phy;
+ struct mt7996_mcu_sr_common_event *event;
+
+ event = (struct mt7996_mcu_sr_common_event *)skb->data;
+ mphy = dev->mt76.phys[event->basic.band_idx];
+ if (!mphy)
+ return;
+
+ phy = (struct mt7996_phy *)mphy->priv;
+
+ switch (le16_to_cpu(event->basic.tag)) {
+ case UNI_EVENT_SR_CFG_SR_ENABLE:
+ phy->sr_enable = le32_to_cpu(event->value) ? true : false;
+ break;
+ case UNI_EVENT_SR_HW_ESR_ENABLE:
+ phy->enhanced_sr_enable = le32_to_cpu(event->value) ? true : false;
+ break;
+ case UNI_EVENT_SR_SW_SD:
+ mt7996_mcu_rx_sr_swsd(dev, skb);
+ break;
+ case UNI_EVENT_SR_HW_IND:
+ mt7996_mcu_rx_sr_hw_indicator(dev, skb);
+ break;
+ default:
+ dev_info(dev->mt76.dev, "Unknown SR event tag %d\n",
+ le16_to_cpu(event->basic.tag));
+ }
+}
#endif
diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
index 9c0db87bb..a5bdb8831 100644
--- a/mt7996/mtk_mcu.h
+++ b/mt7996/mtk_mcu.h
@@ -104,6 +104,62 @@ enum {
EDCCA_JAPAN = 3
};
+enum {
+ UNI_EVENT_SR_CFG_SR_ENABLE = 0x1,
+ UNI_EVENT_SR_SW_SD = 0x83,
+ UNI_EVENT_SR_HW_IND = 0xC9,
+ UNI_EVENT_SR_HW_ESR_ENABLE = 0xD8,
+};
+enum {
+ UNI_CMD_SR_CFG_SR_ENABLE = 0x1,
+ UNI_CMD_SR_SW_SD = 0x84,
+ UNI_CMD_SR_HW_IND = 0xCB,
+ UNI_CMD_SR_HW_ENHANCE_SR_ENABLE = 0xDA,
+};
+
+struct mt7996_mcu_sr_basic_event {
+ struct mt7996_mcu_rxd rxd;
+
+ u8 band_idx;
+ u8 _rsv[3];
+
+ __le16 tag;
+ __le16 len;
+};
+
+struct sr_sd_tlv {
+ u8 _rsv[16];
+ __le32 sr_tx_airtime;
+ __le32 obss_airtime;
+ __le32 my_tx_airtime;
+ __le32 my_rx_airtime;
+ __le32 channel_busy_time;
+ __le32 total_airtime;
+ __le32 total_airtime_ratio;
+ __le32 obss_airtime_ratio;
+ u8 rule;
+ u8 _rsv2[59];
+} __packed;
+
+struct mt7996_mcu_sr_swsd_event {
+ struct mt7996_mcu_sr_basic_event basic;
+ struct sr_sd_tlv tlv[3];
+} __packed;
+
+struct mt7996_mcu_sr_common_event {
+ struct mt7996_mcu_sr_basic_event basic;
+ __le32 value;
+};
+
+struct mt7996_mcu_sr_hw_ind_event {
+ struct mt7996_mcu_sr_basic_event basic;
+ __le16 non_srg_valid_cnt;
+ u8 _rsv[4];
+ __le16 inter_bss_ppdu_cnt;
+ u8 _rsv2[4];
+ __le32 sr_ampdu_mpdu_cnt;
+ __le32 sr_ampdu_mpdu_acked_cnt;
+};
#endif
#endif
--
2.39.2