| From 3e5f0df52e16d5dfab197af0e8768b906fa611a5 Mon Sep 17 00:00:00 2001 |
| From: Benjamin Lin <benjamin-jw.lin@mediatek.com> |
| Date: Mon, 11 Sep 2023 16:35:15 +0800 |
| Subject: [PATCH 2011/2028] mtk: wifi: mt76: mt7996: add support for HW-ATF |
| |
| --- |
| mt7996/debugfs.c | 90 ++++++++++++++++ |
| mt7996/init.c | 43 ++++++++ |
| mt7996/mac.c | 6 ++ |
| mt7996/mcu.c | 265 ++++++++++++++++++++++++++++++++++++++++++----- |
| mt7996/mcu.h | 1 + |
| mt7996/mt7996.h | 96 ++++++++++++++++- |
| 6 files changed, 475 insertions(+), 26 deletions(-) |
| |
| diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c |
| index 21bb2c5d..ed55afa0 100644 |
| --- a/mt7996/debugfs.c |
| +++ b/mt7996/debugfs.c |
| @@ -895,6 +895,91 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_muru_disable, |
| mt7996_fw_debug_muru_disable_get, |
| mt7996_fw_debug_muru_disable_set, "%lld\n"); |
| |
| +static int |
| +mt7996_vow_info_read(struct seq_file *s, void *data) |
| +{ |
| + struct mt7996_dev *dev = dev_get_drvdata(s->private); |
| + struct mt7996_vow_ctrl *vow = &dev->vow; |
| + int i; |
| + |
| + seq_printf(s, "VoW ATF Configuration:\n"); |
| + seq_printf(s, "ATF: %s\n", vow->atf_enable ? "enabled" : "disabled"); |
| + seq_printf(s, "WATF: %s\n", vow->watf_enable ? "enabled" : "disabled"); |
| + seq_printf(s, "Airtime Quantums (unit: 256 us)\n"); |
| + for (i = 0; i < VOW_DRR_QUANTUM_NUM; ++i) |
| + seq_printf(s, "\tL%d: %hhu\n", i, vow->drr_quantum[i]); |
| + seq_printf(s, "Max Airtime Deficit: %hhu (unit: 256 us)\n", vow->max_deficit); |
| + |
| + return 0; |
| +} |
| + |
| +static int |
| +mt7996_atf_enable_get(void *data, u64 *val) |
| +{ |
| + struct mt7996_phy *phy = data; |
| + |
| + *val = phy->dev->vow.atf_enable; |
| + |
| + return 0; |
| +} |
| + |
| +static int |
| +mt7996_atf_enable_set(void *data, u64 val) |
| +{ |
| + struct mt7996_phy *phy = data; |
| + struct mt7996_vow_ctrl *vow = &phy->dev->vow; |
| + int ret; |
| + |
| + vow->max_deficit = val ? 64 : 1; |
| + ret = mt7996_mcu_set_vow_drr_ctrl(phy, NULL, VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND); |
| + if (ret) |
| + return ret; |
| + |
| + vow->atf_enable = !!val; |
| + return mt7996_mcu_set_vow_feature_ctrl(phy); |
| +} |
| + |
| +DEFINE_DEBUGFS_ATTRIBUTE(fops_atf_enable, mt7996_atf_enable_get, |
| + mt7996_atf_enable_set, "%llu\n"); |
| + |
| +static int |
| +mt7996_airtime_read(struct seq_file *s, void *data) |
| +{ |
| + struct mt7996_dev *dev = dev_get_drvdata(s->private); |
| + struct mt76_dev *mdev = &dev->mt76; |
| + struct mt7996_vow_sta_ctrl *vow; |
| + struct ieee80211_sta *sta; |
| + struct mt7996_sta *msta; |
| + struct mt76_wcid *wcid; |
| + struct mt76_vif *vif; |
| + u64 airtime; |
| + u16 i; |
| + |
| + seq_printf(s, "VoW Airtime Information:\n"); |
| + rcu_read_lock(); |
| + for (i = 1; i < MT7996_WTBL_STA; ++i) { |
| + wcid = rcu_dereference(mdev->wcid[i]); |
| + if (!wcid || !wcid->sta) |
| + continue; |
| + |
| + msta = container_of(wcid, struct mt7996_sta, wcid); |
| + sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); |
| + vow = &msta->vow; |
| + vif = &msta->vif->mt76; |
| + |
| + spin_lock_bh(&vow->lock); |
| + airtime = vow->tx_airtime; |
| + vow->tx_airtime = 0; |
| + spin_unlock_bh(&vow->lock); |
| + |
| + seq_printf(s, "%pM WCID: %hu BandIdx: %hhu OmacIdx: 0x%hhx\tTxAirtime: %llu\n", |
| + sta->addr, i, vif->band_idx, vif->omac_idx, airtime); |
| + } |
| + rcu_read_unlock(); |
| + |
| + return 0; |
| +} |
| + |
| int mt7996_init_debugfs(struct mt7996_phy *phy) |
| { |
| struct mt7996_dev *dev = phy->dev; |
| @@ -921,6 +1006,11 @@ int mt7996_init_debugfs(struct mt7996_phy *phy) |
| debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir, |
| mt7996_twt_stats); |
| debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval); |
| + debugfs_create_devm_seqfile(dev->mt76.dev, "vow_info", dir, |
| + mt7996_vow_info_read); |
| + debugfs_create_file("atf_enable", 0600, dir, phy, &fops_atf_enable); |
| + debugfs_create_devm_seqfile(dev->mt76.dev, "airtime", dir, |
| + mt7996_airtime_read); |
| |
| if (phy->mt76->cap.has_5ghz) { |
| debugfs_create_u32("dfs_hw_pattern", 0400, dir, |
| diff --git a/mt7996/init.c b/mt7996/init.c |
| index 19a7cd10..d2cd2221 100644 |
| --- a/mt7996/init.c |
| +++ b/mt7996/init.c |
| @@ -562,6 +562,37 @@ int mt7996_txbf_init(struct mt7996_dev *dev) |
| return mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE); |
| } |
| |
| +static int mt7996_vow_init(struct mt7996_phy *phy) |
| +{ |
| + struct mt7996_vow_ctrl *vow = &phy->dev->vow; |
| + int ret; |
| + |
| + vow->atf_enable = true; |
| + vow->watf_enable = false; |
| + vow->max_deficit = 64; |
| + vow->sch_type = VOW_SCH_TYPE_FOLLOW_POLICY; |
| + vow->sch_policy = VOW_SCH_POLICY_SRR; |
| + |
| + vow->drr_quantum[0] = VOW_DRR_QUANTUM_L0; |
| + vow->drr_quantum[1] = VOW_DRR_QUANTUM_L1; |
| + vow->drr_quantum[2] = VOW_DRR_QUANTUM_L2; |
| + vow->drr_quantum[3] = VOW_DRR_QUANTUM_L3; |
| + vow->drr_quantum[4] = VOW_DRR_QUANTUM_L4; |
| + vow->drr_quantum[5] = VOW_DRR_QUANTUM_L5; |
| + vow->drr_quantum[6] = VOW_DRR_QUANTUM_L6; |
| + vow->drr_quantum[7] = VOW_DRR_QUANTUM_L7; |
| + |
| + ret = mt7996_mcu_set_vow_drr_ctrl(phy, NULL, VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND); |
| + if (ret) |
| + return ret; |
| + |
| + ret = mt7996_mcu_set_vow_drr_ctrl(phy, NULL, VOW_DRR_CTRL_AIRTIME_QUANTUM_ALL); |
| + if (ret) |
| + return ret; |
| + |
| + return mt7996_mcu_set_vow_feature_ctrl(phy); |
| +} |
| + |
| static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, |
| enum mt76_band_id band) |
| { |
| @@ -634,6 +665,12 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, |
| if (ret) |
| goto error; |
| |
| + if (mt7996_vow_should_enable(dev)) { |
| + ret = mt7996_vow_init(phy); |
| + if (ret) |
| + goto error; |
| + } |
| + |
| ret = mt7996_init_debugfs(phy); |
| if (ret) |
| goto error; |
| @@ -1440,6 +1477,12 @@ int mt7996_register_device(struct mt7996_dev *dev) |
| |
| dev->recovery.hw_init_done = true; |
| |
| + if (mt7996_vow_should_enable(dev)) { |
| + ret = mt7996_vow_init(&dev->phy); |
| + if (ret) |
| + goto error; |
| + } |
| + |
| ret = mt7996_init_debugfs(&dev->phy); |
| if (ret) |
| goto error; |
| diff --git a/mt7996/mac.c b/mt7996/mac.c |
| index a9d8f7dd..d51f4129 100644 |
| --- a/mt7996/mac.c |
| +++ b/mt7996/mac.c |
| @@ -103,6 +103,7 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) |
| }; |
| struct ieee80211_sta *sta; |
| struct mt7996_sta *msta; |
| + struct mt7996_vow_sta_ctrl *vow; |
| u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; |
| LIST_HEAD(sta_poll_list); |
| int i; |
| @@ -161,6 +162,7 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) |
| |
| sta = container_of((void *)msta, struct ieee80211_sta, |
| drv_priv); |
| + vow = &msta->vow; |
| for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
| u8 q = mt76_connac_lmac_mapping(i); |
| u32 tx_cur = tx_time[q]; |
| @@ -171,6 +173,10 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) |
| continue; |
| |
| ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur); |
| + |
| + spin_lock_bh(&vow->lock); |
| + vow->tx_airtime += tx_cur; |
| + spin_unlock_bh(&vow->lock); |
| } |
| |
| /* get signal strength of resp frames (CTS/BA/ACK) */ |
| diff --git a/mt7996/mcu.c b/mt7996/mcu.c |
| index 8bb29e3a..c7f9e308 100644 |
| --- a/mt7996/mcu.c |
| +++ b/mt7996/mcu.c |
| @@ -2233,34 +2233,37 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| } |
| |
| static int |
| -mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| - struct ieee80211_sta *sta) |
| +mt7996_mcu_sta_init_vow(struct mt7996_phy *phy, struct mt7996_sta *msta) |
| { |
| -#define MT_STA_BSS_GROUP 1 |
| - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; |
| - struct mt7996_sta *msta; |
| - struct { |
| - u8 __rsv1[4]; |
| + struct mt7996_vow_sta_ctrl *vow = &msta->vow; |
| + u8 omac_idx = msta->vif->mt76.omac_idx; |
| + int ret; |
| |
| - __le16 tag; |
| - __le16 len; |
| - __le16 wlan_idx; |
| - u8 __rsv2[2]; |
| - __le32 action; |
| - __le32 val; |
| - u8 __rsv3[8]; |
| - } __packed req = { |
| - .tag = cpu_to_le16(UNI_VOW_DRR_CTRL), |
| - .len = cpu_to_le16(sizeof(req) - 4), |
| - .action = cpu_to_le32(MT_STA_BSS_GROUP), |
| - .val = cpu_to_le32(mvif->mt76.idx % 16), |
| - }; |
| + /* Assignment of STA BSS group index aligns FW. |
| + * Each band has its own BSS group bitmap space. |
| + * 0: BSS 0 |
| + * 4..18: BSS 0x11..0x1f |
| + */ |
| + vow->bss_grp_idx = (omac_idx <= HW_BSSID_MAX) |
| + ? omac_idx |
| + : HW_BSSID_MAX + omac_idx - EXT_BSSID_START; |
| + vow->paused = false; |
| + vow->drr_quantum[IEEE80211_AC_VO] = VOW_DRR_QUANTUM_IDX0; |
| + vow->drr_quantum[IEEE80211_AC_VI] = VOW_DRR_QUANTUM_IDX1; |
| + vow->drr_quantum[IEEE80211_AC_BE] = VOW_DRR_QUANTUM_IDX2; |
| + vow->drr_quantum[IEEE80211_AC_BK] = VOW_DRR_QUANTUM_IDX2; |
| + vow->tx_airtime = 0; |
| + spin_lock_init(&vow->lock); |
| + |
| + ret = mt7996_mcu_set_vow_drr_ctrl(phy, msta, VOW_DRR_CTRL_STA_BSS_GROUP); |
| + if (ret) |
| + return ret; |
| |
| - msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta; |
| - req.wlan_idx = cpu_to_le16(msta->wcid.idx); |
| + ret = mt7996_mcu_set_vow_drr_ctrl(phy, msta, VOW_DRR_CTRL_STA_PAUSE); |
| + if (ret) |
| + return ret; |
| |
| - return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(VOW), &req, |
| - sizeof(req), true); |
| + return mt7996_mcu_set_vow_drr_ctrl(phy, msta, VOW_DRR_CTRL_STA_ALL); |
| } |
| |
| int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| @@ -2316,7 +2319,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta); |
| } |
| |
| - ret = mt7996_mcu_add_group(dev, vif, sta); |
| + ret = mt7996_mcu_sta_init_vow(mvif->phy, msta); |
| if (ret) { |
| dev_kfree_skb(skb); |
| return ret; |
| @@ -5152,6 +5155,218 @@ int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable) |
| &req, sizeof(req), false); |
| } |
| |
| +int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy, struct mt7996_sta *msta, |
| + enum vow_drr_ctrl_id id) |
| +{ |
| + struct mt7996_vow_sta_ctrl *vow = msta ? &msta->vow : NULL; |
| + u32 val = 0; |
| + struct { |
| + u8 __rsv1[4]; |
| + |
| + __le16 tag; |
| + __le16 len; |
| + __le16 wlan_idx; |
| + u8 band_idx; |
| + u8 wmm_idx; |
| + __le32 ctrl_id; |
| + |
| + union { |
| + __le32 val; |
| + u8 drr_quantum[VOW_DRR_QUANTUM_NUM]; |
| + }; |
| + |
| + u8 __rsv2[3]; |
| + u8 omac_idx; |
| + } __packed req = { |
| + .tag = cpu_to_le16(UNI_VOW_DRR_CTRL), |
| + .len = cpu_to_le16(sizeof(req) - 4), |
| + .wlan_idx = cpu_to_le16(msta ? msta->wcid.idx : 0), |
| + .band_idx = phy->mt76->band_idx, |
| + .wmm_idx = msta ? msta->vif->mt76.wmm_idx : 0, |
| + .ctrl_id = cpu_to_le32(id), |
| + .omac_idx = msta ? msta->vif->mt76.omac_idx : 0 |
| + }; |
| + |
| + switch (id) { |
| + case VOW_DRR_CTRL_STA_ALL: |
| + val |= FIELD_PREP(MT7996_DRR_STA_BSS_GRP_MASK, vow->bss_grp_idx); |
| + val |= FIELD_PREP(MT7996_DRR_STA_AC0_QNTM_MASK, vow->drr_quantum[IEEE80211_AC_BK]); |
| + val |= FIELD_PREP(MT7996_DRR_STA_AC1_QNTM_MASK, vow->drr_quantum[IEEE80211_AC_BE]); |
| + val |= FIELD_PREP(MT7996_DRR_STA_AC2_QNTM_MASK, vow->drr_quantum[IEEE80211_AC_VI]); |
| + val |= FIELD_PREP(MT7996_DRR_STA_AC3_QNTM_MASK, vow->drr_quantum[IEEE80211_AC_VO]); |
| + req.val = cpu_to_le32(val); |
| + break; |
| + case VOW_DRR_CTRL_STA_BSS_GROUP: |
| + req.val = cpu_to_le32(vow->bss_grp_idx); |
| + break; |
| + case VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND: |
| + req.val = cpu_to_le32(phy->dev->vow.max_deficit); |
| + break; |
| + case VOW_DRR_CTRL_AIRTIME_QUANTUM_ALL: |
| + memcpy(req.drr_quantum, phy->dev->vow.drr_quantum, VOW_DRR_QUANTUM_NUM); |
| + break; |
| + case VOW_DRR_CTRL_STA_PAUSE: |
| + req.val = cpu_to_le32(vow->paused); |
| + break; |
| + default: |
| + dev_err(phy->dev->mt76.dev, "Unknown VoW DRR Control ID: %u\n", id); |
| + return -EINVAL; |
| + } |
| + |
| + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(VOW), |
| + &req, sizeof(req), true); |
| +} |
| + |
| +int mt7996_mcu_set_vow_feature_ctrl(struct mt7996_phy *phy) |
| +{ |
| + struct mt7996_vow_ctrl *vow = &phy->dev->vow; |
| + struct { |
| + u8 __rsv1[4]; |
| + |
| + __le16 tag; |
| + __le16 len; |
| + |
| + /* DW0 */ |
| + __le16 apply_bwc_enable_per_grp; |
| + __le16 apply_bwc_refill_period : 1; |
| + __le16 __rsv2 : 3; |
| + __le16 apply_band1_search_rule : 1; |
| + __le16 apply_band0_search_rule : 1; |
| + __le16 __rsv3 : 3; |
| + __le16 apply_watf_enable : 1; |
| + __le16 __rsv4 : 2; |
| + __le16 apply_grp_no_change_in_txop : 1; |
| + __le16 apply_atf_enable : 1; |
| + __le16 apply_bwc_token_refill_enable : 1; |
| + __le16 apply_bwc_enable : 1; |
| + |
| + /* DW1 */ |
| + __le16 apply_bwc_check_time_token_per_grp; |
| + __le16 __rsv5; |
| + |
| + /* DW2 */ |
| + __le16 apply_bwc_check_len_token_per_grp; |
| + __le16 __rsv6; |
| + |
| + /* DW3 */ |
| + u8 band_idx; |
| + u8 __rsv7[3]; |
| + |
| + /* DW4 */ |
| + __le32 __rsv8; |
| + |
| + /* DW5 */ |
| + __le16 bwc_enable_per_grp; |
| + __le16 bwc_refill_period : 3; |
| + __le16 __rsv9 : 1; |
| + __le16 band1_search_rule : 1; |
| + __le16 band0_search_rule : 1; |
| + __le16 __rsv10 : 3; |
| + __le16 watf_enable : 1; |
| + __le16 __rsv11 : 2; |
| + __le16 grp_no_change_in_txop : 1; |
| + __le16 atf_enable : 1; |
| + __le16 bwc_token_refill_enable : 1; |
| + __le16 bwc_enable : 1; |
| + |
| + /* DW6 */ |
| + __le16 bwc_check_time_token_per_grp; |
| + __le16 __rsv12; |
| + |
| + /* DW7 */ |
| + __le16 bwc_check_len_token_per_grp; |
| + __le16 __rsv13; |
| + |
| + /* DW8 */ |
| + __le32 apply_atf_rts_sta_lock : 1; |
| + __le32 atf_rts_sta_lock : 1; |
| + __le32 apply_atf_keep_quantum : 1; |
| + __le32 atf_keep_quantum : 1; |
| + __le32 apply_tx_cnt_mode_ctrl : 1; |
| + __le32 tx_cnt_mode_ctrl : 4; |
| + __le32 apply_tx_measure_mode_enable : 1; |
| + __le32 tx_measure_mode_enable : 1; |
| + __le32 apply_backoff_ctrl : 1; |
| + __le32 backoff_bound_enable : 1; |
| + __le32 backoff_bound : 5; |
| + __le32 apply_atf_rts_fail_charge : 1; |
| + __le32 atf_rts_fail_charge : 1; |
| + __le32 apply_zero_eifs : 1; |
| + __le32 zero_eifs : 1; |
| + __le32 apply_rx_rifs_enable : 1; |
| + __le32 rx_rifs_enable : 1; |
| + __le32 apply_vow_ctrl : 1; |
| + __le32 vow_ctrl_val : 1; |
| + __le32 vow_ctrl_bit : 5; |
| + __le32 __rsv14 : 1; |
| + |
| + /* DW9 */ |
| + __le32 apply_spl_sta_num : 1; |
| + __le32 spl_sta_num : 3; |
| + __le32 dbg_lvl : 2; |
| + __le32 apply_atf_sch_ctrl : 1; |
| + __le32 atf_sch_type : 2; |
| + __le32 atf_sch_policy : 2; |
| + __le32 __rsv15 : 21; |
| + } __packed req = { |
| + .tag = cpu_to_le16(UNI_VOW_FEATURE_CTRL), |
| + .len = cpu_to_le16(sizeof(req) - 4), |
| + /* DW0 */ |
| + .apply_bwc_enable_per_grp = cpu_to_le16(0xffff), |
| + .apply_bwc_refill_period = true, |
| + .apply_band1_search_rule = true, |
| + .apply_band0_search_rule = true, |
| + .apply_watf_enable = true, |
| + .apply_grp_no_change_in_txop = true, |
| + .apply_atf_enable = true, |
| + .apply_bwc_token_refill_enable = true, |
| + .apply_bwc_enable = true, |
| + /* DW1 */ |
| + .apply_bwc_check_time_token_per_grp = cpu_to_le16(0xffff), |
| + /* DW2 */ |
| + .apply_bwc_check_len_token_per_grp = cpu_to_le16(0xffff), |
| + /* DW3 */ |
| + .band_idx = phy->mt76->band_idx, |
| + /* DW5 */ |
| + .bwc_enable_per_grp = cpu_to_le16(0xffff), |
| + .bwc_refill_period = VOW_REFILL_PERIOD_32US, |
| + .band1_search_rule = VOW_SEARCH_WMM_FIRST, |
| + .band0_search_rule = VOW_SEARCH_WMM_FIRST, |
| + .watf_enable = vow->watf_enable, |
| + .grp_no_change_in_txop = true, |
| + .atf_enable = vow->atf_enable, |
| + .bwc_token_refill_enable = true, |
| + .bwc_enable = false, |
| + /* DW6 */ |
| + .bwc_check_time_token_per_grp = cpu_to_le16(0x0), |
| + /* DW7 */ |
| + .bwc_check_len_token_per_grp = cpu_to_le16(0x0), |
| + /* DW8 */ |
| + .apply_atf_rts_sta_lock = false, |
| + .apply_atf_keep_quantum = true, |
| + .atf_keep_quantum = true, |
| + .apply_tx_cnt_mode_ctrl = false, |
| + .apply_tx_measure_mode_enable = false, |
| + .apply_backoff_ctrl = false, |
| + .apply_atf_rts_fail_charge = false, |
| + .apply_zero_eifs = false, |
| + .apply_rx_rifs_enable = false, |
| + .apply_vow_ctrl = true, |
| + .vow_ctrl_val = true, |
| + /* Reset DRR table when SER occurs. */ |
| + .vow_ctrl_bit = 26, |
| + /* DW9 */ |
| + .apply_spl_sta_num = false, |
| + .dbg_lvl = 0, |
| + .apply_atf_sch_ctrl = true, |
| + .atf_sch_type = vow->sch_type, |
| + .atf_sch_policy = vow->sch_policy |
| + }; |
| + |
| + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(VOW), |
| + &req, sizeof(req), true); |
| +} |
| + |
| #ifdef CONFIG_MTK_VENDOR |
| void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif) |
| { |
| diff --git a/mt7996/mcu.h b/mt7996/mcu.h |
| index a2604192..7b8540f6 100644 |
| --- a/mt7996/mcu.h |
| +++ b/mt7996/mcu.h |
| @@ -964,6 +964,7 @@ enum { |
| |
| enum { |
| UNI_VOW_DRR_CTRL, |
| + UNI_VOW_FEATURE_CTRL, |
| UNI_VOW_RX_AT_AIRTIME_EN = 0x0b, |
| UNI_VOW_RX_AT_AIRTIME_CLR_EN = 0x0e, |
| UNI_VOW_RED_ENABLE = 0x18, |
| diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
| index b0eb5d91..b1abe42b 100644 |
| --- a/mt7996/mt7996.h |
| +++ b/mt7996/mt7996.h |
| @@ -115,6 +115,12 @@ |
| #define MT7996_RX_MSDU_PAGE_SIZE (128 + \ |
| SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) |
| |
| +#define MT7996_DRR_STA_BSS_GRP_MASK GENMASK(5, 0) |
| +#define MT7996_DRR_STA_AC0_QNTM_MASK GENMASK(10, 8) |
| +#define MT7996_DRR_STA_AC1_QNTM_MASK GENMASK(14, 12) |
| +#define MT7996_DRR_STA_AC2_QNTM_MASK GENMASK(18, 16) |
| +#define MT7996_DRR_STA_AC3_QNTM_MASK GENMASK(22, 20) |
| + |
| struct mt7996_vif; |
| struct mt7996_sta; |
| struct mt7996_dfs_pulse; |
| @@ -216,6 +222,81 @@ enum mt7996_dpd_ch_num { |
| DPD_CH_NUM_TYPE_MAX, |
| }; |
| |
| +enum { |
| + VOW_SEARCH_AC_FIRST, |
| + VOW_SEARCH_WMM_FIRST |
| +}; |
| + |
| +enum { |
| + VOW_REFILL_PERIOD_1US, |
| + VOW_REFILL_PERIOD_2US, |
| + VOW_REFILL_PERIOD_4US, |
| + VOW_REFILL_PERIOD_8US, |
| + VOW_REFILL_PERIOD_16US, |
| + VOW_REFILL_PERIOD_32US, |
| + VOW_REFILL_PERIOD_64US, |
| + VOW_REFILL_PERIOD_128US |
| +}; |
| + |
| +/* Default DRR airtime quantum of each level */ |
| +enum { |
| + VOW_DRR_QUANTUM_L0 = 6, |
| + VOW_DRR_QUANTUM_L1 = 12, |
| + VOW_DRR_QUANTUM_L2 = 16, |
| + VOW_DRR_QUANTUM_L3 = 20, |
| + VOW_DRR_QUANTUM_L4 = 24, |
| + VOW_DRR_QUANTUM_L5 = 28, |
| + VOW_DRR_QUANTUM_L6 = 32, |
| + VOW_DRR_QUANTUM_L7 = 36 |
| +}; |
| + |
| +enum { |
| + VOW_DRR_QUANTUM_IDX0, |
| + VOW_DRR_QUANTUM_IDX1, |
| + VOW_DRR_QUANTUM_IDX2, |
| + VOW_DRR_QUANTUM_IDX3, |
| + VOW_DRR_QUANTUM_IDX4, |
| + VOW_DRR_QUANTUM_IDX5, |
| + VOW_DRR_QUANTUM_IDX6, |
| + VOW_DRR_QUANTUM_IDX7, |
| + VOW_DRR_QUANTUM_NUM |
| +}; |
| + |
| +enum { |
| + VOW_SCH_TYPE_FOLLOW_POLICY, |
| + VOW_SCH_TYPE_FOLLOW_HW |
| +}; |
| + |
| +enum { |
| + VOW_SCH_POLICY_SRR, /* Shared Round-Robin */ |
| + VOW_SCH_POLICY_WRR /* Weighted Round-Robin */ |
| +}; |
| + |
| +enum vow_drr_ctrl_id { |
| + VOW_DRR_CTRL_STA_ALL, |
| + VOW_DRR_CTRL_STA_BSS_GROUP, |
| + VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND = 0x10, |
| + VOW_DRR_CTRL_AIRTIME_QUANTUM_ALL = 0x28, |
| + VOW_DRR_CTRL_STA_PAUSE = 0x30 |
| +}; |
| + |
| +struct mt7996_vow_ctrl { |
| + bool atf_enable; |
| + bool watf_enable; |
| + u8 drr_quantum[VOW_DRR_QUANTUM_NUM]; |
| + u8 max_deficit; |
| + u8 sch_type; |
| + u8 sch_policy; |
| +}; |
| + |
| +struct mt7996_vow_sta_ctrl { |
| + bool paused; |
| + u8 bss_grp_idx; |
| + u8 drr_quantum[IEEE80211_NUM_ACS]; |
| + u64 tx_airtime; |
| + spinlock_t lock; |
| +}; |
| + |
| struct mt7996_sta { |
| struct mt76_wcid wcid; /* must be first */ |
| |
| @@ -235,6 +316,8 @@ struct mt7996_sta { |
| u8 flowid_mask; |
| struct mt7996_twt_flow flow[MT7996_MAX_STA_TWT_AGRT]; |
| } twt; |
| + |
| + struct mt7996_vow_sta_ctrl vow; |
| }; |
| |
| struct mt7996_vif { |
| @@ -494,6 +577,7 @@ struct mt7996_dev { |
| |
| u8 wtbl_size_group; |
| |
| + struct mt7996_vow_ctrl vow; |
| #ifdef CONFIG_MTK_DEBUG |
| u16 wlan_idx; |
| struct { |
| @@ -734,10 +818,12 @@ 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_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event); |
| int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable); |
| void mt7996_mcu_scs_sta_poll(struct work_struct *work); |
| int mt7996_mcu_set_band_confg(struct mt7996_phy *phy, u16 option, bool enable); |
| +int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy, struct mt7996_sta *msta, |
| + enum vow_drr_ctrl_id id); |
| +int mt7996_mcu_set_vow_feature_ctrl(struct mt7996_phy *phy); |
| |
| static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) |
| { |
| @@ -787,6 +873,14 @@ static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy) |
| return tx_chainmask | (BIT(fls(tx_chainmask)) * phy->has_aux_rx); |
| } |
| |
| +static inline bool |
| +mt7996_vow_should_enable(struct mt7996_dev *dev) |
| +{ |
| + return !wiphy_ext_feature_isset(mt76_hw(dev)->wiphy, |
| + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS) || |
| + mtk_wed_device_active(&dev->mt76.mmio.wed); |
| +} |
| + |
| void mt7996_mac_init(struct mt7996_dev *dev); |
| u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw); |
| bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask); |
| -- |
| 2.18.0 |
| |