]>
Commit | Line | Data |
---|---|---|
7ffa1129 GKH |
1 | From a19c22677377b87e4354f7306f46ad99bc982a9f Mon Sep 17 00:00:00 2001 |
2 | From: Steve Longerbeam <slongerbeam@gmail.com> | |
3 | Date: Mon, 21 Jan 2019 21:35:52 -0200 | |
4 | Subject: media: imx: prpencvf: Stop upstream before disabling IDMA channel | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | From: Steve Longerbeam <slongerbeam@gmail.com> | |
10 | ||
11 | commit a19c22677377b87e4354f7306f46ad99bc982a9f upstream. | |
12 | ||
13 | Upstream must be stopped immediately after receiving the last EOF and | |
14 | before disabling the IDMA channel. This can be accomplished by moving | |
15 | upstream stream off to just after receiving the last EOF completion in | |
16 | prp_stop(). For symmetry also move upstream stream on to end of | |
17 | prp_start(). | |
18 | ||
19 | This fixes a complete system hard lockup on the SabreAuto when streaming | |
20 | from the ADV7180, by repeatedly sending a stream off immediately followed | |
21 | by stream on: | |
22 | ||
23 | while true; do v4l2-ctl -d1 --stream-mmap --stream-count=3; done | |
24 | ||
25 | Eventually this either causes the system lockup or EOF timeouts at all | |
26 | subsequent stream on, until a system reset. | |
27 | ||
28 | The lockup occurs when disabling the IDMA channel at stream off. Stopping | |
29 | the video data stream entering the IDMA channel before disabling the | |
30 | channel itself appears to be a reliable fix for the hard lockup. | |
31 | ||
32 | Fixes: f0d9c8924e2c3 ("[media] media: imx: Add IC subdev drivers") | |
33 | ||
34 | Reported-by: Gaël PORTAY <gael.portay@collabora.com> | |
35 | Tested-by: Gaël PORTAY <gael.portay@collabora.com> | |
36 | Signed-off-by: Steve Longerbeam <slongerbeam@gmail.com> | |
37 | Cc: stable@vger.kernel.org # for 4.13 and up | |
38 | Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> | |
39 | Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | |
40 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
41 | ||
42 | --- | |
43 | drivers/staging/media/imx/imx-ic-prpencvf.c | 26 +++++++++++++++++--------- | |
44 | 1 file changed, 17 insertions(+), 9 deletions(-) | |
45 | ||
46 | --- a/drivers/staging/media/imx/imx-ic-prpencvf.c | |
47 | +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c | |
48 | @@ -680,12 +680,23 @@ static int prp_start(struct prp_priv *pr | |
49 | goto out_free_nfb4eof_irq; | |
50 | } | |
51 | ||
52 | + /* start upstream */ | |
53 | + ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 1); | |
54 | + ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0; | |
55 | + if (ret) { | |
56 | + v4l2_err(&ic_priv->sd, | |
57 | + "upstream stream on failed: %d\n", ret); | |
58 | + goto out_free_eof_irq; | |
59 | + } | |
60 | + | |
61 | /* start the EOF timeout timer */ | |
62 | mod_timer(&priv->eof_timeout_timer, | |
63 | jiffies + msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT)); | |
64 | ||
65 | return 0; | |
66 | ||
67 | +out_free_eof_irq: | |
68 | + devm_free_irq(ic_priv->dev, priv->eof_irq, priv); | |
69 | out_free_nfb4eof_irq: | |
70 | devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv); | |
71 | out_unsetup: | |
72 | @@ -717,6 +728,12 @@ static void prp_stop(struct prp_priv *pr | |
73 | if (ret == 0) | |
74 | v4l2_warn(&ic_priv->sd, "wait last EOF timeout\n"); | |
75 | ||
76 | + /* stop upstream */ | |
77 | + ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 0); | |
78 | + if (ret && ret != -ENOIOCTLCMD) | |
79 | + v4l2_warn(&ic_priv->sd, | |
80 | + "upstream stream off failed: %d\n", ret); | |
81 | + | |
82 | devm_free_irq(ic_priv->dev, priv->eof_irq, priv); | |
83 | devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv); | |
84 | ||
85 | @@ -1148,15 +1165,6 @@ static int prp_s_stream(struct v4l2_subd | |
86 | if (ret) | |
87 | goto out; | |
88 | ||
89 | - /* start/stop upstream */ | |
90 | - ret = v4l2_subdev_call(priv->src_sd, video, s_stream, enable); | |
91 | - ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0; | |
92 | - if (ret) { | |
93 | - if (enable) | |
94 | - prp_stop(priv); | |
95 | - goto out; | |
96 | - } | |
97 | - | |
98 | update_count: | |
99 | priv->stream_count += enable ? 1 : -1; | |
100 | if (priv->stream_count < 0) |