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);
*/
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;
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;
}
}
usleep_range(10, 10);
}
+ iss->crashed = 0;
return 0;
}
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);
{
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;
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);
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.
*/