[PATCHv8 20/26] v4l: vb2-dma-contig: add support for DMABUF exporting
Tomasz Stanislawski
t.stanislaws at samsung.com
Tue Aug 21 06:47:13 PDT 2012
Hi Laurent,
Thank you for your comments.
On 08/21/2012 12:03 PM, Laurent Pinchart wrote:
> Hi Tomasz,
>
> Thanks for the patch.
>
> Just a couple of small comments below.
>
> On Tuesday 14 August 2012 17:34:50 Tomasz Stanislawski wrote:
>> This patch adds support for exporting a dma-contig buffer using
>> DMABUF interface.
>>
>> Signed-off-by: Tomasz Stanislawski <t.stanislaws at samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
>> ---
>> drivers/media/video/videobuf2-dma-contig.c | 204 +++++++++++++++++++++++++
>> 1 file changed, 204 insertions(+)
>>
>> diff --git a/drivers/media/video/videobuf2-dma-contig.c
>> b/drivers/media/video/videobuf2-dma-contig.c index 7fc71a0..bb2b4ac8 100644
>> --- a/drivers/media/video/videobuf2-dma-contig.c
>> +++ b/drivers/media/video/videobuf2-dma-contig.c
>
> [snip]
>
>> +static struct sg_table *vb2_dc_dmabuf_ops_map(
>> + struct dma_buf_attachment *db_attach, enum dma_data_direction dir)
>> +{
>> + struct vb2_dc_attachment *attach = db_attach->priv;
>> + /* stealing dmabuf mutex to serialize map/unmap operations */
>
> Why isn't this operation serialized by the dma-buf core itself ?
>
Indeed, it is a very good question. The lock was introduced in RFCv3 of
DMABUF patches. It was dedicated to serialize attach/detach calls.
No requirements for map/unmap serialization were stated so serialization
was delegated to an exporter.
A deadlock could occur if dma_map_attachment is called from inside
of attach ops. IMO, such an operation is invalid because an attachment
list is not in a valid state while attach ops is being processed.
Do you think that stealing a lock from dma-buf internals is too hacky?
I prefer not to introduce any extra locks in dma-contig allocator
but it is not a big deal to add it.
>> + struct mutex *lock = &db_attach->dmabuf->lock;
>> + struct sg_table *sgt;
>> + int ret;
>> +
>> + mutex_lock(lock);
>> +
>> + sgt = &attach->sgt;
>> + /* return previously mapped sg table */
>> + if (attach->dir == dir) {
>> + mutex_unlock(lock);
>> + return sgt;
>> + }
>> +
>> + /* release any previous cache */
>> + if (attach->dir != DMA_NONE) {
>> + dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
>> + attach->dir);
>> + attach->dir = DMA_NONE;
>> + }
>> +
>> + /* mapping to the client with new direction */
>> + ret = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dir);
>> + if (ret <= 0) {
>> + pr_err("failed to map scatterlist\n");
>> + mutex_unlock(lock);
>> + return ERR_PTR(-EIO);
>> + }
>> +
>> + attach->dir = dir;
>> +
>> + mutex_unlock(lock);
>> +
>> + return sgt;
>> +}
>
> [snip]
>
>> +static int vb2_dc_dmabuf_ops_mmap(struct dma_buf *dbuf,
>> + struct vm_area_struct *vma)
>> +{
>> + /* Dummy support for mmap */
>> + return -ENOTTY;
>
> What about calling the dma-contig mmap handler here ? Is there a specific
> reason why you haven't implemented mmap support for dmabuf ?
>
The mmap ops is mandatory in the latest DMABUF api.
I added a stub function to make DC work with DMABUF without any big effort.
Calling vb2_dc_mmap from mmap ops seams to be a simple and safe way to
handle mmap functionality. Thank you for spotting this :)
>> +}
>> +
>> +static struct dma_buf_ops vb2_dc_dmabuf_ops = {
>> + .attach = vb2_dc_dmabuf_ops_attach,
>> + .detach = vb2_dc_dmabuf_ops_detach,
>> + .map_dma_buf = vb2_dc_dmabuf_ops_map,
>> + .unmap_dma_buf = vb2_dc_dmabuf_ops_unmap,
>> + .kmap = vb2_dc_dmabuf_ops_kmap,
>> + .kmap_atomic = vb2_dc_dmabuf_ops_kmap,
>> + .vmap = vb2_dc_dmabuf_ops_vmap,
>> + .mmap = vb2_dc_dmabuf_ops_mmap,
>> + .release = vb2_dc_dmabuf_ops_release,
>> +};
>> +
>> +static struct sg_table *vb2_dc_get_base_sgt(struct vb2_dc_buf *buf)
>> +{
>> + int ret;
>> + struct sg_table *sgt;
>> +
>> + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
>> + if (!sgt) {
>> + dev_err(buf->dev, "failed to alloc sg table\n");
>> + return ERR_PTR(-ENOMEM);
>> + }
>> +
>> + ret = dma_get_sgtable(buf->dev, sgt, buf->vaddr, buf->dma_addr,
>> + buf->size);
>> + if (ret < 0) {
>> + dev_err(buf->dev, "failed to get scatterlist from DMA API\n");
>> + kfree(sgt);
>> + return ERR_PTR(ret);
>> + }
>
> As this function is only used below, where the exact value of the error code
> is ignored, what about just returning NULL on failure ? Another option is to
> return the error code in vb2_dc_get_dmabuf (not sure if that would be useful
> though).
>
>> +
>> + return sgt;
>> +}
>> +
>> +static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv)
>> +{
>> + struct vb2_dc_buf *buf = buf_priv;
>> + struct dma_buf *dbuf;
>> + struct sg_table *sgt = buf->sgt_base;
>> +
>> + if (!sgt)
>> + sgt = vb2_dc_get_base_sgt(buf);
>> + if (WARN_ON(IS_ERR(sgt)))
>> + return NULL;
>> +
>> + /* cache base sgt for future use */
>> + buf->sgt_base = sgt;
>
> You can move this assignment inside the first if, there's no need to execute
> it every time. The WARN_ON can also be moved inside the first if, as buf-
>> sgt_base will either be NULL or valid. You can then get rid of the sgt
> variable initialization by testing if (!buf->sgt_base).
I agree. I will apply this fix in v9.
>
>> + dbuf = dma_buf_export(buf, &vb2_dc_dmabuf_ops, buf->size, 0);
>> + if (IS_ERR(dbuf))
>> + return NULL;
>> +
>> + /* dmabuf keeps reference to vb2 buffer */
>> + atomic_inc(&buf->refcount);
>> +
>> + return dbuf;
>> +}
>
Regards,
Tomasz Stanislawski
More information about the dri-devel
mailing list