mirror of https://gitee.com/openkylin/linux.git
mt76: mt76x02: track approximate tx airtime for airtime fairness and survey
Estimate by calculating duration for EWMA packet size + estimated A-MPDU length on tx status events Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
b02f42f4ed
commit
355f8d00c5
|
@ -276,3 +276,51 @@ u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status,
|
|||
|
||||
return duration;
|
||||
}
|
||||
|
||||
u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info,
|
||||
int len)
|
||||
{
|
||||
struct mt76_rx_status stat = {
|
||||
.band = info->band,
|
||||
};
|
||||
u32 duration = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
|
||||
struct ieee80211_tx_rate *rate = &info->status.rates[i];
|
||||
u32 cur_duration;
|
||||
|
||||
if (rate->idx < 0 || !rate->count)
|
||||
break;
|
||||
|
||||
if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
|
||||
stat.bw = RATE_INFO_BW_80;
|
||||
else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
|
||||
stat.bw = RATE_INFO_BW_40;
|
||||
else
|
||||
stat.bw = RATE_INFO_BW_20;
|
||||
|
||||
stat.enc_flags = 0;
|
||||
if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
|
||||
stat.enc_flags |= RX_ENC_FLAG_SHORTPRE;
|
||||
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
|
||||
stat.enc_flags |= RX_ENC_FLAG_SHORT_GI;
|
||||
|
||||
stat.rate_idx = rate->idx;
|
||||
if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
|
||||
stat.encoding = RX_ENC_VHT;
|
||||
stat.rate_idx = ieee80211_rate_get_vht_mcs(rate);
|
||||
stat.nss = ieee80211_rate_get_vht_nss(rate);
|
||||
} else if (rate->flags & IEEE80211_TX_RC_MCS) {
|
||||
stat.encoding = RX_ENC_HT;
|
||||
} else {
|
||||
stat.encoding = RX_ENC_LEGACY;
|
||||
}
|
||||
|
||||
cur_duration = mt76_calc_rx_airtime(dev, &stat, len);
|
||||
duration += cur_duration * rate->count;
|
||||
}
|
||||
|
||||
return duration;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_calc_tx_airtime);
|
||||
|
|
|
@ -772,6 +772,8 @@ void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
const u8 *mac);
|
||||
void mt76_sw_scan_complete(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info,
|
||||
int len);
|
||||
|
||||
/* internal */
|
||||
void mt76_tx_free(struct mt76_dev *dev);
|
||||
|
|
|
@ -148,6 +148,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
.txwi_size = sizeof(struct mt76x02_txwi),
|
||||
.drv_flags = MT_DRV_TX_ALIGNED4_SKBS |
|
||||
MT_DRV_SW_RX_AIRTIME,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX,
|
||||
.update_survey = mt76x02_update_channel,
|
||||
.tx_prepare_skb = mt76x02_tx_prepare_skb,
|
||||
.tx_complete_skb = mt76x02_tx_complete_skb,
|
||||
|
|
|
@ -205,6 +205,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
|
|||
{
|
||||
static const struct mt76_driver_ops drv_ops = {
|
||||
.drv_flags = MT_DRV_SW_RX_AIRTIME,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX,
|
||||
.update_survey = mt76x02_update_channel,
|
||||
.tx_prepare_skb = mt76x02u_tx_prepare_skb,
|
||||
.tx_complete_skb = mt76x02u_tx_complete_skb,
|
||||
|
|
|
@ -81,6 +81,7 @@ struct mt76x02_dev {
|
|||
u8 txdone_seq;
|
||||
DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status);
|
||||
spinlock_t txstatus_fifo_lock;
|
||||
u32 tx_airtime;
|
||||
|
||||
struct sk_buff *rx_head;
|
||||
|
||||
|
|
|
@ -483,8 +483,8 @@ mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta,
|
|||
phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate);
|
||||
|
||||
if (st->pktid & MT_PACKET_ID_HAS_RATE) {
|
||||
first_rate = st->rate & ~MT_RXWI_RATE_INDEX;
|
||||
first_rate |= st->pktid & MT_RXWI_RATE_INDEX;
|
||||
first_rate = st->rate & ~MT_PKTID_RATE;
|
||||
first_rate |= st->pktid & MT_PKTID_RATE;
|
||||
|
||||
mt76x02_mac_process_tx_rate(&rate[0], first_rate,
|
||||
dev->mt76.chandef.chan->band);
|
||||
|
@ -537,10 +537,20 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
|||
struct ieee80211_tx_status status = {
|
||||
.info = &info
|
||||
};
|
||||
static const u8 ac_to_tid[4] = {
|
||||
[IEEE80211_AC_BE] = 0,
|
||||
[IEEE80211_AC_BK] = 1,
|
||||
[IEEE80211_AC_VI] = 4,
|
||||
[IEEE80211_AC_VO] = 6
|
||||
};
|
||||
struct mt76_wcid *wcid = NULL;
|
||||
struct mt76x02_sta *msta = NULL;
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
struct sk_buff_head list;
|
||||
u32 duration = 0;
|
||||
u8 cur_pktid;
|
||||
u32 ac = 0;
|
||||
int len = 0;
|
||||
|
||||
if (stat->pktid == MT_PACKET_ID_NO_ACK)
|
||||
return;
|
||||
|
@ -570,10 +580,10 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
|||
|
||||
if (!status.skb && !(stat->pktid & MT_PACKET_ID_HAS_RATE)) {
|
||||
mt76_tx_status_unlock(mdev, &list);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
if (msta && stat->aggr && !status.skb) {
|
||||
u32 stat_val, stat_cache;
|
||||
|
||||
|
@ -586,10 +596,10 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
|||
stat->wcid == msta->status.wcid && msta->n_frames < 32) {
|
||||
msta->n_frames++;
|
||||
mt76_tx_status_unlock(mdev, &list);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cur_pktid = msta->status.pktid;
|
||||
mt76x02_mac_fill_tx_status(dev, msta, status.info,
|
||||
&msta->status, msta->n_frames);
|
||||
|
||||
|
@ -597,16 +607,39 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
|||
msta->n_frames = 1;
|
||||
*update = 0;
|
||||
} else {
|
||||
cur_pktid = stat->pktid;
|
||||
mt76x02_mac_fill_tx_status(dev, msta, status.info, stat, 1);
|
||||
*update = 1;
|
||||
}
|
||||
|
||||
if (status.skb)
|
||||
if (status.skb) {
|
||||
info = *status.info;
|
||||
len = status.skb->len;
|
||||
ac = skb_get_queue_mapping(status.skb);
|
||||
mt76_tx_status_skb_done(mdev, status.skb, &list);
|
||||
} else if (msta) {
|
||||
len = status.info->status.ampdu_len * ewma_pktlen_read(&msta->pktlen);
|
||||
ac = FIELD_GET(MT_PKTID_AC, cur_pktid);
|
||||
}
|
||||
|
||||
mt76_tx_status_unlock(mdev, &list);
|
||||
|
||||
if (!status.skb)
|
||||
ieee80211_tx_status_ext(mt76_hw(dev), &status);
|
||||
|
||||
if (!len)
|
||||
goto out;
|
||||
|
||||
duration = mt76_calc_tx_airtime(&dev->mt76, &info, len);
|
||||
|
||||
spin_lock_bh(&dev->mt76.cc_lock);
|
||||
dev->tx_airtime += duration;
|
||||
spin_unlock_bh(&dev->mt76.cc_lock);
|
||||
|
||||
if (msta)
|
||||
ieee80211_sta_register_airtime(status.sta, ac_to_tid[ac], duration, 0);
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
@ -987,6 +1020,8 @@ void mt76x02_update_channel(struct mt76_dev *mdev)
|
|||
|
||||
state = mdev->chan_state;
|
||||
state->cc_busy += mt76_rr(dev, MT_CH_BUSY);
|
||||
state->cc_tx += dev->tx_airtime;
|
||||
dev->tx_airtime = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02_update_channel);
|
||||
|
||||
|
|
|
@ -23,11 +23,16 @@ struct mt76x02_tx_status {
|
|||
#define MT_VIF_WCID(_n) (254 - ((_n) & 7))
|
||||
#define MT_MAX_VIFS 8
|
||||
|
||||
#define MT_PKTID_RATE GENMASK(4, 0)
|
||||
#define MT_PKTID_AC GENMASK(6, 5)
|
||||
|
||||
struct mt76x02_vif {
|
||||
struct mt76_wcid group_wcid; /* must be first */
|
||||
u8 idx;
|
||||
};
|
||||
|
||||
DECLARE_EWMA(pktlen, 8, 8);
|
||||
|
||||
struct mt76x02_sta {
|
||||
struct mt76_wcid wcid; /* must be first */
|
||||
|
||||
|
@ -35,6 +40,7 @@ struct mt76x02_sta {
|
|||
struct mt76x02_tx_status status;
|
||||
int n_frames;
|
||||
|
||||
struct ewma_pktlen pktlen;
|
||||
};
|
||||
|
||||
#define MT_RXINFO_BA BIT(0)
|
||||
|
|
|
@ -158,7 +158,9 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
/* encode packet rate for no-skb packet id to fix up status reporting */
|
||||
if (pid == MT_PACKET_ID_NO_SKB)
|
||||
pid = MT_PACKET_ID_HAS_RATE |
|
||||
(le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX);
|
||||
(le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX) |
|
||||
FIELD_PREP(MT_PKTID_AC,
|
||||
skb_get_queue_mapping(tx_info->skb));
|
||||
|
||||
txwi->pktid = pid;
|
||||
|
||||
|
@ -171,6 +173,12 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
|
||||
tx_info->info |= MT_TXD_INFO_WIV;
|
||||
|
||||
if (sta) {
|
||||
struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
|
||||
|
||||
ewma_pktlen_add(&msta->pktlen, tx_info->skb->len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02_tx_prepare_skb);
|
||||
|
|
|
@ -104,7 +104,9 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
|
|||
/* encode packet rate for no-skb packet id to fix up status reporting */
|
||||
if (pid == MT_PACKET_ID_NO_SKB)
|
||||
pid = MT_PACKET_ID_HAS_RATE |
|
||||
(le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX);
|
||||
(le16_to_cpu(txwi->rate) & MT_PKTID_RATE) |
|
||||
FIELD_PREP(MT_PKTID_AC,
|
||||
skb_get_queue_mapping(tx_info->skb));
|
||||
|
||||
txwi->pktid = pid;
|
||||
|
||||
|
|
|
@ -264,6 +264,7 @@ int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
|||
msta->wcid.hw_key_idx = -1;
|
||||
mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
|
||||
mt76x02_mac_wcid_set_drop(dev, idx, false);
|
||||
ewma_pktlen_init(&msta->pktlen);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags);
|
||||
|
|
|
@ -23,6 +23,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
.txwi_size = sizeof(struct mt76x02_txwi),
|
||||
.drv_flags = MT_DRV_TX_ALIGNED4_SKBS |
|
||||
MT_DRV_SW_RX_AIRTIME,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX,
|
||||
.update_survey = mt76x02_update_channel,
|
||||
.tx_prepare_skb = mt76x02_tx_prepare_skb,
|
||||
.tx_complete_skb = mt76x02_tx_complete_skb,
|
||||
|
|
|
@ -26,6 +26,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
|
|||
{
|
||||
static const struct mt76_driver_ops drv_ops = {
|
||||
.drv_flags = MT_DRV_SW_RX_AIRTIME,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX,
|
||||
.update_survey = mt76x02_update_channel,
|
||||
.tx_prepare_skb = mt76x02u_tx_prepare_skb,
|
||||
.tx_complete_skb = mt76x02u_tx_complete_skb,
|
||||
|
|
Loading…
Reference in New Issue