[media] v4l: vsp1: Allocate pipelines on demand
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Sun, 17 Jan 2016 21:53:56 +0000 (19:53 -0200)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Wed, 13 Apr 2016 22:03:21 +0000 (19:03 -0300)
Instead of embedding pipelines in the vsp1_video objects allocate them
on demand when they are needed. This fixes the streamon race condition
where pipelines objects from different video nodes could be used for the
same pipeline.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/platform/vsp1/vsp1_bru.c
drivers/media/platform/vsp1/vsp1_drv.c
drivers/media/platform/vsp1/vsp1_pipe.c
drivers/media/platform/vsp1/vsp1_pipe.h
drivers/media/platform/vsp1/vsp1_rpf.c
drivers/media/platform/vsp1/vsp1_video.c
drivers/media/platform/vsp1/vsp1_video.h
drivers/media/platform/vsp1/vsp1_wpf.c

index 3ece402453969fc0f8f30e9a7372be496367d17a..d27de5363c5a663c4ab566cff1acbcdf9d7f7521 100644 (file)
@@ -19,6 +19,7 @@
 #include "vsp1.h"
 #include "vsp1_bru.h"
 #include "vsp1_dl.h"
+#include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
index f1be2680013d24d3708d1953dd4220bdce769acc..596f26d8149497a8aefbbbfe0a511d09daffa4a0 100644 (file)
@@ -30,6 +30,7 @@
 #include "vsp1_hsit.h"
 #include "vsp1_lif.h"
 #include "vsp1_lut.h"
+#include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_sru.h"
 #include "vsp1_uds.h"
index 8ac080f87b08d0b85022ddb98022c18b165151ea..4913b933562cb131defc1c1c07a43188a9152921 100644 (file)
@@ -194,6 +194,7 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
        mutex_init(&pipe->lock);
        spin_lock_init(&pipe->irqlock);
        init_waitqueue_head(&pipe->wq);
+       kref_init(&pipe->kref);
 
        INIT_LIST_HEAD(&pipe->entities);
        pipe->state = VSP1_PIPELINE_STOPPED;
index 9fd688bfe6380632dcf16e590ba20d97c21cad01..7b56113511ddeb8bf8decdef897edf1e4510881e 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef __VSP1_PIPE_H__
 #define __VSP1_PIPE_H__
 
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
@@ -63,7 +64,7 @@ enum vsp1_pipeline_state {
  * @wq: work queue to wait for state change completion
  * @frame_end: frame end interrupt handler
  * @lock: protects the pipeline use count and stream count
- * @use_count: number of video nodes using the pipeline
+ * @kref: pipeline reference count
  * @stream_count: number of streaming video nodes
  * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available
  * @num_inputs: number of RPFs
@@ -86,7 +87,7 @@ struct vsp1_pipeline {
        void (*frame_end)(struct vsp1_pipeline *pipe);
 
        struct mutex lock;
-       unsigned int use_count;
+       struct kref kref;
        unsigned int stream_count;
        unsigned int buffers_ready;
 
index e7b6abbb00244d216ad9c6bf5e4ef3d3a0351a0e..5486ff54a2b3f01ef0ca640a0195a3465857530a 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "vsp1.h"
 #include "vsp1_dl.h"
+#include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
index 4396018d1408913daf8dbece6ae48e80e4870eb9..a9aec5c0bec68cab3172ec912997ce723b75d46b 100644 (file)
@@ -399,14 +399,10 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
        unsigned int i;
        int ret;
 
-       mutex_lock(&mdev->graph_mutex);
-
        /* Walk the graph to locate the entities and video nodes. */
        ret = media_entity_graph_walk_init(&graph, mdev);
-       if (ret) {
-               mutex_unlock(&mdev->graph_mutex);
+       if (ret)
                return ret;
-       }
 
        media_entity_graph_walk_start(&graph, entity);
 
@@ -439,15 +435,11 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
                }
        }
 
-       mutex_unlock(&mdev->graph_mutex);
-
        media_entity_graph_walk_cleanup(&graph);
 
        /* We need one output and at least one input. */
-       if (pipe->num_inputs == 0 || !pipe->output) {
-               ret = -EPIPE;
-               goto error;
-       }
+       if (pipe->num_inputs == 0 || !pipe->output)
+               return -EPIPE;
 
        /* Follow links downstream for each input and make sure the graph
         * contains no loop and that all branches end at the output WPF.
@@ -459,47 +451,66 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
                ret = vsp1_video_pipeline_build_branch(pipe, pipe->inputs[i],
                                                       pipe->output);
                if (ret < 0)
-                       goto error;
+                       return ret;
        }
 
        return 0;
-
-error:
-       vsp1_pipeline_reset(pipe);
-       return ret;
 }
 
 static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe,
                                    struct vsp1_video *video)
 {
+       vsp1_pipeline_init(pipe);
+
+       pipe->frame_end = vsp1_video_pipeline_frame_end;
+
+       return vsp1_video_pipeline_build(pipe, video);
+}
+
+static struct vsp1_pipeline *vsp1_video_pipeline_get(struct vsp1_video *video)
+{
+       struct vsp1_pipeline *pipe;
        int ret;
 
-       mutex_lock(&pipe->lock);
+       /* Get a pipeline object for the video node. If a pipeline has already
+        * been allocated just increment its reference count and return it.
+        * Otherwise allocate a new pipeline and initialize it, it will be freed
+        * when the last reference is released.
+        */
+       if (!video->rwpf->pipe) {
+               pipe = kzalloc(sizeof(*pipe), GFP_KERNEL);
+               if (!pipe)
+                       return ERR_PTR(-ENOMEM);
 
-       /* If we're the first user build and validate the pipeline. */
-       if (pipe->use_count == 0) {
-               ret = vsp1_video_pipeline_build(pipe, video);
-               if (ret < 0)
-                       goto done;
+               ret = vsp1_video_pipeline_init(pipe, video);
+               if (ret < 0) {
+                       vsp1_pipeline_reset(pipe);
+                       kfree(pipe);
+                       return ERR_PTR(ret);
+               }
+       } else {
+               pipe = video->rwpf->pipe;
+               kref_get(&pipe->kref);
        }
 
-       pipe->use_count++;
-       ret = 0;
-
-done:
-       mutex_unlock(&pipe->lock);
-       return ret;
+       return pipe;
 }
 
-static void vsp1_video_pipeline_cleanup(struct vsp1_pipeline *pipe)
+static void vsp1_video_pipeline_release(struct kref *kref)
 {
-       mutex_lock(&pipe->lock);
+       struct vsp1_pipeline *pipe = container_of(kref, typeof(*pipe), kref);
 
-       /* If we're the last user clean up the pipeline. */
-       if (--pipe->use_count == 0)
-               vsp1_pipeline_reset(pipe);
+       vsp1_pipeline_reset(pipe);
+       kfree(pipe);
+}
 
-       mutex_unlock(&pipe->lock);
+static void vsp1_video_pipeline_put(struct vsp1_pipeline *pipe)
+{
+       struct media_device *mdev = &pipe->output->entity.vsp1->media_dev;
+
+       mutex_lock(&mdev->graph_mutex);
+       kref_put(&pipe->kref, vsp1_video_pipeline_release);
+       mutex_unlock(&mdev->graph_mutex);
 }
 
 /* -----------------------------------------------------------------------------
@@ -674,8 +685,8 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
        }
        mutex_unlock(&pipe->lock);
 
-       vsp1_video_pipeline_cleanup(pipe);
        media_entity_pipeline_stop(&video->video.entity);
+       vsp1_video_pipeline_put(pipe);
 
        /* Remove all buffers from the IRQ queue. */
        spin_lock_irqsave(&video->irqlock, flags);
@@ -787,6 +798,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 {
        struct v4l2_fh *vfh = file->private_data;
        struct vsp1_video *video = to_vsp1_video(vfh->vdev);
+       struct media_device *mdev = &video->vsp1->media_dev;
        struct vsp1_pipeline *pipe;
        int ret;
 
@@ -795,20 +807,25 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 
        video->sequence = 0;
 
-       /* Start streaming on the pipeline. No link touching an entity in the
-        * pipeline can be activated or deactivated once streaming is started.
-        *
-        * Use the VSP1 pipeline object embedded in the first video object that
-        * starts streaming.
-        *
-        * FIXME: This is racy, the ioctl is only protected by the video node
-        * lock.
+       /* Get a pipeline for the video node and start streaming on it. No link
+        * touching an entity in the pipeline can be activated or deactivated
+        * once streaming is started.
         */
-       pipe = video->rwpf->pipe ? video->rwpf->pipe : &video->pipe;
+       mutex_lock(&mdev->graph_mutex);
 
-       ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
-       if (ret < 0)
-               return ret;
+       pipe = vsp1_video_pipeline_get(video);
+       if (IS_ERR(pipe)) {
+               mutex_unlock(&mdev->graph_mutex);
+               return PTR_ERR(pipe);
+       }
+
+       ret = __media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+       if (ret < 0) {
+               mutex_unlock(&mdev->graph_mutex);
+               goto err_pipe;
+       }
+
+       mutex_unlock(&mdev->graph_mutex);
 
        /* Verify that the configured format matches the output of the connected
         * subdev.
@@ -817,21 +834,17 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        if (ret < 0)
                goto err_stop;
 
-       ret = vsp1_video_pipeline_init(pipe, video);
-       if (ret < 0)
-               goto err_stop;
-
        /* Start the queue. */
        ret = vb2_streamon(&video->queue, type);
        if (ret < 0)
-               goto err_cleanup;
+               goto err_stop;
 
        return 0;
 
-err_cleanup:
-       vsp1_video_pipeline_cleanup(pipe);
 err_stop:
        media_entity_pipeline_stop(&video->video.entity);
+err_pipe:
+       vsp1_video_pipeline_put(pipe);
        return ret;
 }
 
@@ -947,9 +960,6 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
        spin_lock_init(&video->irqlock);
        INIT_LIST_HEAD(&video->irqqueue);
 
-       vsp1_pipeline_init(&video->pipe);
-       video->pipe.frame_end = vsp1_video_pipeline_frame_end;
-
        /* Initialize the media entity... */
        ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
        if (ret < 0)
index 64abd39ee1e75c5998115afcf6b33a73aa7f89d8..867b00807c46e7357e8841868f94cb2e830d2937 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <media/videobuf2-v4l2.h>
 
-#include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 
 struct vsp1_vb2_buffer {
@@ -44,7 +43,6 @@ struct vsp1_video {
 
        struct mutex lock;
 
-       struct vsp1_pipeline pipe;
        unsigned int pipe_index;
 
        struct vb2_queue queue;
index d1d5c08ca35e30de246977781a052ea063eff3a2..ce1d0b4094dba544db5104363c810568faedf1d2 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "vsp1.h"
 #include "vsp1_dl.h"
+#include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
This page took 0.033349 seconds and 5 git commands to generate.