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

[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
...@@ -1056,6 +1056,23 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, ...@@ -1056,6 +1056,23 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
return ret; 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 * isp_pipeline_resume - Resume streaming on a pipeline
* @pipe: ISP pipeline * @pipe: ISP pipeline
......
...@@ -236,6 +236,7 @@ int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait, ...@@ -236,6 +236,7 @@ int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
enum isp_pipeline_stream_state state); enum isp_pipeline_stream_state state);
void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe);
void omap3isp_configure_bridge(struct isp_device *isp, void omap3isp_configure_bridge(struct isp_device *isp,
enum ccdc_input_entity input, enum ccdc_input_entity input,
const struct isp_parallel_platform_data *pdata, const struct isp_parallel_platform_data *pdata,
......
...@@ -411,6 +411,15 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf) ...@@ -411,6 +411,15 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
struct isp_video *video = vfh->video; struct isp_video *video = vfh->video;
unsigned long addr; 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); addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
if (IS_ERR_VALUE(addr)) if (IS_ERR_VALUE(addr))
return -EIO; return -EIO;
...@@ -447,6 +456,12 @@ static void isp_video_buffer_queue(struct isp_video_buffer *buf) ...@@ -447,6 +456,12 @@ static void isp_video_buffer_queue(struct isp_video_buffer *buf)
unsigned int empty; unsigned int empty;
unsigned int start; unsigned int start;
if (unlikely(video->error)) {
buf->state = ISP_BUF_STATE_ERROR;
wake_up(&buf->wait);
return;
}
empty = list_empty(&video->dmaqueue); empty = list_empty(&video->dmaqueue);
list_add_tail(&buffer->buffer.irqlist, &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) ...@@ -568,6 +583,36 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
return to_isp_buffer(buf); 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 * omap3isp_video_resume - Perform resume operation on the buffers
* @video: ISP video object * @video: ISP video object
...@@ -1105,6 +1150,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) ...@@ -1105,6 +1150,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
omap3isp_video_queue_streamoff(&vfh->queue); omap3isp_video_queue_streamoff(&vfh->queue);
video->queue = NULL; video->queue = NULL;
video->streaming = 0; video->streaming = 0;
video->error = false;
if (video->isp->pdata->set_constraints) if (video->isp->pdata->set_constraints)
video->isp->pdata->set_constraints(video->isp, false); video->isp->pdata->set_constraints(video->isp, false);
......
...@@ -178,6 +178,7 @@ struct isp_video { ...@@ -178,6 +178,7 @@ struct isp_video {
/* Pipeline state */ /* Pipeline state */
struct isp_pipeline pipe; struct isp_pipeline pipe;
struct mutex stream_lock; /* pipeline and stream states */ struct mutex stream_lock; /* pipeline and stream states */
bool error;
/* Video buffers queue */ /* Video buffers queue */
struct isp_video_queue *queue; struct isp_video_queue *queue;
...@@ -207,6 +208,7 @@ int omap3isp_video_register(struct isp_video *video, ...@@ -207,6 +208,7 @@ int omap3isp_video_register(struct isp_video *video,
struct v4l2_device *vdev); struct v4l2_device *vdev);
void omap3isp_video_unregister(struct isp_video *video); void omap3isp_video_unregister(struct isp_video *video);
struct isp_buffer *omap3isp_video_buffer_next(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); void omap3isp_video_resume(struct isp_video *video, int continuous);
struct media_pad *omap3isp_video_remote_pad(struct isp_video *video); struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment