media: imx-jpeg: Lock on ioctl encoder/decoder stop cmd
authorMing Qian <ming.qian@nxp.com>
Fri, 12 Aug 2022 07:22:09 +0000 (15:22 +0800)
committerHans Verkuil <hverkuil-cisco@xs4all.nl>
Fri, 30 Sep 2022 14:43:53 +0000 (16:43 +0200)
the ioctl encoder/decoder cmd is under queue lock,
and buf_done is in the irq, it can't be locked with the mutex,
they are not synchronized.
when v4l2_update_last_buf_state is called to
handle the encoder/decoder stop cmd,
the last src buffer may be done at the same time.

so it's possible that last_src_buf is set,
but the output rdy_queue is empty,
then driver won't mark it stopped,
as v4l2_m2m_is_last_draining_src_buf() will always return false and
v4l2_m2m_dst_buf_is_last() return false too.

In this case, the drain will be blocked.

add the hw lock around the ioctl encoder/decoder cmd,
to synchronize with the buf_done.

Fixes: 4911c5acf935 ("media: imx-jpeg: Implement drain using v4l2-mem2mem helpers")
Signed-off-by: Ming Qian <ming.qian@nxp.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c

index d262a563844f50b71980747a0f83bd73655ca440..bb2bc28b55edf866c5f8400c46aa65a711b0aab5 100644 (file)
@@ -1224,6 +1224,7 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
 {
        struct v4l2_fh *fh = file->private_data;
        struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+       unsigned long flags;
        int ret;
 
        ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd);
@@ -1233,7 +1234,9 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
        if (!vb2_is_streaming(v4l2_m2m_get_src_vq(fh->m2m_ctx)))
                return 0;
 
+       spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags);
        ret = v4l2_m2m_ioctl_decoder_cmd(file, priv, cmd);
+       spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
        if (ret < 0)
                return ret;
 
@@ -1254,6 +1257,7 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv,
 {
        struct v4l2_fh *fh = file->private_data;
        struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
+       unsigned long flags;
        int ret;
 
        ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd);
@@ -1264,7 +1268,9 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv,
            !vb2_is_streaming(v4l2_m2m_get_dst_vq(fh->m2m_ctx)))
                return 0;
 
+       spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags);
        ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, cmd);
+       spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
        if (ret < 0)
                return 0;