[media] v4l: omap4iss: Cancel streaming when a fatal error occurs
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Tue, 5 Nov 2013 15:32:05 +0000 (12:32 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Wed, 11 Dec 2013 11:05:32 +0000 (09:05 -0200)
When a fatal error that prevents any further video streaming occurs in a
pipeline, all queued buffers must be marked as erroneous and new buffers
must be prevented from being queued. Implement this behaviour with a new
omap4iss_pipeline_cancel_stream() function that can be used by
submodules to cancel streaming.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
drivers/staging/media/omap4iss/iss.c
drivers/staging/media/omap4iss/iss.h
drivers/staging/media/omap4iss/iss_resizer.c
drivers/staging/media/omap4iss/iss_video.c
drivers/staging/media/omap4iss/iss_video.h

index 5ad604d0d16b13d49db24f12afec1485098ac8ce..61fbfcd13582b9ac79a74375f21a53c4df9a4e79 100644 (file)
@@ -692,6 +692,23 @@ int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
        return ret;
 }
 
+/*
+ * omap4iss_pipeline_cancel_stream - Cancel stream on a pipeline
+ * @pipe: ISS pipeline
+ *
+ * Cancelling a stream mark all buffers on all video nodes in the pipeline as
+ * erroneous and makes sure no new buffer can be queued. This function is called
+ * when a fatal error that prevents any further operation on the pipeline
+ * occurs.
+ */
+void omap4iss_pipeline_cancel_stream(struct iss_pipeline *pipe)
+{
+       if (pipe->input)
+               omap4iss_video_cancel_stream(pipe->input);
+       if (pipe->output)
+               omap4iss_video_cancel_stream(pipe->output);
+}
+
 /*
  * iss_pipeline_is_last - Verify if entity has an enabled link to the output
  *                       video node
index 3c1e920245139ec371e25ff89d5ed9b65edfac14..346db9233171544cad54338c4f2a5ed03587f986 100644 (file)
@@ -131,6 +131,7 @@ int omap4iss_module_sync_is_stopping(wait_queue_head_t *wait,
 
 int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
                                 enum iss_pipeline_stream_state state);
+void omap4iss_pipeline_cancel_stream(struct iss_pipeline *pipe);
 
 void omap4iss_configure_bridge(struct iss_device *iss,
                               enum ipipeif_input_entity input);
index 4673c057788666aa7615557684dd1e74b1ba20e5..c6225d805d1a2aff7e30138cd45abd9580e7788f 100644 (file)
@@ -312,7 +312,7 @@ void omap4iss_resizer_isr(struct iss_resizer_device *resizer, u32 events)
                dev_dbg(iss->dev, "RSZ Err: FIFO_IN_BLK:%d, FIFO_OVF:%d\n",
                        events & ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR ? 1 : 0,
                        events & ISP5_IRQ_RSZ_FIFO_OVF ? 1 : 0);
-               pipe->error = true;
+               omap4iss_pipeline_cancel_stream(pipe);
        }
 
        if (omap4iss_module_sync_is_stopping(&resizer->wait,
index 910648766e6c7d1840569a4697e341bbc4f40d08..482b72fb819fb373325414018d7e5d80ea590cb3 100644 (file)
@@ -328,6 +328,15 @@ static int iss_video_buf_prepare(struct vb2_buffer *vb)
        if (vb2_plane_size(vb, 0) < size)
                return -ENOBUFS;
 
+       /* Refuse to prepare the buffer is the video node has registered an
+        * error. We don't need to take any lock here as the operation is
+        * inherently racy. The authoritative check will be performed in the
+        * queue handler, which can't return an error, this check is just a best
+        * effort to notify userspace as early as possible.
+        */
+       if (unlikely(video->error))
+               return -EIO;
+
        addr = vb2_dma_contig_plane_dma_addr(vb, 0);
        if (!IS_ALIGNED(addr, 32)) {
                dev_dbg(video->iss->dev,
@@ -346,12 +355,20 @@ static void iss_video_buf_queue(struct vb2_buffer *vb)
        struct iss_video *video = vfh->video;
        struct iss_buffer *buffer = container_of(vb, struct iss_buffer, vb);
        struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity);
-       unsigned int empty;
        unsigned long flags;
+       bool empty;
 
        spin_lock_irqsave(&video->qlock, flags);
+
+       if (unlikely(video->error)) {
+               vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+               spin_unlock_irqrestore(&video->qlock, flags);
+               return;
+       }
+
        empty = list_empty(&video->dmaqueue);
        list_add_tail(&buffer->list, &video->dmaqueue);
+
        spin_unlock_irqrestore(&video->qlock, flags);
 
        if (empty) {
@@ -471,6 +488,33 @@ struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video)
        return buf;
 }
 
+/*
+ * omap4iss_video_cancel_stream - Cancel stream on a video node
+ * @video: ISS video object
+ *
+ * Cancelling a stream mark all buffers on the video node as erroneous and makes
+ * sure no new buffer can be queued.
+ */
+void omap4iss_video_cancel_stream(struct iss_video *video)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&video->qlock, flags);
+
+       while (!list_empty(&video->dmaqueue)) {
+               struct iss_buffer *buf;
+
+               buf = list_first_entry(&video->dmaqueue, struct iss_buffer,
+                                      list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+
+       video->error = true;
+
+       spin_unlock_irqrestore(&video->qlock, flags);
+}
+
 /* -----------------------------------------------------------------------------
  * V4L2 ioctls
  */
@@ -852,6 +896,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        video->queue = &vfh->queue;
        INIT_LIST_HEAD(&video->dmaqueue);
        spin_lock_init(&video->qlock);
+       video->error = false;
        atomic_set(&pipe->frame_number, -1);
 
        ret = vb2_streamon(&vfh->queue, type);
index 73e1a3419b0137e3079c68b9f20f87d2146e663a..878e4a3082e7168f59029bbbeac1a01bcc411bf2 100644 (file)
@@ -163,10 +163,11 @@ struct iss_video {
        /* Pipeline state */
        struct iss_pipeline pipe;
        struct mutex stream_lock;       /* pipeline and stream states */
+       bool error;
 
        /* Video buffers queue */
        struct vb2_queue *queue;
-       spinlock_t qlock;       /* Spinlock for dmaqueue */
+       spinlock_t qlock;               /* protects dmaqueue and error */
        struct list_head dmaqueue;
        enum iss_video_dmaqueue_flags dmaqueue_flags;
        struct vb2_alloc_ctx *alloc_ctx;
@@ -194,6 +195,7 @@ int omap4iss_video_register(struct iss_video *video,
                            struct v4l2_device *vdev);
 void omap4iss_video_unregister(struct iss_video *video);
 struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video);
+void omap4iss_video_cancel_stream(struct iss_video *video);
 struct media_pad *omap4iss_video_remote_pad(struct iss_video *video);
 
 const struct iss_format_info *