| From b02a81b168e9c42350c1f6a9b7e38c60c76cc692 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 38/98] wifi: 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/main.c | 7 +++ |
| mt7996/mcu.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++ |
| mt7996/mcu.h | 6 +++ |
| mt7996/mt7996.h | 15 ++++++ |
| 6 files changed, 153 insertions(+) |
| |
| diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h |
| index 4d054bd..fae76c9 100644 |
| --- a/mt76_connac_mcu.h |
| +++ b/mt76_connac_mcu.h |
| @@ -1232,6 +1232,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 fed74d0..f393e04 100644 |
| --- a/mt7996/init.c |
| +++ b/mt7996/init.c |
| @@ -1211,6 +1211,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/main.c b/mt7996/main.c |
| index 226235c..6fa4a65 100644 |
| --- a/mt7996/main.c |
| +++ b/mt7996/main.c |
| @@ -73,11 +73,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); |
| |
| @@ -105,6 +111,7 @@ static void mt7996_stop(struct ieee80211_hw *hw) |
| 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 141b838..6cedc39 100644 |
| --- a/mt7996/mcu.c |
| +++ b/mt7996/mcu.c |
| @@ -4346,3 +4346,126 @@ 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_dev *dev = (struct mt7996_dev *)data; |
| + struct mt7996_phy *poll_phy; |
| + u8 band_idx = msta->wcid.phy_idx; |
| + |
| + switch (band_idx) { |
| + case MT_BAND0: |
| + poll_phy = dev->mphy.priv; |
| + break; |
| + case MT_BAND1: |
| + poll_phy = mt7996_phy2(dev); |
| + break; |
| + case MT_BAND2: |
| + poll_phy = mt7996_phy3(dev); |
| + break; |
| + default: |
| + poll_phy = NULL; |
| + break; |
| + } |
| + |
| + if (!poll_phy->scs_ctrl.scs_enable) |
| + return; |
| + |
| + 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; |
| + |
| + ieee80211_iterate_stations_atomic(dev->mphy.hw, mt7996_sta_rssi_work, dev); |
| + |
| + 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) { |
| + 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 16ffc3d..ff9cc9c 100644 |
| --- a/mt7996/mcu.h |
| +++ b/mt7996/mcu.h |
| @@ -875,6 +875,12 @@ enum { |
| UNI_CMD_PP_EN_CTRL, |
| }; |
| |
| +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 efdcff7..eb48dbd 100644 |
| --- a/mt7996/mt7996.h |
| +++ b/mt7996/mt7996.h |
| @@ -193,6 +193,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; |
| @@ -235,6 +245,8 @@ struct mt7996_phy { |
| |
| bool has_aux_rx; |
| |
| + struct mt7996_scs_ctrl scs_ctrl; |
| + |
| #ifdef CONFIG_NL80211_TESTMODE |
| struct { |
| u32 *reg_backup; |
| @@ -280,6 +292,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; |
| @@ -555,6 +568,8 @@ void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb); |
| void mt7996_mcu_exit(struct mt7996_dev *dev); |
| int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); |
| int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data); |
| +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) |
| { |
| -- |
| 2.18.0 |
| |