Bläddra i källkod

video: driver: fix streamon deadlock issue

If client queues input buffers before streamon of
input port, these buffers are not actually queued
to driver but instead held in v4l2 framework. They
are queued to driver when input port is streamed on.
In this scenario when input port is streamed on, inst
lock is acquired and as part of this call, vb2 startes
queueing buffers to driver. During this enqueuing,
buf_queue also tries to acquire inst lock which leads
to deadlock. Hence fixed this issue by moving inst lock
acquiring/releasing to start_streaming call for streamon
and stop_streamping call for streamoff.

Change-Id: I67ed28b4f270ea899c4ace88a368148848b31072
Signed-off-by: Darshana Patil <[email protected]>
Darshana Patil 3 år sedan
förälder
incheckning
513e0c1c1b
3 ändrade filer med 83 tillägg och 66 borttagningar
  1. 0 25
      driver/vidc/src/msm_vidc.c
  2. 4 13
      driver/vidc/src/msm_vidc_v4l2.c
  3. 79 28
      driver/vidc/src/msm_vidc_vb2.c

+ 0 - 25
driver/vidc/src/msm_vidc.c

@@ -571,14 +571,6 @@ int msm_vidc_streamon(void *instance, enum v4l2_buf_type type)
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	if (!msm_vidc_allow_streamon(inst, type)) {
-		rc = -EBUSY;
-		goto exit;
-	}
-	rc = msm_vidc_state_change_streamon(inst, type);
-	if (rc)
-		goto exit;
-
 	port = v4l2_type_to_driver_port(inst, type, __func__);
 	port = v4l2_type_to_driver_port(inst, type, __func__);
 	if (port < 0) {
 	if (port < 0) {
 		rc = -EINVAL;
 		rc = -EINVAL;
@@ -589,7 +581,6 @@ int msm_vidc_streamon(void *instance, enum v4l2_buf_type type)
 	if (rc) {
 	if (rc) {
 		i_vpr_e(inst, "%s: vb2_streamon(%d) failed, %d\n",
 		i_vpr_e(inst, "%s: vb2_streamon(%d) failed, %d\n",
 			__func__, type, rc);
 			__func__, type, rc);
-		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
 		goto exit;
 		goto exit;
 	}
 	}
 
 
@@ -603,27 +594,12 @@ int msm_vidc_streamoff(void *instance, enum v4l2_buf_type type)
 	int rc = 0;
 	int rc = 0;
 	struct msm_vidc_inst *inst = instance;
 	struct msm_vidc_inst *inst = instance;
 	int port;
 	int port;
-	enum msm_vidc_allow allow;
 
 
 	if (!inst) {
 	if (!inst) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	allow = msm_vidc_allow_streamoff(inst, type);
-	if (allow == MSM_VIDC_DISALLOW) {
-		rc = -EBUSY;
-		goto exit;
-	} else if (allow == MSM_VIDC_IGNORE) {
-		goto exit;
-	} else if (allow != MSM_VIDC_ALLOW) {
-		rc = -EINVAL;
-		goto exit;
-	}
-	rc = msm_vidc_state_change_streamoff(inst, type);
-	if (rc)
-		goto exit;
-
 	port = v4l2_type_to_driver_port(inst, type, __func__);
 	port = v4l2_type_to_driver_port(inst, type, __func__);
 	if (port < 0) {
 	if (port < 0) {
 		rc = -EINVAL;
 		rc = -EINVAL;
@@ -634,7 +610,6 @@ int msm_vidc_streamoff(void *instance, enum v4l2_buf_type type)
 	if (rc) {
 	if (rc) {
 		i_vpr_e(inst, "%s: vb2_streamoff(%d) failed, %d\n",
 		i_vpr_e(inst, "%s: vb2_streamoff(%d) failed, %d\n",
 			__func__, type, rc);
 			__func__, type, rc);
-		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
 		goto exit;
 		goto exit;
 	}
 	}
 
 

+ 4 - 13
driver/vidc/src/msm_vidc_v4l2.c

@@ -463,18 +463,11 @@ int msm_v4l2_streamon(struct file *filp, void *fh,
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	inst_lock(inst, __func__);
-	if (is_session_error(inst)) {
-		i_vpr_e(inst, "%s: inst in error state\n", __func__);
-		rc = -EBUSY;
-		goto unlock;
-	}
 	rc = msm_vidc_streamon((void *)inst, i);
 	rc = msm_vidc_streamon((void *)inst, i);
 	if (rc)
 	if (rc)
-		goto unlock;
+		goto exit;
 
 
-unlock:
-	inst_unlock(inst, __func__);
+exit:
 	put_inst(inst);
 	put_inst(inst);
 
 
 	return rc;
 	return rc;
@@ -492,13 +485,11 @@ int msm_v4l2_streamoff(struct file *filp, void *fh,
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	inst_lock(inst, __func__);
 	rc = msm_vidc_streamoff((void *)inst, i);
 	rc = msm_vidc_streamoff((void *)inst, i);
 	if (rc)
 	if (rc)
-		goto unlock;
+		goto exit;
 
 
-unlock:
-	inst_unlock(inst, __func__);
+exit:
 	put_inst(inst);
 	put_inst(inst);
 
 
 	return rc;
 	return rc;

+ 79 - 28
driver/vidc/src/msm_vidc_vb2.c

@@ -198,28 +198,48 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	inst = q->drv_priv;
 	inst = q->drv_priv;
+	inst = get_inst_ref(g_core, inst);
 	if (!inst || !inst->core || !inst->capabilities) {
 	if (!inst || !inst->core || !inst->capabilities) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
+	inst_lock(inst, __func__);
+	if (is_session_error(inst)) {
+		i_vpr_e(inst, "%s: inst in error state\n", __func__);
+		rc = -EBUSY;
+		goto unlock;
+	}
+
+	if (!msm_vidc_allow_streamon(inst, q->type)) {
+		rc = -EBUSY;
+		goto unlock;
+	}
+
+	rc = msm_vidc_state_change_streamon(inst, q->type);
+	if (rc)
+		goto unlock;
+
 	if (q->type == INPUT_META_PLANE &&
 	if (q->type == INPUT_META_PLANE &&
 		inst->capabilities->cap[INPUT_META_VIA_REQUEST].value) {
 		inst->capabilities->cap[INPUT_META_VIA_REQUEST].value) {
 		i_vpr_e(inst,
 		i_vpr_e(inst,
 			"%s: invalid input meta port start when request enabled\n",
 			"%s: invalid input meta port start when request enabled\n",
 			__func__);
 			__func__);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto unlock;
 	}
 	}
 
 
 	if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) {
 	if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) {
 		i_vpr_h(inst, "%s: nothing to start on %s\n",
 		i_vpr_h(inst, "%s: nothing to start on %s\n",
 			__func__, v4l2_type_name(q->type));
 			__func__, v4l2_type_name(q->type));
-		return 0;
+		rc = 0;
+		goto unlock;
 	}
 	}
 	if (!is_decode_session(inst) && !is_encode_session(inst)) {
 	if (!is_decode_session(inst) && !is_encode_session(inst)) {
 		i_vpr_e(inst, "%s: invalid session %d\n",
 		i_vpr_e(inst, "%s: invalid session %d\n",
 			__func__, inst->domain);
 			__func__, inst->domain);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto unlock;
 	}
 	}
 	i_vpr_h(inst, "Streamon: %s\n", v4l2_type_name(q->type));
 	i_vpr_h(inst, "Streamon: %s\n", v4l2_type_name(q->type));
 
 
@@ -227,30 +247,30 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
 		inst->once_per_session_set = true;
 		inst->once_per_session_set = true;
 		rc = msm_vidc_prepare_dependency_list(inst);
 		rc = msm_vidc_prepare_dependency_list(inst);
 		if (rc)
 		if (rc)
-			return rc;
+			goto unlock;
 
 
 		rc = msm_vidc_session_set_codec(inst);
 		rc = msm_vidc_session_set_codec(inst);
 		if (rc)
 		if (rc)
-			return rc;
+			goto unlock;
 
 
 		rc = msm_vidc_session_set_secure_mode(inst);
 		rc = msm_vidc_session_set_secure_mode(inst);
 		if (rc)
 		if (rc)
-			return rc;
+			goto unlock;
 
 
 		if (is_encode_session(inst)) {
 		if (is_encode_session(inst)) {
 			rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst,
 			rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst,
 				MSM_VIDC_BUF_ARP);
 				MSM_VIDC_BUF_ARP);
 			if (rc)
 			if (rc)
-				goto error;
+				goto unlock;
 		} else if(is_decode_session(inst)) {
 		} else if(is_decode_session(inst)) {
 			rc = msm_vidc_session_set_default_header(inst);
 			rc = msm_vidc_session_set_default_header(inst);
 			if (rc)
 			if (rc)
-				return rc;
+				goto unlock;
 
 
 			rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst,
 			rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst,
 				MSM_VIDC_BUF_PERSIST);
 				MSM_VIDC_BUF_PERSIST);
 			if (rc)
 			if (rc)
-				goto error;
+				goto unlock;
 		}
 		}
 	}
 	}
 
 
@@ -266,32 +286,32 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
 		else if (is_encode_session(inst))
 		else if (is_encode_session(inst))
 			rc = msm_venc_streamon_input(inst);
 			rc = msm_venc_streamon_input(inst);
 		else
 		else
-			goto error;
+			goto unlock;
 	} else if (q->type == OUTPUT_MPLANE) {
 	} else if (q->type == OUTPUT_MPLANE) {
 		if (is_decode_session(inst))
 		if (is_decode_session(inst))
 			rc = msm_vdec_streamon_output(inst);
 			rc = msm_vdec_streamon_output(inst);
 		else if (is_encode_session(inst))
 		else if (is_encode_session(inst))
 			rc = msm_venc_streamon_output(inst);
 			rc = msm_venc_streamon_output(inst);
 		else
 		else
-			goto error;
+			goto unlock;
 	} else {
 	} else {
 		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
 		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
-		goto error;
+		goto unlock;
 	}
 	}
 	if (rc)
 	if (rc)
-		goto error;
+		goto unlock;
 
 
 	/* print final buffer counts & size details */
 	/* print final buffer counts & size details */
 	msm_vidc_print_buffer_info(inst);
 	msm_vidc_print_buffer_info(inst);
 
 
 	buf_type = v4l2_type_to_driver(q->type, __func__);
 	buf_type = v4l2_type_to_driver(q->type, __func__);
 	if (!buf_type)
 	if (!buf_type)
-		goto error;
+		goto unlock;
 
 
 	/* queue pending buffers */
 	/* queue pending buffers */
 	rc = msm_vidc_queue_deferred_buffers(inst, buf_type);
 	rc = msm_vidc_queue_deferred_buffers(inst, buf_type);
 	if (rc)
 	if (rc)
-		goto error;
+		goto unlock;
 
 
 	/* initialize statistics timer(one time) */
 	/* initialize statistics timer(one time) */
 	if (!inst->stats.time_ms)
 	if (!inst->stats.time_ms)
@@ -300,47 +320,73 @@ int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
 	/* schedule to print buffer statistics */
 	/* schedule to print buffer statistics */
 	rc = schedule_stats_work(inst);
 	rc = schedule_stats_work(inst);
 	if (rc)
 	if (rc)
-		goto error;
+		goto unlock;
 
 
 	if ((q->type == INPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming) ||
 	if ((q->type == INPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming) ||
 		(q->type == OUTPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming)) {
 		(q->type == OUTPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming)) {
 		rc = msm_vidc_get_properties(inst);
 		rc = msm_vidc_get_properties(inst);
 		if (rc)
 		if (rc)
-			goto error;
+			goto unlock;
 	}
 	}
 
 
 	i_vpr_h(inst, "Streamon: %s successful\n", v4l2_type_name(q->type));
 	i_vpr_h(inst, "Streamon: %s successful\n", v4l2_type_name(q->type));
 
 
+unlock:
+	if (rc) {
+		i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type));
+		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
+	}
+	inst_unlock(inst, __func__);
+	put_inst(inst);
 	return rc;
 	return rc;
-
-error:
-	i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type));
-	return -EINVAL;
 }
 }
 
 
 void msm_vidc_stop_streaming(struct vb2_queue *q)
 void msm_vidc_stop_streaming(struct vb2_queue *q)
 {
 {
 	int rc = 0;
 	int rc = 0;
 	struct msm_vidc_inst *inst;
 	struct msm_vidc_inst *inst;
+	enum msm_vidc_allow allow;
 
 
 	if (!q || !q->drv_priv) {
 	if (!q || !q->drv_priv) {
 		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
 		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
 		return;
 		return;
 	}
 	}
 	inst = q->drv_priv;
 	inst = q->drv_priv;
+	inst = get_inst_ref(g_core, inst);
 	if (!inst || !inst->core) {
 	if (!inst || !inst->core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		d_vpr_e("%s: invalid params\n", __func__);
 		return;
 		return;
 	}
 	}
+
+	inst_lock(inst, __func__);
 	if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) {
 	if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) {
 		i_vpr_h(inst, "%s: nothing to stop on %s\n",
 		i_vpr_h(inst, "%s: nothing to stop on %s\n",
 			__func__, v4l2_type_name(q->type));
 			__func__, v4l2_type_name(q->type));
-		return;
+		rc = 0;
+		goto unlock;
+	}
+
+	allow = msm_vidc_allow_streamoff(inst, q->type);
+	if (allow == MSM_VIDC_DISALLOW) {
+		rc = -EBUSY;
+		goto unlock;
+	} else if (allow == MSM_VIDC_IGNORE) {
+		rc = 0;
+		goto unlock;
+	} else if (allow != MSM_VIDC_ALLOW) {
+		rc = -EINVAL;
+		goto unlock;
 	}
 	}
+
+	rc = msm_vidc_state_change_streamoff(inst, q->type);
+	if (rc)
+		goto unlock;
+
 	if (!is_decode_session(inst) && !is_encode_session(inst)) {
 	if (!is_decode_session(inst) && !is_encode_session(inst)) {
 		i_vpr_e(inst, "%s: invalid session %d\n",
 		i_vpr_e(inst, "%s: invalid session %d\n",
 			__func__, inst->domain);
 			__func__, inst->domain);
-		return;
+		rc = -EINVAL;
+		goto unlock;
 	}
 	}
 	i_vpr_h(inst, "Streamoff: %s\n", v4l2_type_name(q->type));
 	i_vpr_h(inst, "Streamoff: %s\n", v4l2_type_name(q->type));
 
 
@@ -356,20 +402,25 @@ void msm_vidc_stop_streaming(struct vb2_queue *q)
 			rc = msm_venc_streamoff_output(inst);
 			rc = msm_venc_streamoff_output(inst);
 	} else {
 	} else {
 		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
 		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
-		goto error;
+		rc = -EINVAL;
+		goto unlock;
 	}
 	}
 	if (rc)
 	if (rc)
-		goto error;
+		goto unlock;
 
 
 	/* Input port streamoff - flush timestamps list*/
 	/* Input port streamoff - flush timestamps list*/
 	if (q->type == INPUT_MPLANE)
 	if (q->type == INPUT_MPLANE)
 		msm_vidc_flush_ts(inst);
 		msm_vidc_flush_ts(inst);
 
 
 	i_vpr_h(inst, "Streamoff: %s successful\n", v4l2_type_name(q->type));
 	i_vpr_h(inst, "Streamoff: %s successful\n", v4l2_type_name(q->type));
-	return;
 
 
-error:
-	i_vpr_e(inst, "Streamoff: %s failed\n", v4l2_type_name(q->type));
+unlock:
+	if (rc) {
+		i_vpr_e(inst, "Streamoff: %s failed\n", v4l2_type_name(q->type));
+		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
+	}
+	inst_unlock(inst, __func__);
+	put_inst(inst);
 	return;
 	return;
 }
 }