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

From: Niklas Söderlund
Date: Thu Jul 02 2020 - 17:42:13 EST


Hi Michael,

On 2020-07-02 14:33:41 +0200, Michael Rodin wrote:
> Hi Niklas,
>
> On Wed, Jul 01, 2020 at 12:17:10AM +0200, Niklas Söderlund wrote:
> > Hi Michael,
> >
> > Thanks for your RFC.
>
> Thanks your your feedback!
>
> > On 2020-06-19 19:46:10 +0200, Michael Rodin wrote:
> > > 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.
> >
> > I think there is value for user-space to detecting the error cases
> > above. But I think the problem could be addressed at a different lever.
> > Defining a VIN specific events and controls for something that applies
> > any video device might not be the neatest solution.
> >
> > Another thing hits me when reading this series, could this not be done
> > in user-space? In 2/2 you add a control which sets the timeout based on
> > the framerate, so user-space must know about that to be able to set the
> > control. User-space also knows when it receives/dequeus a buffer from
> > the video device so the timeout logic could be implemented in the
> > application. Given that the application anyhow needs special care to
> > handle the VIN specific event and control I wonder if it's not neater to
> > make it handle all of it. Do you see any specific benefit of having
> > parts of it in the driver?
>
> Originally I have started this patch series to implement a replacement for
> the CSI-2 error handling you have added in
> commit 4ab44ff ("media: rcar-csi2: restart CSI-2 link if error is detected"),
> which is not correct for multiple reasons:
> 1. The commit message states that the user is informed that something is
> not right. But you have just added new messages which only appear in
> dmesg. This might be sufficient for a desktop PC but not for an embedded
> system, where the user normally can not see dmesg log. So I think that
> V4L2 events are the correct solution for this kind of notification,
> because they are passed directly to the application and the developer
> can implement handling for this issue or display an error in the
> custom human-machine interface.
> 2. It is not correct to restart the CSI-2 link if you don't restart VIN
> module as well. Renesas HW manual R19UH0105EJ0200 Rev.2.00
> (Jul 31, 2019) requires a reset or stop of capture in the VIN module
> before a reset of CSI-2 module (chapter 25.3.13 "Software Reset"). This
> also applies to CSI-2 error handling.
> 3. The CSI-2 driver restarts CSI-2 module for any CSI-2 error. However not
> all CSI2 errors are critical. In some setups they are really harmless so
> streaming can continue without any unnecessary restart. In some setups
> they _always_ occur at each start of streaming and are harmless as
> well, so automatic restart in CSI-2 module ends in an endless restart
> loop, which never comes to an end and breaks streaming instead of any
> help. It is better to leave such errors unhandled and therefore it is
> important to detect whether DMA transfers really stop in rvin_irq().
> 4. Video streaming applications in the automotive/embedded industry often
> want to control when the video streaming pipeline is stopped or started
> to be able to do some tasks in between, so an automatic restart of the
> pipeline is not acceptable for them. It should be at least optional and
> we should do this in rcar-dma.c, e.g. in the proposed irq timeout
> function. However I am not sure yet how to implement a restart of
> streaming inside of the rcar-vin driver correctly.
>
> I think, my patch series provides technically a good solution for the
> described issues. Also it is generic enough to allow also handling of
> failures in upstream subdevices connected to an R-Car3 CSI2 receiver or
> even parallel video input devices in cases when such failures can not be
> fixed or detected in the subdevice drivers and result in a stop of data
> flow on the chip level.
>
> Theoretically, applications also could use timeout parameter of the poll()
> syscall to implement the timeout (which can be e.g. a multiple of the frame
> interval), but the problem is that userspace does not know whether the
> timeout happened because there are no DMA transfers in the driver (i.e. one
> of the upstream subdevices or VIN failed) or because the driver is just
> using the "scratch buffer". The event which I have introduced explicitly
> monitors whether rcar-vin regularly receives new frames from upstream
> and allows applications to try a recovery (I have now renamed the event to
> "FRAME_TIMEOUT" to be more precise about its purpose).
>
> Another reason, why I think that the new v4l2 event is the right solution,
> are proprietary applications, where it is not possible to change the code
> to add any additional handling of driver failures but it is possible to
> start/stop streaming via inter process communication. Since V4L2 events can
> be subscribed and received by a separate process, it is possible to
> implement a middleware in user space, which monitors V4L2 events. Typically
> this middleware could also take over all of the complicated media-ctl
> configuration and monitoring of source changes and other events from
> subdevices, but this is a bit off-topic. I think that (private) V4L2 events
> are really useful in embedded systems where applications/middlewares are
> aware of the underlying hardware and want to be better informed about
> hardware related events than desktop applications.
>
> So if my arguments sound reasonable and you don't reject the overall
> concept of the series, I would send an improved version, where I have fixed
> some details of the timer implementation. I have also a patch for rcar-csi2
> driver with a private CSI-2 error event, which is useful to let the
> application know that the reason for the frame timeout event might be a
> CSI-2 error and not e.g. paused playback.

I'm not arguing that something is needed for user-space to detect these
situations. I'm arguing that adding these events directly into rcar-vin
and/or rcar-csi2 is the wrong level. In my view either support should be
added in the V4L2 subsystem core or in the user-space applications.
Adding custom events and logic to a single driver does not create
reusable and generic solution which can be used by many.

If you wish to work the problem in the kernel I think you should do so
on a V4L2 level and not in the individual driver. As the needs you
describe above could be useful for others users.

>
> > >
> > > 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
> > >
> >
> > --
> > Regards,
> > Niklas Söderlund
>
> --
> Best Regards,
> Michael

--
Regards,
Niklas Söderlund