Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 112da085 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

[media] v4l: omap4iss: Cancel streaming when a fatal error occurs



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: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 216814fb
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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,
+46 −1
Original line number Diff line number Diff line
@@ -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);
+3 −1
Original line number Diff line number Diff line
@@ -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 *