Hi Sumit,
Thanks for the patch!
Sumit Semwal wrote: ...
@@ -962,6 +1030,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);
- 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 = PTR_ERR(dbuf);goto err;}/* this doesn't get filled in until __fill_vb2_buffer(),* since it isn't known until after dma_buf_get()..*/planes[plane].length = dbuf->size;/* Skip the plane if already verified */if (dbuf == vb->planes[plane].dbuf) {dma_buf_put(dbuf);continue;}dprintk(3, "qbuf: buffer description for plane %d changed, ""reattaching dma buf\n", plane);/* Release previously acquired memory if present */if (vb->planes[plane].mem_priv) {call_memop(q, plane, detach_dmabuf,vb->planes[plane].mem_priv);dma_buf_put(vb->planes[plane].dbuf);}vb->planes[plane].mem_priv = NULL;/* Acquire each plane's memory */mem_priv = q->mem_ops->attach_dmabuf(q->alloc_ctx[plane], dbuf);if (IS_ERR(mem_priv)) {dprintk(1, "qbuf: failed acquiring dmabuf ""memory for plane %d\n", plane);ret = PTR_ERR(mem_priv);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 = q->mem_ops->map_dmabuf(vb->planes[plane].mem_priv, write);if (ret) {dprintk(1, "qbuf: failed mapping dmabuf ""memory for plane %d\n", plane);goto err;}- }
Shouldn't the buffer mapping only be done at the first call to __qbuf_dmabuf()? On latter calls, the cache would need to be handled according to presence of V4L2_BUF_FLAG_NO_CACHE_CLEAN / V4L2_BUF_FLAG_NO_CACHE_INVALIDATE in v4l2_buffer.
- /*
* 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 already acquired */
- __vb2_buf_dmabuf_put(vb);
- return ret;
+}
+/**
- __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing
*/ static void __enqueue_in_driver(struct vb2_buffer *vb) @@ -985,6 +1156,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) case V4L2_MEMORY_USERPTR: ret = __qbuf_userptr(vb, b); break;
- case V4L2_MEMORY_DMABUF:
ret = __qbuf_dmabuf(vb, b); default: WARN(1, "Invalid queue type\n"); ret = -EINVAL;break;@@ -1284,6 +1458,7 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) { struct vb2_buffer *vb = NULL; int ret;
- unsigned int plane;
if (q->fileio) { dprintk(1, "dqbuf: file io in progress\n"); @@ -1307,6 +1482,15 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) return ret; }
- /* TODO: this unpins the buffer(dma_buf_unmap_attachment()).. but
* really we want tot do this just after DMA, not when the* buffer is dequeued..*/- if (q->memory == V4L2_MEMORY_DMABUF)
for (plane = 0; plane < vb->num_planes; ++plane)call_memop(q, plane, unmap_dmabuf,vb->planes[plane].mem_priv);
Same here, except reverse: this only should be done when the buffer is destroyed --- either when the user explicitly calls reqbufs(0) or when the file handle owning this buffer is being closed.
Mapping buffers at every prepare_buf and unmapping them in dqbuf is prohibitively expensive. Same goes for many other APIs than V4L2, I think.
I wonder if the means to do this exists already.
I have to admit I haven't followed the dma_buf discussion closely so I might be missing something relevant here.
Kind regards,