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

Commit 661112cb authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

[media] omap3isp: 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
omap3isp_pipeline_cancel_stream() function that can be used by
submodules to cancel streaming.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: default avatarSakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 951ed98e
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -1056,6 +1056,23 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
	return ret;
}

/*
 * omap3isp_pipeline_cancel_stream - Cancel stream on a pipeline
 * @pipe: ISP 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 omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe)
{
	if (pipe->input)
		omap3isp_video_cancel_stream(pipe->input);
	if (pipe->output)
		omap3isp_video_cancel_stream(pipe->output);
}

/*
 * isp_pipeline_resume - Resume streaming on a pipeline
 * @pipe: ISP pipeline
+1 −0
Original line number Diff line number Diff line
@@ -236,6 +236,7 @@ int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,

int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
				 enum isp_pipeline_stream_state state);
void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe);
void omap3isp_configure_bridge(struct isp_device *isp,
			       enum ccdc_input_entity input,
			       const struct isp_parallel_platform_data *pdata,
+46 −0
Original line number Diff line number Diff line
@@ -411,6 +411,15 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
	struct isp_video *video = vfh->video;
	unsigned long addr;

	/* 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 = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
	if (IS_ERR_VALUE(addr))
		return -EIO;
@@ -447,6 +456,12 @@ static void isp_video_buffer_queue(struct isp_video_buffer *buf)
	unsigned int empty;
	unsigned int start;

	if (unlikely(video->error)) {
		buf->state = ISP_BUF_STATE_ERROR;
		wake_up(&buf->wait);
		return;
	}

	empty = list_empty(&video->dmaqueue);
	list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue);

@@ -568,6 +583,36 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
	return to_isp_buffer(buf);
}

/*
 * omap3isp_video_cancel_stream - Cancel stream on a video node
 * @video: ISP video object
 *
 * Cancelling a stream mark all buffers on the video node as erroneous and makes
 * sure no new buffer can be queued.
 */
void omap3isp_video_cancel_stream(struct isp_video *video)
{
	struct isp_video_queue *queue = video->queue;
	unsigned long flags;

	spin_lock_irqsave(&queue->irqlock, flags);

	while (!list_empty(&video->dmaqueue)) {
		struct isp_video_buffer *buf;

		buf = list_first_entry(&video->dmaqueue,
				       struct isp_video_buffer, irqlist);
		list_del(&buf->irqlist);

		buf->state = ISP_BUF_STATE_ERROR;
		wake_up(&buf->wait);
	}

	video->error = true;

	spin_unlock_irqrestore(&queue->irqlock, flags);
}

/*
 * omap3isp_video_resume - Perform resume operation on the buffers
 * @video: ISP video object
@@ -1105,6 +1150,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
	omap3isp_video_queue_streamoff(&vfh->queue);
	video->queue = NULL;
	video->streaming = 0;
	video->error = false;

	if (video->isp->pdata->set_constraints)
		video->isp->pdata->set_constraints(video->isp, false);
+2 −0
Original line number Diff line number Diff line
@@ -178,6 +178,7 @@ struct isp_video {
	/* Pipeline state */
	struct isp_pipeline pipe;
	struct mutex stream_lock;	/* pipeline and stream states */
	bool error;

	/* Video buffers queue */
	struct isp_video_queue *queue;
@@ -207,6 +208,7 @@ int omap3isp_video_register(struct isp_video *video,
			    struct v4l2_device *vdev);
void omap3isp_video_unregister(struct isp_video *video);
struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video);
void omap3isp_video_cancel_stream(struct isp_video *video);
void omap3isp_video_resume(struct isp_video *video, int continuous);
struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);