mt76: mt7921: report tx rate directly from tx status
Report tx rate from tx status packets instead of receiving periodic mcu event. This improves flexibility, accuracy and AQL performance, and simplifies code flow for better readability. Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
273910ac43
commit
970ab80ef9
|
@ -61,6 +61,7 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
|
|||
struct mt7921_sta *msta;
|
||||
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
|
||||
LIST_HEAD(sta_poll_list);
|
||||
struct rate_info *rate;
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
|
@ -71,8 +72,9 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
|
|||
|
||||
while (true) {
|
||||
bool clear = false;
|
||||
u32 addr;
|
||||
u32 addr, val;
|
||||
u16 idx;
|
||||
u8 bw;
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (list_empty(&sta_poll_list)) {
|
||||
|
@ -85,7 +87,7 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
|
|||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
idx = msta->wcid.idx;
|
||||
addr = MT_WTBL_LMAC_OFFS(idx, 0) + 20 * 4;
|
||||
addr = mt7921_mac_wtbl_lmac_addr(idx, MT_WTBL_AC0_CTT_OFFSET);
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
u32 tx_last = msta->airtime_ac[i];
|
||||
|
@ -126,6 +128,43 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
|
|||
ieee80211_sta_register_airtime(sta, tid, tx_cur,
|
||||
rx_cur);
|
||||
}
|
||||
|
||||
/* We don't support reading GI info from txs packets.
|
||||
* For accurate tx status reporting and AQL improvement,
|
||||
* we need to make sure that flags match so polling GI
|
||||
* from per-sta counters directly.
|
||||
*/
|
||||
rate = &msta->wcid.rate;
|
||||
addr = mt7921_mac_wtbl_lmac_addr(idx,
|
||||
MT_WTBL_TXRX_CAP_RATE_OFFSET);
|
||||
val = mt76_rr(dev, addr);
|
||||
|
||||
switch (rate->bw) {
|
||||
case RATE_INFO_BW_160:
|
||||
bw = IEEE80211_STA_RX_BW_160;
|
||||
break;
|
||||
case RATE_INFO_BW_80:
|
||||
bw = IEEE80211_STA_RX_BW_80;
|
||||
break;
|
||||
case RATE_INFO_BW_40:
|
||||
bw = IEEE80211_STA_RX_BW_40;
|
||||
break;
|
||||
default:
|
||||
bw = IEEE80211_STA_RX_BW_20;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
|
||||
u8 offs = MT_WTBL_TXRX_RATE_G2_HE + 2 * bw;
|
||||
|
||||
rate->he_gi = (val & (0x3 << offs)) >> offs;
|
||||
} else if (rate->flags &
|
||||
(RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
|
||||
if (val & BIT(MT_WTBL_TXRX_RATE_G2 + bw))
|
||||
rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
else
|
||||
rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
@ -783,24 +822,6 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi,
|
|||
txwi[7] |= cpu_to_le32(val);
|
||||
}
|
||||
|
||||
static void mt7921_update_txs(struct mt76_wcid *wcid, __le32 *txwi)
|
||||
{
|
||||
struct mt7921_sta *msta = container_of(wcid, struct mt7921_sta, wcid);
|
||||
u32 pid, frame_type;
|
||||
|
||||
frame_type = FIELD_GET(MT_TXD2_FRAME_TYPE, le32_to_cpu(txwi[2]));
|
||||
if (!(frame_type & (IEEE80211_FTYPE_DATA >> 2)))
|
||||
return;
|
||||
|
||||
if (time_is_after_eq_jiffies(msta->next_txs_ts))
|
||||
return;
|
||||
|
||||
msta->next_txs_ts = jiffies + msecs_to_jiffies(250);
|
||||
pid = mt76_get_next_pkt_id(wcid);
|
||||
txwi[5] |= cpu_to_le32(MT_TXD5_TX_STATUS_MCU |
|
||||
FIELD_PREP(MT_TXD5_PID, pid));
|
||||
}
|
||||
|
||||
static void
|
||||
mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
|
||||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
|
@ -885,8 +906,6 @@ mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
|
|||
txwi[6] |= cpu_to_le32(val);
|
||||
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
|
||||
}
|
||||
|
||||
mt7921_update_txs(wcid, txwi);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -928,10 +947,9 @@ int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
|
||||
struct ieee80211_key_conf *key = info->control.hw_key;
|
||||
struct mt76_tx_cb *cb = mt76_tx_skb_cb(tx_info->skb);
|
||||
struct mt76_txwi_cache *t;
|
||||
struct mt7921_txp_common *txp;
|
||||
int id;
|
||||
int id, pid;
|
||||
u8 *txwi = (u8 *)txwi_ptr;
|
||||
|
||||
if (unlikely(tx_info->skb->len <= ETH_HLEN))
|
||||
|
@ -940,8 +958,6 @@ int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
if (!wcid)
|
||||
wcid = &dev->mt76.global_wcid;
|
||||
|
||||
cb->wcid = wcid->idx;
|
||||
|
||||
t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
|
||||
t->skb = tx_info->skb;
|
||||
|
||||
|
@ -949,8 +965,18 @@ int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||
if (id < 0)
|
||||
return id;
|
||||
|
||||
if (sta) {
|
||||
struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
|
||||
|
||||
if (time_after(jiffies, msta->stats.jiffies + HZ / 4)) {
|
||||
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
msta->stats.jiffies = jiffies;
|
||||
}
|
||||
}
|
||||
|
||||
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
|
||||
mt7921_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
|
||||
MT_PACKET_ID_NO_SKB, false);
|
||||
pid, false);
|
||||
|
||||
txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE);
|
||||
memset(txp, 0, sizeof(struct mt7921_txp_common));
|
||||
|
@ -986,42 +1012,6 @@ mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
|
|||
ieee80211_start_tx_ba_session(sta, tid, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7921_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
|
||||
struct ieee80211_sta *sta, bool clear_status,
|
||||
struct list_head *free_list)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_status status = {
|
||||
.sta = sta,
|
||||
.info = info,
|
||||
.skb = skb,
|
||||
.free_list = free_list,
|
||||
};
|
||||
struct ieee80211_hw *hw;
|
||||
|
||||
if (sta) {
|
||||
struct mt7921_sta *msta;
|
||||
|
||||
msta = (struct mt7921_sta *)sta->drv_priv;
|
||||
status.rate = &msta->stats.tx_rate;
|
||||
}
|
||||
|
||||
hw = mt76_tx_status_get_hw(mdev, skb);
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_AMPDU)
|
||||
info->flags |= IEEE80211_TX_STAT_AMPDU;
|
||||
|
||||
if (clear_status)
|
||||
ieee80211_tx_info_clear_status(info);
|
||||
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
||||
info->status.tx_time = 0;
|
||||
ieee80211_tx_status_ext(hw, &status);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
|
||||
{
|
||||
|
@ -1059,31 +1049,27 @@ mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t,
|
|||
struct list_head *free_list)
|
||||
{
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
struct ieee80211_tx_info *info;
|
||||
__le32 *txwi;
|
||||
u16 wcid_idx;
|
||||
|
||||
mt7921_txp_skb_unmap(mdev, t);
|
||||
if (!t->skb)
|
||||
goto out;
|
||||
|
||||
if (!sta)
|
||||
goto out;
|
||||
|
||||
txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
|
||||
if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
mt7921_tx_check_aggr(sta, txwi);
|
||||
|
||||
info = IEEE80211_SKB_CB(t->skb);
|
||||
if (!info->tx_time_est) {
|
||||
if (sta) {
|
||||
struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
|
||||
int pending;
|
||||
|
||||
pending = atomic_dec_return(&wcid->non_aql_packets);
|
||||
if (pending < 0)
|
||||
atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
|
||||
if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
mt7921_tx_check_aggr(sta, txwi);
|
||||
|
||||
wcid_idx = wcid->idx;
|
||||
} else {
|
||||
wcid_idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1]));
|
||||
}
|
||||
|
||||
mt7921_tx_complete_status(mdev, t->skb, sta, clear_status, free_list);
|
||||
__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
|
||||
|
||||
out:
|
||||
t->skb = NULL;
|
||||
mt76_put_txwi(mdev, t);
|
||||
|
@ -1169,10 +1155,14 @@ static bool
|
|||
mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid,
|
||||
__le32 *txs_data)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct rate_info rate = {};
|
||||
struct sk_buff_head list;
|
||||
struct sk_buff *skb;
|
||||
bool cck = false;
|
||||
u32 txrate, txs;
|
||||
|
||||
mt76_tx_status_lock(mdev, &list);
|
||||
skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);
|
||||
|
@ -1180,7 +1170,8 @@ mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid,
|
|||
goto out;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK)))
|
||||
txs = le32_to_cpu(txs_data[0]);
|
||||
if (!(txs & MT_TXS0_ACK_ERROR_MASK))
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
||||
info->status.ampdu_len = 1;
|
||||
|
@ -1188,9 +1179,78 @@ mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid,
|
|||
IEEE80211_TX_STAT_ACK);
|
||||
|
||||
info->status.rates[0].idx = -1;
|
||||
mt76_tx_status_skb_done(mdev, skb, &list);
|
||||
|
||||
if (!wcid->sta)
|
||||
goto out;
|
||||
|
||||
txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
|
||||
|
||||
rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
|
||||
rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
|
||||
|
||||
switch (FIELD_GET(MT_TX_RATE_MODE, txrate)) {
|
||||
case MT_PHY_TYPE_CCK:
|
||||
cck = true;
|
||||
fallthrough;
|
||||
case MT_PHY_TYPE_OFDM:
|
||||
if (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ)
|
||||
sband = &dev->mphy.sband_5g.sband;
|
||||
else
|
||||
sband = &dev->mphy.sband_2g.sband;
|
||||
|
||||
rate.mcs = mt76_get_rate(dev->mphy.dev, sband, rate.mcs, cck);
|
||||
rate.legacy = sband->bitrates[rate.mcs].bitrate;
|
||||
break;
|
||||
case MT_PHY_TYPE_HT:
|
||||
case MT_PHY_TYPE_HT_GF:
|
||||
rate.mcs += (rate.nss - 1) * 8;
|
||||
if (rate.mcs > 31)
|
||||
goto out;
|
||||
|
||||
rate.flags = RATE_INFO_FLAGS_MCS;
|
||||
if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
|
||||
rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
break;
|
||||
case MT_PHY_TYPE_VHT:
|
||||
if (rate.mcs > 9)
|
||||
goto out;
|
||||
|
||||
rate.flags = RATE_INFO_FLAGS_VHT_MCS;
|
||||
break;
|
||||
case MT_PHY_TYPE_HE_SU:
|
||||
case MT_PHY_TYPE_HE_EXT_SU:
|
||||
case MT_PHY_TYPE_HE_TB:
|
||||
case MT_PHY_TYPE_HE_MU:
|
||||
if (rate.mcs > 11)
|
||||
goto out;
|
||||
|
||||
rate.he_gi = wcid->rate.he_gi;
|
||||
rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
|
||||
rate.flags = RATE_INFO_FLAGS_HE_MCS;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (FIELD_GET(MT_TXS0_BW, txs)) {
|
||||
case IEEE80211_STA_RX_BW_160:
|
||||
rate.bw = RATE_INFO_BW_160;
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_80:
|
||||
rate.bw = RATE_INFO_BW_80;
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_40:
|
||||
rate.bw = RATE_INFO_BW_40;
|
||||
break;
|
||||
default:
|
||||
rate.bw = RATE_INFO_BW_20;
|
||||
break;
|
||||
}
|
||||
wcid->rate = rate;
|
||||
|
||||
out:
|
||||
if (skb)
|
||||
mt76_tx_status_skb_done(mdev, skb, &list);
|
||||
mt76_tx_status_unlock(mdev, &list);
|
||||
|
||||
return !!skb;
|
||||
|
@ -1301,15 +1361,8 @@ void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
|
|||
e->skb = t ? t->skb : NULL;
|
||||
}
|
||||
|
||||
if (e->skb) {
|
||||
struct mt76_tx_cb *cb = mt76_tx_skb_cb(e->skb);
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]);
|
||||
|
||||
mt7921_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0,
|
||||
NULL);
|
||||
}
|
||||
if (e->skb)
|
||||
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
|
||||
}
|
||||
|
||||
void mt7921_mac_reset_counters(struct mt7921_phy *phy)
|
||||
|
|
|
@ -317,8 +317,10 @@ struct mt7921_tx_free {
|
|||
/* will support this field in further revision */
|
||||
#define MT_TX_FREE_RATE GENMASK(13, 0)
|
||||
|
||||
#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16)
|
||||
#define MT_TXS0_BW GENMASK(30, 29)
|
||||
#define MT_TXS0_TXS_FORMAT GENMASK(24, 23)
|
||||
#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16)
|
||||
#define MT_TXS0_TX_RATE GENMASK(13, 0)
|
||||
|
||||
#define MT_TXS2_WCID GENMASK(25, 16)
|
||||
|
||||
|
@ -365,4 +367,15 @@ struct mt7921_txp_common {
|
|||
};
|
||||
};
|
||||
|
||||
#define MT_WTBL_TXRX_CAP_RATE_OFFSET 7
|
||||
#define MT_WTBL_TXRX_RATE_G2_HE 24
|
||||
#define MT_WTBL_TXRX_RATE_G2 12
|
||||
|
||||
#define MT_WTBL_AC0_CTT_OFFSET 20
|
||||
|
||||
static inline u32 mt7921_mac_wtbl_lmac_addr(int idx, u8 offset)
|
||||
{
|
||||
return MT_WTBL_LMAC_OFFS(idx, 0) + offset * 4;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1012,22 +1012,22 @@ static void mt7921_sta_statistics(struct ieee80211_hw *hw,
|
|||
struct station_info *sinfo)
|
||||
{
|
||||
struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
|
||||
struct mt7921_sta_stats *stats = &msta->stats;
|
||||
struct rate_info *txrate = &msta->wcid.rate;
|
||||
|
||||
if (!stats->tx_rate.legacy && !stats->tx_rate.flags)
|
||||
if (!txrate->legacy && !txrate->flags)
|
||||
return;
|
||||
|
||||
if (stats->tx_rate.legacy) {
|
||||
sinfo->txrate.legacy = stats->tx_rate.legacy;
|
||||
if (txrate->legacy) {
|
||||
sinfo->txrate.legacy = txrate->legacy;
|
||||
} else {
|
||||
sinfo->txrate.mcs = stats->tx_rate.mcs;
|
||||
sinfo->txrate.nss = stats->tx_rate.nss;
|
||||
sinfo->txrate.bw = stats->tx_rate.bw;
|
||||
sinfo->txrate.he_gi = stats->tx_rate.he_gi;
|
||||
sinfo->txrate.he_dcm = stats->tx_rate.he_dcm;
|
||||
sinfo->txrate.he_ru_alloc = stats->tx_rate.he_ru_alloc;
|
||||
sinfo->txrate.mcs = txrate->mcs;
|
||||
sinfo->txrate.nss = txrate->nss;
|
||||
sinfo->txrate.bw = txrate->bw;
|
||||
sinfo->txrate.he_gi = txrate->he_gi;
|
||||
sinfo->txrate.he_dcm = txrate->he_dcm;
|
||||
sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
|
||||
}
|
||||
sinfo->txrate.flags = stats->tx_rate.flags;
|
||||
sinfo->txrate.flags = txrate->flags;
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
|
||||
}
|
||||
|
||||
|
|
|
@ -93,8 +93,6 @@ struct mt7921_sta {
|
|||
unsigned long ampdu_state;
|
||||
|
||||
struct mt7921_sta_key_conf bip;
|
||||
|
||||
unsigned long next_txs_ts;
|
||||
};
|
||||
|
||||
DECLARE_EWMA(rssi, 10, 8);
|
||||
|
|
Loading…
Reference in New Issue