wifi: mt76: wait for firmware TX completion of mgmt frames before channel switch

After flushing software-pending frames to DMA, mt76_has_tx_pending()
only checks DMA ring q->queued. For token-based drivers, q->queued is
decremented at DMA consumption, but firmware may not have transmitted
the frame yet. Waiting for all tokens is not feasible because data
frames may be stuck in firmware powersave/aggregation queues.

Track PSD queue tokens (firmware ALTX) per phy using an atomic counter.
These frames are sent by firmware immediately without PS buffering, so
the counter reliably reaches zero after transmission.

Increment the counter in mt76_token_consume() and decrement it in
mt76_token_release(), only for PSD queue tokens. Include the counter
in mt76_has_tx_pending() so channel switch waits for firmware TX
completion of management and nullfunc frames.

mt7615 (uses mt76_token_get/put) and non-token drivers are unaffected
as they never call mt76_token_consume/release.

Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
Felix Fietkau
2026-03-07 19:22:34 +00:00
parent da6d90e4f6
commit 447cc8c89c
6 changed files with 33 additions and 1 deletions
+13 -1
View File
@@ -866,9 +866,15 @@ int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi)
token = idr_alloc(&dev->token, *ptxwi, dev->token_start,
dev->token_start + dev->token_size,
GFP_ATOMIC);
if (token >= dev->token_start)
if (token >= dev->token_start) {
dev->token_count++;
if ((*ptxwi)->qid == MT_TXQ_PSD) {
struct mt76_phy *mphy = mt76_dev_phy(dev, (*ptxwi)->phy_idx);
atomic_inc(&mphy->mgmt_tx_pending);
}
}
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
if (mtk_wed_device_active(&dev->mmio.wed) &&
token >= dev->mmio.wed.wlan.token_start)
@@ -913,6 +919,12 @@ mt76_token_release(struct mt76_dev *dev, int token, bool *wake)
if (txwi) {
dev->token_count--;
if (txwi->qid == MT_TXQ_PSD) {
struct mt76_phy *mphy = mt76_dev_phy(dev, txwi->phy_idx);
if (atomic_dec_and_test(&mphy->mgmt_tx_pending))
wake_up(&dev->tx_wait);
}
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
if (mtk_wed_device_active(&dev->mmio.wed) &&
token >= dev->mmio.wed.wlan.token_start &&