[media] v4l: omap4iss: Reset the ISS when the pipeline can't be stopped
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Wed, 9 Oct 2013 14:52:45 +0000 (11:52 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Wed, 11 Dec 2013 11:03:51 +0000 (09:03 -0200)
When a failure to stop a module in the pipeline is detected, the only
way to recover is to reset the ISS. However, as other users can be using
a different pipeline with other modules, the ISS can't be reset
synchronously with the error detection.
Keep track of modules that have failed to stop, and reset the ISS
accordingly when the last user releases the last reference to the ISS.
Refuse to start streaming on a pipeline that contains a crashed module,
as the hardware wouldn't work anyway.
Modify the omap4iss_pipeline_set_stream() function to record the new ISS
pipeline state only when no error occurs, except when stopping the
pipeline in which case the pipeline is still marked as stopped.

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_video.c
drivers/staging/media/omap4iss/iss_video.h

index dffa31e274d6697c891ba7d9a9c921fb9b0213c3..5ad604d0d16b13d49db24f12afec1485098ac8ce 100644 (file)
@@ -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);
index f63caaf90f3339fc948e3a5d4b0b3806d7999d7a..3c1e920245139ec371e25ff89d5ed9b65edfac14 100644 (file)
@@ -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;
 
index 68eab6e6dc3647ca8ee179c9c5350aaf032b9126..910648766e6c7d1840569a4697e341bbc4f40d08 100644 (file)
@@ -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.
         */
index 2c8d256a87c5d0cb8e8852e70ba0fc1ce1447509..73e1a3419b0137e3079c68b9f20f87d2146e663a 100644 (file)
@@ -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;