mt76_npu_dequeue() reads the slot count of a frame from the info word of its first descriptor before checking the done bit of that slot. If the NPU completes the slot in between, the count is still the 0 left by the refill, so a frame spanning two slots is taken as a single slot frame and its second slot is parsed as the start of the next frame. With mt7996 this shows up as bogus tx-free events, which hit the WARN_ON_ONCE() checks in mt7996_mac_tx_free(). From the code, such an event can also release tokens that are still in use. Check the done bit of the first slot before reading the slot count, and order the descriptor reads with dma_rmb(). Fixes: 7fb554b1b623 ("wifi: mt76: Introduce the NPU generic layer") Cc: stable@vger.kernel.org Signed-off-by: Florian Maurer --- drivers/net/wireless/mediatek/mt76/npu.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/npu.c b/drivers/net/wireless/mediatek/mt76/npu.c index 6e503a4a890c..f00ae683a7eb 100644 --- a/drivers/net/wireless/mediatek/mt76/npu.c +++ b/drivers/net/wireless/mediatek/mt76/npu.c @@ -72,18 +72,25 @@ static struct sk_buff *mt76_npu_dequeue(struct mt76_dev *dev, int i, nframes, index = q->tail; struct sk_buff *skb = NULL; + if (!q->queued || + !FIELD_GET(NPU_RX_DMA_DESC_DONE_MASK, desc[index].ctrl)) + return NULL; + + /* The slot count is only valid once the first slot is complete */ + dma_rmb(); nframes = FIELD_GET(NPU_RX_DMA_PKT_COUNT_MASK, desc[index].info); nframes = max_t(int, nframes, 1); if (nframes > q->queued) return NULL; /* Only take the frame once all of its slots are complete */ - for (i = 0; i < nframes; i++) { + for (i = 1; i < nframes; i++) { int idx = (index + i) % q->ndesc; if (!FIELD_GET(NPU_RX_DMA_DESC_DONE_MASK, desc[idx].ctrl)) return NULL; } + dma_rmb(); for (i = 0; i < nframes; i++) { struct mt76_queue_entry *e = &q->entry[index]; -- 2.47.3