| From a3f223f025ce2abc2dc0e42ab835a8cc5ef6d65a 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 028/223] mtk: 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 |
| |
| Change-Id: I5bf83013ea2788dfc93caaaef08486a4f97a3649 |
| --- |
| mt76_connac_mcu.h | 1 + |
| mt7996/main.c | 6 +++ |
| mt7996/mcu.c | 8 ++++ |
| mt7996/mt7996.h | 6 +++ |
| mt7996/mtk_debugfs.c | 82 ++++++++++++++++++++++++++++++++ |
| mt7996/mtk_mcu.c | 111 +++++++++++++++++++++++++++++++++++++++++++ |
| mt7996/mtk_mcu.h | 56 ++++++++++++++++++++++ |
| 7 files changed, 270 insertions(+) |
| |
| diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h |
| index e9afc27b..dd63d4a0 100644 |
| --- a/mt76_connac_mcu.h |
| +++ b/mt76_connac_mcu.h |
| @@ -1056,6 +1056,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 67eab3df..6203e800 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) |
| { |
| @@ -86,6 +89,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 ? 0 : phy->sku_limit_en); |
| |
| diff --git a/mt7996/mcu.c b/mt7996/mcu.c |
| index eb065ffc..78462729 100644 |
| --- a/mt7996/mcu.c |
| +++ b/mt7996/mcu.c |
| @@ -727,6 +727,14 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) |
| case MCU_UNI_EVENT_WED_RRO: |
| mt7996_mcu_wed_rro_event(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; |
| #ifdef CONFIG_NL80211_TESTMODE |
| case MCU_UNI_EVENT_TESTMODE_CTRL: |
| mt7996_tm_rf_test_event(dev, skb); |
| diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
| index c011e8ec..356935b2 100644 |
| --- a/mt7996/mt7996.h |
| +++ b/mt7996/mt7996.h |
| @@ -366,6 +366,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 { |
| @@ -838,6 +842,8 @@ enum edcca_bw_id { |
| #ifdef CONFIG_MTK_DEBUG |
| int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); |
| int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val); |
| +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 |
| |
| #ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c |
| index 60ec6bd4..13ea6274 100644 |
| --- a/mt7996/mtk_debugfs.c |
| +++ b/mt7996/mtk_debugfs.c |
| @@ -2834,6 +2834,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; |
| @@ -2914,6 +2991,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("scs_enable", 0200, dir, phy, &fops_scs_enable); |
| |
| + 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 5c54d02c..dbdf8d80 100644 |
| --- a/mt7996/mtk_mcu.c |
| +++ b/mt7996/mtk_mcu.c |
| @@ -146,4 +146,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 36a58ad6..098e63ae 100644 |
| --- a/mt7996/mtk_mcu.h |
| +++ b/mt7996/mtk_mcu.h |
| @@ -121,6 +121,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.45.2 |
| |