[PATCH 1/2] [RFC] media: rcar-vin: send a V4L2 event to vdev if no frame captured after a timeout

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Data flow from an upstream subdevice can stop permanently due to:
 - CSI2 transmission errors
 - silent failure of the source subdevice
 - disconnection of the source subdevice
In those cases userspace waits for new buffers for an infinitely long time.
In order to address this issue, use a timer to monitor, that rvin_irq() is
capturing at least one frame within a IRQ_TIMEOUT_MS period. Otherwise send
a new private v4l2 event to userspace. This event is exported to userspace
via a new uapi header.

Signed-off-by: Michael Rodin <mrodin@xxxxxxxxxxxxxx>
---
 drivers/media/platform/rcar-vin/rcar-dma.c  | 21 +++++++++++++++++++++
 drivers/media/platform/rcar-vin/rcar-v4l2.c |  1 +
 drivers/media/platform/rcar-vin/rcar-vin.h  |  6 ++++++
 include/uapi/linux/rcar-vin.h               | 10 ++++++++++
 4 files changed, 38 insertions(+)
 create mode 100644 include/uapi/linux/rcar-vin.h

diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index 1a30cd0..bf8d733 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -937,6 +937,20 @@ static void rvin_capture_stop(struct rvin_dev *vin)
 #define RVIN_TIMEOUT_MS 100
 #define RVIN_RETRIES 10
 
+static const struct v4l2_event rvin_irq_timeout = {
+	.type = V4L2_EVENT_RCAR_VIN_IRQ_TIMEOUT,
+};
+
+static void rvin_irq_timer_function(struct timer_list *timer)
+{
+	struct rvin_dev *vin = container_of(timer, struct rvin_dev,
+					    irq_timer);
+
+	vin_err(vin, "%s: frame completion timeout after %i ms!\n",
+		__func__, IRQ_TIMEOUT_MS);
+	v4l2_event_queue(&vin->vdev, &rvin_irq_timeout);
+}
+
 static irqreturn_t rvin_irq(int irq, void *data)
 {
 	struct rvin_dev *vin = data;
@@ -1008,6 +1022,8 @@ static irqreturn_t rvin_irq(int irq, void *data)
 		vin_dbg(vin, "Dropping frame %u\n", vin->sequence);
 	}
 
+	mod_timer(&vin->irq_timer, jiffies + msecs_to_jiffies(IRQ_TIMEOUT_MS));
+
 	vin->sequence++;
 
 	/* Prepare for next frame */
@@ -1252,6 +1268,8 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count)
 	if (ret)
 		dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch,
 				  vin->scratch_phys);
+	else
+		mod_timer(&vin->irq_timer, jiffies + msecs_to_jiffies(IRQ_TIMEOUT_MS));
 
 	return ret;
 }
@@ -1305,6 +1323,8 @@ static void rvin_stop_streaming(struct vb2_queue *vq)
 	/* Free scratch buffer. */
 	dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch,
 			  vin->scratch_phys);
+
+	del_timer_sync(&vin->irq_timer);
 }
 
 static const struct vb2_ops rvin_qops = {
@@ -1370,6 +1390,7 @@ int rvin_dma_register(struct rvin_dev *vin, int irq)
 		goto error;
 	}
 
+	timer_setup(&vin->irq_timer, rvin_irq_timer_function, 0);
 	return 0;
 error:
 	rvin_dma_unregister(vin);
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index f421e25..c644134 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -581,6 +581,7 @@ static int rvin_subscribe_event(struct v4l2_fh *fh,
 {
 	switch (sub->type) {
 	case V4L2_EVENT_SOURCE_CHANGE:
+	case V4L2_EVENT_RCAR_VIN_IRQ_TIMEOUT:
 		return v4l2_event_subscribe(fh, sub, 4, NULL);
 	}
 	return v4l2_ctrl_subscribe_event(fh, sub);
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h
index c19d077..7408f67 100644
--- a/drivers/media/platform/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/rcar-vin/rcar-vin.h
@@ -14,12 +14,14 @@
 #define __RCAR_VIN__
 
 #include <linux/kref.h>
+#include <linux/rcar-vin.h>
 
 #include <media/v4l2-async.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-device.h>
 #include <media/videobuf2-v4l2.h>
+#include <media/v4l2-event.h>
 
 /* Number of HW buffers */
 #define HW_BUFFER_NUM 3
@@ -30,6 +32,8 @@
 /* Max number on VIN instances that can be in a system */
 #define RCAR_VIN_NUM 8
 
+#define IRQ_TIMEOUT_MS 1000
+
 struct rvin_group;
 
 enum model_id {
@@ -196,6 +200,7 @@ struct rvin_info {
  * @compose:		active composing
  * @src_rect:		active size of the video source
  * @std:		active video standard of the video source
+ * @irq_timer:		monitors regular capturing of frames in rvin_irq()
  *
  * @alpha:		Alpha component to fill in for supported pixel formats
  */
@@ -240,6 +245,7 @@ struct rvin_dev {
 	struct v4l2_rect src_rect;
 	v4l2_std_id std;
 
+	struct timer_list irq_timer;
 	unsigned int alpha;
 };
 
diff --git a/include/uapi/linux/rcar-vin.h b/include/uapi/linux/rcar-vin.h
new file mode 100644
index 00000000..4eb7f5e
--- /dev/null
+++ b/include/uapi/linux/rcar-vin.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef RCAR_VIN_USER_H
+#define RCAR_VIN_USER_H
+
+/* class for events sent by the rcar-vin driver */
+#define V4L2_EVENT_RCAR_VIN_CLASS	V4L2_EVENT_PRIVATE_START
+#define V4L2_EVENT_RCAR_VIN_IRQ_TIMEOUT	(V4L2_EVENT_RCAR_VIN_CLASS | 0x1)
+
+#endif /* RCAR_VIN_USER_H */
-- 
2.7.4




[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux