Re: [PATCHv10 20/26] v4l: vb2-dma-contig: add support for DMABUF exporting
Hi Tomasz, On Wednesday 10 October 2012 16:46:39 Tomasz Stanislawski wrote: This patch adds support for exporting a dma-contig buffer using DMABUF interface. Signed-off-by: Tomasz Stanislawski t.stanisl...@samsung.com Signed-off-by: Kyungmin Park kyungmin.p...@samsung.com Acked-by: Hans Verkuil hans.verk...@cisco.com Acked-by: Laurent Pinchart laurent.pinch...@ideasonboard.com --- drivers/media/v4l2-core/videobuf2-dma-contig.c | 200 + 1 file changed, 200 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 0e065ce..b138b5c 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -36,6 +36,7 @@ struct vb2_dc_buf { /* MMAP related */ struct vb2_vmarea_handler handler; atomic_trefcount; + struct sg_table *sgt_base; /* USERPTR related */ struct vm_area_struct *vma; @@ -142,6 +143,10 @@ static void vb2_dc_put(void *buf_priv) if (!atomic_dec_and_test(buf-refcount)) return; + if (buf-sgt_base) { + sg_free_table(buf-sgt_base); + kfree(buf-sgt_base); + } dma_free_coherent(buf-dev, buf-size, buf-vaddr, buf-dma_addr); kfree(buf); } @@ -213,6 +218,200 @@ static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma) } /*/ +/* DMABUF ops for exporters */ +/*/ + +struct vb2_dc_attachment { + struct sg_table sgt; + enum dma_data_direction dir; +}; + +static int vb2_dc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, + struct dma_buf_attachment *dbuf_attach) +{ + struct vb2_dc_attachment *attach; + unsigned int i; + struct scatterlist *rd, *wr; + struct sg_table *sgt; + struct vb2_dc_buf *buf = dbuf-priv; + int ret; + + attach = kzalloc(sizeof(*attach), GFP_KERNEL); + if (!attach) + return -ENOMEM; + + sgt = attach-sgt; + /* Copy the buf-base_sgt scatter list to the attachment, as we can't + * map the same scatter list to multiple attachments at the same time. + */ + ret = sg_alloc_table(sgt, buf-sgt_base-orig_nents, GFP_KERNEL); + if (ret) { + kfree(attach); + return -ENOMEM; + } + + rd = buf-sgt_base-sgl; + wr = sgt-sgl; + for (i = 0; i sgt-orig_nents; ++i) { + sg_set_page(wr, sg_page(rd), rd-length, rd-offset); + rd = sg_next(rd); + wr = sg_next(wr); + } + + attach-dir = DMA_NONE; + dbuf_attach-priv = attach; + + return 0; +} + +static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf, + struct dma_buf_attachment *db_attach) +{ + struct vb2_dc_attachment *attach = db_attach-priv; + struct sg_table *sgt; + + if (!attach) + return; + + sgt = attach-sgt; + + /* release the scatterlist cache */ + if (attach-dir != DMA_NONE) + dma_unmap_sg(db_attach-dev, sgt-sgl, sgt-orig_nents, + attach-dir); + sg_free_table(sgt); + kfree(attach); + db_attach-priv = NULL; +} + +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 */ + 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; +} + +static void vb2_dc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach, + struct sg_table *sgt, enum dma_data_direction dir) +{ + /* nothing to be done here */ +} + +static void vb2_dc_dmabuf_ops_release(struct dma_buf *dbuf) +{ + /* drop reference obtained in vb2_dc_get_dmabuf */ + vb2_dc_put(dbuf-priv); +} + +static void *vb2_dc_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum) +{ + struct
[PATCHv10 20/26] v4l: vb2-dma-contig: add support for DMABUF exporting
This patch adds support for exporting a dma-contig buffer using DMABUF interface. Signed-off-by: Tomasz Stanislawski t.stanisl...@samsung.com Signed-off-by: Kyungmin Park kyungmin.p...@samsung.com Acked-by: Hans Verkuil hans.verk...@cisco.com --- drivers/media/v4l2-core/videobuf2-dma-contig.c | 200 1 file changed, 200 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 0e065ce..b138b5c 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -36,6 +36,7 @@ struct vb2_dc_buf { /* MMAP related */ struct vb2_vmarea_handler handler; atomic_trefcount; + struct sg_table *sgt_base; /* USERPTR related */ struct vm_area_struct *vma; @@ -142,6 +143,10 @@ static void vb2_dc_put(void *buf_priv) if (!atomic_dec_and_test(buf-refcount)) return; + if (buf-sgt_base) { + sg_free_table(buf-sgt_base); + kfree(buf-sgt_base); + } dma_free_coherent(buf-dev, buf-size, buf-vaddr, buf-dma_addr); kfree(buf); } @@ -213,6 +218,200 @@ static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma) } /*/ +/* DMABUF ops for exporters */ +/*/ + +struct vb2_dc_attachment { + struct sg_table sgt; + enum dma_data_direction dir; +}; + +static int vb2_dc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, + struct dma_buf_attachment *dbuf_attach) +{ + struct vb2_dc_attachment *attach; + unsigned int i; + struct scatterlist *rd, *wr; + struct sg_table *sgt; + struct vb2_dc_buf *buf = dbuf-priv; + int ret; + + attach = kzalloc(sizeof(*attach), GFP_KERNEL); + if (!attach) + return -ENOMEM; + + sgt = attach-sgt; + /* Copy the buf-base_sgt scatter list to the attachment, as we can't +* map the same scatter list to multiple attachments at the same time. +*/ + ret = sg_alloc_table(sgt, buf-sgt_base-orig_nents, GFP_KERNEL); + if (ret) { + kfree(attach); + return -ENOMEM; + } + + rd = buf-sgt_base-sgl; + wr = sgt-sgl; + for (i = 0; i sgt-orig_nents; ++i) { + sg_set_page(wr, sg_page(rd), rd-length, rd-offset); + rd = sg_next(rd); + wr = sg_next(wr); + } + + attach-dir = DMA_NONE; + dbuf_attach-priv = attach; + + return 0; +} + +static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf, + struct dma_buf_attachment *db_attach) +{ + struct vb2_dc_attachment *attach = db_attach-priv; + struct sg_table *sgt; + + if (!attach) + return; + + sgt = attach-sgt; + + /* release the scatterlist cache */ + if (attach-dir != DMA_NONE) + dma_unmap_sg(db_attach-dev, sgt-sgl, sgt-orig_nents, + attach-dir); + sg_free_table(sgt); + kfree(attach); + db_attach-priv = NULL; +} + +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 */ + 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; +} + +static void vb2_dc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach, + struct sg_table *sgt, enum dma_data_direction dir) +{ + /* nothing to be done here */ +} + +static void vb2_dc_dmabuf_ops_release(struct dma_buf *dbuf) +{ + /* drop reference obtained in vb2_dc_get_dmabuf */ + vb2_dc_put(dbuf-priv); +} + +static void *vb2_dc_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum) +{ + struct vb2_dc_buf *buf = dbuf-priv; + + return buf-vaddr + pgnum * PAGE_SIZE; +} + +static void