summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/media/omap4iss/iss.c24
-rw-r--r--drivers/staging/media/omap4iss/iss.h5
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c8
-rw-r--r--drivers/staging/media/omap4iss/iss_video.h2
4 files changed, 39 insertions, 0 deletions
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index dffa31e274d6..5ad604d0d16b 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -573,12 +573,22 @@ static int iss_pipeline_link_notify(struct media_link *link, u32 flags,
static int iss_pipeline_enable(struct iss_pipeline *pipe,
enum iss_pipeline_stream_state mode)
{
+ struct iss_device *iss = pipe->output->iss;
struct media_entity *entity;
struct media_pad *pad;
struct v4l2_subdev *subdev;
unsigned long flags;
int ret;
+ /* If one of the entities in the pipeline has crashed it will not work
+ * properly. Refuse to start streaming in that case. This check must be
+ * performed before the loop below to avoid starting entities if the
+ * pipeline won't start anyway (those entities would then likely fail to
+ * stop, making the problem worse).
+ */
+ if (pipe->entities & iss->crashed)
+ return -EIO;
+
spin_lock_irqsave(&pipe->lock, flags);
pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
spin_unlock_irqrestore(&pipe->lock, flags);
@@ -617,6 +627,7 @@ static int iss_pipeline_enable(struct iss_pipeline *pipe,
*/
static int iss_pipeline_disable(struct iss_pipeline *pipe)
{
+ struct iss_device *iss = pipe->output->iss;
struct media_entity *entity;
struct media_pad *pad;
struct v4l2_subdev *subdev;
@@ -641,6 +652,11 @@ static int iss_pipeline_disable(struct iss_pipeline *pipe)
if (ret < 0) {
dev_dbg(iss->dev, "%s: module stop timeout.\n",
subdev->name);
+ /* If the entity failed to stopped, assume it has
+ * crashed. Mark it as such, the ISS will be reset when
+ * applications will release it.
+ */
+ iss->crashed |= 1U << subdev->entity.id;
failure = -ETIMEDOUT;
}
}
@@ -715,6 +731,7 @@ static int iss_reset(struct iss_device *iss)
usleep_range(10, 10);
}
+ iss->crashed = 0;
return 0;
}
@@ -1058,6 +1075,13 @@ void omap4iss_put(struct iss_device *iss)
BUG_ON(iss->ref_count == 0);
if (--iss->ref_count == 0) {
iss_disable_interrupts(iss);
+ /* Reset the ISS if an entity has failed to stop. This is the
+ * only way to recover from such conditions, although it would
+ * be worth investigating whether resetting the ISP only can't
+ * fix the problem in some cases.
+ */
+ if (iss->crashed)
+ iss_reset(iss);
iss_disable_clocks(iss);
}
mutex_unlock(&iss->iss_mutex);
diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h
index f63caaf90f33..3c1e92024513 100644
--- a/drivers/staging/media/omap4iss/iss.h
+++ b/drivers/staging/media/omap4iss/iss.h
@@ -77,6 +77,10 @@ struct iss_reg {
u32 val;
};
+/*
+ * struct iss_device - ISS device structure.
+ * @crashed: Bitmask of crashed entities (indexed by entity ID)
+ */
struct iss_device {
struct v4l2_device v4l2_dev;
struct media_device media_dev;
@@ -93,6 +97,7 @@ struct iss_device {
u64 raw_dmamask;
struct mutex iss_mutex; /* For handling ref_count field */
+ bool crashed;
int has_context;
int ref_count;
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 68eab6e6dc36..910648766e6c 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -772,6 +772,8 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
{
struct iss_video_fh *vfh = to_iss_video_fh(fh);
struct iss_video *video = video_drvdata(file);
+ struct media_entity_graph graph;
+ struct media_entity *entity;
enum iss_pipeline_state state;
struct iss_pipeline *pipe;
struct iss_video *far_end;
@@ -791,6 +793,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
pipe->external = NULL;
pipe->external_rate = 0;
pipe->external_bpp = 0;
+ pipe->entities = 0;
if (video->iss->pdata->set_constraints)
video->iss->pdata->set_constraints(video->iss, true);
@@ -799,6 +802,11 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
if (ret < 0)
goto err_media_entity_pipeline_start;
+ entity = &video->video.entity;
+ media_entity_graph_walk_start(&graph, entity);
+ while ((entity = media_entity_graph_walk_next(&graph)))
+ pipe->entities |= 1 << entity->id;
+
/* Verify that the currently configured format matches the output of
* the connected subdev.
*/
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
index 2c8d256a87c5..73e1a3419b01 100644
--- a/drivers/staging/media/omap4iss/iss_video.h
+++ b/drivers/staging/media/omap4iss/iss_video.h
@@ -77,6 +77,7 @@ enum iss_pipeline_state {
/*
* struct iss_pipeline - An OMAP4 ISS hardware pipeline
+ * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
* @error: A hardware error occurred during capture
*/
struct iss_pipeline {
@@ -86,6 +87,7 @@ struct iss_pipeline {
enum iss_pipeline_stream_state stream_state;
struct iss_video *input;
struct iss_video *output;
+ unsigned int entities;
atomic_t frame_number;
bool do_propagation; /* of frame number */
bool error;
OpenPOWER on IntegriCloud