On Thu, Oct 24, 2019 at 12:23:16AM +0200, Lorenzo Bianconi wrote: > mt76 dma layer is supposed to unmap skb data buffers while keep txwi > mapped on hw dma ring. At the moment mt76 wrongly unmap txwi or does > not unmap data fragments in even positions for non-linear skbs. This > issue may result in hw hangs with A-MSDU if the system relies on IOMMU > or SWIOTLB. Fix this behaviour properly unmapping data fragments on > non-linear skbs. If we have to keep txwi mapped, before unmap fragments, when then txwi is unmaped ? Stanislaw > Fixes: 17f1de56df05 ("mt76: add common code shared between multiple chipsets") > Signed-off-by: Lorenzo Bianconi <lorenzo@xxxxxxxxxx> > --- > drivers/net/wireless/mediatek/mt76/dma.c | 10 +++++++--- > 1 file changed, 7 insertions(+), 3 deletions(-) > > diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c > index c747eb24581c..8c27956875e7 100644 > --- a/drivers/net/wireless/mediatek/mt76/dma.c > +++ b/drivers/net/wireless/mediatek/mt76/dma.c > @@ -93,11 +93,14 @@ static void > mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx, > struct mt76_queue_entry *prev_e) > { > - struct mt76_queue_entry *e = &q->entry[idx]; > __le32 __ctrl = READ_ONCE(q->desc[idx].ctrl); > + struct mt76_queue_entry *e = &q->entry[idx]; > u32 ctrl = le32_to_cpu(__ctrl); > + bool mcu = e->skb && !e->txwi; > + bool first = e->skb == DMA_DUMMY_DATA || e->txwi == DMA_DUMMY_DATA || > + (e->skb && !skb_is_nonlinear(e->skb)); > > - if (!e->txwi || !e->skb) { > + if (!first || mcu) { > __le32 addr = READ_ONCE(q->desc[idx].buf0); > u32 len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl); > > @@ -105,7 +108,8 @@ mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx, > DMA_TO_DEVICE); > } > > - if (!(ctrl & MT_DMA_CTL_LAST_SEC0)) { > + if (!(ctrl & MT_DMA_CTL_LAST_SEC0) || > + e->txwi == DMA_DUMMY_DATA) { > __le32 addr = READ_ONCE(q->desc[idx].buf1); > u32 len = FIELD_GET(MT_DMA_CTL_SD_LEN1, ctrl); > > -- > 2.21.0 >