diff options
author | Vinod Koul <vinod.koul@intel.com> | 2016-01-06 10:47:47 +0100 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2016-01-06 10:47:47 +0100 |
commit | d3f1e93ce8e00be19711c35f0c67c54a58aea559 (patch) | |
tree | 58010cdfa4fc473fc0693410b4a444755c4438c9 /drivers/dma | |
parent | Merge branch 'topic/univ_api' into for-linus (diff) | |
parent | dmaengine: Add might_sleep() to dmaengine_synchronize() (diff) | |
download | linux-d3f1e93ce8e00be19711c35f0c67c54a58aea559.tar.xz linux-d3f1e93ce8e00be19711c35f0c67c54a58aea559.zip |
Merge branch 'topic/async' into for-linus
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/dma-axi-dmac.c | 8 | ||||
-rw-r--r-- | drivers/dma/dmaengine.c | 5 | ||||
-rw-r--r-- | drivers/dma/virt-dma.h | 13 |
3 files changed, 25 insertions, 1 deletions
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index 5b2395e7e04d..c3468094393e 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -307,6 +307,13 @@ static int axi_dmac_terminate_all(struct dma_chan *c) return 0; } +static void axi_dmac_synchronize(struct dma_chan *c) +{ + struct axi_dmac_chan *chan = to_axi_dmac_chan(c); + + vchan_synchronize(&chan->vchan); +} + static void axi_dmac_issue_pending(struct dma_chan *c) { struct axi_dmac_chan *chan = to_axi_dmac_chan(c); @@ -613,6 +620,7 @@ static int axi_dmac_probe(struct platform_device *pdev) dma_dev->device_prep_dma_cyclic = axi_dmac_prep_dma_cyclic; dma_dev->device_prep_interleaved_dma = axi_dmac_prep_interleaved; dma_dev->device_terminate_all = axi_dmac_terminate_all; + dma_dev->device_synchronize = axi_dmac_synchronize; dma_dev->dev = &pdev->dev; dma_dev->chancnt = 1; dma_dev->src_addr_widths = BIT(dmac->chan.src_width); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 21c8c0bce3af..c50a247be2e0 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -266,8 +266,11 @@ static void dma_chan_put(struct dma_chan *chan) module_put(dma_chan_to_owner(chan)); /* This channel is not in use anymore, free it */ - if (!chan->client_count && chan->device->device_free_chan_resources) + if (!chan->client_count && chan->device->device_free_chan_resources) { + /* Make sure all operations have completed */ + dmaengine_synchronize(chan); chan->device->device_free_chan_resources(chan); + } /* If the channel is used via a DMA request router, free the mapping */ if (chan->router && chan->router->route_free) { diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h index bff8c39dd716..d9731ca5e262 100644 --- a/drivers/dma/virt-dma.h +++ b/drivers/dma/virt-dma.h @@ -163,4 +163,17 @@ static inline void vchan_free_chan_resources(struct virt_dma_chan *vc) vchan_dma_desc_free_list(vc, &head); } +/** + * vchan_synchronize() - synchronize callback execution to the current context + * @vc: virtual channel to synchronize + * + * Makes sure that all scheduled or active callbacks have finished running. For + * proper operation the caller has to ensure that no new callbacks are scheduled + * after the invocation of this function started. + */ +static inline void vchan_synchronize(struct virt_dma_chan *vc) +{ + tasklet_kill(&vc->task); +} + #endif |