소스 검색

video: driver: resolve subsystem restart failure

Allow streamoff from msm_vidc_vb2_queue_deinit after
errors to flush out the pending buffer in driver
in order to avoid v4l2 framework printing below warning.

videobuf2_common: driver bug: stop_streaming operation
is leaving buf in active state.

Call trace
__vb2_queue_cancel+0x214/0x288
vb2_core_queue_release+0x28/0x5c
vb2_queue_release+0x18/0x28
msm_vidc_vb2_queue_deinit+0x40/0x118 [msm_video]
msm_vidc_close+0x7c/0x144 [msm_video]
msm_v4l2_close+0x44/0x164 [msm_video]

There is a deadlock if driver acquires inst lock
in msm_vb2_stop_streaming, because this function
will be called from msm_vidc_close which already
acquired the inst lock. Hence, acquire inst lock
in msm_v4l2_stramoff instead of msm_vb2_stop_streaming.

Change-Id: Iec4c0e416a8a2705af28dbd5138f25d9f3016d12
Signed-off-by: Ankush Mitra <[email protected]>
Ankush Mitra 2 년 전
부모
커밋
f1771aae41
3개의 변경된 파일35개의 추가작업 그리고 34개의 파일을 삭제
  1. 30 23
      driver/vidc/src/msm_vidc_driver.c
  2. 5 2
      driver/vidc/src/msm_vidc_v4l2.c
  3. 0 9
      driver/vidc/src/msm_vidc_vb2.c

+ 30 - 23
driver/vidc/src/msm_vidc_driver.c

@@ -3868,12 +3868,6 @@ int msm_vidc_vb2_queue_deinit(struct msm_vidc_inst *inst)
 		return 0;
 	}
 
-	vb2_queue_release(inst->bufq[OUTPUT_META_PORT].vb2q);
-	msm_vidc_vmem_free((void **)&inst->bufq[OUTPUT_META_PORT].vb2q);
-	inst->bufq[OUTPUT_META_PORT].vb2q = NULL;
-	vb2_queue_release(inst->bufq[INPUT_META_PORT].vb2q);
-	msm_vidc_vmem_free((void **)&inst->bufq[INPUT_META_PORT].vb2q);
-	inst->bufq[INPUT_META_PORT].vb2q = NULL;
 	/*
 	 * vb2_queue_release() for input and output queues
 	 * is called from v4l2_m2m_ctx_release()
@@ -3882,6 +3876,13 @@ int msm_vidc_vb2_queue_deinit(struct msm_vidc_inst *inst)
 	inst->bufq[OUTPUT_PORT].vb2q = NULL;
 	inst->bufq[INPUT_PORT].vb2q = NULL;
 	v4l2_m2m_release(inst->m2m_dev);
+
+	vb2_queue_release(inst->bufq[OUTPUT_META_PORT].vb2q);
+	msm_vidc_vmem_free((void **)&inst->bufq[OUTPUT_META_PORT].vb2q);
+	inst->bufq[OUTPUT_META_PORT].vb2q = NULL;
+	vb2_queue_release(inst->bufq[INPUT_META_PORT].vb2q);
+	msm_vidc_vmem_free((void **)&inst->bufq[INPUT_META_PORT].vb2q);
+	inst->bufq[INPUT_META_PORT].vb2q = NULL;
 	inst->vb2q_init = false;
 
 	return rc;
@@ -4158,38 +4159,44 @@ int msm_vidc_session_close(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
 	struct msm_vidc_core *core;
+	bool wait_for_response;
 
 	if (!inst || !inst->core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
+	core = inst->core;
 
+	wait_for_response = true;
 	rc = venus_hfi_session_close(inst);
-	if (rc)
-		return rc;
+	if (rc) {
+		i_vpr_e(inst, "%s: session close cmd failed\n", __func__);
+		wait_for_response = false;
+	}
 
 	/* we are not supposed to send any more commands after close */
 	i_vpr_h(inst, "%s: free session packet data\n", __func__);
 	msm_vidc_vmem_free((void **)&inst->packet);
 	inst->packet = NULL;
 
-	core = inst->core;
-	i_vpr_h(inst, "%s: wait on close for time: %d ms\n",
+	if (wait_for_response) {
+		i_vpr_h(inst, "%s: wait on close for time: %d ms\n",
 		__func__, core->capabilities[HW_RESPONSE_TIMEOUT].value);
-	inst_unlock(inst, __func__);
-	rc = wait_for_completion_timeout(
-			&inst->completions[SIGNAL_CMD_CLOSE],
-			msecs_to_jiffies(
-			core->capabilities[HW_RESPONSE_TIMEOUT].value));
-	if (!rc) {
-		i_vpr_e(inst, "%s: session close timed out\n", __func__);
-		rc = -ETIMEDOUT;
-		msm_vidc_inst_timeout(inst);
-	} else {
-		rc = 0;
-		i_vpr_h(inst, "%s: close successful\n", __func__);
+		inst_unlock(inst, __func__);
+		rc = wait_for_completion_timeout(
+				&inst->completions[SIGNAL_CMD_CLOSE],
+				msecs_to_jiffies(
+				core->capabilities[HW_RESPONSE_TIMEOUT].value));
+		if (!rc) {
+			i_vpr_e(inst, "%s: session close timed out\n", __func__);
+			rc = -ETIMEDOUT;
+			msm_vidc_inst_timeout(inst);
+		} else {
+			rc = 0;
+			i_vpr_h(inst, "%s: close successful\n", __func__);
+		}
+		inst_lock(inst, __func__);
 	}
-	inst_lock(inst, __func__);
 
 	return rc;
 }

+ 5 - 2
driver/vidc/src/msm_vidc_v4l2.c

@@ -514,11 +514,14 @@ int msm_v4l2_streamoff(struct file *filp, void *fh,
 		return -EINVAL;
 	}
 
+	client_lock(inst, __func__);
+	inst_lock(inst, __func__);
 	rc = msm_vidc_streamoff((void *)inst, i);
 	if (rc)
-		goto exit;
+		i_vpr_e(inst, "%s: msm_vidc_stramoff failed\n", __func__);
 
-exit:
+	inst_unlock(inst, __func__);
+	client_unlock(inst, __func__);
 	put_inst(inst);
 
 	return rc;

+ 0 - 9
driver/vidc/src/msm_vidc_vb2.c

@@ -577,26 +577,17 @@ void msm_vb2_stop_streaming(struct vb2_queue *q)
 		return;
 	}
 	inst = q->drv_priv;
-	inst = get_inst_ref(g_core, inst);
 	if (!inst) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return;
 	}
 
-	client_lock(inst, __func__);
-	inst_lock(inst, __func__);
 	rc = inst->event_handle(inst, MSM_VIDC_STREAMOFF, q);
 	if (rc) {
 		i_vpr_e(inst, "Streamoff: %s failed\n", v4l2_type_name(q->type));
 		msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__);
-		goto unlock;
 	}
 
-unlock:
-	inst_unlock(inst, __func__);
-	client_unlock(inst, __func__);
-	put_inst(inst);
-
 	return;
 }