[PATCHv10 11/26] v4l: vb2-dma-contig: add support for dma_buf importing
From: Sumit SemwalThis patch makes changes for adding dma-contig as a dma_buf user. It provides function implementations for the {attach, detach, map, unmap}_dmabuf() mem_ops of DMABUF memory type. Signed-off-by: Sumit Semwal Signed-off-by: Sumit Semwal [author of the original patch] Signed-off-by: Tomasz Stanislawski [integration with refactored dma-contig allocator] Acked-by: Laurent Pinchart --- drivers/media/v4l2-core/Kconfig|1 + drivers/media/v4l2-core/videobuf2-dma-contig.c | 120 +++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 2e787cc..e30583b 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -69,6 +69,7 @@ config VIDEOBUF2_DMA_CONTIG tristate select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS + select DMA_SHARED_BUFFER config VIDEOBUF2_VMALLOC tristate diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 494a824..a5804cf 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -10,6 +10,7 @@ * the Free Software Foundation. */ +#include #include #include #include @@ -38,6 +39,9 @@ struct vb2_dc_buf { /* USERPTR related */ struct vm_area_struct *vma; + + /* DMABUF related */ + struct dma_buf_attachment *db_attach; }; /*/ @@ -108,7 +112,8 @@ static void vb2_dc_prepare(void *buf_priv) struct vb2_dc_buf *buf = buf_priv; struct sg_table *sgt = buf->dma_sgt; - if (!sgt) + /* DMABUF exporter will flush the cache for us */ + if (!sgt || buf->db_attach) return; dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); @@ -119,7 +124,8 @@ static void vb2_dc_finish(void *buf_priv) struct vb2_dc_buf *buf = buf_priv; struct sg_table *sgt = buf->dma_sgt; - if (!sgt) + /* DMABUF exporter will flush the cache for us */ + if (!sgt || buf->db_attach) return; dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); @@ -377,6 +383,112 @@ fail_buf: } /*/ +/* callbacks for DMABUF buffers*/ +/*/ + +static int vb2_dc_map_dmabuf(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + struct sg_table *sgt; + unsigned long contig_size; + + if (WARN_ON(!buf->db_attach)) { + pr_err("trying to pin a non attached buffer\n"); + return -EINVAL; + } + + if (WARN_ON(buf->dma_sgt)) { + pr_err("dmabuf buffer is already pinned\n"); + return 0; + } + + /* get the associated scatterlist for this buffer */ + sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); + if (IS_ERR_OR_NULL(sgt)) { + pr_err("Error getting dmabuf scatterlist\n"); + return -EINVAL; + } + + /* checking if dmabuf is big enough to store contiguous chunk */ + contig_size = vb2_dc_get_contiguous_size(sgt); + if (contig_size < buf->size) { + pr_err("contiguous chunk is too small %lu/%lu b\n", + contig_size, buf->size); + dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); + return -EFAULT; + } + + buf->dma_addr = sg_dma_address(sgt->sgl); + buf->dma_sgt = sgt; + + return 0; +} + +static void vb2_dc_unmap_dmabuf(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + struct sg_table *sgt = buf->dma_sgt; + + if (WARN_ON(!buf->db_attach)) { + pr_err("trying to unpin a not attached buffer\n"); + return; + } + + if (WARN_ON(!sgt)) { + pr_err("dmabuf buffer is already unpinned\n"); + return; + } + + dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); + + buf->dma_addr = 0; + buf->dma_sgt = NULL; +} + +static void vb2_dc_detach_dmabuf(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + + /* if vb2 works correctly you should never detach mapped buffer */ + if (WARN_ON(buf->dma_addr)) + vb2_dc_unmap_dmabuf(buf); + + /* detach this attachment */ + dma_buf_detach(buf->db_attach->dmabuf, buf->db_attach); + kfree(buf); +} + +static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, + unsigned long size, int write) +{ + struct vb2_dc_conf *conf = alloc_ctx; + struct vb2_dc_buf *buf; + struct dma_buf_attachment *dba; + + if (dbuf->size < size) + return ERR_PTR(-EFAULT); + +
[PATCHv10 11/26] v4l: vb2-dma-contig: add support for dma_buf importing
From: Sumit Semwal sumit.sem...@ti.com This patch makes changes for adding dma-contig as a dma_buf user. It provides function implementations for the {attach, detach, map, unmap}_dmabuf() mem_ops of DMABUF memory type. Signed-off-by: Sumit Semwal sumit.sem...@ti.com Signed-off-by: Sumit Semwal sumit.sem...@linaro.org [author of the original patch] Signed-off-by: Tomasz Stanislawski t.stanisl...@samsung.com [integration with refactored dma-contig allocator] Acked-by: Laurent Pinchart laurent.pinch...@ideasonboard.com --- drivers/media/v4l2-core/Kconfig|1 + drivers/media/v4l2-core/videobuf2-dma-contig.c | 120 +++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 2e787cc..e30583b 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -69,6 +69,7 @@ config VIDEOBUF2_DMA_CONTIG tristate select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS + select DMA_SHARED_BUFFER config VIDEOBUF2_VMALLOC tristate diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 494a824..a5804cf 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -10,6 +10,7 @@ * the Free Software Foundation. */ +#include linux/dma-buf.h #include linux/module.h #include linux/scatterlist.h #include linux/sched.h @@ -38,6 +39,9 @@ struct vb2_dc_buf { /* USERPTR related */ struct vm_area_struct *vma; + + /* DMABUF related */ + struct dma_buf_attachment *db_attach; }; /*/ @@ -108,7 +112,8 @@ static void vb2_dc_prepare(void *buf_priv) struct vb2_dc_buf *buf = buf_priv; struct sg_table *sgt = buf-dma_sgt; - if (!sgt) + /* DMABUF exporter will flush the cache for us */ + if (!sgt || buf-db_attach) return; dma_sync_sg_for_device(buf-dev, sgt-sgl, sgt-nents, buf-dma_dir); @@ -119,7 +124,8 @@ static void vb2_dc_finish(void *buf_priv) struct vb2_dc_buf *buf = buf_priv; struct sg_table *sgt = buf-dma_sgt; - if (!sgt) + /* DMABUF exporter will flush the cache for us */ + if (!sgt || buf-db_attach) return; dma_sync_sg_for_cpu(buf-dev, sgt-sgl, sgt-nents, buf-dma_dir); @@ -377,6 +383,112 @@ fail_buf: } /*/ +/* callbacks for DMABUF buffers*/ +/*/ + +static int vb2_dc_map_dmabuf(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + struct sg_table *sgt; + unsigned long contig_size; + + if (WARN_ON(!buf-db_attach)) { + pr_err(trying to pin a non attached buffer\n); + return -EINVAL; + } + + if (WARN_ON(buf-dma_sgt)) { + pr_err(dmabuf buffer is already pinned\n); + return 0; + } + + /* get the associated scatterlist for this buffer */ + sgt = dma_buf_map_attachment(buf-db_attach, buf-dma_dir); + if (IS_ERR_OR_NULL(sgt)) { + pr_err(Error getting dmabuf scatterlist\n); + return -EINVAL; + } + + /* checking if dmabuf is big enough to store contiguous chunk */ + contig_size = vb2_dc_get_contiguous_size(sgt); + if (contig_size buf-size) { + pr_err(contiguous chunk is too small %lu/%lu b\n, + contig_size, buf-size); + dma_buf_unmap_attachment(buf-db_attach, sgt, buf-dma_dir); + return -EFAULT; + } + + buf-dma_addr = sg_dma_address(sgt-sgl); + buf-dma_sgt = sgt; + + return 0; +} + +static void vb2_dc_unmap_dmabuf(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + struct sg_table *sgt = buf-dma_sgt; + + if (WARN_ON(!buf-db_attach)) { + pr_err(trying to unpin a not attached buffer\n); + return; + } + + if (WARN_ON(!sgt)) { + pr_err(dmabuf buffer is already unpinned\n); + return; + } + + dma_buf_unmap_attachment(buf-db_attach, sgt, buf-dma_dir); + + buf-dma_addr = 0; + buf-dma_sgt = NULL; +} + +static void vb2_dc_detach_dmabuf(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + + /* if vb2 works correctly you should never detach mapped buffer */ + if (WARN_ON(buf-dma_addr)) + vb2_dc_unmap_dmabuf(buf); + + /* detach this attachment */ + dma_buf_detach(buf-db_attach-dmabuf, buf-db_attach); + kfree(buf); +} + +static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, + unsigned long size, int write) +{ + struct vb2_dc_conf *conf = alloc_ctx; + struct vb2_dc_buf