diff mbox series

[v4,6/7] media: mediatek: vcodec: replace v4l2_m2m_next_src_buf with v4l2_m2m_src_buf_remove

Message ID 20240807082444.21280-7-yunfei.dong@mediatek.com (mailing list archive)
State New
Headers show
Series media: mediatek: vcodec: fix v4l2_ctrl_request_complete fail | expand

Commit Message

Yunfei Dong Aug. 7, 2024, 8:24 a.m. UTC
There isn't lock to protect source buffer when get next src buffer,
if the source buffer is removed for some unknown reason before lat
work queue execute done, will lead to remove source buffer or buffer
done error.

Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
---
 .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 30 +++++++++++++------
 1 file changed, 21 insertions(+), 9 deletions(-)

Comments

Sebastian Fricke Aug. 23, 2024, 3:23 p.m. UTC | #1
Hey Yunfei,

On 07.08.2024 16:24, Yunfei Dong wrote:
>There isn't lock to protect source buffer when get next src buffer,
>if the source buffer is removed for some unknown reason before lat
>work queue execute done, will lead to remove source buffer or buffer
>done error.

This is really hard to understand, can try wording this a bit clearer?
Stuff like: if the source buffer is removed ... will lead to remove
source buffer, just leaves me scratching my head.
And there is a spinlock in the m2m framework in `v4l2_m2m_next_buf` so I
suppose you mean something else when you say that there is no lock to
protect the source buffer?

You might not know all reasons but for this commit description you
should at least know one reason. Please highlight a case how this can
happen, so that you can justify the change.

>
>Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
>---
> .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 30 +++++++++++++------
> 1 file changed, 21 insertions(+), 9 deletions(-)
>
>diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
>index 8aa379872ddc..3dba3549000a 100644
>--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
>+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
>@@ -321,6 +321,7 @@ static void mtk_vdec_worker(struct work_struct *work)
> 		container_of(work, struct mtk_vcodec_dec_ctx, decode_work);
> 	struct mtk_vcodec_dec_dev *dev = ctx->dev;
> 	struct vb2_v4l2_buffer *vb2_v4l2_src = ctx->last_vb2_v4l2_src;
>+	struct vb2_v4l2_buffer *vb2_v4l2_dst;
> 	struct vb2_buffer *vb2_src;
> 	struct mtk_vcodec_mem *bs_src;
> 	struct mtk_video_dec_buf *dec_buf_src;
>@@ -329,7 +330,7 @@ static void mtk_vdec_worker(struct work_struct *work)
> 	bool res_chg = false;
> 	int ret;
>
>-	vb2_v4l2_src = vb2_v4l2_src ? vb2_v4l2_src : v4l2_m2m_next_src_buf(ctx->m2m_ctx);
>+	vb2_v4l2_src = vb2_v4l2_src ? vb2_v4l2_src : v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> 	if (!vb2_v4l2_src) {
> 		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
> 		mtk_v4l2_vdec_dbg(1, ctx, "[%d] no available source buffer", ctx->id);
>@@ -381,17 +382,28 @@ static void mtk_vdec_worker(struct work_struct *work)
> 	    ctx->current_codec == V4L2_PIX_FMT_VP8_FRAME) {
> 		if (src_buf_req)
> 			v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl);
>-		v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx, state);
>-	} else {
>-		if (ret != -EAGAIN) {
>-			v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
>-			ctx->last_vb2_v4l2_src = NULL;
>-		} else {
>-			ctx->last_vb2_v4l2_src = vb2_v4l2_src;
>-		}
>+		vb2_v4l2_dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
>+		v4l2_m2m_buf_done(vb2_v4l2_dst, state);
>+		v4l2_m2m_buf_done(vb2_v4l2_src, state);

This is another case where you just remove again completely what you
have added in the previous patch.

>
> 		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
>+		return;
> 	}
>+
>+	/* If each codec return -EAGAIN to decode again, need to backup current source
>+	 * buffer, then the driver will get this buffer next time.

I would reword this like:

	/* Store the current source buffer for the next attempt to decode,
    * if this decode returned -EAGAIN */

>+	 *
>+	 * If each codec decode error, must to set buffer done with error status for
>+	 * this buffer have been removed from ready list.
>+	 */
>+	ctx->last_vb2_v4l2_src = (ret != -EAGAIN) ? NULL : vb2_v4l2_src;

Okay and here you add the same thing again as in the previous patch but
differently, this collection of commits feels more and more to me like a
work in progress. Please make sure in the future that each commit does
one job and does it completely.
It is not only confussing but also makes it hard to read the changes as
the bigger picture is missing in these tiny commits.

Please try to combine the patches where possible.

Regards,
Sebastian Fricke

>+	if (ret && ret != -EAGAIN) {
>+		if (src_buf_req)
>+			v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl);
>+		v4l2_m2m_buf_done(vb2_v4l2_src, state);
>+	}
>+
>+	v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
> }
>
> static void vb2ops_vdec_stateless_buf_queue(struct vb2_buffer *vb)
>-- 
>2.46.0
>
>
Yunfei Dong Aug. 27, 2024, 2:56 a.m. UTC | #2
Hi Sebastian,

Thanks for your suggestion.
On Fri, 2024-08-23 at 17:23 +0200, Sebastian Fricke wrote:
> Hey Yunfei,
> 
> On 07.08.2024 16:24, Yunfei Dong wrote:
> > There isn't lock to protect source buffer when get next src buffer,
> > if the source buffer is removed for some unknown reason before lat
> > work queue execute done, will lead to remove source buffer or
> > buffer
> > done error.
> 
> This is really hard to understand, can try wording this a bit
> clearer?
> Stuff like: if the source buffer is removed ... will lead to remove
> source buffer, just leaves me scratching my head.
> And there is a spinlock in the m2m framework in `v4l2_m2m_next_buf`
> so I
> suppose you mean something else when you say that there is no lock to
> protect the source buffer?
> 
> You might not know all reasons but for this commit description you
> should at least know one reason. Please highlight a case how this can
> happen, so that you can justify the change.
> 
> > 
> > Signed-off-by: Yunfei Dong <yunfei.dong@mediatek.com>
> > ---
> > .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 30 +++++++++++++---
> > ---
> > 1 file changed, 21 insertions(+), 9 deletions(-)
> > 
> > diff --git
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > index 8aa379872ddc..3dba3549000a 100644
> > ---
> > a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > +++
> > b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_sta
> > teless.c
> > @@ -321,6 +321,7 @@ static void mtk_vdec_worker(struct work_struct
> > *work)
> > 		container_of(work, struct mtk_vcodec_dec_ctx,
> > decode_work);
> > 	struct mtk_vcodec_dec_dev *dev = ctx->dev;
> > 	struct vb2_v4l2_buffer *vb2_v4l2_src = ctx->last_vb2_v4l2_src;
> > +	struct vb2_v4l2_buffer *vb2_v4l2_dst;
> > 	struct vb2_buffer *vb2_src;
> > 	struct mtk_vcodec_mem *bs_src;
> > 	struct mtk_video_dec_buf *dec_buf_src;
> > @@ -329,7 +330,7 @@ static void mtk_vdec_worker(struct work_struct
> > *work)
> > 	bool res_chg = false;
> > 	int ret;
> > 
> > -	vb2_v4l2_src = vb2_v4l2_src ? vb2_v4l2_src :
> > v4l2_m2m_next_src_buf(ctx->m2m_ctx);
> > +	vb2_v4l2_src = vb2_v4l2_src ? vb2_v4l2_src :
> > v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> > 	if (!vb2_v4l2_src) {
> > 		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
> > 		mtk_v4l2_vdec_dbg(1, ctx, "[%d] no available source
> > buffer", ctx->id);
> > @@ -381,17 +382,28 @@ static void mtk_vdec_worker(struct
> > work_struct *work)
> > 	    ctx->current_codec == V4L2_PIX_FMT_VP8_FRAME) {
> > 		if (src_buf_req)
> > 			v4l2_ctrl_request_complete(src_buf_req, &ctx-
> > >ctrl_hdl);
> > -		v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx-
> > >m2m_ctx, state);
> > -	} else {
> > -		if (ret != -EAGAIN) {
> > -			v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
> > -			ctx->last_vb2_v4l2_src = NULL;
> > -		} else {
> > -			ctx->last_vb2_v4l2_src = vb2_v4l2_src;
> > -		}
> > +		vb2_v4l2_dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
> > +		v4l2_m2m_buf_done(vb2_v4l2_dst, state);
> > +		v4l2_m2m_buf_done(vb2_v4l2_src, state);
> 
> This is another case where you just remove again completely what you
> have added in the previous patch.
> 
> > 
> > 		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
> > +		return;
> > 	}
> > +
> > +	/* If each codec return -EAGAIN to decode again, need to backup
> > current source
> > +	 * buffer, then the driver will get this buffer next time.
> 
> I would reword this like:
> 
> 	/* Store the current source buffer for the next attempt to
> decode,
>     * if this decode returned -EAGAIN */
> 
> > +	 *
> > +	 * If each codec decode error, must to set buffer done with
> > error status for
> > +	 * this buffer have been removed from ready list.
> > +	 */
> > +	ctx->last_vb2_v4l2_src = (ret != -EAGAIN) ? NULL :
> > vb2_v4l2_src;
> 
> Okay and here you add the same thing again as in the previous patch
> but
> differently, this collection of commits feels more and more to me
> like a
> work in progress. Please make sure in the future that each commit
> does
> one job and does it completely.
> It is not only confussing but also makes it hard to read the changes
> as
> the bigger picture is missing in these tiny commits.
> 
> Please try to combine the patches where possible.
> 
Path 5/7 is used to store the source buffer.
path 6/7 is used to handle decoder again when decoder error.

I will check whether it's possible to combine patch 5 and 6 together.

Best Regards,
Yunfei Dong
> Regards,
> Sebastian Fricke
> 
> > +	if (ret && ret != -EAGAIN) {
> > +		if (src_buf_req)
> > +			v4l2_ctrl_request_complete(src_buf_req, &ctx-
> > >ctrl_hdl);
> > +		v4l2_m2m_buf_done(vb2_v4l2_src, state);
> > +	}
> > +
> > +	v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
> > }
> > 
> > static void vb2ops_vdec_stateless_buf_queue(struct vb2_buffer *vb)
> > -- 
> > 2.46.0
> > 
> >
diff mbox series

Patch

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
index 8aa379872ddc..3dba3549000a 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
@@ -321,6 +321,7 @@  static void mtk_vdec_worker(struct work_struct *work)
 		container_of(work, struct mtk_vcodec_dec_ctx, decode_work);
 	struct mtk_vcodec_dec_dev *dev = ctx->dev;
 	struct vb2_v4l2_buffer *vb2_v4l2_src = ctx->last_vb2_v4l2_src;
+	struct vb2_v4l2_buffer *vb2_v4l2_dst;
 	struct vb2_buffer *vb2_src;
 	struct mtk_vcodec_mem *bs_src;
 	struct mtk_video_dec_buf *dec_buf_src;
@@ -329,7 +330,7 @@  static void mtk_vdec_worker(struct work_struct *work)
 	bool res_chg = false;
 	int ret;
 
-	vb2_v4l2_src = vb2_v4l2_src ? vb2_v4l2_src : v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	vb2_v4l2_src = vb2_v4l2_src ? vb2_v4l2_src : v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
 	if (!vb2_v4l2_src) {
 		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
 		mtk_v4l2_vdec_dbg(1, ctx, "[%d] no available source buffer", ctx->id);
@@ -381,17 +382,28 @@  static void mtk_vdec_worker(struct work_struct *work)
 	    ctx->current_codec == V4L2_PIX_FMT_VP8_FRAME) {
 		if (src_buf_req)
 			v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl);
-		v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx, state);
-	} else {
-		if (ret != -EAGAIN) {
-			v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-			ctx->last_vb2_v4l2_src = NULL;
-		} else {
-			ctx->last_vb2_v4l2_src = vb2_v4l2_src;
-		}
+		vb2_v4l2_dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+		v4l2_m2m_buf_done(vb2_v4l2_dst, state);
+		v4l2_m2m_buf_done(vb2_v4l2_src, state);
 
 		v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+		return;
 	}
+
+	/* If each codec return -EAGAIN to decode again, need to backup current source
+	 * buffer, then the driver will get this buffer next time.
+	 *
+	 * If each codec decode error, must to set buffer done with error status for
+	 * this buffer have been removed from ready list.
+	 */
+	ctx->last_vb2_v4l2_src = (ret != -EAGAIN) ? NULL : vb2_v4l2_src;
+	if (ret && ret != -EAGAIN) {
+		if (src_buf_req)
+			v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl);
+		v4l2_m2m_buf_done(vb2_v4l2_src, state);
+	}
+
+	v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
 }
 
 static void vb2ops_vdec_stateless_buf_queue(struct vb2_buffer *vb)