aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Baldyga <r.baldyga@samsung.com>2015-02-11 07:23:18 -0500
committerVinod Koul <vinod.koul@intel.com>2015-02-15 23:03:36 -0500
commit88987d2c7534a0269f567fb101e6d71a08f0f01d (patch)
treec9305c6ff9b11138f51889126e15f55af2b4350c
parentaee4d1fac887252faf6f7caf7bf1616131d5dbcd (diff)
dmaengine: pl330: add DMA_PAUSE feature
DMA_PAUSE command is used for halting DMA transfer on chosen channel. It can be useful when we want to safely read residue before terminating all requests on channel. Otherwise there can be situation when some data is transferred before channel termination but after reading residue, which obviously results with data loss. To avoid this situation we can pause channel, read residue and then terminate all requests. This scenario is common, for example, in serial port drivers. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/pl330.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 944b67622916..0e1f56772855 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -2155,6 +2155,33 @@ static int pl330_terminate_all(struct dma_chan *chan)
2155 return 0; 2155 return 0;
2156} 2156}
2157 2157
2158/*
2159 * We don't support DMA_RESUME command because of hardware
2160 * limitations, so after pausing the channel we cannot restore
2161 * it to active state. We have to terminate channel and setup
2162 * DMA transfer again. This pause feature was implemented to
2163 * allow safely read residue before channel termination.
2164 */
2165int pl330_pause(struct dma_chan *chan)
2166{
2167 struct dma_pl330_chan *pch = to_pchan(chan);
2168 struct pl330_dmac *pl330 = pch->dmac;
2169 unsigned long flags;
2170
2171 pm_runtime_get_sync(pl330->ddma.dev);
2172 spin_lock_irqsave(&pch->lock, flags);
2173
2174 spin_lock(&pl330->lock);
2175 _stop(pch->thread);
2176 spin_unlock(&pl330->lock);
2177
2178 spin_unlock_irqrestore(&pch->lock, flags);
2179 pm_runtime_mark_last_busy(pl330->ddma.dev);
2180 pm_runtime_put_autosuspend(pl330->ddma.dev);
2181
2182 return 0;
2183}
2184
2158static void pl330_free_chan_resources(struct dma_chan *chan) 2185static void pl330_free_chan_resources(struct dma_chan *chan)
2159{ 2186{
2160 struct dma_pl330_chan *pch = to_pchan(chan); 2187 struct dma_pl330_chan *pch = to_pchan(chan);
@@ -2842,6 +2869,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
2842 pd->device_tx_status = pl330_tx_status; 2869 pd->device_tx_status = pl330_tx_status;
2843 pd->device_prep_slave_sg = pl330_prep_slave_sg; 2870 pd->device_prep_slave_sg = pl330_prep_slave_sg;
2844 pd->device_config = pl330_config; 2871 pd->device_config = pl330_config;
2872 pd->device_pause = pl330_pause;
2845 pd->device_terminate_all = pl330_terminate_all; 2873 pd->device_terminate_all = pl330_terminate_all;
2846 pd->device_issue_pending = pl330_issue_pending; 2874 pd->device_issue_pending = pl330_issue_pending;
2847 pd->src_addr_widths = PL330_DMA_BUSWIDTHS; 2875 pd->src_addr_widths = PL330_DMA_BUSWIDTHS;