mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 05:16:57 +00:00
wifi: mt76: mt7996: fix TX DMA mapping leak for AddBA req frames
mt7996/mt7992 hand the firmware a HW MAC-TXP for AddBA req action frames
(MT_TXD7_MAC_TXD, set in mt7996_mac_write_txwi_80211()), but are otherwise
FW-TXP devices. On tx free mt76_connac_txp_skb_unmap() therefore decodes the
per-frame txp as a struct mt76_connac_fw_txp. For a MAC-TXP the fw_txp.nbuf
byte aliases the AddBA TID word (MT_TXP1_TID_ADDBA), which is always zero, so
the unmap loop runs zero times and the skb DMA mapping in buf[1] is never
unmapped. buf[1].skip_unmap is set unconditionally, so the generic DMA-ring
cleanup skips it as well.
Each AddBA req therefore leaks one TX DMA mapping, roughly one per
(re)association. With WED enabled these mappings are bounced through the WED
swiotlb pool, so under continuous client reconnect churn the pool is exhausted
after ~1-2 days, after which DMA mapping fails for WED, the WiFi MCU and other
on-SoC consumers.
Keep the deferred (token release) unmap that the design relies on, and add an
mt7996-specific txp unmap that inspects MT_TXD7_MAC_TXD and unmaps buf[1] from
the MAC-TXP layout for those frames, delegating to mt76_connac_txp_skb_unmap()
otherwise.
Fixes: cb6ebbdffef2 ("wifi: mt76: mt7996: support writing MAC TXD for AddBA Request")
Cc: [email protected]
Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
+30
-1
@@ -1244,6 +1244,35 @@ mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta,
|
||||
clear_bit(tid, &wcid->ampdu_state);
|
||||
}
|
||||
|
||||
/* mt7996/mt7992 provide a HW MAC-TXP for AddBA req frames (MT_TXD7_MAC_TXD),
|
||||
* but are otherwise FW-TXP devices. mt76_connac_txp_skb_unmap() would decode
|
||||
* the MAC-TXP as a fw-txp and read nbuf as 0, leaving the skb mapping in
|
||||
* buf[1] leaked. Unmap it from the MAC-TXP layout instead.
|
||||
*/
|
||||
static void
|
||||
mt7996_txp_skb_unmap(struct mt76_dev *mdev, struct mt76_txwi_cache *t)
|
||||
{
|
||||
u8 *txwi_ptr = mt76_get_txwi_ptr(mdev, t);
|
||||
__le32 *txwi = (__le32 *)txwi_ptr;
|
||||
__le32 *txp;
|
||||
dma_addr_t addr;
|
||||
u32 val;
|
||||
|
||||
if (!(le32_to_cpu(txwi[7]) & MT_TXD7_MAC_TXD)) {
|
||||
mt76_connac_txp_skb_unmap(mdev, t);
|
||||
return;
|
||||
}
|
||||
|
||||
txp = (__le32 *)(txwi_ptr + MT_TXD_SIZE);
|
||||
val = le32_to_cpu(txp[3]);
|
||||
addr = le32_to_cpu(txp[2]);
|
||||
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
|
||||
addr |= (dma_addr_t)FIELD_GET(MT_TXP3_DMA_ADDR_H, val) << 32;
|
||||
#endif
|
||||
dma_unmap_single(mdev->dma_dev, addr, FIELD_GET(MT_TXP_BUF_LEN, val),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
@@ -1253,7 +1282,7 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
|
||||
__le32 *txwi;
|
||||
u16 wcid_idx;
|
||||
|
||||
mt76_connac_txp_skb_unmap(mdev, t);
|
||||
mt7996_txp_skb_unmap(mdev, t);
|
||||
if (!t->skb)
|
||||
goto out;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user