blob: 6d0dee23e403217b367d2e1df243e2854d9335bf [file] [log] [blame]
From 503baaaad8a49fcdcc2030a8eddacfec35c167b0 Mon Sep 17 00:00:00 2001
From: Howard Hsu <howard-yh.hsu@mediatek.com>
Date: Mon, 8 May 2023 09:03:50 +0800
Subject: [PATCH 018/223] mtk: mt76: mt7996: enable SCS feature for mt7996
driver
Enable Smart Carrier Sense algorithn by default to improve performance
in a noisy environment.
Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
---
mt76_connac_mcu.h | 1 +
mt7996/init.c | 1 +
mt7996/mac.c | 2 +
mt7996/main.c | 7 +++
mt7996/mcu.c | 105 +++++++++++++++++++++++++++++++++++++++++++
mt7996/mcu.h | 6 +++
mt7996/mt7996.h | 15 +++++++
mt7996/mtk_debugfs.c | 11 +++++
8 files changed, 148 insertions(+)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
index a7d7ecce..fcacd546 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -1279,6 +1279,7 @@ enum {
MCU_UNI_CMD_GET_STAT_INFO = 0x23,
MCU_UNI_CMD_SNIFFER = 0x24,
MCU_UNI_CMD_SR = 0x25,
+ MCU_UNI_CMD_SCS = 0x26,
MCU_UNI_CMD_ROC = 0x27,
MCU_UNI_CMD_SET_DBDC_PARMS = 0x28,
MCU_UNI_CMD_TXPOWER = 0x2b,
diff --git a/mt7996/init.c b/mt7996/init.c
index a34e034d..0a8e929a 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
@@ -1432,6 +1432,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
dev->mt76.phy.priv = &dev->phy;
INIT_WORK(&dev->rc_work, mt7996_mac_sta_rc_work);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7996_mac_work);
+ INIT_DELAYED_WORK(&dev->scs_work, mt7996_mcu_scs_sta_poll);
INIT_LIST_HEAD(&dev->sta_rc_list);
INIT_LIST_HEAD(&dev->twt_list);
diff --git a/mt7996/mac.c b/mt7996/mac.c
index d73644f6..789caa44 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -1815,6 +1815,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev)
cancel_delayed_work_sync(&phy2->mt76->mac_work);
if (phy3)
cancel_delayed_work_sync(&phy3->mt76->mac_work);
+ cancel_delayed_work_sync(&dev->scs_work);
mutex_lock(&dev->mt76.mutex);
for (i = 0; i < 10; i++) {
@@ -1850,6 +1851,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev)
ieee80211_queue_delayed_work(phy3->mt76->hw,
&phy3->mt76->mac_work,
MT7996_WATCHDOG_TIME);
+ ieee80211_queue_delayed_work(mt76_hw(dev), &dev->scs_work, HZ);
}
void mt7996_mac_reset_work(struct work_struct *work)
diff --git a/mt7996/main.c b/mt7996/main.c
index 9ff9ae0e..a1c3874c 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
@@ -81,11 +81,17 @@ int mt7996_run(struct ieee80211_hw *hw)
if (ret)
goto out;
+ ret = mt7996_mcu_set_scs(phy, SCS_ENABLE);
+ if (ret)
+ goto out;
+
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
MT7996_WATCHDOG_TIME);
+ ieee80211_queue_delayed_work(mt76_hw(dev), &dev->scs_work, HZ);
+
if (!running)
mt7996_mac_reset_counters(phy);
@@ -113,6 +119,7 @@ static void mt7996_stop(struct ieee80211_hw *hw, bool suspend)
struct mt7996_phy *phy = mt7996_hw_phy(hw);
cancel_delayed_work_sync(&phy->mt76->mac_work);
+ cancel_delayed_work_sync(&dev->scs_work);
mutex_lock(&dev->mt76.mutex);
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
index b15075ab..98edae2c 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -4832,3 +4832,108 @@ int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 da
return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TXPOWER),
&req, sizeof(req), false);
}
+
+int mt7996_mcu_set_scs_stats(struct mt7996_phy *phy)
+{
+ struct mt7996_scs_ctrl ctrl = phy->scs_ctrl;
+ struct {
+ u8 band_idx;
+ u8 _rsv[3];
+
+ __le16 tag;
+ __le16 len;
+
+ u8 _rsv2[6];
+ s8 min_rssi;
+ u8 _rsv3;
+ } __packed req = {
+ .band_idx = phy->mt76->band_idx,
+ .tag = cpu_to_le16(UNI_CMD_SCS_SEND_DATA),
+ .len = cpu_to_le16(sizeof(req) - 4),
+
+ .min_rssi = ctrl.sta_min_rssi,
+ };
+
+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(SCS),
+ &req, sizeof(req), false);
+}
+
+void mt7996_sta_rssi_work(void *data, struct ieee80211_sta *sta)
+{
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_phy *poll_phy = (struct mt7996_phy *) data;
+
+ if (poll_phy->scs_ctrl.sta_min_rssi > msta->ack_signal)
+ poll_phy->scs_ctrl.sta_min_rssi = msta->ack_signal;
+}
+
+void mt7996_mcu_scs_sta_poll(struct work_struct *work)
+{
+ struct mt7996_dev *dev = container_of(work, struct mt7996_dev,
+ scs_work.work);
+ bool scs_enable_flag = false;
+ u8 i;
+
+ for (i = 0; i < __MT_MAX_BAND; i++) {
+ struct mt7996_phy *phy;
+
+ switch (i) {
+ case MT_BAND0:
+ phy = dev->mphy.priv;
+ break;
+ case MT_BAND1:
+ phy = mt7996_phy2(dev);
+ break;
+ case MT_BAND2:
+ phy = mt7996_phy3(dev);
+ break;
+ default:
+ phy = NULL;
+ break;
+ }
+
+ if (!phy || !test_bit(MT76_STATE_RUNNING, &phy->mt76->state) ||
+ !phy->scs_ctrl.scs_enable)
+ continue;
+
+ ieee80211_iterate_stations_atomic(phy->mt76->hw,
+ mt7996_sta_rssi_work, phy);
+
+ scs_enable_flag = true;
+ if (mt7996_mcu_set_scs_stats(phy))
+ dev_err(dev->mt76.dev, "Failed to send scs mcu cmd\n");
+ phy->scs_ctrl.sta_min_rssi = 0;
+ }
+
+ if (scs_enable_flag)
+ ieee80211_queue_delayed_work(mt76_hw(dev), &dev->scs_work, HZ);
+}
+
+
+int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable)
+{
+ struct mt7996_dev *dev = phy->dev;
+ struct {
+ u8 band_idx;
+ u8 _rsv[3];
+
+ __le16 tag;
+ __le16 len;
+
+ u8 scs_enable;
+ u8 _rsv2[3];
+ } __packed req = {
+ .band_idx = phy->mt76->band_idx,
+ .tag = cpu_to_le16(UNI_CMD_SCS_ENABLE),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .scs_enable = enable,
+ };
+
+ phy->scs_ctrl.scs_enable = enable;
+
+ if (enable == SCS_ENABLE)
+ ieee80211_queue_delayed_work(mt76_hw(dev), &dev->scs_work, HZ);
+
+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(SCS),
+ &req, sizeof(req), false);
+}
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
index abf8ef48..f889cb8b 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -966,6 +966,12 @@ enum pp_mode {
PP_USR_MODE,
};
+enum {
+ UNI_CMD_SCS_SEND_DATA,
+ UNI_CMD_SCS_SET_PD_THR_RANGE = 2,
+ UNI_CMD_SCS_ENABLE,
+};
+
#define MT7996_PATCH_SEC GENMASK(31, 24)
#define MT7996_PATCH_SCRAMBLE_KEY GENMASK(15, 8)
#define MT7996_PATCH_AES_KEY GENMASK(7, 0)
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
index 8770839c..6cb6c724 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -243,6 +243,16 @@ struct mt7996_hif {
int irq;
};
+struct mt7996_scs_ctrl {
+ u8 scs_enable;
+ s8 sta_min_rssi;
+};
+
+enum {
+ SCS_DISABLE = 0,
+ SCS_ENABLE,
+};
+
struct mt7996_wed_rro_addr {
u32 head_low;
u32 head_high : 4;
@@ -293,6 +303,8 @@ struct mt7996_phy {
u8 pp_mode;
u16 punct_bitmap;
+ struct mt7996_scs_ctrl scs_ctrl;
+
#ifdef CONFIG_NL80211_TESTMODE
struct {
u32 *reg_backup;
@@ -339,6 +351,7 @@ struct mt7996_dev {
struct work_struct rc_work;
struct work_struct dump_work;
struct work_struct reset_work;
+ struct delayed_work scs_work;
wait_queue_head_t reset_wait;
struct {
u32 state;
@@ -635,6 +648,8 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy);
#ifdef CONFIG_NL80211_TESTMODE
void mt7996_tm_rf_test_event(struct mt7996_dev *dev, struct sk_buff *skb);
#endif
+int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable);
+void mt7996_mcu_scs_sta_poll(struct work_struct *work);
static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
{
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
index d1f3d16c..1807a744 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
@@ -2429,6 +2429,16 @@ static int mt7996_token_read(struct seq_file *s, void *data)
return 0;
}
+static int
+mt7996_scs_enable_set(void *data, u64 val)
+{
+ struct mt7996_phy *phy = data;
+
+ return mt7996_mcu_set_scs(phy, (u8) val);
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_scs_enable, NULL,
+ mt7996_scs_enable_set, "%lld\n");
+
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
@@ -2499,6 +2509,7 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_devm_seqfile(dev->mt76.dev, "token", dir, mt7996_token_read);
debugfs_create_u8("sku_disable", 0600, dir, &dev->dbg.sku_disable);
+ debugfs_create_file("scs_enable", 0200, dir, phy, &fops_scs_enable);
return 0;
}
--
2.45.2