Commit 43eaa368 authored by Ryder Lee's avatar Ryder Lee Committed by Felix Fietkau

wifi: mt76: add PPDU based TxS support for WED device

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: default avatarYi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
Signed-off-by: default avatarYi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
Signed-off-by: default avatarRyder Lee <ryder.lee@mediatek.com>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent dc877523
...@@ -270,6 +270,10 @@ struct mt76_sta_stats { ...@@ -270,6 +270,10 @@ struct mt76_sta_stats {
u64 tx_bw[4]; /* 20, 40, 80, 160 */ u64 tx_bw[4]; /* 20, 40, 80, 160 */
u64 tx_nss[4]; /* 1, 2, 3, 4 */ u64 tx_nss[4]; /* 1, 2, 3, 4 */
u64 tx_mcs[16]; /* mcs idx */ u64 tx_mcs[16]; /* mcs idx */
u64 tx_bytes;
u32 tx_packets;
u32 tx_retries;
u32 tx_failed;
}; };
enum mt76_wcid_flags { enum mt76_wcid_flags {
...@@ -364,7 +368,8 @@ struct mt76_rx_tid { ...@@ -364,7 +368,8 @@ struct mt76_rx_tid {
#define MT_PACKET_ID_MASK GENMASK(6, 0) #define MT_PACKET_ID_MASK GENMASK(6, 0)
#define MT_PACKET_ID_NO_ACK 0 #define MT_PACKET_ID_NO_ACK 0
#define MT_PACKET_ID_NO_SKB 1 #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) #define MT_PACKET_ID_HAS_RATE BIT(7)
/* This is timer for when to give up when waiting for TXS callback, /* 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 * with starting time being the time at which the DMA_DONE callback
......
...@@ -354,6 +354,8 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, ...@@ -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 sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid, struct ieee80211_key_conf *key, int pid,
enum mt76_txq_id qid, u32 changed); 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, bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
int pid, __le32 *txs_data); int pid, __le32 *txs_data);
void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev, void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
......
...@@ -158,6 +158,14 @@ enum { ...@@ -158,6 +158,14 @@ enum {
#define MT_TXS4_TIMESTAMP GENMASK(31, 0) #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 */ /* RXD DW1 */
#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0) #define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0)
#define MT_RXD1_NORMAL_GROUP_1 BIT(11) #define MT_RXD1_NORMAL_GROUP_1 BIT(11)
......
...@@ -490,6 +490,10 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, ...@@ -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; p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;
q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS + q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
mt76_connac_lmac_mapping(skb_get_queue_mapping(skb)); 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) | val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
...@@ -550,35 +554,29 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, ...@@ -550,35 +554,29 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
} }
EXPORT_SYMBOL_GPL(mt76_connac2_mac_write_txwi); EXPORT_SYMBOL_GPL(mt76_connac2_mac_write_txwi);
bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,
int pid, __le32 *txs_data) __le32 *txs_data)
{ {
struct mt76_sta_stats *stats = &wcid->stats; struct mt76_sta_stats *stats = &wcid->stats;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct mt76_phy *mphy; struct mt76_phy *mphy;
struct ieee80211_tx_info *info;
struct sk_buff_head list;
struct rate_info rate = {}; struct rate_info rate = {};
struct sk_buff *skb;
bool cck = false; bool cck = false;
u32 txrate, txs, mode; 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]); txs = le32_to_cpu(txs_data[0]);
info = IEEE80211_SKB_CB(skb); /* PPDU based reporting */
if (!(txs & MT_TXS0_ACK_ERROR_MASK)) if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) {
info->flags |= IEEE80211_TX_STAT_ACK; stats->tx_bytes +=
le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE);
info->status.ampdu_len = 1; stats->tx_packets +=
info->status.ampdu_ack_len = !!(info->flags & le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_CNT);
IEEE80211_TX_STAT_ACK); stats->tx_failed +=
le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT);
info->status.rates[0].idx = -1; stats->tx_retries +=
le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_CNT);
}
txrate = FIELD_GET(MT_TXS0_TX_RATE, txs); txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
...@@ -613,7 +611,7 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, ...@@ -613,7 +611,7 @@ 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:
case MT_PHY_TYPE_HT_GF: case MT_PHY_TYPE_HT_GF:
if (rate.mcs > 31) if (rate.mcs > 31)
goto out; return false;
rate.flags = RATE_INFO_FLAGS_MCS; rate.flags = RATE_INFO_FLAGS_MCS;
if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
...@@ -621,7 +619,7 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, ...@@ -621,7 +619,7 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
break; break;
case MT_PHY_TYPE_VHT: case MT_PHY_TYPE_VHT:
if (rate.mcs > 9) if (rate.mcs > 9)
goto out; return false;
rate.flags = RATE_INFO_FLAGS_VHT_MCS; rate.flags = RATE_INFO_FLAGS_VHT_MCS;
break; break;
...@@ -630,14 +628,14 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, ...@@ -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_TB:
case MT_PHY_TYPE_HE_MU: case MT_PHY_TYPE_HE_MU:
if (rate.mcs > 11) if (rate.mcs > 11)
goto out; return false;
rate.he_gi = wcid->rate.he_gi; rate.he_gi = wcid->rate.he_gi;
rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate); rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
rate.flags = RATE_INFO_FLAGS_HE_MCS; rate.flags = RATE_INFO_FLAGS_HE_MCS;
break; break;
default: default:
goto out; return false;
} }
stats->tx_mode[mode]++; stats->tx_mode[mode]++;
...@@ -662,10 +660,34 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, ...@@ -662,10 +660,34 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
} }
wcid->rate = rate; wcid->rate = rate;
out: return true;
if (skb) }
mt76_tx_status_skb_done(dev, skb, &list); 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); mt76_tx_status_unlock(dev, &list);
return !!skb; return !!skb;
......
...@@ -176,7 +176,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) ...@@ -176,7 +176,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
/* /*
* We don't support reading GI info from txs packets. * We don't support reading GI info from txs packets.
* For accurate tx status reporting and AQL improvement, * 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. * from per-sta counters directly.
*/ */
rate = &msta->wcid.rate; rate = &msta->wcid.rate;
...@@ -1001,7 +1001,7 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data) ...@@ -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); wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
pid = le32_get_bits(txs_data[3], MT_TXS3_PID); pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
if (pid < MT_PACKET_ID_FIRST) if (pid < MT_PACKET_ID_WED)
return; return;
if (wcidx >= mt7915_wtbl_size(dev)) if (wcidx >= mt7915_wtbl_size(dev))
...@@ -1015,7 +1015,11 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data) ...@@ -1015,7 +1015,11 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
msta = container_of(wcid, struct mt7915_sta, wcid); msta = container_of(wcid, struct mt7915_sta, wcid);
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); mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data);
if (!wcid->sta) if (!wcid->sta)
goto out; goto out;
......
...@@ -1010,6 +1010,23 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw, ...@@ -1010,6 +1010,23 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
} }
sinfo->txrate.flags = txrate->flags; sinfo->txrate.flags = txrate->flags;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 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) static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta)
......
...@@ -75,6 +75,7 @@ static const u32 mt7915_offs[] = { ...@@ -75,6 +75,7 @@ static const u32 mt7915_offs[] = {
[AGG_AWSCR0] = 0x05c, [AGG_AWSCR0] = 0x05c,
[AGG_PCR0] = 0x06c, [AGG_PCR0] = 0x06c,
[AGG_ACR0] = 0x084, [AGG_ACR0] = 0x084,
[AGG_ACR4] = 0x08c,
[AGG_MRCR] = 0x098, [AGG_MRCR] = 0x098,
[AGG_ATCR1] = 0x0f0, [AGG_ATCR1] = 0x0f0,
[AGG_ATCR3] = 0x0f4, [AGG_ATCR3] = 0x0f4,
...@@ -148,6 +149,7 @@ static const u32 mt7916_offs[] = { ...@@ -148,6 +149,7 @@ static const u32 mt7916_offs[] = {
[AGG_AWSCR0] = 0x030, [AGG_AWSCR0] = 0x030,
[AGG_PCR0] = 0x040, [AGG_PCR0] = 0x040,
[AGG_ACR0] = 0x054, [AGG_ACR0] = 0x054,
[AGG_ACR4] = 0x05c,
[AGG_MRCR] = 0x068, [AGG_MRCR] = 0x068,
[AGG_ATCR1] = 0x1a8, [AGG_ATCR1] = 0x1a8,
[AGG_ATCR3] = 0x080, [AGG_ATCR3] = 0x080,
......
...@@ -99,6 +99,7 @@ static int mt7915_pci_hif2_probe(struct pci_dev *pdev) ...@@ -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) static int mt7915_wed_offload_enable(struct mtk_wed_device *wed)
{ {
struct mt7915_dev *dev; struct mt7915_dev *dev;
struct mt7915_phy *phy;
int ret; int ret;
dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
...@@ -112,18 +113,38 @@ static int mt7915_wed_offload_enable(struct mtk_wed_device *wed) ...@@ -112,18 +113,38 @@ static int mt7915_wed_offload_enable(struct mtk_wed_device *wed)
if (!ret) if (!ret)
return -EAGAIN; 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; return 0;
} }
static void mt7915_wed_offload_disable(struct mtk_wed_device *wed) static void mt7915_wed_offload_disable(struct mtk_wed_device *wed)
{ {
struct mt7915_dev *dev; struct mt7915_dev *dev;
struct mt7915_phy *phy;
dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
spin_lock_bh(&dev->mt76.token_lock); spin_lock_bh(&dev->mt76.token_lock);
dev->mt76.token_size = MT7915_TOKEN_SIZE; dev->mt76.token_size = MT7915_TOKEN_SIZE;
spin_unlock_bh(&dev->mt76.token_lock); 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 #endif
......
...@@ -46,6 +46,7 @@ enum offs_rev { ...@@ -46,6 +46,7 @@ enum offs_rev {
AGG_AWSCR0, AGG_AWSCR0,
AGG_PCR0, AGG_PCR0,
AGG_ACR0, AGG_ACR0,
AGG_ACR4,
AGG_MRCR, AGG_MRCR,
AGG_ATCR1, AGG_ATCR1,
AGG_ATCR3, AGG_ATCR3,
...@@ -465,6 +466,9 @@ enum offs_rev { ...@@ -465,6 +466,9 @@ enum offs_rev {
#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0) #define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0)
#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16) #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(_band) MT_WF_AGG(_band, __OFFS(AGG_MRCR))
#define MT_AGG_MRCR_BAR_CNT_LIMIT GENMASK(15, 12) #define MT_AGG_MRCR_BAR_CNT_LIMIT GENMASK(15, 12)
#define MT_AGG_MRCR_LAST_RTS_CTS_RN BIT(6) #define MT_AGG_MRCR_LAST_RTS_CTS_RN BIT(6)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment