Commit b5b4541e authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] vb2: add debugging code to check for unbalanced ops

When a vb2_queue is freed check if all the mem_ops and queue ops were balanced.
So the number of calls to e.g. buf_finish has to match the number of calls to
buf_prepare, etc.

This code is only enabled if CONFIG_VIDEO_ADV_DEBUG is set.
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Acked-by: default avatarPawel Osciak <pawel@osciak.com>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 952c9ee2
...@@ -33,12 +33,63 @@ module_param(debug, int, 0644); ...@@ -33,12 +33,63 @@ module_param(debug, int, 0644);
printk(KERN_DEBUG "vb2: " fmt, ## arg); \ printk(KERN_DEBUG "vb2: " fmt, ## arg); \
} while (0) } while (0)
#define call_memop(q, op, args...) \ #ifdef CONFIG_VIDEO_ADV_DEBUG
(((q)->mem_ops->op) ? \
((q)->mem_ops->op(args)) : 0) /*
* If advanced debugging is on, then count how often each op is called,
* which can either be per-buffer or per-queue.
*
* If the op failed then the 'fail_' variant is called to decrease the
* counter. That makes it easy to check that the 'init' and 'cleanup'
* (and variations thereof) stay balanced.
*/
#define call_memop(vb, op, args...) \
({ \
struct vb2_queue *_q = (vb)->vb2_queue; \
dprintk(2, "call_memop(%p, %d, %s)%s\n", \
_q, (vb)->v4l2_buf.index, #op, \
_q->mem_ops->op ? "" : " (nop)"); \
(vb)->cnt_mem_ ## op++; \
_q->mem_ops->op ? _q->mem_ops->op(args) : 0; \
})
#define fail_memop(vb, op) ((vb)->cnt_mem_ ## op--)
#define call_qop(q, op, args...) \
({ \
dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \
(q)->ops->op ? "" : " (nop)"); \
(q)->cnt_ ## op++; \
(q)->ops->op ? (q)->ops->op(args) : 0; \
})
#define fail_qop(q, op) ((q)->cnt_ ## op--)
#define call_vb_qop(vb, op, args...) \
({ \
struct vb2_queue *_q = (vb)->vb2_queue; \
dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \
_q, (vb)->v4l2_buf.index, #op, \
_q->ops->op ? "" : " (nop)"); \
(vb)->cnt_ ## op++; \
_q->ops->op ? _q->ops->op(args) : 0; \
})
#define fail_vb_qop(vb, op) ((vb)->cnt_ ## op--)
#else
#define call_memop(vb, op, args...) \
((vb)->vb2_queue->mem_ops->op ? (vb)->vb2_queue->mem_ops->op(args) : 0)
#define fail_memop(vb, op)
#define call_qop(q, op, args...) \ #define call_qop(q, op, args...) \
(((q)->ops->op) ? ((q)->ops->op(args)) : 0) ((q)->ops->op ? (q)->ops->op(args) : 0)
#define fail_qop(q, op)
#define call_vb_qop(vb, op, args...) \
((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0)
#define fail_vb_qop(vb, op)
#endif
/* Flags that are set by the vb2 core */ /* Flags that are set by the vb2 core */
#define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ #define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
...@@ -65,7 +116,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) ...@@ -65,7 +116,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
for (plane = 0; plane < vb->num_planes; ++plane) { for (plane = 0; plane < vb->num_planes; ++plane) {
unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]); unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]);
mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], mem_priv = call_memop(vb, alloc, q->alloc_ctx[plane],
size, q->gfp_flags); size, q->gfp_flags);
if (IS_ERR_OR_NULL(mem_priv)) if (IS_ERR_OR_NULL(mem_priv))
goto free; goto free;
...@@ -77,9 +128,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) ...@@ -77,9 +128,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
return 0; return 0;
free: free:
fail_memop(vb, alloc);
/* Free already allocated memory if one of the allocations failed */ /* Free already allocated memory if one of the allocations failed */
for (; plane > 0; --plane) { for (; plane > 0; --plane) {
call_memop(q, put, vb->planes[plane - 1].mem_priv); call_memop(vb, put, vb->planes[plane - 1].mem_priv);
vb->planes[plane - 1].mem_priv = NULL; vb->planes[plane - 1].mem_priv = NULL;
} }
...@@ -91,11 +143,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) ...@@ -91,11 +143,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
*/ */
static void __vb2_buf_mem_free(struct vb2_buffer *vb) static void __vb2_buf_mem_free(struct vb2_buffer *vb)
{ {
struct vb2_queue *q = vb->vb2_queue;
unsigned int plane; unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane) { for (plane = 0; plane < vb->num_planes; ++plane) {
call_memop(q, put, vb->planes[plane].mem_priv); call_memop(vb, put, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL; vb->planes[plane].mem_priv = NULL;
dprintk(3, "Freed plane %d of buffer %d\n", plane, dprintk(3, "Freed plane %d of buffer %d\n", plane,
vb->v4l2_buf.index); vb->v4l2_buf.index);
...@@ -108,12 +159,11 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb) ...@@ -108,12 +159,11 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb)
*/ */
static void __vb2_buf_userptr_put(struct vb2_buffer *vb) static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
{ {
struct vb2_queue *q = vb->vb2_queue;
unsigned int plane; unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane) { for (plane = 0; plane < vb->num_planes; ++plane) {
if (vb->planes[plane].mem_priv) if (vb->planes[plane].mem_priv)
call_memop(q, put_userptr, vb->planes[plane].mem_priv); call_memop(vb, put_userptr, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL; vb->planes[plane].mem_priv = NULL;
} }
} }
...@@ -122,15 +172,15 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) ...@@ -122,15 +172,15 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
* __vb2_plane_dmabuf_put() - release memory associated with * __vb2_plane_dmabuf_put() - release memory associated with
* a DMABUF shared plane * a DMABUF shared plane
*/ */
static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p) static void __vb2_plane_dmabuf_put(struct vb2_buffer *vb, struct vb2_plane *p)
{ {
if (!p->mem_priv) if (!p->mem_priv)
return; return;
if (p->dbuf_mapped) if (p->dbuf_mapped)
call_memop(q, unmap_dmabuf, p->mem_priv); call_memop(vb, unmap_dmabuf, p->mem_priv);
call_memop(q, detach_dmabuf, p->mem_priv); call_memop(vb, detach_dmabuf, p->mem_priv);
dma_buf_put(p->dbuf); dma_buf_put(p->dbuf);
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
} }
...@@ -141,11 +191,10 @@ static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p) ...@@ -141,11 +191,10 @@ static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p)
*/ */
static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb)
{ {
struct vb2_queue *q = vb->vb2_queue;
unsigned int plane; unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane) for (plane = 0; plane < vb->num_planes; ++plane)
__vb2_plane_dmabuf_put(q, &vb->planes[plane]); __vb2_plane_dmabuf_put(vb, &vb->planes[plane]);
} }
/** /**
...@@ -250,10 +299,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, ...@@ -250,10 +299,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
* callback, if given. An error in initialization * callback, if given. An error in initialization
* results in queue setup failure. * results in queue setup failure.
*/ */
ret = call_qop(q, buf_init, vb); ret = call_vb_qop(vb, buf_init, vb);
if (ret) { if (ret) {
dprintk(1, "Buffer %d %p initialization" dprintk(1, "Buffer %d %p initialization"
" failed\n", buffer, vb); " failed\n", buffer, vb);
fail_vb_qop(vb, buf_init);
__vb2_buf_mem_free(vb); __vb2_buf_mem_free(vb);
kfree(vb); kfree(vb);
break; break;
...@@ -325,18 +375,77 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) ...@@ -325,18 +375,77 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
} }
/* Call driver-provided cleanup function for each buffer, if provided */ /* Call driver-provided cleanup function for each buffer, if provided */
if (q->ops->buf_cleanup) { for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; ++buffer) {
++buffer) { if (q->bufs[buffer])
if (NULL == q->bufs[buffer]) call_vb_qop(q->bufs[buffer], buf_cleanup, q->bufs[buffer]);
continue;
q->ops->buf_cleanup(q->bufs[buffer]);
}
} }
/* Release video buffer memory */ /* Release video buffer memory */
__vb2_free_mem(q, buffers); __vb2_free_mem(q, buffers);
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
* Check that all the calls were balances during the life-time of this
* queue. If not (or if the debug level is 1 or up), then dump the
* counters to the kernel log.
*/
if (q->num_buffers) {
bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
q->cnt_wait_prepare != q->cnt_wait_finish;
if (unbalanced || debug) {
pr_info("vb2: counters for queue %p:%s\n", q,
unbalanced ? " UNBALANCED!" : "");
pr_info("vb2: setup: %u start_streaming: %u stop_streaming: %u\n",
q->cnt_queue_setup, q->cnt_start_streaming,
q->cnt_stop_streaming);
pr_info("vb2: wait_prepare: %u wait_finish: %u\n",
q->cnt_wait_prepare, q->cnt_wait_finish);
}
q->cnt_queue_setup = 0;
q->cnt_wait_prepare = 0;
q->cnt_wait_finish = 0;
q->cnt_start_streaming = 0;
q->cnt_stop_streaming = 0;
}
for (buffer = 0; buffer < q->num_buffers; ++buffer) {
struct vb2_buffer *vb = q->bufs[buffer];
bool unbalanced = vb->cnt_mem_alloc != vb->cnt_mem_put ||
vb->cnt_mem_prepare != vb->cnt_mem_finish ||
vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr ||
vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf ||
vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf ||
vb->cnt_buf_queue != vb->cnt_buf_done ||
vb->cnt_buf_prepare != vb->cnt_buf_finish ||
vb->cnt_buf_init != vb->cnt_buf_cleanup;
if (unbalanced || debug) {
pr_info("vb2: counters for queue %p, buffer %d:%s\n",
q, buffer, unbalanced ? " UNBALANCED!" : "");
pr_info("vb2: buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n",
vb->cnt_buf_init, vb->cnt_buf_cleanup,
vb->cnt_buf_prepare, vb->cnt_buf_finish);
pr_info("vb2: buf_queue: %u buf_done: %u\n",
vb->cnt_buf_queue, vb->cnt_buf_done);
pr_info("vb2: alloc: %u put: %u prepare: %u finish: %u mmap: %u\n",
vb->cnt_mem_alloc, vb->cnt_mem_put,
vb->cnt_mem_prepare, vb->cnt_mem_finish,
vb->cnt_mem_mmap);
pr_info("vb2: get_userptr: %u put_userptr: %u\n",
vb->cnt_mem_get_userptr, vb->cnt_mem_put_userptr);
pr_info("vb2: attach_dmabuf: %u detach_dmabuf: %u map_dmabuf: %u unmap_dmabuf: %u\n",
vb->cnt_mem_attach_dmabuf, vb->cnt_mem_detach_dmabuf,
vb->cnt_mem_map_dmabuf, vb->cnt_mem_unmap_dmabuf);
pr_info("vb2: get_dmabuf: %u num_users: %u vaddr: %u cookie: %u\n",
vb->cnt_mem_get_dmabuf,
vb->cnt_mem_num_users,
vb->cnt_mem_vaddr,
vb->cnt_mem_cookie);
}
}
#endif
/* Free videobuf buffers */ /* Free videobuf buffers */
for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
++buffer) { ++buffer) {
...@@ -428,7 +537,7 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) ...@@ -428,7 +537,7 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
* case anyway. If num_users() returns more than 1, * case anyway. If num_users() returns more than 1,
* we are not the only user of the plane's memory. * we are not the only user of the plane's memory.
*/ */
if (mem_priv && call_memop(q, num_users, mem_priv) > 1) if (mem_priv && call_memop(vb, num_users, mem_priv) > 1)
return true; return true;
} }
return false; return false;
...@@ -716,8 +825,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) ...@@ -716,8 +825,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
*/ */
ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes,
q->plane_sizes, q->alloc_ctx); q->plane_sizes, q->alloc_ctx);
if (ret) if (ret) {
fail_qop(q, queue_setup);
return ret; return ret;
}
/* Finally, allocate buffers and video memory */ /* Finally, allocate buffers and video memory */
ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes); ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes);
...@@ -736,6 +847,8 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) ...@@ -736,6 +847,8 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
ret = call_qop(q, queue_setup, q, NULL, &num_buffers, ret = call_qop(q, queue_setup, q, NULL, &num_buffers,
&num_planes, q->plane_sizes, q->alloc_ctx); &num_planes, q->plane_sizes, q->alloc_ctx);
if (ret)
fail_qop(q, queue_setup);
if (!ret && allocated_buffers < num_buffers) if (!ret && allocated_buffers < num_buffers)
ret = -ENOMEM; ret = -ENOMEM;
...@@ -816,8 +929,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create ...@@ -816,8 +929,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
*/ */
ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
&num_planes, q->plane_sizes, q->alloc_ctx); &num_planes, q->plane_sizes, q->alloc_ctx);
if (ret) if (ret) {
fail_qop(q, queue_setup);
return ret; return ret;
}
/* Finally, allocate buffers and video memory */ /* Finally, allocate buffers and video memory */
ret = __vb2_queue_alloc(q, create->memory, num_buffers, ret = __vb2_queue_alloc(q, create->memory, num_buffers,
...@@ -841,6 +956,8 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create ...@@ -841,6 +956,8 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
*/ */
ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
&num_planes, q->plane_sizes, q->alloc_ctx); &num_planes, q->plane_sizes, q->alloc_ctx);
if (ret)
fail_qop(q, queue_setup);
if (!ret && allocated_buffers < num_buffers) if (!ret && allocated_buffers < num_buffers)
ret = -ENOMEM; ret = -ENOMEM;
...@@ -895,12 +1012,10 @@ EXPORT_SYMBOL_GPL(vb2_create_bufs); ...@@ -895,12 +1012,10 @@ EXPORT_SYMBOL_GPL(vb2_create_bufs);
*/ */
void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no)
{ {
struct vb2_queue *q = vb->vb2_queue;
if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
return NULL; return NULL;
return call_memop(q, vaddr, vb->planes[plane_no].mem_priv); return call_memop(vb, vaddr, vb->planes[plane_no].mem_priv);
} }
EXPORT_SYMBOL_GPL(vb2_plane_vaddr); EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
...@@ -918,12 +1033,10 @@ EXPORT_SYMBOL_GPL(vb2_plane_vaddr); ...@@ -918,12 +1033,10 @@ EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
*/ */
void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no)
{ {
struct vb2_queue *q = vb->vb2_queue;
if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
return NULL; return NULL;
return call_memop(q, cookie, vb->planes[plane_no].mem_priv); return call_memop(vb, cookie, vb->planes[plane_no].mem_priv);
} }
EXPORT_SYMBOL_GPL(vb2_plane_cookie); EXPORT_SYMBOL_GPL(vb2_plane_cookie);
...@@ -951,12 +1064,19 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) ...@@ -951,12 +1064,19 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR) if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR)
return; return;
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
* Although this is not a callback, it still does have to balance
* with the buf_queue op. So update this counter manually.
*/
vb->cnt_buf_done++;
#endif
dprintk(4, "Done processing on buffer %d, state: %d\n", dprintk(4, "Done processing on buffer %d, state: %d\n",
vb->v4l2_buf.index, state); vb->v4l2_buf.index, state);
/* sync buffers */ /* sync buffers */
for (plane = 0; plane < vb->num_planes; ++plane) for (plane = 0; plane < vb->num_planes; ++plane)
call_memop(q, finish, vb->planes[plane].mem_priv); call_memop(vb, finish, vb->planes[plane].mem_priv);
/* Add the buffer to the done buffers list */ /* Add the buffer to the done buffers list */
spin_lock_irqsave(&q->done_lock, flags); spin_lock_irqsave(&q->done_lock, flags);
...@@ -1102,19 +1222,20 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) ...@@ -1102,19 +1222,20 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
/* Release previously acquired memory if present */ /* Release previously acquired memory if present */
if (vb->planes[plane].mem_priv) if (vb->planes[plane].mem_priv)
call_memop(q, put_userptr, vb->planes[plane].mem_priv); call_memop(vb, put_userptr, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL; vb->planes[plane].mem_priv = NULL;
vb->v4l2_planes[plane].m.userptr = 0; vb->v4l2_planes[plane].m.userptr = 0;
vb->v4l2_planes[plane].length = 0; vb->v4l2_planes[plane].length = 0;
/* Acquire each plane's memory */ /* Acquire each plane's memory */
mem_priv = call_memop(q, get_userptr, q->alloc_ctx[plane], mem_priv = call_memop(vb, get_userptr, q->alloc_ctx[plane],
planes[plane].m.userptr, planes[plane].m.userptr,
planes[plane].length, write); planes[plane].length, write);
if (IS_ERR_OR_NULL(mem_priv)) { if (IS_ERR_OR_NULL(mem_priv)) {
dprintk(1, "qbuf: failed acquiring userspace " dprintk(1, "qbuf: failed acquiring userspace "
"memory for plane %d\n", plane); "memory for plane %d\n", plane);
fail_memop(vb, get_userptr);
ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL; ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL;
goto err; goto err;
} }
...@@ -1125,9 +1246,10 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) ...@@ -1125,9 +1246,10 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
* Call driver-specific initialization on the newly acquired buffer, * Call driver-specific initialization on the newly acquired buffer,
* if provided. * if provided.
*/ */
ret = call_qop(q, buf_init, vb); ret = call_vb_qop(vb, buf_init, vb);
if (ret) { if (ret) {
dprintk(1, "qbuf: buffer initialization failed\n"); dprintk(1, "qbuf: buffer initialization failed\n");
fail_vb_qop(vb, buf_init);
goto err; goto err;
} }
...@@ -1143,7 +1265,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) ...@@ -1143,7 +1265,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
/* In case of errors, release planes that were already acquired */ /* In case of errors, release planes that were already acquired */
for (plane = 0; plane < vb->num_planes; ++plane) { for (plane = 0; plane < vb->num_planes; ++plane) {
if (vb->planes[plane].mem_priv) if (vb->planes[plane].mem_priv)
call_memop(q, put_userptr, vb->planes[plane].mem_priv); call_memop(vb, put_userptr, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL; vb->planes[plane].mem_priv = NULL;
vb->v4l2_planes[plane].m.userptr = 0; vb->v4l2_planes[plane].m.userptr = 0;
vb->v4l2_planes[plane].length = 0; vb->v4l2_planes[plane].length = 0;
...@@ -1208,14 +1330,15 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) ...@@ -1208,14 +1330,15 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
dprintk(1, "qbuf: buffer for plane %d changed\n", plane); dprintk(1, "qbuf: buffer for plane %d changed\n", plane);
/* Release previously acquired memory if present */ /* Release previously acquired memory if present */
__vb2_plane_dmabuf_put(q, &vb->planes[plane]); __vb2_plane_dmabuf_put(vb, &vb->planes[plane]);
memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane)); memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane));
/* Acquire each plane's memory */ /* Acquire each plane's memory */
mem_priv = call_memop(q, attach_dmabuf, q->alloc_ctx[plane], mem_priv = call_memop(vb, attach_dmabuf, q->alloc_ctx[plane],
dbuf, planes[plane].length, write); dbuf, planes[plane].length, write);
if (IS_ERR(mem_priv)) { if (IS_ERR(mem_priv)) {
dprintk(1, "qbuf: failed to attach dmabuf\n"); dprintk(1, "qbuf: failed to attach dmabuf\n");
fail_memop(vb, attach_dmabuf);
ret = PTR_ERR(mem_priv); ret = PTR_ERR(mem_priv);
dma_buf_put(dbuf); dma_buf_put(dbuf);
goto err; goto err;
...@@ -1230,10 +1353,11 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) ...@@ -1230,10 +1353,11 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
* the buffer(s).. * the buffer(s)..
*/ */
for (plane = 0; plane < vb->num_planes; ++plane) { for (plane = 0; plane < vb->num_planes; ++plane) {
ret = call_memop(q, map_dmabuf, vb->planes[plane].mem_priv); ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv);
if (ret) { if (ret) {
dprintk(1, "qbuf: failed to map dmabuf for plane %d\n", dprintk(1, "qbuf: failed to map dmabuf for plane %d\n",
plane); plane);
fail_memop(vb, map_dmabuf);
goto err; goto err;
} }
vb->planes[plane].dbuf_mapped = 1; vb->planes[plane].dbuf_mapped = 1;
...@@ -1243,9 +1367,10 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) ...@@ -1243,9 +1367,10 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
* Call driver-specific initialization on the newly acquired buffer, * Call driver-specific initialization on the newly acquired buffer,
* if provided. * if provided.
*/ */
ret = call_qop(q, buf_init, vb); ret = call_vb_qop(vb, buf_init, vb);
if (ret) { if (ret) {
dprintk(1, "qbuf: buffer initialization failed\n"); dprintk(1, "qbuf: buffer initialization failed\n");
fail_vb_qop(vb, buf_init);
goto err; goto err;
} }
...@@ -1277,9 +1402,9 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) ...@@ -1277,9 +1402,9 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
/* sync buffers */ /* sync buffers */
for (plane = 0; plane < vb->num_planes; ++plane) for (plane = 0; plane < vb->num_planes; ++plane)
call_memop(q, prepare, vb->planes[plane].mem_priv); call_memop(vb, prepare, vb->planes[plane].mem_priv);
q->ops->buf_queue(vb); call_vb_qop(vb, buf_queue, vb);
} }
static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
...@@ -1334,8 +1459,11 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) ...@@ -1334,8 +1459,11 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
ret = -EINVAL; ret = -EINVAL;
} }
if (!ret) if (!ret) {
ret = call_qop(q, buf_prepare, vb); ret = call_vb_qop(vb, buf_prepare, vb);
if (ret)
fail_vb_qop(vb, buf_prepare);
}
if (ret) if (ret)
dprintk(1, "qbuf: buffer preparation failed: %d\n", ret); dprintk(1, "qbuf: buffer preparation failed: %d\n", ret);
vb->state = ret ? VB2_BUF_STATE_DEQUEUED : VB2_BUF_STATE_PREPARED; vb->state = ret ? VB2_BUF_STATE_DEQUEUED : VB2_BUF_STATE_PREPARED;
...@@ -1432,6 +1560,8 @@ static int vb2_start_streaming(struct vb2_queue *q) ...@@ -1432,6 +1560,8 @@ static int vb2_start_streaming(struct vb2_queue *q)
/* Tell the driver to start streaming */ /* Tell the driver to start streaming */
ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count)); ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
if (ret)
fail_qop(q, start_streaming);
/* /*
* If there are not enough buffers queued to start streaming, then * If there are not enough buffers queued to start streaming, then
...@@ -1686,7 +1816,7 @@ static void __vb2_dqbuf(struct vb2_buffer *vb) ...@@ -1686,7 +1816,7 @@ static void __vb2_dqbuf(struct vb2_buffer *vb)
for (i = 0; i < vb->num_planes; ++i) { for (i = 0; i < vb->num_planes; ++i) {
if (!vb->planes[i].dbuf_mapped) if (!vb->planes[i].dbuf_mapped)
continue; continue;
call_memop(q, unmap_dmabuf, vb->planes[i].mem_priv); call_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv);
vb->planes[i].dbuf_mapped = 0; vb->planes[i].dbuf_mapped = 0;
} }
} }
...@@ -1704,7 +1834,7 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n ...@@ -1704,7 +1834,7 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = call_qop(q, buf_finish, vb); ret = call_vb_qop(vb, buf_finish, vb);
if (ret) { if (ret) {
dprintk(1, "dqbuf: buffer finish failed\n"); dprintk(1, "dqbuf: buffer finish failed\n");
return ret; return ret;
...@@ -2002,10 +2132,11 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) ...@@ -2002,10 +2132,11 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
vb_plane = &vb->planes[eb->plane]; vb_plane = &vb->planes[eb->plane];
dbuf = call_memop(q, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE); dbuf = call_memop(vb, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE);
if (IS_ERR_OR_NULL(dbuf)) { if (IS_ERR_OR_NULL(dbuf)) {
dprintk(1, "Failed to export buffer %d, plane %d\n", dprintk(1, "Failed to export buffer %d, plane %d\n",
eb->index, eb->plane); eb->index, eb->plane);
fail_memop(vb, get_dmabuf);
return -EINVAL; return -EINVAL;
} }
...@@ -2097,9 +2228,11 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) ...@@ -2097,9 +2228,11 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
return -EINVAL; return -EINVAL;
} }
ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma); ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
if (ret) if (ret) {
fail_memop(vb, mmap);
return ret; return ret;
}
dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane); dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane);
return 0; return 0;
......
...@@ -203,6 +203,37 @@ struct vb2_buffer { ...@@ -203,6 +203,37 @@ struct vb2_buffer {
struct list_head done_entry; struct list_head done_entry;
struct vb2_plane planes[VIDEO_MAX_PLANES]; struct vb2_plane planes[VIDEO_MAX_PLANES];
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
* Counters for how often these buffer-related ops are
* called. Used to check for unbalanced ops.
*/
u32 cnt_mem_alloc;
u32 cnt_mem_put;
u32 cnt_mem_get_dmabuf;
u32 cnt_mem_get_userptr;
u32 cnt_mem_put_userptr;
u32 cnt_mem_prepare;
u32 cnt_mem_finish;
u32 cnt_mem_attach_dmabuf;
u32 cnt_mem_detach_dmabuf;
u32 cnt_mem_map_dmabuf;
u32 cnt_mem_unmap_dmabuf;
u32 cnt_mem_vaddr;
u32 cnt_mem_cookie;
u32 cnt_mem_num_users;
u32 cnt_mem_mmap;
u32 cnt_buf_init;
u32 cnt_buf_prepare;
u32 cnt_buf_finish;
u32 cnt_buf_cleanup;
u32 cnt_buf_queue;
/* This counts the number of calls to vb2_buffer_done() */
u32 cnt_buf_done;
#endif
}; };
/** /**
...@@ -366,6 +397,18 @@ struct vb2_queue { ...@@ -366,6 +397,18 @@ struct vb2_queue {
unsigned int retry_start_streaming:1; unsigned int retry_start_streaming:1;
struct vb2_fileio_data *fileio; struct vb2_fileio_data *fileio;
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
* Counters for how often these queue-related ops are
* called. Used to check for unbalanced ops.
*/
u32 cnt_queue_setup;
u32 cnt_wait_prepare;
u32 cnt_wait_finish;
u32 cnt_start_streaming;
u32 cnt_stop_streaming;
#endif
}; };
void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no); void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment