Commit 689d3c5e authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Vinod Koul

dmaengine: omap-dma: Fix polled channel completion detection and handling

When based on the CCR_ENABLE bit the channel is stopped we should not call
omap_dma_callback(), only change the return value to DMA_COMPLETE. Client
drivers will do the right thing to clean up the channel after the transfer
has been completed.
Check the CCR_ENABLE only if the channel is running and not paused since
pause in sDMA means that the channel is stopped.
This will fix one hard to reproduce race condition when the channel is
terminated during transfer (affecting cyclic operation).

Fixes: 1a7cf7b2 ("dmaengine: omap-dma: Handle cases when the channel is polled for completion")
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
parent f55532a0
...@@ -48,6 +48,7 @@ struct omap_chan { ...@@ -48,6 +48,7 @@ struct omap_chan {
unsigned dma_sig; unsigned dma_sig;
bool cyclic; bool cyclic;
bool paused; bool paused;
bool running;
int dma_ch; int dma_ch;
struct omap_desc *desc; struct omap_desc *desc;
...@@ -294,6 +295,8 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d) ...@@ -294,6 +295,8 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d)
/* Enable channel */ /* Enable channel */
omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE); omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE);
c->running = true;
} }
static void omap_dma_stop(struct omap_chan *c) static void omap_dma_stop(struct omap_chan *c)
...@@ -355,6 +358,8 @@ static void omap_dma_stop(struct omap_chan *c) ...@@ -355,6 +358,8 @@ static void omap_dma_stop(struct omap_chan *c)
omap_dma_chan_write(c, CLNK_CTRL, val); omap_dma_chan_write(c, CLNK_CTRL, val);
} }
c->running = false;
} }
static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d, static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d,
...@@ -673,15 +678,20 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, ...@@ -673,15 +678,20 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan,
struct omap_chan *c = to_omap_dma_chan(chan); struct omap_chan *c = to_omap_dma_chan(chan);
struct virt_dma_desc *vd; struct virt_dma_desc *vd;
enum dma_status ret; enum dma_status ret;
uint32_t ccr;
unsigned long flags; unsigned long flags;
ccr = omap_dma_chan_read(c, CCR); ret = dma_cookie_status(chan, cookie, txstate);
/* The channel is no longer active, handle the completion right away */
if (!c->paused && c->running) {
uint32_t ccr = omap_dma_chan_read(c, CCR);
/*
* The channel is no longer active, set the return value
* accordingly
*/
if (!(ccr & CCR_ENABLE)) if (!(ccr & CCR_ENABLE))
omap_dma_callback(c->dma_ch, 0, c); ret = DMA_COMPLETE;
}
ret = dma_cookie_status(chan, cookie, txstate);
if (ret == DMA_COMPLETE || !txstate) if (ret == DMA_COMPLETE || !txstate)
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment