mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 05:16:57 +00:00
wifi: mt76: mt7915: HW ATF support for mt7986+
Add hardware airtime fairness (ATF) support, using the MAC's weighted DWRR scheduler (VoW) to balance TX airtime between stations. This supplements mac80211's software airtime fairness rather than replacing it: software ATF keeps scheduling the host TX queues, while the hardware scheduler enforces fairness on the offloaded path where the host has no airtime accounting, such as when WED is active. It is enabled by default on mt7916 and newer chipsets; mt7915 is excluded. A station's TX airtime weight is taken from mac80211 through the sta_set_airtime_weight op and applied to the hardware scheduler directly; the per-AC DWRR quantum levels are derived from it on the fly, mapping the weight logarithmically onto the global hardware quantum table. ATF and WATF are enabled by default and can be toggled together at runtime through the "vow_atf" debugfs file. Signed-off-by: Lian Chen <[email protected]> Signed-off-by: Benjamin Lin <[email protected]> Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
+124
-3
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user