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);