msm: vidc: Fix VP9 decoder failure due to scaling feature

VP9 decoder does not release the output buffers in port
reconfiguration sequence due to scaling feature. Support
the feature by doing appropriate changes in driver.

Change-Id: I1a5602f15c1206d0f248a5311678201743a494fc
Signed-off-by: Maheshwar Ajja <majja@codeaurora.org>
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 854aa0a..8b97da5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -426,6 +426,12 @@
 		if (vb2->type != type || vb2->index != index)
 			continue;
 
+		if (mbuf->flags & MSM_VIDC_FLAG_RBR_PENDING) {
+			print_vidc_buffer(VIDC_DBG,
+				"skip rel buf (rbr pending)", inst, mbuf);
+			continue;
+		}
+
 		print_vidc_buffer(VIDC_DBG, "release buf", inst, mbuf);
 		msm_comm_unmap_vidc_buffer(inst, mbuf);
 		list_del(&mbuf->list);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 8074c05..51023f0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -190,7 +190,7 @@
 				&inst->registeredbufs.list, list) {
 			if (temp->vvb.vb2_buf.type ==
 				V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
-					temp->deferred) {
+					temp->flags & MSM_VIDC_FLAG_DEFERRED) {
 				filled_len = max(filled_len,
 					temp->vvb.vb2_buf.planes[0].bytesused);
 				device_addr = temp->smem[0].device_addr;
@@ -676,7 +676,7 @@
 	list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) {
 		if (temp->vvb.vb2_buf.type ==
 				V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
-					temp->deferred) {
+					temp->flags & MSM_VIDC_FLAG_DEFERRED) {
 			filled_len = max(filled_len,
 				temp->vvb.vb2_buf.planes[0].bytesused);
 			device_addr = temp->smem[0].device_addr;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 1b8e438..a013fe9 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -3830,7 +3830,7 @@
 			continue;
 
 		/* count only deferred buffers */
-		if (!mbuf->deferred)
+		if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED))
 			continue;
 
 		++count;
@@ -3858,7 +3858,7 @@
 			continue;
 
 		/* count only deferred buffers */
-		if (!mbuf->deferred)
+		if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED))
 			continue;
 
 		++count;
@@ -3906,6 +3906,41 @@
 	}
 }
 
+static int msm_comm_qbuf_rbr(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct vidc_frame_data frame_data = {0};
+
+	if (!inst || !inst->core || !inst->core->device || !mbuf) {
+		dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR, "%s: inst is in bad state\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_comm_scale_clocks_and_bus(inst);
+	populate_frame_data(&frame_data, mbuf, inst);
+
+	rc = call_hfi_op(hdev, session_ftb, inst->session, &frame_data);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to issue ftb: %d\n", rc);
+		goto err_bad_input;
+	}
+
+	log_frame(inst, &frame_data, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+err_bad_input:
+	return rc;
+}
+
+
 /*
  * Attempts to queue `vb` to hardware.  If, for various reasons, the buffer
  * cannot be queued to hardware, the buffer will be staged for commit in the
@@ -3937,10 +3972,6 @@
 		return -EINVAL;
 	}
 
-	/* initially assume every buffer is going to be deferred */
-	if (mbuf)
-		mbuf->deferred = true;
-
 	batch_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_VIDC_QBUF_MODE)
 		== V4L2_VIDC_QBUF_BATCHED;
 	capture_count = (batch_mode ? &count_single_batch : &count_buffers)
@@ -3968,7 +3999,7 @@
 
 	if (defer) {
 		if (mbuf) {
-			mbuf->deferred = true;
+			mbuf->flags |= MSM_VIDC_FLAG_DEFERRED;
 			print_vidc_buffer(VIDC_DBG, "deferred qbuf",
 				inst, mbuf);
 		}
@@ -4009,7 +4040,7 @@
 	list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) {
 		struct vidc_frame_data *frame_data = NULL;
 
-		if (!temp->deferred)
+		if (!(temp->flags & MSM_VIDC_FLAG_DEFERRED))
 			continue;
 
 		switch (temp->vvb.vb2_buf.type) {
@@ -4031,7 +4062,7 @@
 		populate_frame_data(frame_data, temp, inst);
 
 		/* this buffer going to be queued (not deferred) */
-		temp->deferred = false;
+		temp->flags &= ~MSM_VIDC_FLAG_DEFERRED;
 
 		print_vidc_buffer(VIDC_DBG, "qbuf", inst, temp);
 	}
@@ -4820,7 +4851,7 @@
 
 int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
 {
-	int rc =  0;
+	int i, rc =  0;
 	bool ip_flush = false;
 	bool op_flush = false;
 	struct msm_vidc_buffer *mbuf, *next;
@@ -4845,8 +4876,6 @@
 		return 0;
 	}
 
-	/* Finish FLUSH As Soon As Possible. */
-
 	msm_clock_data_reset(inst);
 
 	if (inst->state == MSM_VIDC_CORE_INVALID) {
@@ -4859,22 +4888,41 @@
 
 	mutex_lock(&inst->registeredbufs.lock);
 	list_for_each_entry_safe(mbuf, next, &inst->registeredbufs.list, list) {
-		/* flush only deferred buffers (which are not queued yet) */
-		if (!mbuf->deferred)
-			continue;
-
-		/* don't flush input buffers if flush not requested on it */
+		/* don't flush input buffers if input flush is not requested */
 		if (!ip_flush && mbuf->vvb.vb2_buf.type ==
 				V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 			continue;
 
+		/* flush only deferred or rbr pending buffers */
+		if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED ||
+			mbuf->flags & MSM_VIDC_FLAG_RBR_PENDING))
+			continue;
+
+		/*
+		 * flush buffers which are queued by client already,
+		 * the refcount will be two or more for those buffers.
+		 */
+		if (!(mbuf->smem[0].refcount >= 2))
+			continue;
+
 		print_vidc_buffer(VIDC_DBG, "flush buf", inst, mbuf);
 		msm_comm_flush_vidc_buffer(inst, mbuf);
-		msm_comm_unmap_vidc_buffer(inst, mbuf);
 
-		/* remove from list */
-		list_del(&mbuf->list);
-		kref_put_mbuf(mbuf);
+		for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
+			if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
+				print_vidc_buffer(VIDC_ERR,
+					"dqbuf: unmap failed.", inst, mbuf);
+			if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
+				print_vidc_buffer(VIDC_ERR,
+					"dqbuf: unmap failed..", inst, mbuf);
+		}
+		if (!mbuf->smem[0].refcount) {
+			list_del(&mbuf->list);
+			kref_put_mbuf(mbuf);
+		} else {
+			/* buffer is no more a deferred buffer */
+			mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+		}
 	}
 	mutex_unlock(&inst->registeredbufs.lock);
 
@@ -5750,27 +5798,27 @@
 
 	if (vb2->num_planes == 1)
 		dprintk(tag,
-			"%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d\n",
+			"%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d mflags 0x%x\n",
 			str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
 			"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
 			vb2->index, vb2->planes[0].m.fd,
 			vb2->planes[0].data_offset, mbuf->smem[0].device_addr,
 			vb2->planes[0].length, vb2->planes[0].bytesused,
 			mbuf->vvb.flags, mbuf->vvb.vb2_buf.timestamp,
-			mbuf->smem[0].refcount);
+			mbuf->smem[0].refcount, mbuf->flags);
 	else
 		dprintk(tag,
-			"%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d, extradata: fd %d off %d daddr %x size %d filled %d refcnt %d\n",
+			"%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d mflags 0x%x, extradata: fd %d off %d daddr %x size %d filled %d refcnt %d\n",
 			str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
 			"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
 			vb2->index, vb2->planes[0].m.fd,
 			vb2->planes[0].data_offset, mbuf->smem[0].device_addr,
 			vb2->planes[0].length, vb2->planes[0].bytesused,
 			mbuf->vvb.flags, mbuf->vvb.vb2_buf.timestamp,
-			mbuf->smem[0].refcount, vb2->planes[1].m.fd,
-			vb2->planes[1].data_offset, mbuf->smem[1].device_addr,
-			vb2->planes[1].length, vb2->planes[1].bytesused,
-			mbuf->smem[1].refcount);
+			mbuf->smem[0].refcount, mbuf->flags,
+			vb2->planes[1].m.fd, vb2->planes[1].data_offset,
+			mbuf->smem[1].device_addr, vb2->planes[1].length,
+			vb2->planes[1].bytesused, mbuf->smem[1].refcount);
 }
 
 void print_vb2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
@@ -5789,13 +5837,14 @@
 			vb2->planes[0].bytesused);
 	else
 		dprintk(tag,
-			"%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d\n",
+			"%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d filled %d\n",
 			str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
 			"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
 			vb2->index, vb2->planes[0].m.fd,
 			vb2->planes[0].data_offset, vb2->planes[0].length,
 			vb2->planes[0].bytesused, vb2->planes[1].m.fd,
-			vb2->planes[1].data_offset, vb2->planes[1].length);
+			vb2->planes[1].data_offset, vb2->planes[1].length,
+			vb2->planes[1].bytesused);
 }
 
 void print_v4l2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
@@ -5815,7 +5864,7 @@
 			v4l2->m.planes[0].bytesused);
 	else
 		dprintk(tag,
-			"%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d\n",
+			"%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d filled %d\n",
 			str, v4l2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
 			"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
 			v4l2->index, v4l2->m.planes[0].m.fd,
@@ -5824,7 +5873,8 @@
 			v4l2->m.planes[0].bytesused,
 			v4l2->m.planes[1].m.fd,
 			v4l2->m.planes[1].data_offset,
-			v4l2->m.planes[1].length);
+			v4l2->m.planes[1].length,
+			v4l2->m.planes[1].bytesused);
 }
 
 bool msm_comm_compare_vb2_plane(struct msm_vidc_inst *inst,
@@ -6042,6 +6092,9 @@
 		kref_init(&mbuf->kref);
 	}
 
+	/* Initially assume all the buffer are going to be deferred */
+	mbuf->flags |= MSM_VIDC_FLAG_DEFERRED;
+
 	vbuf = to_vb2_v4l2_buffer(vb2);
 	memcpy(&mbuf->vvb, vbuf, sizeof(struct vb2_v4l2_buffer));
 	vb = &mbuf->vvb.vb2_buf;
@@ -6088,6 +6141,16 @@
 			if (found_plane0)
 				rc = -EEXIST;
 		}
+		/*
+		 * If RBR pending on this buffer then enable RBR_PENDING flag
+		 * and clear the DEFERRED flag to avoid this buffer getting
+		 * queued to video hardware in msm_comm_qbuf() which tries to
+		 * queue all the DEFERRED buffers.
+		 */
+		if (rc == -EEXIST) {
+			mbuf->flags |= MSM_VIDC_FLAG_RBR_PENDING;
+			mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+		}
 	}
 
 	/* add the new buffer to list */
@@ -6184,10 +6247,14 @@
 		}
 	}
 	if (found) {
+		/* send RBR event to client */
 		msm_vidc_queue_rbr_event(inst,
 			mbuf->vvb.vb2_buf.planes[0].m.fd,
 			mbuf->vvb.vb2_buf.planes[0].data_offset);
 
+		/* clear RBR_PENDING flag */
+		mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING;
+
 		for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
 			if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
 				print_vidc_buffer(VIDC_ERR,
@@ -6223,7 +6290,7 @@
 	if (!found)
 		goto unlock;
 
-	/* found means client queued the buffer already */
+	/* buffer found means client queued the buffer already */
 	if (inst->in_reconfig || inst->in_flush) {
 		print_vidc_buffer(VIDC_DBG, "rbr flush buf", inst, mbuf);
 		msm_comm_flush_vidc_buffer(inst, mbuf);
@@ -6235,12 +6302,16 @@
 		/* don't queue the buffer */
 		found = false;
 	}
+	/* clear DEFERRED flag, if any, as the buffer is going to be queued */
+	if (found)
+		mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+
 unlock:
 	mutex_unlock(&inst->registeredbufs.lock);
 
 	if (found) {
 		print_vidc_buffer(VIDC_DBG, "rbr qbuf", inst, mbuf);
-		rc = msm_comm_qbuf(inst, mbuf);
+		rc = msm_comm_qbuf_rbr(inst, mbuf);
 		if (rc)
 			print_vidc_buffer(VIDC_ERR,
 				"rbr qbuf failed", inst, mbuf);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 57dfd52..195410d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -399,12 +399,17 @@
 int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
 void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
 
+enum msm_vidc_flags {
+	MSM_VIDC_FLAG_DEFERRED            = BIT(0),
+	MSM_VIDC_FLAG_RBR_PENDING         = BIT(1),
+};
+
 struct msm_vidc_buffer {
 	struct list_head list;
 	struct kref kref;
 	struct msm_smem smem[VIDEO_MAX_PLANES];
 	struct vb2_v4l2_buffer vvb;
-	bool deferred;
+	enum msm_vidc_flags flags;
 };
 
 void msm_comm_handle_thermal_event(void);