Re: [PATCHv9 03/25] v4l: vb2: add support for shared buffer (dma_buf)
Just a small heads-up for an upcoming change... On Tue October 2 2012 16:27:14 Tomasz Stanislawski wrote: From: Sumit Semwal sumit.sem...@ti.com This patch adds support for DMABUF memory type in videobuf2. It calls relevant APIs of dma_buf for v4l reqbuf / qbuf / dqbuf operations. For this version, the support is for videobuf2 as a user of the shared buffer; so the allocation of the buffer is done outside of V4L2. [A sample allocator of dma-buf shared buffer is given at [1]] [1]: Rob Clark's DRM: https://github.com/robclark/kernel-omap4/commits/drmplane-dmabuf Signed-off-by: Tomasz Stanislawski t.stanisl...@samsung.com [original work in the PoC for buffer sharing] Signed-off-by: Sumit Semwal sumit.sem...@ti.com Signed-off-by: Sumit Semwal sumit.sem...@linaro.org Acked-by: Laurent Pinchart laurent.pinch...@ideasonboard.com --- drivers/media/video/Kconfig |1 + drivers/media/video/videobuf2-core.c | 207 +- include/media/videobuf2-core.h | 27 + 3 files changed, 232 insertions(+), 3 deletions(-) snip @@ -970,6 +1040,109 @@ static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) } /** + * __qbuf_dmabuf() - handle qbuf of a DMABUF buffer + */ +static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) +{ + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + struct vb2_queue *q = vb-vb2_queue; + void *mem_priv; + unsigned int plane; + int ret; + int write = !V4L2_TYPE_IS_OUTPUT(q-type); + + /* Verify and copy relevant information provided by the userspace */ + ret = __fill_vb2_buffer(vb, b, planes); Note that this code will have to change a bit when my multiplanar fixes go in: http://www.spinics.net/lists/linux-media/msg54601.html __fill_vb2_buffer is now a void function, so there won't be any need to check the error. + if (ret) + return ret; + + for (plane = 0; plane vb-num_planes; ++plane) { + struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd); + + if (IS_ERR_OR_NULL(dbuf)) { + dprintk(1, qbuf: invalid dmabuf fd for plane %d\n, + plane); + ret = -EINVAL; + goto err; + } + + /* use DMABUF size if length is not provided */ + if (planes[plane].length == 0) + planes[plane].length = dbuf-size; + + if (planes[plane].length planes[plane].data_offset + + q-plane_sizes[plane]) { + ret = -EINVAL; + goto err; + } + + /* Skip the plane if already verified */ + if (dbuf == vb-planes[plane].dbuf + vb-v4l2_planes[plane].length == planes[plane].length) { + dma_buf_put(dbuf); + continue; + } + + dprintk(1, qbuf: buffer for plane %d changed\n, plane); + + /* Release previously acquired memory if present */ + __vb2_plane_dmabuf_put(q, vb-planes[plane]); + memset(vb-v4l2_planes[plane], 0, sizeof(struct v4l2_plane)); + + /* Acquire each plane's memory */ + mem_priv = call_memop(q, attach_dmabuf, q-alloc_ctx[plane], + dbuf, planes[plane].length, write); + if (IS_ERR(mem_priv)) { + dprintk(1, qbuf: failed to attach dmabuf\n); + ret = PTR_ERR(mem_priv); + dma_buf_put(dbuf); + goto err; + } + + vb-planes[plane].dbuf = dbuf; + vb-planes[plane].mem_priv = mem_priv; + } + + /* TODO: This pins the buffer(s) with dma_buf_map_attachment()).. but + * really we want to do this just before the DMA, not while queueing + * the buffer(s).. + */ + for (plane = 0; plane vb-num_planes; ++plane) { + ret = call_memop(q, map_dmabuf, vb-planes[plane].mem_priv); + if (ret) { + dprintk(1, qbuf: failed to map dmabuf for plane %d\n, + plane); + goto err; + } + vb-planes[plane].dbuf_mapped = 1; + } + + /* + * Call driver-specific initialization on the newly acquired buffer, + * if provided. + */ + ret = call_qop(q, buf_init, vb); + if (ret) { + dprintk(1, qbuf: buffer initialization failed\n); + goto err; + } + + /* + * Now that everything is in order, copy relevant information + * provided by userspace. + */ + for (plane = 0; plane vb-num_planes; ++plane) + vb-v4l2_planes[plane] = planes[plane]; + + return 0; +err: + /* In case of errors, release planes that were
[PATCHv9 03/25] v4l: vb2: add support for shared buffer (dma_buf)
From: Sumit Semwal sumit.sem...@ti.com This patch adds support for DMABUF memory type in videobuf2. It calls relevant APIs of dma_buf for v4l reqbuf / qbuf / dqbuf operations. For this version, the support is for videobuf2 as a user of the shared buffer; so the allocation of the buffer is done outside of V4L2. [A sample allocator of dma-buf shared buffer is given at [1]] [1]: Rob Clark's DRM: https://github.com/robclark/kernel-omap4/commits/drmplane-dmabuf Signed-off-by: Tomasz Stanislawski t.stanisl...@samsung.com [original work in the PoC for buffer sharing] Signed-off-by: Sumit Semwal sumit.sem...@ti.com Signed-off-by: Sumit Semwal sumit.sem...@linaro.org Acked-by: Laurent Pinchart laurent.pinch...@ideasonboard.com --- drivers/media/video/Kconfig |1 + drivers/media/video/videobuf2-core.c | 207 +- include/media/videobuf2-core.h | 27 + 3 files changed, 232 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c128fac..c558d37 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -45,6 +45,7 @@ config V4L2_MEM2MEM_DEV depends on VIDEOBUF2_CORE config VIDEOBUF2_CORE + select DMA_SHARED_BUFFER tristate config VIDEOBUF2_MEMOPS diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 268c7dd..901bc56 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -109,6 +109,36 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) } /** + * __vb2_plane_dmabuf_put() - release memory associated with + * a DMABUF shared plane + */ +static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p) +{ + if (!p-mem_priv) + return; + + if (p-dbuf_mapped) + call_memop(q, unmap_dmabuf, p-mem_priv); + + call_memop(q, detach_dmabuf, p-mem_priv); + dma_buf_put(p-dbuf); + memset(p, 0, sizeof(*p)); +} + +/** + * __vb2_buf_dmabuf_put() - release memory associated with + * a DMABUF shared buffer + */ +static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb-vb2_queue; + unsigned int plane; + + for (plane = 0; plane vb-num_planes; ++plane) + __vb2_plane_dmabuf_put(q, vb-planes[plane]); +} + +/** * __setup_offsets() - setup unique offsets (cookies) for every plane in * every buffer on the queue */ @@ -230,6 +260,8 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) /* Free MMAP buffers or release USERPTR buffers */ if (q-memory == V4L2_MEMORY_MMAP) __vb2_buf_mem_free(vb); + else if (q-memory == V4L2_MEMORY_DMABUF) + __vb2_buf_dmabuf_put(vb); else __vb2_buf_userptr_put(vb); } @@ -363,6 +395,8 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) b-m.offset = vb-v4l2_planes[0].m.mem_offset; else if (q-memory == V4L2_MEMORY_USERPTR) b-m.userptr = vb-v4l2_planes[0].m.userptr; + else if (q-memory == V4L2_MEMORY_DMABUF) + b-m.fd = vb-v4l2_planes[0].m.fd; } /* @@ -454,13 +488,28 @@ static int __verify_mmap_ops(struct vb2_queue *q) } /** + * __verify_dmabuf_ops() - verify that all memory operations required for + * DMABUF queue type have been provided + */ +static int __verify_dmabuf_ops(struct vb2_queue *q) +{ + if (!(q-io_modes VB2_DMABUF) || !q-mem_ops-attach_dmabuf || + !q-mem_ops-detach_dmabuf || !q-mem_ops-map_dmabuf || + !q-mem_ops-unmap_dmabuf) + return -EINVAL; + + return 0; +} + +/** * __verify_memory_type() - Check whether the memory type and buffer type * passed to a buffer operation are compatible with the queue. */ static int __verify_memory_type(struct vb2_queue *q, enum v4l2_memory memory, enum v4l2_buf_type type) { - if (memory != V4L2_MEMORY_MMAP memory != V4L2_MEMORY_USERPTR) { + if (memory != V4L2_MEMORY_MMAP memory != V4L2_MEMORY_USERPTR + memory != V4L2_MEMORY_DMABUF) { dprintk(1, reqbufs: unsupported memory type\n); return -EINVAL; } @@ -484,6 +533,11 @@ static int __verify_memory_type(struct vb2_queue *q, return -EINVAL; } + if (memory == V4L2_MEMORY_DMABUF __verify_dmabuf_ops(q)) { + dprintk(1, reqbufs: DMABUF for current setup unsupported\n); + return -EINVAL; + } + /* * Place the busy tests at the end: -EBUSY can be ignored when * create_bufs is called with count == 0, but count == 0 should still @@ -853,6 +907,16 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct