[PATCH] DMAEngine: sirf: let the users be able to pause and resume specific buffer
Barry Song
21cnbao at gmail.com
Sun Jul 28 22:14:24 EDT 2013
2013/7/4 Barry Song <Baohua.Song at csr.com>
>
> From: Qipan Li <Qipan.Li at csr.com>
>
> this patch adds a buffer_index in pause and resume entries, then users
> can pause and resume a buffer they want, but don't pause the whole dma.
>
> a typical application scenerios is Ping-Pang in two buffers:
> at the beginning, we enable buf1 and buf2 to receive dma data, after
> buf1 is full, we pause buf1 and handle the data in this buffer to avoid
> overflow in buf1. but at the same time, dma is still tranferring in buf2.
> once we have finished data process in buf1, we enable buf1 again.
> this will maximize the chance of dma transferring. users pause buf1 by:
> dmaengine_device_control(sirfport->rx_dma_chan, DMA_PAUSE, 1);
> users pause buf2 by:
> dmaengine_device_control(sirfport->rx_dma_chan, DMA_PAUSE, 2);
> users can still pause the whole dma transferring by dmaengine_pause().
>
> Signed-off-by: Qipan Li <Qipan.Li at csr.com>
> Signed-off-by: Barry Song <Baohua.Song at csr.com>
> ---
> drivers/dma/sirf-dma.c | 102
> ++++++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 80 insertions(+), 22 deletions(-)
Hi Vinod, as we still have some other patches of dma clients depending
on this, would you give some comments about it?
>
> diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
> index 1d627e2..7d500d2 100644
> --- a/drivers/dma/sirf-dma.c
> +++ b/drivers/dma/sirf-dma.c
> @@ -315,43 +315,101 @@ static int sirfsoc_dma_terminate_all(struct
> sirfsoc_dma_chan *schan)
> return 0;
> }
>
> -static int sirfsoc_dma_pause_chan(struct sirfsoc_dma_chan *schan)
> +static int sirfsoc_dma_pause_chan(struct sirfsoc_dma_chan *schan,
> + unsigned long buf_index)
> {
> struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
> int cid = schan->chan.chan_id;
> unsigned long flags;
> + unsigned long loop_ctrl_val;
>
> spin_lock_irqsave(&schan->lock, flags);
> -
> - if (!sdma->is_marco)
> - writel_relaxed(readl_relaxed(sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL)
> - & ~((1 << cid) | 1 << (cid + 16)),
> - sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL);
> - else
> - writel_relaxed((1 << cid) | 1 << (cid + 16),
> - sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL_CLR);
> -
> + if (!sdma->is_marco) {
> + loop_ctrl_val = readl_relaxed(sdma->base +
> + SIRFSOC_DMA_CH_LOOP_CTRL);
> + switch (buf_index) {
> + case 1:
> + writel_relaxed(loop_ctrl_val & ~(1 << cid),
> + sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL);
> + break;
> + case 2:
> + writel_relaxed(loop_ctrl_val & ~(1 << (cid + 16)),
> + sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL);
> + break;
> + case 0:
> + default:
> + writel_relaxed(loop_ctrl_val &
> + ~((1 << cid) | 1 << (cid + 16)),
> + sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL);
> + break;
> + }
> + } else {
> + switch (buf_index) {
> + case 1:
> + writel_relaxed((1 << cid), sdma->base +
> +
> SIRFSOC_DMA_CH_LOOP_CTRL_CLR);
> + break;
> + case 2:
> + writel_relaxed(1 << (cid + 16), sdma->base +
> +
> SIRFSOC_DMA_CH_LOOP_CTRL_CLR);
> + break;
> + case 0:
> + default:
> + writel_relaxed((1 << cid) | 1 << (cid + 16),
> + sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL_CLR);
> + break;
> + }
> + }
> spin_unlock_irqrestore(&schan->lock, flags);
>
> return 0;
> }
>
> -static int sirfsoc_dma_resume_chan(struct sirfsoc_dma_chan *schan)
> +static int sirfsoc_dma_resume_chan(struct sirfsoc_dma_chan *schan,
> + unsigned long buf_index)
> {
> struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
> int cid = schan->chan.chan_id;
> unsigned long flags;
> + unsigned long loop_ctrl_val;
>
> spin_lock_irqsave(&schan->lock, flags);
> -
> - if (!sdma->is_marco)
> - writel_relaxed(readl_relaxed(sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL)
> - | ((1 << cid) | 1 << (cid + 16)),
> - sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL);
> - else
> - writel_relaxed((1 << cid) | 1 << (cid + 16),
> - sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL);
> -
> + if (!sdma->is_marco) {
> + loop_ctrl_val = readl_relaxed(sdma->base +
> + SIRFSOC_DMA_CH_LOOP_CTRL);
> + switch (buf_index) {
> + case 1:
> + writel_relaxed(loop_ctrl_val | (1 << cid),
> + sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL);
> + break;
> + case 2:
> + writel_relaxed(loop_ctrl_val | 1 << (cid + 16),
> + sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL);
> + break;
> + case 0:
> + default:
> + writel_relaxed(loop_ctrl_val | (1 << cid) |
> + 1 << (cid + 16),
> + sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL);
> + break;
> + }
> + } else {
> + switch (buf_index) {
> + case 1:
> + writel_relaxed((1 << cid),
> + sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL);
> + break;
> + case 2:
> + writel_relaxed((1 << (cid + 16)),
> + sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL);
> + break;
> + case 0:
> + default:
> + writel_relaxed((1 << cid) | 1 << (cid + 16),
> + sdma->base +
> SIRFSOC_DMA_CH_LOOP_CTRL);
> + break;
> + }
> + }
> spin_unlock_irqrestore(&schan->lock, flags);
>
> return 0;
> @@ -365,9 +423,9 @@ static int sirfsoc_dma_control(struct dma_chan *chan,
> enum dma_ctrl_cmd cmd,
>
> switch (cmd) {
> case DMA_PAUSE:
> - return sirfsoc_dma_pause_chan(schan);
> + return sirfsoc_dma_pause_chan(schan, arg);
> case DMA_RESUME:
> - return sirfsoc_dma_resume_chan(schan);
> + return sirfsoc_dma_resume_chan(schan, arg);
> case DMA_TERMINATE_ALL:
> return sirfsoc_dma_terminate_all(schan);
> case DMA_SLAVE_CONFIG:
> --
> 1.8.2.3
-barry
More information about the linux-arm-kernel
mailing list