aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2016-04-05 08:20:20 -0400
committerVinod Koul <vinod.koul@intel.com>2016-04-05 12:09:42 -0400
commit689d3c5ecc9e2eac714d32ca152b72988bc2a67b (patch)
treeaeda7249f373886568493bf2a5d826d83d8854de
parentf55532a0c0b8bb6148f4e07853b876ef73bc69ca (diff)
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: 1a7cf7b26f25 ("dmaengine: omap-dma: Handle cases when the channel is polled for completion") Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/omap-dma.c22
1 files changed, 16 insertions, 6 deletions
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index 43bd5aee7ffe..6ea9044d8b71 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -48,6 +48,7 @@ struct omap_chan {
48 unsigned dma_sig; 48 unsigned dma_sig;
49 bool cyclic; 49 bool cyclic;
50 bool paused; 50 bool paused;
51 bool running;
51 52
52 int dma_ch; 53 int dma_ch;
53 struct omap_desc *desc; 54 struct omap_desc *desc;
@@ -294,6 +295,8 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d)
294 295
295 /* Enable channel */ 296 /* Enable channel */
296 omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE); 297 omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE);
298
299 c->running = true;
297} 300}
298 301
299static void omap_dma_stop(struct omap_chan *c) 302static void omap_dma_stop(struct omap_chan *c)
@@ -355,6 +358,8 @@ static void omap_dma_stop(struct omap_chan *c)
355 358
356 omap_dma_chan_write(c, CLNK_CTRL, val); 359 omap_dma_chan_write(c, CLNK_CTRL, val);
357 } 360 }
361
362 c->running = false;
358} 363}
359 364
360static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d, 365static 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 struct omap_chan *c = to_omap_dma_chan(chan); 678 struct omap_chan *c = to_omap_dma_chan(chan);
674 struct virt_dma_desc *vd; 679 struct virt_dma_desc *vd;
675 enum dma_status ret; 680 enum dma_status ret;
676 uint32_t ccr;
677 unsigned long flags; 681 unsigned long flags;
678 682
679 ccr = omap_dma_chan_read(c, CCR);
680 /* The channel is no longer active, handle the completion right away */
681 if (!(ccr & CCR_ENABLE))
682 omap_dma_callback(c->dma_ch, 0, c);
683
684 ret = dma_cookie_status(chan, cookie, txstate); 683 ret = dma_cookie_status(chan, cookie, txstate);
684
685 if (!c->paused && c->running) {
686 uint32_t ccr = omap_dma_chan_read(c, CCR);
687 /*
688 * The channel is no longer active, set the return value
689 * accordingly
690 */
691 if (!(ccr & CCR_ENABLE))
692 ret = DMA_COMPLETE;
693 }
694
685 if (ret == DMA_COMPLETE || !txstate) 695 if (ret == DMA_COMPLETE || !txstate)
686 return ret; 696 return ret;
687 697