[PATCH v3 1/3] dma: Support multiple interleaved frames with non-contiguous memory

Srikanth Thokala sthokal at xilinx.com
Mon Feb 17 04:52:38 EST 2014


On Mon, Feb 17, 2014 at 3:14 PM, Lars-Peter Clausen <lars at metafoo.de> wrote:
> On 02/17/2014 10:42 AM, Srikanth Thokala wrote:
>>
>> On Mon, Feb 17, 2014 at 3:05 PM, Lars-Peter Clausen <lars at metafoo.de>
>> wrote:
>>>
>>> On 02/17/2014 10:29 AM, Srikanth Thokala wrote:
>>>>
>>>>
>>>> On Mon, Feb 17, 2014 at 2:13 PM, Vinod Koul <vinod.koul at intel.com>
>>>> wrote:
>>>>>
>>>>>
>>>>> On Sat, Feb 15, 2014 at 05:30:17PM +0530, Srikanth Thokala wrote:
>>>>>>
>>>>>>
>>>>>> The current implementation of interleaved DMA API support multiple
>>>>>> frames only when the memory is contiguous by incrementing src_start/
>>>>>> dst_start members of interleaved template.
>>>>>>
>>>>>> But, when the memory is non-contiguous it will restrict slave device
>>>>>> to not submit multiple frames in a batch.  This patch handles this
>>>>>> issue by allowing the slave device to send array of interleaved dma
>>>>>> templates each having a different memory location.
>>>>>
>>>>>
>>>>> This seems to be missing the numbers of templates you are sending,
>>>>> wouldnt this
>>>>> require sending ARRAY_SiZE too?
>>>>>
>>>>> And why send double pointer?
>>>>
>>>>
>>>>
>>>> Array size is not required, when we pass the double pointer.  The last
>>>> element would be
>>>> pointed to NULL and we could get the number of templates from this
>>>> condition.
>>>> Here is an example snippet,
>>>>
>>>> In slave device driver,
>>>>
>>>>           struct dma_interleaved_template **xts;
>>>>
>>>>           xts = kcalloc(frm_cnt+1, sizeof(struct
>>>> dma_interleaved_template *), GFP_KERNEL);
>>>>           /* Error check for xts */
>>>>           for (i = 0; i < frm_cnt; i++) {
>>>>                   xts[i] = kmalloc(sizeof(struct
>>>> dma_interleaved_template), GFP_KERNEL);
>>>>                   /* Error check for xts[i] */
>>>>           }
>>>>           xts[i] = NULL;
>>>>
>>>> In DMA engine driver,  we could get the number of frames by,
>>>>
>>>>           for (; xts[frmno] != NULL; frmno++);
>>>>
>>>> I felt this way is simpler than adding an extra argument to the API.
>>>> Please let me know
>>>> your opinion and suggest me a better way.
>>>
>>>
>>>
>>> I think Vinod's suggestion of passing in an array of
>>> interleaved_templates
>>> and the size of the array is better than what you are currently doing.
>>
>>
>> Ok, Lars.  I will update with this in my v4. Thanks.
>>
>>>
>>> Btw. you also need to update the current implementations and users of the
>>> API accordingly.
>>
>>
>> Yes, I have updated them in this patch.
>
>
> But you didn't update them accordingly to your proposed semantics. The
> caller didn't NULL terminate the array and the drivers did blindly assume
> there will always be exactly one transfer.

Ok, got it.  I will correct in v4.  Thanks for pointing this.

Srikanth

>
>
>>
>> Thanks
>> Srikanth
>>
>>
>>>
>>>
>>>>
>>>>>
>>>>> --
>>>>> ~Vinod
>>>>>
>>>>>>
>>>>>> Signed-off-by: Srikanth Thokala <sthokal at xilinx.com>
>>>>>> ---
>>>>>>    Documentation/dmaengine.txt              |    2 +-
>>>>>>    drivers/dma/imx-dma.c                    |    3 ++-
>>>>>>    drivers/dma/sirf-dma.c                   |    3 ++-
>>>>>>    drivers/media/platform/m2m-deinterlace.c |    2 +-
>>>>>>    include/linux/dmaengine.h                |    6 +++---
>>>>>>    5 files changed, 9 insertions(+), 7 deletions(-)
>>>>>>
>>>>>> diff --git a/Documentation/dmaengine.txt b/Documentation/dmaengine.txt
>>>>>> index 879b6e3..c642614 100644
>>>>>> --- a/Documentation/dmaengine.txt
>>>>>> +++ b/Documentation/dmaengine.txt
>>>>>> @@ -94,7 +94,7 @@ The slave DMA usage consists of following steps:
>>>>>>                 size_t period_len, enum dma_data_direction direction);
>>>>>>
>>>>>>         struct dma_async_tx_descriptor
>>>>>> *(*device_prep_interleaved_dma)(
>>>>>> -             struct dma_chan *chan, struct dma_interleaved_template
>>>>>> *xt,
>>>>>> +             struct dma_chan *chan, struct dma_interleaved_template
>>>>>> **xts,
>>>>>>                 unsigned long flags);
>>>>>>
>>>>>>       The peripheral driver is expected to have mapped the scatterlist
>>>>>> for
>>>>>> diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
>>>>>> index 6f9ac20..e2c52ce 100644
>>>>>> --- a/drivers/dma/imx-dma.c
>>>>>> +++ b/drivers/dma/imx-dma.c
>>>>>> @@ -954,12 +954,13 @@ static struct dma_async_tx_descriptor
>>>>>> *imxdma_prep_dma_memcpy(
>>>>>>    }
>>>>>>
>>>>>>    static struct dma_async_tx_descriptor *imxdma_prep_dma_interleaved(
>>>>>> -     struct dma_chan *chan, struct dma_interleaved_template *xt,
>>>>>> +     struct dma_chan *chan, struct dma_interleaved_template **xts,
>>>>>>         unsigned long flags)
>>>>>>    {
>>>>>>         struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
>>>>>>         struct imxdma_engine *imxdma = imxdmac->imxdma;
>>>>>>         struct imxdma_desc *desc;
>>>>>> +     struct dma_interleaved_template *xt = *xts;
>>>>>>
>>>>>>         dev_dbg(imxdma->dev, "%s channel: %d src_start=0x%llx
>>>>>> dst_start=0x%llx\n"
>>>>>>                 "   src_sgl=%s dst_sgl=%s numf=%zu frame_size=%zu\n",
>>>>>> __func__,
>>>>>> diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
>>>>>> index d4d3a31..b6a150b 100644
>>>>>> --- a/drivers/dma/sirf-dma.c
>>>>>> +++ b/drivers/dma/sirf-dma.c
>>>>>> @@ -509,12 +509,13 @@ sirfsoc_dma_tx_status(struct dma_chan *chan,
>>>>>> dma_cookie_t cookie,
>>>>>>    }
>>>>>>
>>>>>>    static struct dma_async_tx_descriptor
>>>>>> *sirfsoc_dma_prep_interleaved(
>>>>>> -     struct dma_chan *chan, struct dma_interleaved_template *xt,
>>>>>> +     struct dma_chan *chan, struct dma_interleaved_template **xts,
>>>>>>         unsigned long flags)
>>>>>>    {
>>>>>>         struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
>>>>>>         struct sirfsoc_dma_chan *schan =
>>>>>> dma_chan_to_sirfsoc_dma_chan(chan);
>>>>>>         struct sirfsoc_dma_desc *sdesc = NULL;
>>>>>> +     struct dma_interleaved_template *xt = *xts;
>>>>>>         unsigned long iflags;
>>>>>>         int ret;
>>>>>>
>>>>>> diff --git a/drivers/media/platform/m2m-deinterlace.c
>>>>>> b/drivers/media/platform/m2m-deinterlace.c
>>>>>> index 6bb86b5..468110a 100644
>>>>>> --- a/drivers/media/platform/m2m-deinterlace.c
>>>>>> +++ b/drivers/media/platform/m2m-deinterlace.c
>>>>>> @@ -343,7 +343,7 @@ static void deinterlace_issue_dma(struct
>>>>>> deinterlace_ctx *ctx, int op,
>>>>>>         ctx->xt->dst_sgl = true;
>>>>>>         flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
>>>>>>
>>>>>> -     tx = dmadev->device_prep_interleaved_dma(chan, ctx->xt, flags);
>>>>>> +     tx = dmadev->device_prep_interleaved_dma(chan, &ctx->xt, flags);
>>>>>>         if (tx == NULL) {
>>>>>>                 v4l2_warn(&pcdev->v4l2_dev, "DMA interleaved prep
>>>>>> error\n");
>>>>>>                 return;
>>>>>> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
>>>>>> index c5c92d5..2f77a9a 100644
>>>>>> --- a/include/linux/dmaengine.h
>>>>>> +++ b/include/linux/dmaengine.h
>>>>>> @@ -675,7 +675,7 @@ struct dma_device {
>>>>>>                 size_t period_len, enum dma_transfer_direction
>>>>>> direction,
>>>>>>                 unsigned long flags, void *context);
>>>>>>         struct dma_async_tx_descriptor
>>>>>> *(*device_prep_interleaved_dma)(
>>>>>> -             struct dma_chan *chan, struct dma_interleaved_template
>>>>>> *xt,
>>>>>> +             struct dma_chan *chan, struct dma_interleaved_template
>>>>>> **xts,
>>>>>>                 unsigned long flags);
>>>>>>         int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd
>>>>>> cmd,
>>>>>>                 unsigned long arg);
>>>>>> @@ -752,10 +752,10 @@ static inline struct dma_async_tx_descriptor
>>>>>> *dmaengine_prep_dma_cyclic(
>>>>>>    }
>>>>>>
>>>>>>    static inline struct dma_async_tx_descriptor
>>>>>> *dmaengine_prep_interleaved_dma(
>>>>>> -             struct dma_chan *chan, struct dma_interleaved_template
>>>>>> *xt,
>>>>>> +             struct dma_chan *chan, struct dma_interleaved_template
>>>>>> **xts,
>>>>>>                 unsigned long flags)
>>>>>>    {
>>>>>> -     return chan->device->device_prep_interleaved_dma(chan, xt,
>>>>>> flags);
>>>>>> +     return chan->device->device_prep_interleaved_dma(chan, xts,
>>>>>> flags);
>>>>>>    }
>>>>>>
>>>>>>    static inline int dma_get_slave_caps(struct dma_chan *chan, struct
>>>>>> dma_slave_caps *caps)
>>>>>> --
>>>>>> 1.7.9.5
>>>>>>
>>>>>> --
>>>>>> To unsubscribe from this list: send the line "unsubscribe dmaengine"
>>>>>> in
>>>>>> the body of a message to majordomo at vger.kernel.org
>>>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> --
>>>>> To unsubscribe from this list: send the line "unsubscribe linux-kernel"
>>>>> in
>>>>> the body of a message to majordomo at vger.kernel.org
>>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>>> Please read the FAQ at  http://www.tux.org/lkml/
>>>
>>>
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-kernel"
>>> in
>>> the body of a message to majordomo at vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>> Please read the FAQ at  http://www.tux.org/lkml/
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/



More information about the linux-arm-kernel mailing list