msm: vidc: Release DPBs only held by driver during reconfig

For VP9 there is a chance that firmware holds back DPBs
during port reconfig(scalability). These buffers shouldn't
be freed when firmware has ownership. Modified release
output buffer to take care of this and during close
instance we free all DPB's irrespective of ownership.

CRs-Fixed: 1010707
Change-Id: Iecb1e3784b4c4b45063694d933ee66f755a84935
Signed-off-by: Vaibhav Deshu Venkatesh <vdeshuve@codeaurora.org>
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index bf0148c..68848a8 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -504,6 +504,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "Mpeg2",
@@ -512,6 +513,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "H263",
@@ -520,6 +522,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "VC1",
@@ -528,6 +531,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "VC1 SP",
@@ -536,6 +540,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "H264",
@@ -544,6 +549,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "H264_MVC",
@@ -552,6 +558,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "HEVC",
@@ -560,6 +567,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "VP8",
@@ -568,6 +576,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed,
 		.type = OUTPUT_PORT,
+		.defer_outputs = false,
 	},
 	{
 		.name = "VP9",
@@ -576,6 +585,7 @@
 		.num_planes = 1,
 		.get_frame_size = get_frame_size_compressed_full_yuv,
 		.type = OUTPUT_PORT,
+		.defer_outputs = true,
 	},
 };
 
@@ -1767,7 +1777,7 @@
 			case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE:
 				if (!msm_comm_g_ctrl_for_id(inst, control.id)) {
 					rc = msm_comm_release_output_buffers(
-						inst);
+						inst, false);
 					if (rc)
 						dprintk(VIDC_ERR,
 							"%s Release output buffers failed\n",
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 5d206d3..4a1fd76 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1388,7 +1388,13 @@
 				"Failed to release persist buffers\n");
 		}
 
-		if (msm_comm_release_output_buffers(inst)) {
+		/*
+		 * At this point all buffes should be with driver
+		 * irrespective of scenario
+		 */
+		msm_comm_validate_output_buffers(inst);
+
+		if (msm_comm_release_output_buffers(inst, true)) {
 			dprintk(VIDC_ERR,
 				"Failed to release output buffers\n");
 		}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 564ab99..00feba6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1414,7 +1414,7 @@
 	put_inst(inst);
 }
 
-void validate_output_buffers(struct msm_vidc_inst *inst)
+void msm_comm_validate_output_buffers(struct msm_vidc_inst *inst)
 {
 	struct internal_buf *binfo;
 	u32 buffers_owned_by_driver = 0;
@@ -1440,11 +1440,13 @@
 	}
 	mutex_unlock(&inst->outputbufs.lock);
 
-	if (buffers_owned_by_driver != output_buf->buffer_count_actual)
+	if (buffers_owned_by_driver != output_buf->buffer_count_actual) {
 		dprintk(VIDC_WARN,
 			"OUTPUT Buffer count mismatch %d of %d\n",
 			buffers_owned_by_driver,
 			output_buf->buffer_count_actual);
+		msm_vidc_handle_hw_error(inst->core);
+	}
 }
 
 int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst)
@@ -1524,7 +1526,11 @@
 
 	if (msm_comm_get_stream_output_mode(inst) ==
 			HAL_VIDEO_DECODER_SECONDARY) {
-		validate_output_buffers(inst);
+
+		if (!(inst->fmts[OUTPUT_PORT].defer_outputs &&
+				inst->in_reconfig))
+			msm_comm_validate_output_buffers(inst);
+
 		if (!inst->in_reconfig) {
 			rc = msm_comm_queue_output_buffers(inst);
 			if (rc) {
@@ -4051,7 +4057,8 @@
 	return rc;
 }
 
-int msm_comm_release_output_buffers(struct msm_vidc_inst *inst)
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst,
+	bool force_release)
 {
 	struct msm_smem *handle;
 	struct internal_buf *buf, *dummy;
@@ -4093,6 +4100,11 @@
 			goto exit;
 		}
 
+		if ((buf->buffer_ownership == FIRMWARE) && !force_release) {
+			dprintk(VIDC_INFO, "DPB is with f/w. Can't free it\n");
+			continue;
+		}
+
 		buffer_info.buffer_size = handle->size;
 		buffer_info.buffer_type = buf->buffer_type;
 		buffer_info.num_buffers = 1;
@@ -4352,13 +4364,17 @@
 int msm_comm_set_output_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
+	bool force_release = true;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
 		return -EINVAL;
 	}
 
-	if (msm_comm_release_output_buffers(inst))
+	if (inst->fmts[OUTPUT_PORT].defer_outputs)
+		force_release = false;
+
+	if (msm_comm_release_output_buffers(inst, force_release))
 		dprintk(VIDC_WARN, "Failed to release output buffers\n");
 
 	rc = set_output_buffers(inst, HAL_BUFFER_OUTPUT);
@@ -4366,7 +4382,7 @@
 		goto error;
 	return rc;
 error:
-	msm_comm_release_output_buffers(inst);
+	msm_comm_release_output_buffers(inst, true);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index c042fe9..7f2ab04 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -55,7 +55,9 @@
 int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
 					bool check_for_reuse);
 int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
-int msm_comm_release_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst,
+	bool force_release);
+void msm_comm_validate_output_buffers(struct msm_vidc_inst *inst);
 int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
 int msm_comm_suspend(int core_id);
 enum hal_extradata_id msm_comm_get_hal_extradata_index(
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index 0af0220..cf5ce22 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -117,7 +117,7 @@
 
 #define MSM_VIDC_ERROR(value)					\
 	do {							\
-		dprintk(VIDC_WARN, "Fatal Level = %d\n", value);\
+		dprintk(VIDC_DBG, "Fatal Level = %d\n", value);\
 		BUG_ON(value);					\
 	} while (0)
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index b4f3cd7..fb90fdf7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -148,6 +148,7 @@
 	int num_planes;
 	int type;
 	u32 (*get_frame_size)(int plane, u32 height, u32 width);
+	bool defer_outputs;
 };
 
 struct msm_vidc_drv {