On i.MX6, the nearest upstream entity to the CSI can only be the
CSI video muxes or the Synopsys DW MIPI CSI-2 receiver.
However the i.MX53 has no CSI video muxes or a MIPI CSI-2 receiver.
So allow for the nearest upstream entity to the CSI to be something
other than those.
Fixes: bf3cfaa712e5c ("media: staging/imx: get CSI bus type from nearest
upstream entity")
Signed-off-by: Steve Longerbeam <slongerbeam(a)gmail.com>
Cc: stable(a)vger.kernel.org
---
drivers/staging/media/imx/imx-media-csi.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index 555aa45e02e3..b9af7d3d4974 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -154,9 +154,10 @@ static inline bool requires_passthrough(struct v4l2_fwnode_endpoint *ep,
/*
* Parses the fwnode endpoint from the source pad of the entity
* connected to this CSI. This will either be the entity directly
- * upstream from the CSI-2 receiver, or directly upstream from the
- * video mux. The endpoint is needed to determine the bus type and
- * bus config coming into the CSI.
+ * upstream from the CSI-2 receiver, directly upstream from the
+ * video mux, or directly upstream from the CSI itself. The endpoint
+ * is needed to determine the bus type and bus config coming into
+ * the CSI.
*/
static int csi_get_upstream_endpoint(struct csi_priv *priv,
struct v4l2_fwnode_endpoint *ep)
@@ -172,7 +173,8 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv,
if (!priv->src_sd)
return -EPIPE;
- src = &priv->src_sd->entity;
+ sd = priv->src_sd;
+ src = &sd->entity;
if (src->function == MEDIA_ENT_F_VID_MUX) {
/*
@@ -186,6 +188,14 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv,
src = &sd->entity;
}
+ /*
+ * If the source is neither the video mux nor the CSI-2 receiver,
+ * get the source pad directly upstream from CSI itself.
+ */
+ if (src->function != MEDIA_ENT_F_VID_MUX &&
+ sd->grp_id != IMX_MEDIA_GRP_ID_CSI2)
+ src = &priv->sd.entity;
+
/* get source pad of entity directly upstream from src */
pad = imx_media_find_upstream_pad(priv->md, src, 0);
if (IS_ERR(pad))
--
2.17.1
Upstream must be stopped immediately after receiving the last EOF and
before disabling the IDMA channel. This can be accomplished by moving
upstream stream off to just after receiving the last EOF completion in
prp_stop(). For symmetry also move upstream stream on to end of
prp_start().
This fixes a complete system hard lockup on the SabreAuto when streaming
from the ADV7180, by repeatedly sending a stream off immediately followed
by stream on:
while true; do v4l2-ctl -d1 --stream-mmap --stream-count=3; done
Eventually this either causes the system lockup or EOF timeouts at all
subsequent stream on, until a system reset.
The lockup occurs when disabling the IDMA channel at stream off. Stopping
the video data stream entering the IDMA channel before disabling the
channel itself appears to be a reliable fix for the hard lockup.
Fixes: f0d9c8924e2c3 ("[media] media: imx: Add IC subdev drivers")
Reported-by: Gaël PORTAY <gael.portay(a)collabora.com>
Tested-by: Gaël PORTAY <gael.portay(a)collabora.com>
Signed-off-by: Steve Longerbeam <slongerbeam(a)gmail.com>
Cc: stable(a)vger.kernel.org
---
Changes in v4:
- none.
Changes in v3:
- Reword the commit subject and message. No functional changes.
Changes in v2:
- Add Fixes: and Cc: stable
---
drivers/staging/media/imx/imx-ic-prpencvf.c | 26 ++++++++++++++-------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 053a911d477a..3637693c2bc8 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -706,12 +706,23 @@ static int prp_start(struct prp_priv *priv)
goto out_free_nfb4eof_irq;
}
+ /* start upstream */
+ ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 1);
+ ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
+ if (ret) {
+ v4l2_err(&ic_priv->sd,
+ "upstream stream on failed: %d\n", ret);
+ goto out_free_eof_irq;
+ }
+
/* start the EOF timeout timer */
mod_timer(&priv->eof_timeout_timer,
jiffies + msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
return 0;
+out_free_eof_irq:
+ devm_free_irq(ic_priv->dev, priv->eof_irq, priv);
out_free_nfb4eof_irq:
devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv);
out_unsetup:
@@ -743,6 +754,12 @@ static void prp_stop(struct prp_priv *priv)
if (ret == 0)
v4l2_warn(&ic_priv->sd, "wait last EOF timeout\n");
+ /* stop upstream */
+ ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 0);
+ if (ret && ret != -ENOIOCTLCMD)
+ v4l2_warn(&ic_priv->sd,
+ "upstream stream off failed: %d\n", ret);
+
devm_free_irq(ic_priv->dev, priv->eof_irq, priv);
devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv);
@@ -1173,15 +1190,6 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable)
if (ret)
goto out;
- /* start/stop upstream */
- ret = v4l2_subdev_call(priv->src_sd, video, s_stream, enable);
- ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
- if (ret) {
- if (enable)
- prp_stop(priv);
- goto out;
- }
-
update_count:
priv->stream_count += enable ? 1 : -1;
if (priv->stream_count < 0)
--
2.17.1
Disable the CSI immediately after receiving the last EOF before stream
off (and thus before disabling the IDMA channel). Do this by moving the
wait for EOF completion into a new function csi_idmac_wait_last_eof().
This fixes a complete system hard lockup on the SabreAuto when streaming
from the ADV7180, by repeatedly sending a stream off immediately followed
by stream on:
while true; do v4l2-ctl -d4 --stream-mmap --stream-count=3; done
Eventually this either causes the system lockup or EOF timeouts at all
subsequent stream on, until a system reset.
The lockup occurs when disabling the IDMA channel at stream off. Disabling
the CSI before disabling the IDMA channel appears to be a reliable fix for
the hard lockup.
Fixes: 4a34ec8e470cb ("[media] media: imx: Add CSI subdev driver")
Reported-by: Gaël PORTAY <gael.portay(a)collabora.com>
Signed-off-by: Steve Longerbeam <slongerbeam(a)gmail.com>
Cc: stable(a)vger.kernel.org
---
Changes in v4:
- Disabling SMFC will have no effect if both CSI's are streaming. So
go back to disabling CSI before channel as in v2, but split up
csi_idmac_stop such that ipu_csi_disable can still be called within
csi_stop.
Changes in v3:
- switch from disabling the CSI before the channel to disabling the
SMFC before the channel.
Changes in v2:
- restore an empty line
- Add Fixes: and Cc: stable
---
drivers/staging/media/imx/imx-media-csi.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index 7abfe0aa1418..920e38885292 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -662,7 +662,7 @@ static int csi_idmac_start(struct csi_priv *priv)
return ret;
}
-static void csi_idmac_stop(struct csi_priv *priv)
+static void csi_idmac_wait_last_eof(struct csi_priv *priv)
{
unsigned long flags;
int ret;
@@ -679,7 +679,10 @@ static void csi_idmac_stop(struct csi_priv *priv)
&priv->last_eof_comp, msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
if (ret == 0)
v4l2_warn(&priv->sd, "wait last EOF timeout\n");
+}
+static void csi_idmac_stop(struct csi_priv *priv)
+{
devm_free_irq(priv->dev, priv->eof_irq, priv);
devm_free_irq(priv->dev, priv->nfb4eof_irq, priv);
@@ -786,6 +789,16 @@ static int csi_start(struct csi_priv *priv)
static void csi_stop(struct csi_priv *priv)
{
+ if (priv->dest == IPU_CSI_DEST_IDMAC)
+ csi_idmac_wait_last_eof(priv);
+
+ /*
+ * Disable the CSI asap, after syncing with the last EOF.
+ * Doing so after the IDMA channel is disabled has shown to
+ * create hard system-wide hangs.
+ */
+ ipu_csi_disable(priv->csi);
+
if (priv->dest == IPU_CSI_DEST_IDMAC) {
csi_idmac_stop(priv);
@@ -793,8 +806,6 @@ static void csi_stop(struct csi_priv *priv)
if (priv->fim)
imx_media_fim_set_stream(priv->fim, NULL, false);
}
-
- ipu_csi_disable(priv->csi);
}
static const struct csi_skip_desc csi_skip[12] = {
--
2.17.1
srp_queuecommand() can be called from the following contexts:
* From inside scsi_queue_rq(). This function can be called by several
kernel threads, including the SCSI error handler thread.
* From inside scsi_send_eh_cmnd(). This function is only called from the
SCSI error handler thread.
In scsi-mq mode it is not allowed to sleep inside srp_queuecommand()
since the flag BLK_MQ_F_BLOCKING has not been set. Since setting the
request queue flag BLK_MQ_F_BLOCKING would slow down the hot path, make
srp_queuecommand() skip the mutex_lock() and mutex_unlock() calls when
called from inside scsi_queue_rq() from the SCSI EH thread.
This patch avoids that the following appears in the kernel log:
BUG: sleeping function called from invalid context at kernel/locking/mutex.c:908
in_atomic(): 1, irqs_disabled(): 0, pid: 30974, name: scsi_eh_4
INFO: lockdep is turned off.
Preemption disabled at:
[<ffffffff816b1d65>] __blk_mq_delay_run_hw_queue+0x185/0x290
CPU: 3 PID: 30974 Comm: scsi_eh_4 Not tainted 4.20.0-rc6-dbg+ #6
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
Call Trace:
dump_stack+0x86/0xca
___might_sleep.cold.80+0x128/0x139
__might_sleep+0x71/0xe0
__mutex_lock+0xc8/0xbe0
mutex_lock_nested+0x1b/0x20
srp_queuecommand+0x7f2/0x19a0 [ib_srp]
scsi_dispatch_cmd+0x15d/0x510
scsi_queue_rq+0x123/0xa90
blk_mq_dispatch_rq_list+0x678/0xc20
blk_mq_sched_dispatch_requests+0x25c/0x310
__blk_mq_run_hw_queue+0xd6/0x180
__blk_mq_delay_run_hw_queue+0x262/0x290
blk_mq_run_hw_queue+0x11f/0x1b0
blk_mq_run_hw_queues+0x87/0xb0
scsi_run_queue+0x402/0x6f0
scsi_run_host_queues+0x30/0x50
scsi_error_handler+0x2d3/0xa80
kthread+0x1cf/0x1f0
ret_from_fork+0x24/0x30
Cc: Sergey Gorenko <sergeygo(a)mellanox.com>
Cc: Max Gurtovoy <maxg(a)mellanox.com>
Cc: Laurence Oberman <loberman(a)redhat.com>
Cc: <stable(a)vger.kernel.org>
Fixes: a95cadb9dafe ("IB/srp: Add periodic reconnect functionality") # v3.13
Signed-off-by: Bart Van Assche <bvanassche(a)acm.org>
---
drivers/infiniband/ulp/srp/ib_srp.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 31d91538bbf4..23e5c9afb8fb 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -2352,13 +2352,19 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
u32 tag;
u16 idx;
int len, ret;
- const bool in_scsi_eh = !in_interrupt() && current == shost->ehandler;
+ const bool in_scsi_eh = !in_interrupt() && current == shost->ehandler
+ && rcu_preempt_depth() == 0;
/*
- * The SCSI EH thread is the only context from which srp_queuecommand()
- * can get invoked for blocked devices (SDEV_BLOCK /
+ * The scsi_send_eh_cmnd() function is the only function that can call
+ * .queuecommand() for blocked devices (SDEV_BLOCK /
* SDEV_CREATED_BLOCK). Avoid racing with srp_reconnect_rport() by
- * locking the rport mutex if invoked from inside the SCSI EH.
+ * locking the rport mutex if invoked from inside that function.
+ * Recognize this context by checking whether called from the SCSI EH
+ * thread and whether no RCU read lock is held. If
+ * blk_mq_run_hw_queues() is called from the context of the SCSI EH
+ * thread then an RCU read lock is held around scsi_queue_rq() calls
+ * becase the SRP driver does not set BLK_MQ_F_BLOCKING.
*/
if (in_scsi_eh)
mutex_lock(&rport->mutex);
--
2.20.1.97.g81188d93c3-goog