The pause loop delays after its final status read, so an acknowledgment that arrives during that delay is cleared without being observed and the caller receives -EAGAIN. Use readx_poll_timeout_atomic() to check the status after the final delay. Keep the two-microsecond polling interval, 40-microsecond timeout and -EAGAIN return value when suspension is not acknowledged. Fixes: 1fe20f1b8454 ("dmaengine: Introduce DW AXI DMAC driver") Cc: stable@vger.kernel.org Signed-off-by: James Hilliard --- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index 040c12d07db2..1a53fbc951a9 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -1219,7 +1219,8 @@ static int dma_chan_pause(struct dma_chan *dchan) { struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan); unsigned long flags; - unsigned int timeout = 20; /* timeout iterations */ + u32 status; + int ret; u64 val; spin_lock_irqsave(&chan->vc.lock, flags); @@ -1250,12 +1251,9 @@ static int dma_chan_pause(struct dma_chan *dchan) } } - do { - if (axi_chan_irq_read(chan) & DWAXIDMAC_IRQ_SUSPENDED) - break; - - udelay(2); - } while (--timeout); + ret = readx_poll_timeout_atomic(axi_chan_irq_read, chan, + status, status & DWAXIDMAC_IRQ_SUSPENDED, + 2, 40); axi_chan_irq_clear(chan, DWAXIDMAC_IRQ_SUSPENDED); @@ -1263,7 +1261,7 @@ static int dma_chan_pause(struct dma_chan *dchan) spin_unlock_irqrestore(&chan->vc.lock, flags); - return timeout ? 0 : -EAGAIN; + return ret ? -EAGAIN : 0; } /* Called in chan locked context */ -- 2.53.0