aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2016-01-17 16:53:56 -0500
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2016-04-13 18:03:21 -0400
commita0cdac5610ea900dcf6a78d4d0216aef2bca7b80 (patch)
tree970a24dc99e7eba62b5011f546b916f2788d9dc5
parent76c29755960c911b4e1bec3da90d4d5f6b44d3f3 (diff)
[media] v4l: vsp1: Allocate pipelines on demand
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>
-rw-r--r--drivers/media/platform/vsp1/vsp1_bru.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_pipe.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_pipe.h5
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c124
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c1
8 files changed, 75 insertions, 61 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 3ece40245396..d27de5363c5a 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -19,6 +19,7 @@
19#include "vsp1.h" 19#include "vsp1.h"
20#include "vsp1_bru.h" 20#include "vsp1_bru.h"
21#include "vsp1_dl.h" 21#include "vsp1_dl.h"
22#include "vsp1_pipe.h"
22#include "vsp1_rwpf.h" 23#include "vsp1_rwpf.h"
23#include "vsp1_video.h" 24#include "vsp1_video.h"
24 25
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index f1be2680013d..596f26d81494 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -30,6 +30,7 @@
30#include "vsp1_hsit.h" 30#include "vsp1_hsit.h"
31#include "vsp1_lif.h" 31#include "vsp1_lif.h"
32#include "vsp1_lut.h" 32#include "vsp1_lut.h"
33#include "vsp1_pipe.h"
33#include "vsp1_rwpf.h" 34#include "vsp1_rwpf.h"
34#include "vsp1_sru.h" 35#include "vsp1_sru.h"
35#include "vsp1_uds.h" 36#include "vsp1_uds.h"
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 8ac080f87b08..4913b933562c 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -194,6 +194,7 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
194 mutex_init(&pipe->lock); 194 mutex_init(&pipe->lock);
195 spin_lock_init(&pipe->irqlock); 195 spin_lock_init(&pipe->irqlock);
196 init_waitqueue_head(&pipe->wq); 196 init_waitqueue_head(&pipe->wq);
197 kref_init(&pipe->kref);
197 198
198 INIT_LIST_HEAD(&pipe->entities); 199 INIT_LIST_HEAD(&pipe->entities);
199 pipe->state = VSP1_PIPELINE_STOPPED; 200 pipe->state = VSP1_PIPELINE_STOPPED;
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index 9fd688bfe638..7b56113511dd 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -13,6 +13,7 @@
13#ifndef __VSP1_PIPE_H__ 13#ifndef __VSP1_PIPE_H__
14#define __VSP1_PIPE_H__ 14#define __VSP1_PIPE_H__
15 15
16#include <linux/kref.h>
16#include <linux/list.h> 17#include <linux/list.h>
17#include <linux/spinlock.h> 18#include <linux/spinlock.h>
18#include <linux/wait.h> 19#include <linux/wait.h>
@@ -63,7 +64,7 @@ enum vsp1_pipeline_state {
63 * @wq: work queue to wait for state change completion 64 * @wq: work queue to wait for state change completion
64 * @frame_end: frame end interrupt handler 65 * @frame_end: frame end interrupt handler
65 * @lock: protects the pipeline use count and stream count 66 * @lock: protects the pipeline use count and stream count
66 * @use_count: number of video nodes using the pipeline 67 * @kref: pipeline reference count
67 * @stream_count: number of streaming video nodes 68 * @stream_count: number of streaming video nodes
68 * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available 69 * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available
69 * @num_inputs: number of RPFs 70 * @num_inputs: number of RPFs
@@ -86,7 +87,7 @@ struct vsp1_pipeline {
86 void (*frame_end)(struct vsp1_pipeline *pipe); 87 void (*frame_end)(struct vsp1_pipeline *pipe);
87 88
88 struct mutex lock; 89 struct mutex lock;
89 unsigned int use_count; 90 struct kref kref;
90 unsigned int stream_count; 91 unsigned int stream_count;
91 unsigned int buffers_ready; 92 unsigned int buffers_ready;
92 93
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index e7b6abbb0024..5486ff54a2b3 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -17,6 +17,7 @@
17 17
18#include "vsp1.h" 18#include "vsp1.h"
19#include "vsp1_dl.h" 19#include "vsp1_dl.h"
20#include "vsp1_pipe.h"
20#include "vsp1_rwpf.h" 21#include "vsp1_rwpf.h"
21#include "vsp1_video.h" 22#include "vsp1_video.h"
22 23
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 4396018d1408..a9aec5c0bec6 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -399,14 +399,10 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
399 unsigned int i; 399 unsigned int i;
400 int ret; 400 int ret;
401 401
402 mutex_lock(&mdev->graph_mutex);
403
404 /* Walk the graph to locate the entities and video nodes. */ 402 /* Walk the graph to locate the entities and video nodes. */
405 ret = media_entity_graph_walk_init(&graph, mdev); 403 ret = media_entity_graph_walk_init(&graph, mdev);
406 if (ret) { 404 if (ret)
407 mutex_unlock(&mdev->graph_mutex);
408 return ret; 405 return ret;
409 }
410 406
411 media_entity_graph_walk_start(&graph, entity); 407 media_entity_graph_walk_start(&graph, entity);
412 408
@@ -439,15 +435,11 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
439 } 435 }
440 } 436 }
441 437
442 mutex_unlock(&mdev->graph_mutex);
443
444 media_entity_graph_walk_cleanup(&graph); 438 media_entity_graph_walk_cleanup(&graph);
445 439
446 /* We need one output and at least one input. */ 440 /* We need one output and at least one input. */
447 if (pipe->num_inputs == 0 || !pipe->output) { 441 if (pipe->num_inputs == 0 || !pipe->output)
448 ret = -EPIPE; 442 return -EPIPE;
449 goto error;
450 }
451 443
452 /* Follow links downstream for each input and make sure the graph 444 /* Follow links downstream for each input and make sure the graph
453 * contains no loop and that all branches end at the output WPF. 445 * 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,
459 ret = vsp1_video_pipeline_build_branch(pipe, pipe->inputs[i], 451 ret = vsp1_video_pipeline_build_branch(pipe, pipe->inputs[i],
460 pipe->output); 452 pipe->output);
461 if (ret < 0) 453 if (ret < 0)
462 goto error; 454 return ret;
463 } 455 }
464 456
465 return 0; 457 return 0;
466
467error:
468 vsp1_pipeline_reset(pipe);
469 return ret;
470} 458}
471 459
472static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe, 460static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe,
473 struct vsp1_video *video) 461 struct vsp1_video *video)
474{ 462{
463 vsp1_pipeline_init(pipe);
464
465 pipe->frame_end = vsp1_video_pipeline_frame_end;
466
467 return vsp1_video_pipeline_build(pipe, video);
468}
469
470static struct vsp1_pipeline *vsp1_video_pipeline_get(struct vsp1_video *video)
471{
472 struct vsp1_pipeline *pipe;
475 int ret; 473 int ret;
476 474
477 mutex_lock(&pipe->lock); 475 /* Get a pipeline object for the video node. If a pipeline has already
476 * been allocated just increment its reference count and return it.
477 * Otherwise allocate a new pipeline and initialize it, it will be freed
478 * when the last reference is released.
479 */
480 if (!video->rwpf->pipe) {
481 pipe = kzalloc(sizeof(*pipe), GFP_KERNEL);
482 if (!pipe)
483 return ERR_PTR(-ENOMEM);
478 484
479 /* If we're the first user build and validate the pipeline. */ 485 ret = vsp1_video_pipeline_init(pipe, video);
480 if (pipe->use_count == 0) { 486 if (ret < 0) {
481 ret = vsp1_video_pipeline_build(pipe, video); 487 vsp1_pipeline_reset(pipe);
482 if (ret < 0) 488 kfree(pipe);
483 goto done; 489 return ERR_PTR(ret);
490 }
491 } else {
492 pipe = video->rwpf->pipe;
493 kref_get(&pipe->kref);
484 } 494 }
485 495
486 pipe->use_count++; 496 return pipe;
487 ret = 0;
488
489done:
490 mutex_unlock(&pipe->lock);
491 return ret;
492} 497}
493 498
494static void vsp1_video_pipeline_cleanup(struct vsp1_pipeline *pipe) 499static void vsp1_video_pipeline_release(struct kref *kref)
495{ 500{
496 mutex_lock(&pipe->lock); 501 struct vsp1_pipeline *pipe = container_of(kref, typeof(*pipe), kref);
497 502
498 /* If we're the last user clean up the pipeline. */ 503 vsp1_pipeline_reset(pipe);
499 if (--pipe->use_count == 0) 504 kfree(pipe);
500 vsp1_pipeline_reset(pipe); 505}
501 506
502 mutex_unlock(&pipe->lock); 507static void vsp1_video_pipeline_put(struct vsp1_pipeline *pipe)
508{
509 struct media_device *mdev = &pipe->output->entity.vsp1->media_dev;
510
511 mutex_lock(&mdev->graph_mutex);
512 kref_put(&pipe->kref, vsp1_video_pipeline_release);
513 mutex_unlock(&mdev->graph_mutex);
503} 514}
504 515
505/* ----------------------------------------------------------------------------- 516/* -----------------------------------------------------------------------------
@@ -674,8 +685,8 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
674 } 685 }
675 mutex_unlock(&pipe->lock); 686 mutex_unlock(&pipe->lock);
676 687
677 vsp1_video_pipeline_cleanup(pipe);
678 media_entity_pipeline_stop(&video->video.entity); 688 media_entity_pipeline_stop(&video->video.entity);
689 vsp1_video_pipeline_put(pipe);
679 690
680 /* Remove all buffers from the IRQ queue. */ 691 /* Remove all buffers from the IRQ queue. */
681 spin_lock_irqsave(&video->irqlock, flags); 692 spin_lock_irqsave(&video->irqlock, flags);
@@ -787,6 +798,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
787{ 798{
788 struct v4l2_fh *vfh = file->private_data; 799 struct v4l2_fh *vfh = file->private_data;
789 struct vsp1_video *video = to_vsp1_video(vfh->vdev); 800 struct vsp1_video *video = to_vsp1_video(vfh->vdev);
801 struct media_device *mdev = &video->vsp1->media_dev;
790 struct vsp1_pipeline *pipe; 802 struct vsp1_pipeline *pipe;
791 int ret; 803 int ret;
792 804
@@ -795,20 +807,25 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
795 807
796 video->sequence = 0; 808 video->sequence = 0;
797 809
798 /* Start streaming on the pipeline. No link touching an entity in the 810 /* Get a pipeline for the video node and start streaming on it. No link
799 * pipeline can be activated or deactivated once streaming is started. 811 * touching an entity in the pipeline can be activated or deactivated
800 * 812 * once streaming is started.
801 * Use the VSP1 pipeline object embedded in the first video object that
802 * starts streaming.
803 *
804 * FIXME: This is racy, the ioctl is only protected by the video node
805 * lock.
806 */ 813 */
807 pipe = video->rwpf->pipe ? video->rwpf->pipe : &video->pipe; 814 mutex_lock(&mdev->graph_mutex);
808 815
809 ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe); 816 pipe = vsp1_video_pipeline_get(video);
810 if (ret < 0) 817 if (IS_ERR(pipe)) {
811 return ret; 818 mutex_unlock(&mdev->graph_mutex);
819 return PTR_ERR(pipe);
820 }
821
822 ret = __media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
823 if (ret < 0) {
824 mutex_unlock(&mdev->graph_mutex);
825 goto err_pipe;
826 }
827
828 mutex_unlock(&mdev->graph_mutex);
812 829
813 /* Verify that the configured format matches the output of the connected 830 /* Verify that the configured format matches the output of the connected
814 * subdev. 831 * subdev.
@@ -817,21 +834,17 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
817 if (ret < 0) 834 if (ret < 0)
818 goto err_stop; 835 goto err_stop;
819 836
820 ret = vsp1_video_pipeline_init(pipe, video);
821 if (ret < 0)
822 goto err_stop;
823
824 /* Start the queue. */ 837 /* Start the queue. */
825 ret = vb2_streamon(&video->queue, type); 838 ret = vb2_streamon(&video->queue, type);
826 if (ret < 0) 839 if (ret < 0)
827 goto err_cleanup; 840 goto err_stop;
828 841
829 return 0; 842 return 0;
830 843
831err_cleanup:
832 vsp1_video_pipeline_cleanup(pipe);
833err_stop: 844err_stop:
834 media_entity_pipeline_stop(&video->video.entity); 845 media_entity_pipeline_stop(&video->video.entity);
846err_pipe:
847 vsp1_video_pipeline_put(pipe);
835 return ret; 848 return ret;
836} 849}
837 850
@@ -947,9 +960,6 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
947 spin_lock_init(&video->irqlock); 960 spin_lock_init(&video->irqlock);
948 INIT_LIST_HEAD(&video->irqqueue); 961 INIT_LIST_HEAD(&video->irqqueue);
949 962
950 vsp1_pipeline_init(&video->pipe);
951 video->pipe.frame_end = vsp1_video_pipeline_frame_end;
952
953 /* Initialize the media entity... */ 963 /* Initialize the media entity... */
954 ret = media_entity_pads_init(&video->video.entity, 1, &video->pad); 964 ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
955 if (ret < 0) 965 if (ret < 0)
diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h
index 64abd39ee1e7..867b00807c46 100644
--- a/drivers/media/platform/vsp1/vsp1_video.h
+++ b/drivers/media/platform/vsp1/vsp1_video.h
@@ -18,7 +18,6 @@
18 18
19#include <media/videobuf2-v4l2.h> 19#include <media/videobuf2-v4l2.h>
20 20
21#include "vsp1_pipe.h"
22#include "vsp1_rwpf.h" 21#include "vsp1_rwpf.h"
23 22
24struct vsp1_vb2_buffer { 23struct vsp1_vb2_buffer {
@@ -44,7 +43,6 @@ struct vsp1_video {
44 43
45 struct mutex lock; 44 struct mutex lock;
46 45
47 struct vsp1_pipeline pipe;
48 unsigned int pipe_index; 46 unsigned int pipe_index;
49 47
50 struct vb2_queue queue; 48 struct vb2_queue queue;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index d1d5c08ca35e..ce1d0b4094db 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -17,6 +17,7 @@
17 17
18#include "vsp1.h" 18#include "vsp1.h"
19#include "vsp1_dl.h" 19#include "vsp1_dl.h"
20#include "vsp1_pipe.h"
20#include "vsp1_rwpf.h" 21#include "vsp1_rwpf.h"
21#include "vsp1_video.h" 22#include "vsp1_video.h"
22 23