Skip to content

Commit

Permalink
wifi: mt76: add PPDU based TxS support for WED device
Browse files Browse the repository at this point in the history
Given that there's no data coming from network stack for binding flows,
hence driver counts and reports station's statistics directly through
NL80211_STA_INFO_* based on active PPDU based TxS for offloading data.

Apart from that, WA firmware and its offloading engine (SDO) have hardcoded
"2" as PID, so we introduce MT_PACKET_ID_WED to differentiate WED reporting.

Note that PPDU format TxS is mutually exclusive with MT_TXD5_TX_STATUS_HOST.

Co-developed-by: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
Signed-off-by: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
  • Loading branch information
Ryder Lee authored and Felix Fietkau committed Sep 15, 2022
1 parent dc87752 commit 43eaa36
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 32 deletions.
7 changes: 6 additions & 1 deletion drivers/net/wireless/mediatek/mt76/mt76.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,10 @@ struct mt76_sta_stats {
u64 tx_bw[4]; /* 20, 40, 80, 160 */
u64 tx_nss[4]; /* 1, 2, 3, 4 */
u64 tx_mcs[16]; /* mcs idx */
u64 tx_bytes;
u32 tx_packets;
u32 tx_retries;
u32 tx_failed;
};

enum mt76_wcid_flags {
Expand Down Expand Up @@ -364,7 +368,8 @@ struct mt76_rx_tid {
#define MT_PACKET_ID_MASK GENMASK(6, 0)
#define MT_PACKET_ID_NO_ACK 0
#define MT_PACKET_ID_NO_SKB 1
#define MT_PACKET_ID_FIRST 2
#define MT_PACKET_ID_WED 2
#define MT_PACKET_ID_FIRST 3
#define MT_PACKET_ID_HAS_RATE BIT(7)
/* This is timer for when to give up when waiting for TXS callback,
* with starting time being the time at which the DMA_DONE callback
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt76_connac.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
enum mt76_txq_id qid, u32 changed);
bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,
__le32 *txs_data);
bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
int pid, __le32 *txs_data);
void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
Expand Down
8 changes: 8 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ enum {

#define MT_TXS4_TIMESTAMP GENMASK(31, 0)

/* PPDU based TXS */
#define MT_TXS5_MPDU_TX_BYTE GENMASK(22, 0)
#define MT_TXS5_MPDU_TX_CNT GENMASK(31, 23)

#define MT_TXS6_MPDU_FAIL_CNT GENMASK(31, 23)

#define MT_TXS7_MPDU_RETRY_CNT GENMASK(31, 23)

/* RXD DW1 */
#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0)
#define MT_RXD1_NORMAL_GROUP_1 BIT(11)
Expand Down
74 changes: 48 additions & 26 deletions drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,10 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;
q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));

/* counting non-offloading skbs */
wcid->stats.tx_bytes += skb->len;
wcid->stats.tx_packets++;
}

val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
Expand Down Expand Up @@ -550,35 +554,29 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
}
EXPORT_SYMBOL_GPL(mt76_connac2_mac_write_txwi);

bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
int pid, __le32 *txs_data)
bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,
__le32 *txs_data)
{
struct mt76_sta_stats *stats = &wcid->stats;
struct ieee80211_supported_band *sband;
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, mode;

mt76_tx_status_lock(dev, &list);
skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
if (!skb)
goto out;

txs = le32_to_cpu(txs_data[0]);

info = IEEE80211_SKB_CB(skb);
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;
/* PPDU based reporting */
if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) {
stats->tx_bytes +=
le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE);
stats->tx_packets +=
le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_CNT);
stats->tx_failed +=
le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT);
stats->tx_retries +=
le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_CNT);
}

txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);

Expand Down Expand Up @@ -613,15 +611,15 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
case MT_PHY_TYPE_HT:
case MT_PHY_TYPE_HT_GF:
if (rate.mcs > 31)
goto out;
return false;

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;
return false;

rate.flags = RATE_INFO_FLAGS_VHT_MCS;
break;
Expand All @@ -630,14 +628,14 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
case MT_PHY_TYPE_HE_TB:
case MT_PHY_TYPE_HE_MU:
if (rate.mcs > 11)
goto out;
return false;

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;
return false;
}

stats->tx_mode[mode]++;
Expand All @@ -662,10 +660,34 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
}
wcid->rate = rate;

out:
if (skb)
mt76_tx_status_skb_done(dev, skb, &list);
return true;
}
EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_txs);

bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
int pid, __le32 *txs_data)
{
struct sk_buff_head list;
struct sk_buff *skb;

mt76_tx_status_lock(dev, &list);
skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
if (skb) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
bool noacked = !(info->flags & IEEE80211_TX_STAT_ACK);

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

info->status.ampdu_len = 1;
info->status.ampdu_ack_len = !noacked;
info->status.rates[0].idx = -1;

wcid->stats.tx_failed += noacked;

mt76_connac2_mac_fill_txs(dev, wcid, txs_data);
mt76_tx_status_skb_done(dev, skb, &list);
}
mt76_tx_status_unlock(dev, &list);

return !!skb;
Expand Down
14 changes: 9 additions & 5 deletions drivers/net/wireless/mediatek/mt76/mt7915/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
/*
* 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
* we need to make sure that flags match so polling GI
* from per-sta counters directly.
*/
rate = &msta->wcid.rate;
Expand Down Expand Up @@ -1001,7 +1001,7 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
pid = le32_get_bits(txs_data[3], MT_TXS3_PID);

if (pid < MT_PACKET_ID_FIRST)
if (pid < MT_PACKET_ID_WED)
return;

if (wcidx >= mt7915_wtbl_size(dev))
Expand All @@ -1015,7 +1015,11 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)

msta = container_of(wcid, struct mt7915_sta, wcid);

mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data);
if (pid == MT_PACKET_ID_WED)
mt76_connac2_mac_fill_txs(&dev->mt76, wcid, txs_data);
else
mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data);

if (!wcid->sta)
goto out;

Expand Down Expand Up @@ -1046,7 +1050,7 @@ bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len)
return false;
case PKT_TYPE_TXS:
for (rxd += 2; rxd + 8 <= end; rxd += 8)
mt7915_mac_add_txs(dev, rxd);
mt7915_mac_add_txs(dev, rxd);
return false;
case PKT_TYPE_RX_FW_MONITOR:
mt7915_debugfs_rx_fw_monitor(dev, data, len);
Expand Down Expand Up @@ -1083,7 +1087,7 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
break;
case PKT_TYPE_TXS:
for (rxd += 2; rxd + 8 <= end; rxd += 8)
mt7915_mac_add_txs(dev, rxd);
mt7915_mac_add_txs(dev, rxd);
dev_kfree_skb(skb);
break;
case PKT_TYPE_RX_FW_MONITOR:
Expand Down
17 changes: 17 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt7915/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,23 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
}
sinfo->txrate.flags = txrate->flags;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);

/* offloading flows bypass networking stack, so driver counts and
* reports sta statistics via NL80211_STA_INFO when WED is active.
*/
if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) {
sinfo->tx_bytes = msta->wcid.stats.tx_bytes;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);

sinfo->tx_packets = msta->wcid.stats.tx_packets;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);

sinfo->tx_failed = msta->wcid.stats.tx_failed;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);

sinfo->tx_retries = msta->wcid.stats.tx_retries;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
}
}

static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta)
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ static const u32 mt7915_offs[] = {
[AGG_AWSCR0] = 0x05c,
[AGG_PCR0] = 0x06c,
[AGG_ACR0] = 0x084,
[AGG_ACR4] = 0x08c,
[AGG_MRCR] = 0x098,
[AGG_ATCR1] = 0x0f0,
[AGG_ATCR3] = 0x0f4,
Expand Down Expand Up @@ -148,6 +149,7 @@ static const u32 mt7916_offs[] = {
[AGG_AWSCR0] = 0x030,
[AGG_PCR0] = 0x040,
[AGG_ACR0] = 0x054,
[AGG_ACR4] = 0x05c,
[AGG_MRCR] = 0x068,
[AGG_ATCR1] = 0x1a8,
[AGG_ATCR3] = 0x080,
Expand Down
21 changes: 21 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt7915/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ static int mt7915_pci_hif2_probe(struct pci_dev *pdev)
static int mt7915_wed_offload_enable(struct mtk_wed_device *wed)
{
struct mt7915_dev *dev;
struct mt7915_phy *phy;
int ret;

dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
Expand All @@ -112,18 +113,38 @@ static int mt7915_wed_offload_enable(struct mtk_wed_device *wed)
if (!ret)
return -EAGAIN;

phy = &dev->phy;
mt76_set(dev, MT_AGG_ACR4(phy->band_idx), MT_AGG_ACR_PPDU_TXS2H);

phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL;
if (phy)
mt76_set(dev, MT_AGG_ACR4(phy->band_idx),
MT_AGG_ACR_PPDU_TXS2H);

return 0;
}

static void mt7915_wed_offload_disable(struct mtk_wed_device *wed)
{
struct mt7915_dev *dev;
struct mt7915_phy *phy;

dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);

spin_lock_bh(&dev->mt76.token_lock);
dev->mt76.token_size = MT7915_TOKEN_SIZE;
spin_unlock_bh(&dev->mt76.token_lock);

/* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than
* MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set.
*/
phy = &dev->phy;
mt76_clear(dev, MT_AGG_ACR4(phy->band_idx), MT_AGG_ACR_PPDU_TXS2H);

phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL;
if (phy)
mt76_clear(dev, MT_AGG_ACR4(phy->band_idx),
MT_AGG_ACR_PPDU_TXS2H);
}
#endif

Expand Down
4 changes: 4 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt7915/regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ enum offs_rev {
AGG_AWSCR0,
AGG_PCR0,
AGG_ACR0,
AGG_ACR4,
AGG_MRCR,
AGG_ATCR1,
AGG_ATCR3,
Expand Down Expand Up @@ -465,6 +466,9 @@ enum offs_rev {
#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0)
#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16)

#define MT_AGG_ACR4(_band) MT_WF_AGG(_band, __OFFS(AGG_ACR4))
#define MT_AGG_ACR_PPDU_TXS2H BIT(1)

#define MT_AGG_MRCR(_band) MT_WF_AGG(_band, __OFFS(AGG_MRCR))
#define MT_AGG_MRCR_BAR_CNT_LIMIT GENMASK(15, 12)
#define MT_AGG_MRCR_LAST_RTS_CTS_RN BIT(6)
Expand Down

0 comments on commit 43eaa36

Please sign in to comment.