Skip to content
Permalink
Browse files
mt76: mt7915: report tx rate directly from tx status
Report tx rate from tx status packets instead of receving periodic mcu
event. This improves flexibility, accuracy and AQL performance, and
simplifies code flow for better readability.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
  • Loading branch information
ryderlee1110 authored and intel-lab-lkp committed Jul 14, 2021
1 parent 763e8a2 commit 787e54058191f647390d63f0f608de62a3d3a3e8
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 331 deletions.
@@ -244,6 +244,8 @@ struct mt76_wcid {
struct ewma_signal rssi;
int inactive_count;

struct rate_info rate;

u16 idx;
u8 hw_key_idx;
u8 hw_key_idx2;
@@ -377,56 +377,9 @@ static int mt7915_sta_fixed_rate_set(void *data, u64 rate)
DEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL,
mt7915_sta_fixed_rate_set, "%llx\n");

static int
mt7915_sta_stats_show(struct seq_file *s, void *data)
{
struct ieee80211_sta *sta = s->private;
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
struct mt7915_sta_stats *stats = &msta->stats;
struct rate_info *rate = &stats->prob_rate;
static const char * const bw[] = {
"BW20", "BW5", "BW10", "BW40",
"BW80", "BW160", "BW_HE_RU"
};

if (!rate->legacy && !rate->flags)
return 0;

seq_puts(s, "Probing rate - ");
if (rate->flags & RATE_INFO_FLAGS_MCS)
seq_puts(s, "HT ");
else if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
seq_puts(s, "VHT ");
else if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
seq_puts(s, "HE ");
else
seq_printf(s, "Bitrate %d\n", rate->legacy);

if (rate->flags) {
seq_printf(s, "%s NSS%d MCS%d ",
bw[rate->bw], rate->nss, rate->mcs);

if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
seq_puts(s, "SGI ");
else if (rate->he_gi)
seq_puts(s, "HE GI ");

if (rate->he_dcm)
seq_puts(s, "DCM ");
}

seq_printf(s, "\nPPDU PER: %ld.%1ld%%\n",
stats->per / 10, stats->per % 10);

return 0;
}

DEFINE_SHOW_ATTRIBUTE(mt7915_sta_stats);

void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir)
{
debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate);
debugfs_create_file("stats", 0400, dir, sta, &mt7915_sta_stats_fops);
}
#endif
@@ -350,7 +350,6 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev)
mphy->chainmask = dev->chainmask & ~dev->mphy.chainmask;
mphy->antenna_mask = BIT(hweight8(mphy->chainmask)) - 1;

INIT_LIST_HEAD(&phy->stats_list);
INIT_DELAYED_WORK(&mphy->mac_work, mt7915_mac_work);

mt7915_eeprom_parse_band_config(phy);
@@ -787,7 +786,6 @@ int mt7915_register_device(struct mt7915_dev *dev)
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
INIT_LIST_HEAD(&dev->phy.stats_list);
INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work);
INIT_LIST_HEAD(&dev->sta_rc_list);
@@ -88,15 +88,14 @@ bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask)
0, 5000);
}

static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid)
static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw)
{
mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));

return MT_WTBL_LMAC_OFFS(wcid, 0);
return MT_WTBL_LMAC_OFFS(wcid, dw);
}

/* TODO: use txfree airtime info to avoid runtime accessing in the long run */
static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
{
static const u8 ac_to_tid[] = {
@@ -107,6 +106,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
};
struct ieee80211_sta *sta;
struct mt7915_sta *msta;
struct rate_info *rate;
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
LIST_HEAD(sta_poll_list);
int i;
@@ -119,8 +119,9 @@ static void mt7915_mac_sta_poll(struct mt7915_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)) {
@@ -133,7 +134,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
spin_unlock_bh(&dev->sta_poll_lock);

idx = msta->wcid.idx;
addr = mt7915_mac_wtbl_lmac_addr(dev, idx) + 20 * 4;
addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 20);

for (i = 0; i < IEEE80211_NUM_ACS; i++) {
u32 tx_last = msta->airtime_ac[i];
@@ -174,6 +175,42 @@ static void mt7915_mac_sta_poll(struct mt7915_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 = mt7915_mac_wtbl_lmac_addr(dev, idx, 7);
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 = 24 + 2 * bw;

rate->he_gi = (val & (0x3 << offs)) >> offs;
} else if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) {
if (val & BIT(12 + bw))
rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
else
rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
}
}

rcu_read_unlock();
@@ -1016,6 +1053,17 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (!wcid)
wcid = &dev->mt76.global_wcid;

if (sta) {
struct mt7915_sta *msta;

msta = (struct mt7915_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);

mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key,
@@ -1184,8 +1232,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
msta = container_of(wcid, struct mt7915_sta, wcid);
phy = msta->vif->phy;
spin_lock_bh(&dev->sta_poll_lock);
if (list_empty(&msta->stats_list))
list_add_tail(&msta->stats_list, &phy->stats_list);
if (list_empty(&msta->poll_list))
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
@@ -1221,28 +1267,109 @@ static bool
mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid,
__le32 *txs_data)
{
struct ieee80211_supported_band *sband;
struct mt7915_sta *msta;
struct mt76_dev *mdev = &dev->mt76;
struct mt76_phy *mphy;
struct ieee80211_tx_info *info;
struct sk_buff_head list;
struct rate_info rate = {};
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);
if (!skb)
goto out;

txs = le32_to_cpu(txs_data[0]);

info = IEEE80211_SKB_CB(skb);
if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK)))
if (!(txs & MT_TXS0_ACK_ERROR_MASK))
info->flags |= IEEE80211_TX_STAT_ACK;

info->status.ampdu_len = 1;
info->status.ampdu_ack_len = !!(info->flags &
IEEE80211_TX_STAT_ACK);

info->status.rates[0].idx = -1;
mt76_tx_status_skb_done(mdev, skb, &list);

if (!wcid->sta)
goto out;

msta = container_of(wcid, struct mt7915_sta, wcid);
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:
mphy = &dev->mphy;
if (wcid->ext_phy && dev->mt76.phy2)
mphy = dev->mt76.phy2;

if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
sband = &mphy->sband_5g.sband;
else
sband = &mphy->sband_2g.sband;

rate.mcs = mt76_get_rate(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:
mt76_tx_status_skb_done(mdev, skb, &list);
mt76_tx_status_unlock(mdev, &list);

return !!skb;
@@ -1737,30 +1864,6 @@ mt7915_mac_update_stats(struct mt7915_phy *phy)
}
}

static void
mt7915_mac_sta_stats_work(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
struct mt7915_sta *msta;
LIST_HEAD(list);

spin_lock_bh(&dev->sta_poll_lock);
list_splice_init(&phy->stats_list, &list);

while (!list_empty(&list)) {
msta = list_first_entry(&list, struct mt7915_sta, stats_list);
list_del_init(&msta->stats_list);
spin_unlock_bh(&dev->sta_poll_lock);

/* use MT_TX_FREE_RATE to report Tx rate for further devices */
mt7915_mcu_get_tx_rate(dev, RATE_CTRL_RU_INFO, msta->wcid.idx);

spin_lock_bh(&dev->sta_poll_lock);
}

spin_unlock_bh(&dev->sta_poll_lock);
}

void mt7915_mac_sta_rc_work(struct work_struct *work)
{
struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work);
@@ -1817,11 +1920,6 @@ void mt7915_mac_work(struct work_struct *work)
mt7915_mac_update_stats(phy);
}

if (++phy->sta_work_count == 10) {
phy->sta_work_count = 0;
mt7915_mac_sta_stats_work(phy);
}

mutex_unlock(&mphy->dev->mutex);

mt76_tx_status_check(mphy->dev, NULL, false);

0 comments on commit 787e540

Please sign in to comment.