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 <vkalia@codeaurora.org>
This commit is contained in:
Vinay Kalia
2012-09-25 15:12:06 -07:00
parent 2e542e4409
commit a67f6464ff
8 changed files with 83 additions and 53 deletions
+24 -14
View File
@@ -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:
+22 -12
View File
@@ -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;
+8 -6
View File
@@ -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);
+22 -11
View File
@@ -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)
@@ -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);
@@ -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;
-7
View File
@@ -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)
-1
View File
@@ -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];