Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 46bca081 authored by Arun Menon's avatar Arun Menon
Browse files

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: default avatarArun Menon <avmenon@codeaurora.org>
parent 590a4fbe
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -481,12 +481,12 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
			!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) &&
@@ -501,12 +501,14 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
			*/
			dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n");
			rc = buf_ref_get(inst, temp);
			if (rc < 0)
				return rc;
			if (rc > 0) {
				save_v4l2_buffer(b, temp);
				rc = -EEXIST;
			goto exit;
			}
		}
		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);
+11 −6
Original line number Diff line number Diff line
@@ -542,6 +542,7 @@ static void handle_event_change(enum command_response cmd, void *data)
					"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);

@@ -552,6 +553,7 @@ static void handle_event_change(enum command_response cmd, void *data)
				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,
@@ -948,7 +950,7 @@ int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo)
	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]);
@@ -975,7 +977,7 @@ int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo)
	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);
@@ -1027,12 +1029,12 @@ static void handle_dynamic_buffer(struct msm_vidc_inst *inst,
		}
		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);
		}
	}
@@ -2931,6 +2933,9 @@ void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst)
				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);