From a67f6464ffbeccb97cc5c27cc704881bc8324e42 Mon Sep 17 00:00:00 2001 From: Vinay Kalia Date: Wed, 19 Sep 2012 22:02:49 -0700 Subject: [PATCH] msm: vidc: Protect queued buffers list with lock Queued buffers list can be accessed across different threads so it should be protected with a lock. Without proper locking the lists might get corrupted resulting in frame drops and crash eventually. CRs-fixed: 400702 Change-Id: Ie316b6744db342203e23a83bf6194983ea5eecca Signed-off-by: Vinay Kalia --- drivers/media/video/msm_vidc/msm_vdec.c | 38 ++++++++++++------- drivers/media/video/msm_vidc/msm_venc.c | 34 +++++++++++------ drivers/media/video/msm_vidc/msm_vidc.c | 14 ++++--- .../media/video/msm_vidc/msm_vidc_common.c | 33 ++++++++++------ .../media/video/msm_vidc/msm_vidc_common.h | 2 +- .../media/video/msm_vidc/msm_vidc_internal.h | 7 +++- drivers/media/video/videobuf2-core.c | 7 ---- include/media/videobuf2-core.h | 1 - 8 files changed, 83 insertions(+), 53 deletions(-) diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c index ead118d1262..d843d875f5e 100644 --- a/drivers/media/video/msm_vidc/msm_vdec.c +++ b/drivers/media/video/msm_vidc/msm_vdec.c @@ -281,7 +281,7 @@ static const struct msm_vidc_format vdec_formats[] = { int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i) { int rc = 0; - struct vb2_queue *q; + struct buf_queue *q; q = msm_comm_get_vb2q(inst, i); if (!q) { dprintk(VIDC_ERR, @@ -289,7 +289,9 @@ int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i) return -EINVAL; } dprintk(VIDC_DBG, "Calling streamon\n"); - rc = vb2_streamon(q, i); + mutex_lock(&q->lock); + rc = vb2_streamon(&q->vb2_bufq, i); + mutex_unlock(&q->lock); if (rc) dprintk(VIDC_ERR, "streamon failed on port: %d\n", i); return rc; @@ -298,7 +300,7 @@ int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i) int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i) { int rc = 0; - struct vb2_queue *q; + struct buf_queue *q; q = msm_comm_get_vb2q(inst, i); if (!q) { @@ -307,7 +309,9 @@ int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i) return -EINVAL; } dprintk(VIDC_DBG, "Calling streamoff\n"); - rc = vb2_streamoff(q, i); + mutex_lock(&q->lock); + rc = vb2_streamoff(&q->vb2_bufq, i); + mutex_unlock(&q->lock); if (rc) dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i); return rc; @@ -403,7 +407,7 @@ int msm_vdec_release_buf(struct msm_vidc_inst *inst, int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) { - struct vb2_queue *q = NULL; + struct buf_queue *q = NULL; int rc = 0; q = msm_comm_get_vb2q(inst, b->type); if (!q) { @@ -411,14 +415,16 @@ int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) , b->type); return -EINVAL; } - rc = vb2_qbuf(q, b); + mutex_lock(&q->lock); + rc = vb2_qbuf(&q->vb2_bufq, b); + mutex_unlock(&q->lock); if (rc) dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc); return rc; } int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) { - struct vb2_queue *q = NULL; + struct buf_queue *q = NULL; int rc = 0; q = msm_comm_get_vb2q(inst, b->type); if (!q) { @@ -426,7 +432,9 @@ int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) , b->type); return -EINVAL; } - rc = vb2_dqbuf(q, b, true); + mutex_lock(&q->lock); + rc = vb2_dqbuf(&q->vb2_bufq, b, true); + mutex_unlock(&q->lock); if (rc) dprintk(VIDC_WARN, "Failed to dqbuf, %d\n", rc); return rc; @@ -434,7 +442,7 @@ int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b) { - struct vb2_queue *q = NULL; + struct buf_queue *q = NULL; int rc = 0; if (!inst || !b) { dprintk(VIDC_ERR, @@ -448,7 +456,9 @@ int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b) return -EINVAL; } - rc = vb2_reqbufs(q, b); + mutex_lock(&q->lock); + rc = vb2_reqbufs(&q->vb2_bufq, b); + mutex_unlock(&q->lock); if (rc) dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc); return rc; @@ -770,11 +780,11 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count) "Streamon called on: %d capability\n", q->type); switch (q->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (inst->vb2_bufq[CAPTURE_PORT].streaming) + if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming) rc = start_streaming(inst); break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (inst->vb2_bufq[OUTPUT_PORT].streaming) + if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming) rc = start_streaming(inst); break; default: @@ -797,11 +807,11 @@ static int msm_vdec_stop_streaming(struct vb2_queue *q) dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type); switch (q->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (!inst->vb2_bufq[CAPTURE_PORT].streaming) + if (!inst->bufq[CAPTURE_PORT].vb2_bufq.streaming) rc = stop_streaming(inst); break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (!inst->vb2_bufq[OUTPUT_PORT].streaming) + if (!inst->bufq[OUTPUT_PORT].vb2_bufq.streaming) rc = stop_streaming(inst); break; default: diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c index c137c08f50c..f2faedb859f 100644 --- a/drivers/media/video/msm_vidc/msm_venc.c +++ b/drivers/media/video/msm_vidc/msm_venc.c @@ -700,11 +700,11 @@ static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count) dprintk(VIDC_DBG, "Streamon called on: %d capability\n", q->type); switch (q->type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (inst->vb2_bufq[CAPTURE_PORT].streaming) + if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming) rc = start_streaming(inst); break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (inst->vb2_bufq[OUTPUT_PORT].streaming) + if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming) rc = start_streaming(inst); break; default: @@ -1419,7 +1419,7 @@ int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b) { - struct vb2_queue *q = NULL; + struct buf_queue *q = NULL; int rc = 0; if (!inst || !b) { dprintk(VIDC_ERR, @@ -1433,7 +1433,9 @@ int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b) return -EINVAL; } - rc = vb2_reqbufs(q, b); + mutex_lock(&q->lock); + rc = vb2_reqbufs(&q->vb2_bufq, b); + mutex_unlock(&q->lock); if (rc) dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc); return rc; @@ -1479,7 +1481,7 @@ int msm_venc_prepare_buf(struct msm_vidc_inst *inst, int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) { - struct vb2_queue *q = NULL; + struct buf_queue *q = NULL; int rc = 0; q = msm_comm_get_vb2q(inst, b->type); if (!q) { @@ -1487,7 +1489,9 @@ int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) "Failed to find buffer queue for type = %d\n", b->type); return -EINVAL; } - rc = vb2_qbuf(q, b); + mutex_lock(&q->lock); + rc = vb2_qbuf(&q->vb2_bufq, b); + mutex_unlock(&q->lock); if (rc) dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc); return rc; @@ -1495,7 +1499,7 @@ int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) { - struct vb2_queue *q = NULL; + struct buf_queue *q = NULL; int rc = 0; q = msm_comm_get_vb2q(inst, b->type); if (!q) { @@ -1503,7 +1507,9 @@ int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) "Failed to find buffer queue for type = %d\n", b->type); return -EINVAL; } - rc = vb2_dqbuf(q, b, true); + mutex_lock(&q->lock); + rc = vb2_dqbuf(&q->vb2_bufq, b, true); + mutex_unlock(&q->lock); if (rc) dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc); return rc; @@ -1512,7 +1518,7 @@ int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i) { int rc = 0; - struct vb2_queue *q; + struct buf_queue *q; q = msm_comm_get_vb2q(inst, i); if (!q) { dprintk(VIDC_ERR, @@ -1520,7 +1526,9 @@ int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i) return -EINVAL; } dprintk(VIDC_DBG, "Calling streamon\n"); - rc = vb2_streamon(q, i); + mutex_lock(&q->lock); + rc = vb2_streamon(&q->vb2_bufq, i); + mutex_unlock(&q->lock); if (rc) dprintk(VIDC_ERR, "streamon failed on port: %d\n", i); return rc; @@ -1529,7 +1537,7 @@ int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i) int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i) { int rc = 0; - struct vb2_queue *q; + struct buf_queue *q; q = msm_comm_get_vb2q(inst, i); if (!q) { dprintk(VIDC_ERR, @@ -1537,7 +1545,9 @@ int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i) return -EINVAL; } dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i); - rc = vb2_streamoff(q, i); + mutex_lock(&q->lock); + rc = vb2_streamoff(&q->vb2_bufq, i); + mutex_unlock(&q->lock); if (rc) dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i); return rc; diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c index 5eeae0165c4..8ff7714c220 100644 --- a/drivers/media/video/msm_vidc/msm_vidc.c +++ b/drivers/media/video/msm_vidc/msm_vidc.c @@ -27,8 +27,8 @@ static int get_poll_flags(void *instance) { struct msm_vidc_inst *inst = instance; - struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT]; - struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT]; + struct vb2_queue *outq = &inst->bufq[OUTPUT_PORT].vb2_bufq; + struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq; struct vb2_buffer *out_vb = NULL; struct vb2_buffer *cap_vb = NULL; unsigned long flags; @@ -62,8 +62,8 @@ int msm_vidc_poll(void *instance, struct file *filp, struct poll_table_struct *wait) { struct msm_vidc_inst *inst = instance; - struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT]; - struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT]; + struct vb2_queue *outq = &inst->bufq[OUTPUT_PORT].vb2_bufq; + struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq; poll_wait(filp, &inst->event_handler.wait, wait); poll_wait(filp, &capq->done_wq, wait); @@ -306,9 +306,9 @@ static inline int vb2_bufq_init(struct msm_vidc_inst *inst, { struct vb2_queue *q = NULL; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - q = &inst->vb2_bufq[CAPTURE_PORT]; + q = &inst->bufq[CAPTURE_PORT].vb2_bufq; } else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - q = &inst->vb2_bufq[OUTPUT_PORT]; + q = &inst->bufq[OUTPUT_PORT].vb2_bufq; } else { dprintk(VIDC_ERR, "buf_type = %d not recognised\n", type); return -EINVAL; @@ -404,6 +404,8 @@ void *msm_vidc_open(int core_id, int session_type) } mutex_init(&inst->sync_lock); + mutex_init(&inst->bufq[CAPTURE_PORT].lock); + mutex_init(&inst->bufq[OUTPUT_PORT].lock); spin_lock_init(&inst->lock); inst->session_type = session_type; INIT_LIST_HEAD(&inst->pendingq); diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c index 974f77584c6..6a12d3f74f6 100644 --- a/drivers/media/video/msm_vidc/msm_vidc_common.c +++ b/drivers/media/video/msm_vidc/msm_vidc_common.c @@ -258,13 +258,13 @@ const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc( return &fmt[i]; } -struct vb2_queue *msm_comm_get_vb2q( +struct buf_queue *msm_comm_get_vb2q( struct msm_vidc_inst *inst, enum v4l2_buf_type type) { if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return &inst->vb2_bufq[CAPTURE_PORT]; + return &inst->bufq[CAPTURE_PORT]; if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return &inst->vb2_bufq[OUTPUT_PORT]; + return &inst->bufq[OUTPUT_PORT]; return NULL; } @@ -527,21 +527,25 @@ static void handle_session_close(enum command_response cmd, void *data) } } -static struct vb2_buffer *get_vb_from_device_addr(struct vb2_queue *q, +static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq, u32 dev_addr) { struct vb2_buffer *vb = NULL; + struct vb2_queue *q = NULL; int found = 0; - if (!q) { + if (!bufq) { dprintk(VIDC_ERR, "Invalid parameter\n"); return NULL; } + q = &bufq->vb2_bufq; + mutex_lock(&bufq->lock); list_for_each_entry(vb, &q->queued_list, queued_entry) { if (vb->v4l2_planes[0].m.userptr == dev_addr) { found = 1; break; } } + mutex_unlock(&bufq->lock); if (!found) { dprintk(VIDC_ERR, "Failed to find the buffer in queued list: %d, %d\n", @@ -563,7 +567,9 @@ static void handle_ebd(enum command_response cmd, void *data) vb = response->clnt_data; inst = (struct msm_vidc_inst *)response->session_id; if (vb) { + mutex_lock(&inst->bufq[OUTPUT_PORT].lock); vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + mutex_unlock(&inst->bufq[OUTPUT_PORT].lock); wake_up(&inst->kernel_event_queue); } } @@ -580,7 +586,7 @@ static void handle_fbd(enum command_response cmd, void *data) } inst = (struct msm_vidc_inst *)response->session_id; fill_buf_done = (struct vidc_hal_fbd *)&response->output_done; - vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT], + vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT], (u32)fill_buf_done->packet_buffer1); if (vb) { vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1; @@ -628,7 +634,9 @@ static void handle_fbd(enum command_response cmd, void *data) dprintk(VIDC_DBG, "Filled length = %d; flags %x\n", vb->v4l2_planes[0].bytesused, vb->v4l2_buf.flags); + mutex_lock(&inst->bufq[CAPTURE_PORT].lock); vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + mutex_unlock(&inst->bufq[CAPTURE_PORT].lock); wake_up(&inst->kernel_event_queue); } else { /* @@ -645,18 +653,19 @@ static void handle_fbd(enum command_response cmd, void *data) */ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS && fill_buf_done->filled_len1 == 0) { - struct vb2_queue *q = &inst->vb2_bufq[CAPTURE_PORT]; + struct buf_queue *q = &inst->bufq[CAPTURE_PORT]; - if (!list_empty(&q->queued_list)) { - vb = list_first_entry(&q->queued_list, + if (!list_empty(&q->vb2_bufq.queued_list)) { + vb = list_first_entry(&q->vb2_bufq.queued_list, struct vb2_buffer, queued_entry); vb->v4l2_planes[0].bytesused = 0; vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS; + mutex_lock(&q->lock); vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + mutex_unlock(&q->lock); } } - } } @@ -672,7 +681,7 @@ static void handle_seq_hdr_done(enum command_response cmd, void *data) } inst = (struct msm_vidc_inst *)response->session_id; fill_buf_done = (struct vidc_hal_fbd *)&response->output_done; - vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT], + vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT], (u32)fill_buf_done->packet_buffer1); if (vb) vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1; @@ -682,7 +691,9 @@ static void handle_seq_hdr_done(enum command_response cmd, void *data) dprintk(VIDC_DBG, "Filled length = %d; flags %x\n", vb->v4l2_planes[0].bytesused, vb->v4l2_buf.flags); + mutex_lock(&inst->bufq[CAPTURE_PORT].lock); vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + mutex_unlock(&inst->bufq[CAPTURE_PORT].lock); } void handle_cmd_response(enum command_response cmd, void *data) diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h index 1301e5cc2b5..07087245881 100644 --- a/drivers/media/video/msm_vidc/msm_vidc_common.h +++ b/drivers/media/video/msm_vidc/msm_vidc_common.h @@ -23,7 +23,7 @@ const struct msm_vidc_format *msm_comm_get_pixel_fmt_index( const struct msm_vidc_format fmt[], int size, int index, int fmt_type); const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc( const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type); -struct vb2_queue *msm_comm_get_vb2q( +struct buf_queue *msm_comm_get_vb2q( struct msm_vidc_inst *inst, enum v4l2_buf_type type); int msm_comm_try_state(struct msm_vidc_inst *inst, int state); int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst); diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h index 1f2eff8bbe5..caf8849bdcf 100644 --- a/drivers/media/video/msm_vidc/msm_vidc_internal.h +++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h @@ -188,6 +188,11 @@ struct session_prop { u32 bitrate; }; +struct buf_queue { + struct vb2_queue vb2_bufq; + struct mutex lock; +}; + struct msm_vidc_core { struct list_head list; struct mutex sync_lock; @@ -216,7 +221,7 @@ struct msm_vidc_inst { struct session_prop prop; int state; const struct msm_vidc_format *fmts[MAX_PORT_NUM]; - struct vb2_queue vb2_bufq[MAX_PORT_NUM]; + struct buf_queue bufq[MAX_PORT_NUM]; spinlock_t lock; struct list_head pendingq; struct list_head internalbufs; diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index a7d13a81079..668cc733ee2 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -1330,14 +1330,11 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) return -EINVAL; } - mutex_lock(&q->q_lock); ret = __vb2_get_done_vb(q, &vb, nonblocking); if (ret < 0) { dprintk(1, "dqbuf: error getting next done buffer\n"); - mutex_unlock(&q->q_lock); return ret; } - mutex_unlock(&q->q_lock); ret = call_qop(q, buf_finish, vb); if (ret) { dprintk(1, "dqbuf: buffer finish failed\n"); @@ -1449,17 +1446,14 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) /* * Let driver notice that streaming state has been enabled. */ - mutex_lock(&q->q_lock); ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count)); if (ret) { dprintk(1, "streamon: driver refused to start streaming\n"); __vb2_queue_cancel(q); - mutex_unlock(&q->q_lock); return ret; } q->streaming = 1; - mutex_unlock(&q->q_lock); dprintk(3, "Streamon successful\n"); return 0; } @@ -1733,7 +1727,6 @@ int vb2_queue_init(struct vb2_queue *q) INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); - mutex_init(&q->q_lock); init_waitqueue_head(&q->done_wq); if (q->buf_struct_size == 0) diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 2918b947dd5..a15d1f1b319 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -289,7 +289,6 @@ struct vb2_queue { atomic_t queued_count; struct list_head done_list; spinlock_t done_lock; - struct mutex q_lock; wait_queue_head_t done_wq; void *alloc_ctx[VIDEO_MAX_PLANES];