Re: [PATCHv9 03/25] v4l: vb2: add support for shared buffer (dma_buf)

2012-10-05 Thread Hans Verkuil
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)

2012-10-02 Thread Tomasz Stanislawski
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