From: Vishal Sagar Date: Tue, 23 Oct 2018 10:19:26 +0000 (+0530) Subject: xilinx: v4l: dma: Stop subdevs in reverse order of starting X-Git-Tag: xilinx-v2018.3~22 X-Git-Url: https://rtime.felk.cvut.cz/gitweb/zynq/linux.git/commitdiff_plain/290efcf0745d3731bdd2bd4f8c5b2c1df6b87eff xilinx: v4l: dma: Stop subdevs in reverse order of starting Patch fixes the incorrect sequence of stopping subdevs in a media pipeline. The order of stopping should be reverse the order of starting a video pipe. The video pipe should be started from sink to source and be disabled from source to sink. Signed-off-by: Vishal Sagar Reviewed-by: Satish Kumar Nagireddy Signed-off-by: Michal Simek --- diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 977b2bb9d6db..79e58067ace2 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -40,6 +40,11 @@ #define XVIP_DMA_MIN_HEIGHT 1U #define XVIP_DMA_MAX_HEIGHT 8191U +struct xventity_list { + struct list_head list; + struct media_entity *entity; +}; + /* ----------------------------------------------------------------------------- * Helper functions */ @@ -96,6 +101,61 @@ static int xvip_dma_verify_format(struct xvip_dma *dma) * Pipeline Stream Management */ +static int xvip_entity_start_stop(struct xvip_composite_device *xdev, + struct media_entity *entity, bool start) +{ + struct v4l2_subdev *subdev; + bool is_streaming; + int ret = 0; + + dev_dbg(xdev->dev, "%s entity %s\n", + start ? "Starting" : "Stopping", entity->name); + subdev = media_entity_to_v4l2_subdev(entity); + + /* This is to maintain list of stream on/off devices */ + is_streaming = xvip_subdev_set_streaming(xdev, subdev, start); + + /* + * start or stop the subdev only once in case if they are + * shared between sub-graphs + */ + if (start && !is_streaming) { + /* power-on subdevice */ + ret = v4l2_subdev_call(subdev, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_err(xdev->dev, + "s_power on failed on subdev\n"); + xvip_subdev_set_streaming(xdev, subdev, 0); + return ret; + } + + /* stream-on subdevice */ + ret = v4l2_subdev_call(subdev, video, s_stream, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_err(xdev->dev, + "s_stream on failed on subdev\n"); + v4l2_subdev_call(subdev, core, s_power, 0); + xvip_subdev_set_streaming(xdev, subdev, 0); + } + } else if (!start && is_streaming) { + /* stream-off subdevice */ + ret = v4l2_subdev_call(subdev, video, s_stream, 0); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_err(xdev->dev, + "s_stream off failed on subdev\n"); + xvip_subdev_set_streaming(xdev, subdev, 1); + } + + /* power-off subdevice */ + ret = v4l2_subdev_call(subdev, core, s_power, 0); + if (ret < 0 && ret != -ENOIOCTLCMD) + dev_err(xdev->dev, + "s_power off failed on subdev\n"); + } + + return ret; +} + /** * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline * @xdev: Composite video device @@ -113,9 +173,9 @@ static int xvip_pipeline_start_stop(struct xvip_composite_device *xdev, struct media_graph graph; struct media_entity *entity = &dma->video.entity; struct media_device *mdev = entity->graph_obj.mdev; - struct v4l2_subdev *subdev; - bool is_streaming; - int ret; + struct xventity_list *temp, *_temp; + LIST_HEAD(ent_list); + int ret = 0; mutex_lock(&mdev->graph_mutex); @@ -126,54 +186,44 @@ static int xvip_pipeline_start_stop(struct xvip_composite_device *xdev, media_graph_walk_start(&graph, entity); + /* get the list of entities */ while ((entity = media_graph_walk_next(&graph))) { + struct xventity_list *ele; + /* We want to stream on/off only subdevs */ if (!is_media_entity_v4l2_subdev(entity)) continue; - subdev = media_entity_to_v4l2_subdev(entity); - - /* This is to maintain list of stream on/off devices */ - is_streaming = xvip_subdev_set_streaming(xdev, subdev, start); + /* Maintain the pipeline sequence in a list */ + ele = kzalloc(sizeof(*ele), GFP_KERNEL); + if (!ele) { + ret = -ENOMEM; + goto error; + } - /* - * start or stop the subdev only once in case if they are - * shared between sub-graphs - */ - if (start && !is_streaming) { - /* power-on subdevice */ - ret = v4l2_subdev_call(subdev, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_err(xdev->dev, - "s_power on failed on subdev\n"); - xvip_subdev_set_streaming(xdev, subdev, 0); - goto error; - } + ele->entity = entity; + list_add(&ele->list, &ent_list); + } - /* stream-on subdevice */ - ret = v4l2_subdev_call(subdev, video, s_stream, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_err(xdev->dev, - "s_stream on failed on subdev\n"); - v4l2_subdev_call(subdev, core, s_power, 0); - xvip_subdev_set_streaming(xdev, subdev, 0); - } - } else if (!start && is_streaming) { - /* stream-off subdevice */ - ret = v4l2_subdev_call(subdev, video, s_stream, 0); - if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_err(xdev->dev, - "s_stream off failed on subdev\n"); - xvip_subdev_set_streaming(xdev, subdev, 1); + if (start) { + list_for_each_entry_safe(temp, _temp, &ent_list, list) { + /* Enable all subdevs from sink to source */ + ret = xvip_entity_start_stop(xdev, temp->entity, start); + if (ret < 0) { + dev_err(xdev->dev, "ret = %d for entity %s\n", + ret, temp->entity->name); + break; } - - /* power-off subdevice */ - ret = v4l2_subdev_call(subdev, core, s_power, 0); - if (ret < 0 && ret != -ENOIOCTLCMD) - dev_err(xdev->dev, - "s_power off failed on subdev\n"); - } + } else { + list_for_each_entry_safe_reverse(temp, _temp, &ent_list, list) + /* Enable all subdevs from source to sink */ + xvip_entity_start_stop(xdev, temp->entity, start); + } + + list_for_each_entry_safe(temp, _temp, &ent_list, list) { + list_del(&temp->list); + kfree(temp); } error: @@ -271,11 +321,10 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe, dma = to_xvip_dma(media_entity_to_video_device(entity)); - if (dma->pad.flags & MEDIA_PAD_FL_SINK) { + if (dma->pad.flags & MEDIA_PAD_FL_SINK) num_outputs++; - } else { + else num_inputs++; - } } mutex_unlock(&mdev->graph_mutex);