media: imx: csi: Stop upstream before disabling IDMA channel
authorSteve Longerbeam <slongerbeam@gmail.com>
Mon, 21 Jan 2019 23:35:51 +0000 (21:35 -0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 Mar 2019 13:35:31 +0000 (14:35 +0100)
commit 4bc1ab41eee9d02ad2483bf8f51a7b72e3504eba upstream.

Move upstream stream off to just after receiving the last EOF completion
and disabling the CSI (and thus before disabling the IDMA channel) in
csi_stop(). For symmetry also move upstream stream on to beginning of
csi_start().

Doing this makes csi_s_stream() more symmetric with prp_s_stream() which
will require the same change to fix a hard lockup.

Signed-off-by: Steve Longerbeam <slongerbeam@gmail.com>
Cc: stable@vger.kernel.org # for 4.13 and up
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/media/imx/imx-media-csi.c

index 5bc8f84d09a20d59af264b3bde2a53330f8dfe63..69df8b23227aa79b2e8c350e06ef62b23d961d19 100644 (file)
@@ -648,10 +648,16 @@ static int csi_start(struct csi_priv *priv)
                usleep_range(delay_usec, delay_usec + 1000);
        }
 
+       /* start upstream */
+       ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 1);
+       ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
+       if (ret)
+               return ret;
+
        if (priv->dest == IPU_CSI_DEST_IDMAC) {
                ret = csi_idmac_start(priv);
                if (ret)
-                       return ret;
+                       goto stop_upstream;
        }
 
        ret = csi_setup(priv);
@@ -679,6 +685,8 @@ fim_off:
 idmac_stop:
        if (priv->dest == IPU_CSI_DEST_IDMAC)
                csi_idmac_stop(priv);
+stop_upstream:
+       v4l2_subdev_call(priv->src_sd, video, s_stream, 0);
        return ret;
 }
 
@@ -694,6 +702,9 @@ static void csi_stop(struct csi_priv *priv)
         */
        ipu_csi_disable(priv->csi);
 
+       /* stop upstream */
+       v4l2_subdev_call(priv->src_sd, video, s_stream, 0);
+
        if (priv->dest == IPU_CSI_DEST_IDMAC) {
                csi_idmac_stop(priv);
 
@@ -861,23 +872,13 @@ static int csi_s_stream(struct v4l2_subdev *sd, int enable)
                goto update_count;
 
        if (enable) {
-               /* upstream must be started first, before starting CSI */
-               ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 1);
-               ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
-               if (ret)
-                       goto out;
-
                dev_dbg(priv->dev, "stream ON\n");
                ret = csi_start(priv);
-               if (ret) {
-                       v4l2_subdev_call(priv->src_sd, video, s_stream, 0);
+               if (ret)
                        goto out;
-               }
        } else {
                dev_dbg(priv->dev, "stream OFF\n");
-               /* CSI must be stopped first, then stop upstream */
                csi_stop(priv);
-               v4l2_subdev_call(priv->src_sd, video, s_stream, 0);
        }
 
 update_count: