Forráskód Böngészése

Merge "video: driver: fix streamon deadlock issue"

qctecmdr 3 éve
szülő
commit
964a9fed8c

+ 1 - 1
driver/platform/kalama/src/msm_vidc_kalama.c

@@ -1616,7 +1616,7 @@ static struct msm_platform_inst_capability instance_data_kalama[] = {
 		msm_vidc_adjust_all_intra, NULL},
 
 	{INPUT_METADATA_FD, ENC|DEC, CODECS_ALL,
-		-1, INT_MAX, 1, -1,
+		INVALID_FD, INT_MAX, 1, INVALID_FD,
 		V4L2_CID_MPEG_VIDC_INPUT_METADATA_FD,
 		0,
 		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED,

+ 1 - 1
driver/platform/waipio/src/msm_vidc_waipio.c

@@ -1474,7 +1474,7 @@ static struct msm_platform_inst_capability instance_data_waipio[] = {
 		msm_vidc_adjust_all_intra, NULL},
 
 	{INPUT_METADATA_FD, ENC|DEC, CODECS_ALL,
-		-1, INT_MAX, 1, -1,
+		INVALID_FD, INT_MAX, 1, INVALID_FD,
 		V4L2_CID_MPEG_VIDC_INPUT_METADATA_FD,
 		0,
 		CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED,

+ 2 - 0
driver/vidc/inc/msm_vidc.h

@@ -28,6 +28,8 @@ int msm_vidc_g_param(void *instance, struct v4l2_streamparm *sp);
 int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
 int msm_vidc_querybuf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_create_bufs(void *instance, struct v4l2_create_buffers *b);
+int msm_vidc_prepare_buf(void *instance, struct media_device *mdev,
+	struct v4l2_buffer *b);
 int msm_vidc_release_buffer(void *instance, int buffer_type,
 		unsigned int buffer_index);
 int msm_vidc_qbuf(void *instance, struct media_device *mdev,

+ 1 - 1
driver/vidc/inc/msm_vidc_driver.h

@@ -450,7 +450,7 @@ bool res_is_less_than(u32 width, u32 height,
 bool res_is_less_than_or_equal_to(u32 width, u32 height,
 	u32 ref_width, u32 ref_height);
 int msm_vidc_get_properties(struct msm_vidc_inst *inst);
-int msm_vidc_create_input_metadata_buffer(struct msm_vidc_inst *inst, u32 buf_fd);
+int msm_vidc_create_input_metadata_buffer(struct msm_vidc_inst *inst, int buf_fd);
 int msm_vidc_update_input_meta_buffer_index(struct msm_vidc_inst *inst, struct vb2_buffer *vb2);
 #endif // _MSM_VIDC_DRIVER_H_
 

+ 2 - 0
driver/vidc/inc/msm_vidc_v4l2.h

@@ -38,6 +38,8 @@ int msm_v4l2_querybuf(struct file *file, void *fh,
 		struct v4l2_buffer *b);
 int msm_v4l2_create_bufs(struct file *filp, void *fh,
 		struct v4l2_create_buffers *b);
+int msm_v4l2_prepare_buf(struct file *filp, void *fh,
+		struct v4l2_buffer *b);
 int msm_v4l2_qbuf(struct file *file, void *fh,
 		struct v4l2_buffer *b);
 int msm_v4l2_dqbuf(struct file *file, void *fh,

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

@@ -474,6 +474,35 @@ exit:
 }
 EXPORT_SYMBOL(msm_vidc_create_bufs);
 
+int msm_vidc_prepare_buf(void *instance, struct media_device *mdev,
+	struct v4l2_buffer *b)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = instance;
+	struct vb2_queue *q;
+
+	if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst)) {
+		d_vpr_e("%s: invalid params %pK %pK\n", __func__, inst, b);
+		return -EINVAL;
+	}
+
+	q = msm_vidc_get_vb2q(inst, b->type, __func__);
+	if (!q) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = vb2_prepare_buf(q, mdev, b);
+	if (rc) {
+		i_vpr_e(inst, "%s: failed with %d\n", __func__, rc);
+		goto exit;
+	}
+
+exit:
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_prepare_buf);
+
 int msm_vidc_qbuf(void *instance, struct media_device *mdev,
 		struct v4l2_buffer *b)
 {
@@ -542,14 +571,6 @@ int msm_vidc_streamon(void *instance, enum v4l2_buf_type type)
 		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__);
 	if (port < 0) {
 		rc = -EINVAL;
@@ -560,7 +581,6 @@ int msm_vidc_streamon(void *instance, enum v4l2_buf_type type)
 	if (rc) {
 		i_vpr_e(inst, "%s: vb2_streamon(%d) failed, %d\n",
 			__func__, type, rc);
-		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
 		goto exit;
 	}
 
@@ -574,27 +594,12 @@ int msm_vidc_streamoff(void *instance, enum v4l2_buf_type type)
 	int rc = 0;
 	struct msm_vidc_inst *inst = instance;
 	int port;
-	enum msm_vidc_allow allow;
 
 	if (!inst) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		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__);
 	if (port < 0) {
 		rc = -EINVAL;
@@ -605,7 +610,6 @@ int msm_vidc_streamoff(void *instance, enum v4l2_buf_type type)
 	if (rc) {
 		i_vpr_e(inst, "%s: vb2_streamoff(%d) failed, %d\n",
 			__func__, type, rc);
-		msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
 		goto exit;
 	}
 

+ 6 - 0
driver/vidc/src/msm_vidc_control.c

@@ -1102,6 +1102,12 @@ int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl)
 	}
 
 	if (ctrl->id == V4L2_CID_MPEG_VIDC_INPUT_METADATA_FD) {
+		if (ctrl->val == INVALID_FD || ctrl->val == INT_MAX) {
+			i_vpr_e(inst,
+				"%s: client configured invalid input metadata fd %d\n",
+				__func__, ctrl->val);
+			return 0;
+		}
 		if (!capability->cap[INPUT_META_VIA_REQUEST].value) {
 			i_vpr_e(inst,
 				"%s: input metadata not enabled via request\n", __func__);

+ 2 - 2
driver/vidc/src/msm_vidc_driver.c

@@ -6270,7 +6270,7 @@ int msm_vidc_get_properties(struct msm_vidc_inst *inst)
 	return 0;
 }
 
-int msm_vidc_create_input_metadata_buffer(struct msm_vidc_inst *inst, u32 fd)
+int msm_vidc_create_input_metadata_buffer(struct msm_vidc_inst *inst, int fd)
 {
 	int rc = 0;
 	struct msm_vidc_buffer *buf = NULL;
@@ -6282,7 +6282,7 @@ int msm_vidc_create_input_metadata_buffer(struct msm_vidc_inst *inst, u32 fd)
 		return -EINVAL;
 	}
 
-	if (fd <= 0) {
+	if (fd < 0) {
 		i_vpr_e(inst, "%s: invalid input metadata buffer fd %d\n",
 			__func__, fd);
 		return -EINVAL;

+ 2 - 0
driver/vidc/src/msm_vidc_platform.c

@@ -62,6 +62,7 @@ static struct v4l2_ioctl_ops msm_v4l2_ioctl_ops_enc = {
 	.vidioc_reqbufs                 = msm_v4l2_reqbufs,
 	.vidioc_querybuf                = msm_v4l2_querybuf,
 	.vidioc_create_bufs             = msm_v4l2_create_bufs,
+	.vidioc_prepare_buf             = msm_v4l2_prepare_buf,
 	.vidioc_qbuf                    = msm_v4l2_qbuf,
 	.vidioc_dqbuf                   = msm_v4l2_dqbuf,
 	.vidioc_streamon                = msm_v4l2_streamon,
@@ -101,6 +102,7 @@ static struct v4l2_ioctl_ops msm_v4l2_ioctl_ops_dec = {
 	.vidioc_reqbufs                 = msm_v4l2_reqbufs,
 	.vidioc_querybuf                = msm_v4l2_querybuf,
 	.vidioc_create_bufs             = msm_v4l2_create_bufs,
+	.vidioc_prepare_buf             = msm_v4l2_prepare_buf,
 	.vidioc_qbuf                    = msm_v4l2_qbuf,
 	.vidioc_dqbuf                   = msm_v4l2_dqbuf,
 	.vidioc_streamon                = msm_v4l2_streamon,

+ 32 - 14
driver/vidc/src/msm_vidc_v4l2.c

@@ -371,6 +371,31 @@ unlock:
 	return rc;
 }
 
+int msm_v4l2_prepare_buf(struct file *filp, void *fh,
+				struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = get_vidc_inst(filp, fh);
+	struct video_device *vdev = video_devdata(filp);
+	int rc = 0;
+
+	inst = get_inst_ref(g_core, inst);
+	if (!inst) {
+		d_vpr_e("%s: invalid instance\n", __func__);
+		return -EINVAL;
+	}
+
+	inst_lock(inst, __func__);
+	rc = msm_vidc_prepare_buf((void *)inst, vdev->v4l2_dev->mdev, b);
+	if (rc)
+		goto unlock;
+
+unlock:
+	inst_unlock(inst, __func__);
+	put_inst(inst);
+
+	return rc;
+}
+
 int msm_v4l2_qbuf(struct file *filp, void *fh,
 				struct v4l2_buffer *b)
 {
@@ -438,18 +463,11 @@ int msm_v4l2_streamon(struct file *filp, void *fh,
 		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);
 	if (rc)
-		goto unlock;
+		goto exit;
 
-unlock:
-	inst_unlock(inst, __func__);
+exit:
 	put_inst(inst);
 
 	return rc;
@@ -467,13 +485,11 @@ int msm_v4l2_streamoff(struct file *filp, void *fh,
 		return -EINVAL;
 	}
 
-	inst_lock(inst, __func__);
 	rc = msm_vidc_streamoff((void *)inst, i);
 	if (rc)
-		goto unlock;
+		goto exit;
 
-unlock:
-	inst_unlock(inst, __func__);
+exit:
 	put_inst(inst);
 
 	return rc;
@@ -748,17 +764,19 @@ unlock:
 
 int msm_v4l2_request_validate(struct media_request *req)
 {
+	d_vpr_l("%s()\n", __func__);
 	return vb2_request_validate(req);
 }
 
 void msm_v4l2_request_queue(struct media_request *req)
 {
+	d_vpr_l("%s()\n", __func__);
 	v4l2_m2m_request_queue(req);
 }
 
 void msm_v4l2_m2m_device_run(void *priv)
 {
-	d_vpr_l("%s: \n", __func__);
+	d_vpr_l("%s()\n", __func__);
 }
 
 void msm_v4l2_m2m_job_abort(void *priv)

+ 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;
 	}
 	inst = q->drv_priv;
+	inst = get_inst_ref(g_core, inst);
 	if (!inst || !inst->core || !inst->capabilities) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		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 &&
 		inst->capabilities->cap[INPUT_META_VIA_REQUEST].value) {
 		i_vpr_e(inst,
 			"%s: invalid input meta port start when request enabled\n",
 			__func__);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto unlock;
 	}
 
 	if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) {
 		i_vpr_h(inst, "%s: nothing to start on %s\n",
 			__func__, v4l2_type_name(q->type));
-		return 0;
+		rc = 0;
+		goto unlock;
 	}
 	if (!is_decode_session(inst) && !is_encode_session(inst)) {
 		i_vpr_e(inst, "%s: invalid session %d\n",
 			__func__, inst->domain);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto unlock;
 	}
 	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;
 		rc = msm_vidc_prepare_dependency_list(inst);
 		if (rc)
-			return rc;
+			goto unlock;
 
 		rc = msm_vidc_session_set_codec(inst);
 		if (rc)
-			return rc;
+			goto unlock;
 
 		rc = msm_vidc_session_set_secure_mode(inst);
 		if (rc)
-			return rc;
+			goto unlock;
 
 		if (is_encode_session(inst)) {
 			rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst,
 				MSM_VIDC_BUF_ARP);
 			if (rc)
-				goto error;
+				goto unlock;
 		} else if(is_decode_session(inst)) {
 			rc = msm_vidc_session_set_default_header(inst);
 			if (rc)
-				return rc;
+				goto unlock;
 
 			rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst,
 				MSM_VIDC_BUF_PERSIST);
 			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))
 			rc = msm_venc_streamon_input(inst);
 		else
-			goto error;
+			goto unlock;
 	} else if (q->type == OUTPUT_MPLANE) {
 		if (is_decode_session(inst))
 			rc = msm_vdec_streamon_output(inst);
 		else if (is_encode_session(inst))
 			rc = msm_venc_streamon_output(inst);
 		else
-			goto error;
+			goto unlock;
 	} else {
 		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
-		goto error;
+		goto unlock;
 	}
 	if (rc)
-		goto error;
+		goto unlock;
 
 	/* print final buffer counts & size details */
 	msm_vidc_print_buffer_info(inst);
 
 	buf_type = v4l2_type_to_driver(q->type, __func__);
 	if (!buf_type)
-		goto error;
+		goto unlock;
 
 	/* queue pending buffers */
 	rc = msm_vidc_queue_deferred_buffers(inst, buf_type);
 	if (rc)
-		goto error;
+		goto unlock;
 
 	/* initialize statistics timer(one time) */
 	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 */
 	rc = schedule_stats_work(inst);
 	if (rc)
-		goto error;
+		goto unlock;
 
 	if ((q->type == INPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming) ||
 		(q->type == OUTPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming)) {
 		rc = msm_vidc_get_properties(inst);
 		if (rc)
-			goto error;
+			goto unlock;
 	}
 
 	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;
-
-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)
 {
 	int rc = 0;
 	struct msm_vidc_inst *inst;
+	enum msm_vidc_allow allow;
 
 	if (!q || !q->drv_priv) {
 		d_vpr_e("%s: invalid input, q = %pK\n", __func__, q);
 		return;
 	}
 	inst = q->drv_priv;
+	inst = get_inst_ref(g_core, inst);
 	if (!inst || !inst->core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return;
 	}
+
+	inst_lock(inst, __func__);
 	if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) {
 		i_vpr_h(inst, "%s: nothing to stop on %s\n",
 			__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)) {
 		i_vpr_e(inst, "%s: invalid session %d\n",
 			__func__, inst->domain);
-		return;
+		rc = -EINVAL;
+		goto unlock;
 	}
 	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);
 	} else {
 		i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type);
-		goto error;
+		rc = -EINVAL;
+		goto unlock;
 	}
 	if (rc)
-		goto error;
+		goto unlock;
 
 	/* Input port streamoff - flush timestamps list*/
 	if (q->type == INPUT_MPLANE)
 		msm_vidc_flush_ts(inst);
 
 	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;
 }