diff --git a/mt76_connac.h b/mt76_connac.h index 2aa60789..b34354f3 100644 --- a/mt76_connac.h +++ b/mt76_connac.h @@ -78,6 +78,67 @@ enum { REPEATER_BSSID_MAX = 0x3f, }; +#define VOW_DRR_QUANTUM_NUM 8 + +/* Per-level DRR airtime quantum (unit: 256us). Halved from the hardware's + * default assignment so that scaling down from the mac80211-provided airtime + * weight maps onto the available levels. + */ +#define VOW_DRR_QUANTUM_TABLE { 3, 6, 8, 10, 12, 14, 16, 18 } + +/* Airtime token refill period; the value is the log2 of the period in us. */ +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, +}; + +/* Max airtime deficit bound (unit: 256us): generous while ATF is enabled, + * minimal when disabled. + */ +#define VOW_MAX_DEFICIT_ON 64 +#define VOW_MAX_DEFICIT_OFF 1 + +/* Layout of the per-station DRR config value (VOW_DRR_CTRL_STA_ALL). The AC + * quantum fields are in hardware (LMAC) order, i.e. AC0 = BK ... AC3 = VO. + */ +#define VOW_DRR_STA_BSS_GRP_MASK GENMASK(5, 0) +#define VOW_DRR_STA_AC0_QNTM_MASK GENMASK(10, 8) +#define VOW_DRR_STA_AC1_QNTM_MASK GENMASK(14, 12) +#define VOW_DRR_STA_AC2_QNTM_MASK GENMASK(18, 16) +#define VOW_DRR_STA_AC3_QNTM_MASK GENMASK(22, 20) + +/* A station references one of the global DWRR quantum levels per AC. The + * mac80211 airtime weight spans a wider, finer range than the eight hardware + * levels and differs from them by orders of magnitude, so map it onto a quantum + * index logarithmically, centring the default weight (256) on index 3. Voice + * and video are biased down by two and one octaves respectively, giving + * latency-sensitive traffic smaller, more frequently refilled quanta. + */ +static inline u8 mt76_connac_vow_dwrr_quantum(u16 weight, u8 ac) +{ + u32 w = weight; + int idx; + + switch (ac) { + case IEEE80211_AC_VO: + w /= 4; + break; + case IEEE80211_AC_VI: + w /= 2; + break; + } + + idx = 3 + ilog2(w) - ilog2(IEEE80211_DEFAULT_AIRTIME_WEIGHT); + + return clamp(idx, 0, VOW_DRR_QUANTUM_NUM - 1); +} + struct mt76_connac_reg_map { u32 phys; u32 maps; diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h index ea2fc6cc..1e81c02a 100644 --- a/mt76_connac_mcu.h +++ b/mt76_connac_mcu.h @@ -1241,6 +1241,7 @@ enum { MCU_EXT_CMD_THERMAL_CTRL = 0x2c, MCU_EXT_CMD_WTBL_UPDATE = 0x32, MCU_EXT_CMD_SET_DRR_CTRL = 0x36, + MCU_EXT_CMD_SET_FEATURE_CTRL = 0x38, MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, MCU_EXT_CMD_ATE_CTRL = 0x3d, MCU_EXT_CMD_PROTECT_CTRL = 0x3e, @@ -1250,6 +1251,7 @@ enum { MCU_EXT_CMD_MUAR_UPDATE = 0x48, MCU_EXT_CMD_BCN_OFFLOAD = 0x49, MCU_EXT_CMD_RX_AIRTIME_CTRL = 0x4a, + MCU_EXT_CMD_AT_PROC_MODULE = 0x4b, MCU_EXT_CMD_SET_RX_PATH = 0x4e, MCU_EXT_CMD_EFUSE_FREE_BLOCK = 0x4f, MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c index 30586fb4..b2c8256d 100644 --- a/mt7915/debugfs.c +++ b/mt7915/debugfs.c @@ -208,6 +208,29 @@ static const struct file_operations mt7915_sys_recovery_ops = { .llseek = default_llseek, }; +static int mt7915_vow_atf_set(void *data, u64 val) +{ + struct mt7915_dev *dev = data; + + dev->vow_atf_en = !!val; + mt7915_mcu_set_vow_feature_ctrl(dev); + + return mt7915_mcu_set_vow_drr_ctrl(dev, NULL, + VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND, 0); +} + +static int mt7915_vow_atf_get(void *data, u64 *val) +{ + struct mt7915_dev *dev = data; + + *val = dev->vow_atf_en; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_vow_atf, mt7915_vow_atf_get, mt7915_vow_atf_set, + "%lld\n"); + static int mt7915_radar_trigger(void *data, u64 val) { @@ -1323,6 +1346,8 @@ int mt7915_init_debugfs(struct mt7915_phy *phy) debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir, mt7915_twt_stats); debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval); + if (!is_mt7915(&dev->mt76)) + debugfs_create_file("vow_atf", 0600, dir, dev, &fops_vow_atf); if (!dev->dbdc_support || phy->mt76->band_idx) { debugfs_create_u32("dfs_hw_pattern", 0400, dir, diff --git a/mt7915/init.c b/mt7915/init.c index 04788db0..617574c1 100644 --- a/mt7915/init.c +++ b/mt7915/init.c @@ -620,6 +620,33 @@ mt7915_init_led_mux(struct mt7915_dev *dev) } } +void mt7915_vow_init(struct mt7915_dev *dev) +{ + dev->vow_atf_en = true; + + mt7915_mcu_set_vow_drr_ctrl(dev, NULL, VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND, 0); + mt7915_mcu_set_vow_drr_ctrl(dev, NULL, VOW_DRR_CTRL_AIRTIME_QUANTUM_ALL, 0); + mt7915_mcu_set_vow_feature_ctrl(dev); +} + +/* Assignment of BSS group index aligns FW. + * 0: Band 0 - BSS 0 + * 4: Band 1 - BSS 0 + * 9..23: Band 0 - BSS 0x11..0x1f + * 25..39: Band 1 - BSS 0x11..0x1f + */ +u8 mt7915_vow_sta_bss_grp(struct mt76_vif_link *mvif) +{ + const u8 hw_bssid_num = HW_BSSID_MAX + 1; + + if (mvif->omac_idx < hw_bssid_num) + return mvif->band_idx * hw_bssid_num + mvif->omac_idx; + + /* Extended BSS */ + return hw_bssid_num * 2 + (mvif->band_idx == 0 ? 1 : 17) + + mvif->omac_idx - EXT_BSSID_1; +} + void mt7915_mac_init(struct mt7915_dev *dev) { int i; @@ -647,6 +674,9 @@ void mt7915_mac_init(struct mt7915_dev *dev) mt7915_mac_init_band(dev, i); mt7915_init_led_mux(dev); + + if (!is_mt7915(&dev->mt76)) + mt7915_vow_init(dev); } int mt7915_txbf_init(struct mt7915_dev *dev) diff --git a/mt7915/main.c b/mt7915/main.c index 8fb0ee33..42c548a3 100644 --- a/mt7915/main.c +++ b/mt7915/main.c @@ -280,6 +280,9 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, out: mutex_unlock(&dev->mt76.mutex); + if (!is_mt7915(&dev->mt76)) + mt7915_mcu_set_vow_band(dev, mvif); + return ret; } @@ -739,6 +742,13 @@ mt7915_channel_switch_beacon(struct ieee80211_hw *hw, mutex_unlock(&dev->mt76.mutex); } +static void +mt7915_sta_vow_set_airtime_weight(struct mt7915_dev *dev, + struct mt7915_sta *msta, u16 weight) +{ + mt7915_mcu_set_vow_drr_ctrl(dev, msta, VOW_DRR_CTRL_STA_ALL, weight); +} + int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { @@ -776,6 +786,12 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, true); + if (!is_mt7915(&dev->mt76)) { + mt7915_mcu_set_vow_drr_ctrl(dev, msta, VOW_DRR_CTRL_STA_PAUSE, 0); + mt7915_sta_vow_set_airtime_weight(dev, msta, + IEEE80211_DEFAULT_AIRTIME_WEIGHT); + } + return 0; } @@ -1355,6 +1371,19 @@ static void mt7915_sta_set_decap_offload(struct ieee80211_hw *hw, mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta); } +static void mt7915_sta_set_airtime_weight(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 weight) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + + if (is_mt7915(&dev->mt76) || !msta->wcid.sta) + return; + + mt7915_sta_vow_set_airtime_weight(dev, msta, weight); +} + static int mt7915_sta_set_txpwr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -1855,6 +1884,7 @@ const struct ieee80211_ops mt7915_ops = { .sta_set_txpwr = mt7915_sta_set_txpwr, .sta_set_4addr = mt7915_sta_set_4addr, .sta_set_decap_offload = mt7915_sta_set_decap_offload, + .sta_set_airtime_weight = mt7915_sta_set_airtime_weight, .add_twt_setup = mt7915_mac_add_twt_setup, .twt_teardown_request = mt7915_twt_teardown_request, .set_frag_threshold = mt7915_set_frag_threshold, diff --git a/mt7915/mcu.c b/mt7915/mcu.c index 05c635af..d571b713 100644 --- a/mt7915/mcu.c +++ b/mt7915/mcu.c @@ -1702,7 +1702,7 @@ mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, { #define MT_STA_BSS_GROUP 1 struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct mt7915_sta *msta; + struct mt7915_sta *msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; struct { __le32 action; u8 wlan_idx_lo; @@ -1713,10 +1713,11 @@ mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, u8 rsv1[8]; } __packed req = { .action = cpu_to_le32(MT_STA_BSS_GROUP), - .val = cpu_to_le32(mvif->mt76.idx % 16), + .val = cpu_to_le32(is_mt7915(&dev->mt76) ? + mvif->mt76.idx % 16 : + mt7915_vow_sta_bss_grp(&mvif->mt76)), }; - msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; req.wlan_idx_lo = to_wcid_lo(msta->wcid.idx); req.wlan_idx_hi = to_wcid_hi(msta->wcid.idx); @@ -3656,6 +3657,126 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) &req, sizeof(req), false); } +int mt7915_mcu_set_vow_drr_ctrl(struct mt7915_dev *dev, struct mt7915_sta *msta, + enum vow_drr_ctrl_id id, u16 weight) +{ + u32 setting = 0; + struct { + __le32 action; + u8 wlan_idx_lo; + u8 status; + u8 wlan_idx_hi; + u8 rsv0[5]; + union { + __le32 com_value; + struct { + u8 air_time_quantum[VOW_DRR_QUANTUM_NUM]; + } air_time_quantum_all; + } air_time_ctrl; + } __packed req = { + .action = cpu_to_le32(id), + .wlan_idx_lo = msta ? to_wcid_lo(msta->wcid.idx) : 0, + .wlan_idx_hi = msta ? to_wcid_hi(msta->wcid.idx) : 0, + }; + + switch (id) { + case VOW_DRR_CTRL_STA_ALL: + setting |= FIELD_PREP(VOW_DRR_STA_BSS_GRP_MASK, + mt7915_vow_sta_bss_grp(&msta->vif->mt76)); + setting |= FIELD_PREP(VOW_DRR_STA_AC0_QNTM_MASK, + mt76_connac_vow_dwrr_quantum(weight, IEEE80211_AC_BK)); + setting |= FIELD_PREP(VOW_DRR_STA_AC1_QNTM_MASK, + mt76_connac_vow_dwrr_quantum(weight, IEEE80211_AC_BE)); + setting |= FIELD_PREP(VOW_DRR_STA_AC2_QNTM_MASK, + mt76_connac_vow_dwrr_quantum(weight, IEEE80211_AC_VI)); + setting |= FIELD_PREP(VOW_DRR_STA_AC3_QNTM_MASK, + mt76_connac_vow_dwrr_quantum(weight, IEEE80211_AC_VO)); + setting |= UMAC_BWC_GROUP_MIN << 24; + req.air_time_ctrl.com_value = cpu_to_le32(setting); + break; + case VOW_DRR_CTRL_STA_PAUSE: + /* com_value 0 keeps the station unpaused */ + break; + case VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND: + req.air_time_ctrl.com_value = + cpu_to_le32(dev->vow_atf_en ? VOW_MAX_DEFICIT_ON : + VOW_MAX_DEFICIT_OFF); + break; + case VOW_DRR_CTRL_AIRTIME_QUANTUM_ALL: { + static const u8 quantum[VOW_DRR_QUANTUM_NUM] = VOW_DRR_QUANTUM_TABLE; + + memcpy(req.air_time_ctrl.air_time_quantum_all.air_time_quantum, + quantum, sizeof(quantum)); + break; + } + default: + break; + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), + &req, sizeof(req), false); +} + +int mt7915_mcu_set_vow_feature_ctrl(struct mt7915_dev *dev) +{ + u16 value = 0; + struct vow_feature_ctrl { + __le16 bss_flag; + __le16 vow_ctrl_flag; + __le16 bss_value[9]; + __le16 vow_ctrl_val; + __le16 time_token_value[2]; + __le16 length_token_value[2]; + __le32 tx_ctrl; + __le32 sch_ctrl; + } __packed req = { + .bss_flag = cpu_to_le16(0xffff), + .vow_ctrl_flag = cpu_to_le16(0xf231), + .bss_value[0] = cpu_to_le16(0xffff), + .bss_value[2] = cpu_to_le16(0xffff), + .bss_value[8] = cpu_to_le16(0xffff), + .time_token_value[0] = cpu_to_le16(0xffff), + }; + + value |= VOW_REFILL_PERIOD_32US; + value |= 1 << 4; + value |= 1 << 5; + value |= dev->vow_atf_en << 9; /* WATF enable */ + value |= 1 << 12; + value |= dev->vow_atf_en << 13; /* ATF enable */ + value |= 1 << 14; + req.vow_ctrl_val = cpu_to_le16(value); + + if (dev->vow_atf_en) + req.tx_ctrl = cpu_to_le32(0x6bf69e1f); + + req.sch_ctrl = cpu_to_le32(1 << 6); + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_FEATURE_CTRL), + &req, sizeof(req), false); +} + +int mt7915_mcu_set_vow_band(struct mt7915_dev *dev, struct mt7915_vif *mvif) +{ + struct module_ctrl { + __le16 action; + __le16 sub_action; + __le32 rsv1[5]; + u8 rsv2[72]; + u8 group_idx; + u8 band_idx; + u8 rsv3[2]; + } __packed req = { + .action = cpu_to_le16(0x1), + .sub_action = cpu_to_le16(0x4), + .group_idx = mt7915_vow_sta_bss_grp(&mvif->mt76), + .band_idx = mvif->mt76.band_idx, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(AT_PROC_MODULE), + &req, sizeof(req), false); +} + int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action) { struct { diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h index b2fc7138..f88ba909 100644 --- a/mt7915/mt7915.h +++ b/mt7915/mt7915.h @@ -134,6 +134,16 @@ struct mt7915_twt_flow { DECLARE_EWMA(avg_signal, 10, 8) +#define UMAC_BWC_GROUP_MIN 40 + +enum vow_drr_ctrl_id { + VOW_DRR_CTRL_STA_ALL = 0x00, + VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND = 0x10, + VOW_DRR_CTRL_AIRTIME_QUANTUM_ALL = 0x28, + VOW_DRR_CTRL_STA_PAUSE = 0x30, +}; + + struct mt7915_sta { struct mt76_wcid wcid; /* must be first */ @@ -323,6 +333,8 @@ struct mt7915_dev { u8 n_agrt; } twt; + bool vow_atf_en; + struct reset_control *rstc; void __iomem *dcm; void __iomem *sku; @@ -509,6 +521,12 @@ int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable, int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode, u8 en); int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band); +int mt7915_mcu_set_vow_drr_ctrl(struct mt7915_dev *dev, struct mt7915_sta *msta, + enum vow_drr_ctrl_id id, u16 weight); +int mt7915_mcu_set_vow_feature_ctrl(struct mt7915_dev *dev); +int mt7915_mcu_set_vow_band(struct mt7915_dev *dev, struct mt7915_vif *mvif); +void mt7915_vow_init(struct mt7915_dev *dev); +u8 mt7915_vow_sta_bss_grp(struct mt76_vif_link *mvif); int mt7915_mcu_set_sku_en(struct mt7915_phy *phy); int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy); int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len,