msm: vidc: fix a race condition in dynamic buffer handling
Fixes a race condition while ftb is queued to the driver
and release reference event for the same has been returned
from the firmware. Without this change, we would end up
having a buffer which is registered in the list but not
queued to firmware. As a result during flush this buffer is
not returned back to client and results in video freeze.
Change-Id: Iaf224a56a5b6c5042bdd662bb14cd63b29586854
Signed-off-by: Arun Menon <avmenon@codeaurora.org>
(cherry picked from commit ffd889ee71c5913025a15998c6aba82177e60576)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 8fbd725..e5ee6f4 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -451,12 +451,12 @@
!b->m.planes[i].length) {
continue;
}
+ mutex_lock(&inst->sync_lock);
temp = get_registered_buf(inst, b, i, &plane);
if (temp && !is_dynamic_output_buffer_mode(b, inst)) {
dprintk(VIDC_DBG,
"This memory region has already been prepared\n");
rc = -EINVAL;
- goto exit;
}
if (temp && is_dynamic_output_buffer_mode(b, inst) &&
@@ -471,12 +471,14 @@
*/
dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n");
rc = buf_ref_get(inst, temp);
- if (rc < 0)
- return rc;
- save_v4l2_buffer(b, temp);
- rc = -EEXIST;
- goto exit;
+ if (rc > 0) {
+ save_v4l2_buffer(b, temp);
+ rc = -EEXIST;
+ }
}
+ mutex_unlock(&inst->sync_lock);
+ if (rc < 0)
+ goto exit;
temp = get_same_fd_buffer(inst, &inst->registered_bufs,
b->m.planes[i].reserved[0], &plane);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index b6d2f6d..bf1c2cf 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -510,6 +510,7 @@
"RELEASE REFERENCE EVENT FROM F/W - fd = %d offset = %d\n",
ptr[0], ptr[1]);
+ mutex_lock(&inst->sync_lock);
/* Decrement buffer reference count*/
buf_ref_put(inst, binfo);
@@ -520,6 +521,7 @@
if (unmap_and_deregister_buf(inst, binfo))
dprintk(VIDC_ERR,
"%s: buffer unmap failed\n", __func__);
+ mutex_unlock(&inst->sync_lock);
/*send event to client*/
v4l2_event_queue_fh(&inst->event_handler,
@@ -878,7 +880,7 @@
atomic_inc(&binfo->ref_count);
cnt = atomic_read(&binfo->ref_count);
if (cnt > 2) {
- dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+ dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
cnt = -EINVAL;
}
dprintk(VIDC_DBG, "REF_GET[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
@@ -905,7 +907,7 @@
else if (cnt == 1)
qbuf_again = true;
else {
- dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+ dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
cnt = -EINVAL;
}
mutex_unlock(&inst->lock);
@@ -957,12 +959,12 @@
}
if (flags & HAL_BUFFERFLAG_READONLY) {
dprintk(VIDC_DBG,
- "_F_B_D_ fd[0] = %d -> Reference with f/w",
- binfo->fd[0]);
+ "_F_B_D_ fd[0] = %d -> Reference with f/w, addr: 0x%x",
+ binfo->fd[0], device_addr);
} else {
dprintk(VIDC_DBG,
- "_F_B_D_ fd[0] = %d -> FBD_ref_released\n",
- binfo->fd[0]);
+ "_F_B_D_ fd[0] = %d -> FBD_ref_released, addr: 0x%x\n",
+ binfo->fd[0], device_addr);
buf_ref_put(inst, binfo);
}
}
@@ -2616,6 +2618,9 @@
dprintk(VIDC_DBG,
"released buffer held in driver before issuing flush: 0x%x fd[0]: %d\n",
binfo->device_addr[0], binfo->fd[0]);
+ /*delete this buffer info from registered list*/
+ list_del(&binfo->list);
+ kfree(binfo);
/*send event to client*/
v4l2_event_queue_fh(&inst->event_handler,
&buf_event);