linux-renesas-soc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/30] v4l: add support for multiplexed streams
@ 2018-11-01 23:31 Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 01/30] media: entity: Use pad as a starting point for graph walk Niklas Söderlund
                   ` (30 more replies)
  0 siblings, 31 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Niklas Söderlund

Hi all,

This series adds support for multiplexed streams within a media device
link. The use-case addressed in this series covers CSI-2 Virtual
Channels on the Renesas R-Car Gen3 platforms. The v4l2 changes have been
a joint effort between Sakari and Laurent and floating around for some
time [1].

I have added driver support for the devices used on the Renesas Gen3
platforms, a ADV7482 connected to the R-Car CSI-2 receiver. With these
changes I can control which of the analog inputs of the ADV7482 the
video source is captured from and on which CSI-2 virtual channel the
video is transmitted on to the R-Car CSI-2 receiver.

The series adds two new subdev IOCTLs [GS]_ROUTING which allows
user-space to get and set routes inside a subdevice. I have added RFC
support for these to v4l-utils [2] which can be used to test this
series, example:

    Check the internal routing of the adv748x csi-2 transmitter:
    v4l2-ctl -d /dev/v4l-subdev24 --get-routing
    0/0 -> 1/0 [ENABLED]
    0/0 -> 1/1 []
    0/0 -> 1/2 []
    0/0 -> 1/3 []


    Select that video should be outputed on VC 2 and check the result:
    $ v4l2-ctl -d /dev/v4l-subdev24 --set-routing '0/0 -> 1/2 [1]'

    $ v4l2-ctl -d /dev/v4l-subdev24 --get-routing
    0/0 -> 1/0 []
    0/0 -> 1/1 []
    0/0 -> 1/2 [ENABLED]
    0/0 -> 1/3 []

This series is tested on R-Car M3-N and for your testing needs this
series is available at

    git://git.ragnatech.se/linux v4l2/mux

* Changes since v1
- Rebased on latest media-tree.
- Incorporated changes to patch 'v4l: subdev: compat: Implement handling 
  for VIDIOC_SUBDEV_[GS]_ROUTING' by Sakari.
- Added review tags.

Thanks.

1. git://linuxtv.org/sailus/media_tree.git vc
2. git://git.ragnatech.se/v4l-utils routing

Laurent Pinchart (4):
  media: entity: Add has_route entity operation
  media: entity: Add media_has_route() function
  media: entity: Use routing information during graph traversal
  v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations

Niklas Söderlund (7):
  adv748x: csi2: add translation from pixelcode to CSI-2 datatype
  adv748x: csi2: only allow formats on sink pads
  adv748x: csi2: describe the multiplexed stream
  adv748x: csi2: add internal routing configuration
  adv748x: afe: add routing support
  rcar-csi2: use frame description information to configure CSI-2 bus
  rcar-csi2: expose the subdevice internal routing

Sakari Ailus (19):
  media: entity: Use pad as a starting point for graph walk
  media: entity: Use pads instead of entities in the media graph walk
    stack
  media: entity: Walk the graph based on pads
  v4l: mc: Start walk from a specific pad in use count calculation
  media: entity: Move the pipeline from entity to pads
  media: entity: Use pad as the starting point for a pipeline
  media: entity: Swap pads if route is checked from source to sink
  media: entity: Skip link validation for pads to which there is no
    route to
  media: entity: Add an iterator helper for connected pads
  media: entity: Add only connected pads to the pipeline
  media: entity: Add debug information in graph walk route check
  media: entity: Look for indirect routes
  v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING
  v4l: subdev: Take routing information into account in link validation
  v4l: subdev: Improve link format validation debug messages
  v4l: mc: Add an S_ROUTING helper function for power state changes
  v4l: Add bus type to frame descriptors
  v4l: Add CSI-2 bus configuration to frame descriptors
  v4l: Add stream to frame descriptor

 Documentation/media/kapi/mc-core.rst          |  15 +-
 drivers/media/i2c/adv748x/adv748x-afe.c       |  65 ++++
 drivers/media/i2c/adv748x/adv748x-csi2.c      | 124 +++++++-
 drivers/media/i2c/adv748x/adv748x.h           |   1 +
 drivers/media/media-entity.c                  | 252 ++++++++++------
 drivers/media/pci/intel/ipu3/ipu3-cio2.c      |   6 +-
 .../media/platform/exynos4-is/fimc-capture.c  |   8 +-
 .../platform/exynos4-is/fimc-isp-video.c      |   8 +-
 drivers/media/platform/exynos4-is/fimc-isp.c  |   2 +-
 drivers/media/platform/exynos4-is/fimc-lite.c |  10 +-
 drivers/media/platform/exynos4-is/media-dev.c |  20 +-
 drivers/media/platform/omap3isp/isp.c         |   2 +-
 drivers/media/platform/omap3isp/ispvideo.c    |  25 +-
 drivers/media/platform/omap3isp/ispvideo.h    |   2 +-
 .../media/platform/qcom/camss/camss-video.c   |   6 +-
 drivers/media/platform/rcar-vin/rcar-csi2.c   | 188 +++++++++---
 drivers/media/platform/rcar-vin/rcar-dma.c    |   8 +-
 .../media/platform/s3c-camif/camif-capture.c  |   6 +-
 drivers/media/platform/vimc/vimc-capture.c    |   6 +-
 drivers/media/platform/vsp1/vsp1_video.c      |  18 +-
 drivers/media/platform/xilinx/xilinx-dma.c    |  20 +-
 drivers/media/platform/xilinx/xilinx-dma.h    |   2 +-
 drivers/media/usb/au0828/au0828-core.c        |   4 +-
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c |  77 +++++
 drivers/media/v4l2-core/v4l2-ioctl.c          |  20 +-
 drivers/media/v4l2-core/v4l2-mc.c             |  76 +++--
 drivers/media/v4l2-core/v4l2-subdev.c         | 285 ++++++++++++++++--
 .../staging/media/davinci_vpfe/vpfe_video.c   |  47 +--
 drivers/staging/media/imx/imx-media-utils.c   |   8 +-
 drivers/staging/media/omap4iss/iss.c          |   2 +-
 drivers/staging/media/omap4iss/iss_video.c    |  38 +--
 drivers/staging/media/omap4iss/iss_video.h    |   2 +-
 include/media/media-entity.h                  | 122 +++++---
 include/media/v4l2-mc.h                       |  22 ++
 include/media/v4l2-subdev.h                   |  34 +++
 include/uapi/linux/v4l2-subdev.h              |  40 +++
 36 files changed, 1241 insertions(+), 330 deletions(-)

-- 
2.19.1

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH v2 01/30] media: entity: Use pad as a starting point for graph walk
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 21:43   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 02/30] media: entity: Use pads instead of entities in the media graph walk stack Niklas Söderlund
                   ` (29 subsequent siblings)
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

With the upcoming use of the recently added has_route() media entity op, all
the pads in an entity will no longer be considered interconnected. This has
an effect where the media graph is traversed: the starting pad does make a
difference.

Prepare for this change by using pad instead of the entity as an argument
for the graph walk operations. The actual graph traversal algorithm change
is in further patches.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 Documentation/media/kapi/mc-core.rst            |  2 +-
 drivers/media/media-entity.c                    | 17 ++++++++---------
 drivers/media/platform/exynos4-is/media-dev.c   |  4 ++--
 drivers/media/platform/omap3isp/ispvideo.c      |  2 +-
 drivers/media/platform/vsp1/vsp1_video.c        |  2 +-
 drivers/media/platform/xilinx/xilinx-dma.c      |  2 +-
 drivers/media/v4l2-core/v4l2-mc.c               |  6 +++---
 drivers/staging/media/davinci_vpfe/vpfe_video.c |  6 +++---
 drivers/staging/media/omap4iss/iss_video.c      |  4 ++--
 include/media/media-entity.h                    | 10 ++++------
 10 files changed, 26 insertions(+), 29 deletions(-)

diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
index 0c05503eaf1fa6c7..27aefb9a778b2ad6 100644
--- a/Documentation/media/kapi/mc-core.rst
+++ b/Documentation/media/kapi/mc-core.rst
@@ -165,7 +165,7 @@ Drivers initiate a graph traversal by calling
 :c:func:`media_graph_walk_start()`
 
 The graph structure, provided by the caller, is initialized to start graph
-traversal at the given entity.
+traversal at the given pad in an entity.
 
 Drivers can then retrieve the next entity by calling
 :c:func:`media_graph_walk_next()`
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 0b1cb3559140a1fe..2bbc07de71aa5e6d 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -300,17 +300,16 @@ void media_graph_walk_cleanup(struct media_graph *graph)
 }
 EXPORT_SYMBOL_GPL(media_graph_walk_cleanup);
 
-void media_graph_walk_start(struct media_graph *graph,
-			    struct media_entity *entity)
+void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad)
 {
 	media_entity_enum_zero(&graph->ent_enum);
-	media_entity_enum_set(&graph->ent_enum, entity);
+	media_entity_enum_set(&graph->ent_enum, pad->entity);
 
 	graph->top = 0;
 	graph->stack[graph->top].entity = NULL;
-	stack_push(graph, entity);
-	dev_dbg(entity->graph_obj.mdev->dev,
-		"begin graph walk at '%s'\n", entity->name);
+	stack_push(graph, pad->entity);
+	dev_dbg(pad->graph_obj.mdev->dev,
+		"begin graph walk at '%s':%u\n", pad->entity->name, pad->index);
 }
 EXPORT_SYMBOL_GPL(media_graph_walk_start);
 
@@ -428,7 +427,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 			goto error_graph_walk_start;
 	}
 
-	media_graph_walk_start(&pipe->graph, entity);
+	media_graph_walk_start(&pipe->graph, entity->pads);
 
 	while ((entity = media_graph_walk_next(graph))) {
 		DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
@@ -509,7 +508,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 	 * Link validation on graph failed. We revert what we did and
 	 * return the error.
 	 */
-	media_graph_walk_start(graph, entity_err);
+	media_graph_walk_start(graph, entity_err->pads);
 
 	while ((entity_err = media_graph_walk_next(graph))) {
 		/* Sanity check for negative stream_count */
@@ -560,7 +559,7 @@ void __media_pipeline_stop(struct media_entity *entity)
 	if (WARN_ON(!pipe))
 		return;
 
-	media_graph_walk_start(graph, entity);
+	media_graph_walk_start(graph, entity->pads);
 
 	while ((entity = media_graph_walk_next(graph))) {
 		/* Sanity check for negative stream_count */
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 870501b0f351addb..51d2a571c06db6a3 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -1144,7 +1144,7 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
 	 * through active links. This is needed as we cannot power on/off the
 	 * subdevs in random order.
 	 */
-	media_graph_walk_start(graph, entity);
+	media_graph_walk_start(graph, entity->pads);
 
 	while ((entity = media_graph_walk_next(graph))) {
 		if (!is_media_entity_v4l2_video_device(entity))
@@ -1159,7 +1159,7 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
 	return 0;
 
 err:
-	media_graph_walk_start(graph, entity_err);
+	media_graph_walk_start(graph, entity_err->pads);
 
 	while ((entity_err = media_graph_walk_next(graph))) {
 		if (!is_media_entity_v4l2_video_device(entity_err))
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 5658f6a326f77f66..50ad35bc644eae29 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -238,7 +238,7 @@ static int isp_video_get_graph_data(struct isp_video *video,
 		return ret;
 	}
 
-	media_graph_walk_start(&graph, entity);
+	media_graph_walk_start(&graph, entity->pads);
 
 	while ((entity = media_graph_walk_next(&graph))) {
 		struct isp_video *__video;
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 771dfe1f7c20e526..e35b2e2340b82f00 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -580,7 +580,7 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
 	if (ret)
 		return ret;
 
-	media_graph_walk_start(&graph, entity);
+	media_graph_walk_start(&graph, entity->pads);
 
 	while ((entity = media_graph_walk_next(&graph))) {
 		struct v4l2_subdev *subdev;
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index 4ae9d38c94332fa4..566c2d0fb97dc162 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -193,7 +193,7 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
 		return ret;
 	}
 
-	media_graph_walk_start(&graph, entity);
+	media_graph_walk_start(&graph, entity->pads);
 
 	while ((entity = media_graph_walk_next(&graph))) {
 		struct xvip_dma *dma;
diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
index 014a2a97cadd8706..9ed480fe5b6e4762 100644
--- a/drivers/media/v4l2-core/v4l2-mc.c
+++ b/drivers/media/v4l2-core/v4l2-mc.c
@@ -341,7 +341,7 @@ static int pipeline_pm_use_count(struct media_entity *entity,
 {
 	int use = 0;
 
-	media_graph_walk_start(graph, entity);
+	media_graph_walk_start(graph, entity->pads);
 
 	while ((entity = media_graph_walk_next(graph))) {
 		if (is_media_entity_v4l2_video_device(entity))
@@ -404,7 +404,7 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
 	if (!change)
 		return 0;
 
-	media_graph_walk_start(graph, entity);
+	media_graph_walk_start(graph, entity->pads);
 
 	while (!ret && (entity = media_graph_walk_next(graph)))
 		if (is_media_entity_v4l2_subdev(entity))
@@ -413,7 +413,7 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
 	if (!ret)
 		return ret;
 
-	media_graph_walk_start(graph, first);
+	media_graph_walk_start(graph, first->pads);
 
 	while ((first = media_graph_walk_next(graph))
 	       && first != entity)
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index 5e42490331b7620f..912d93fc7a483cd4 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -150,7 +150,7 @@ static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
 		mutex_unlock(&mdev->graph_mutex);
 		return -ENOMEM;
 	}
-	media_graph_walk_start(&graph, entity);
+	media_graph_walk_start(&graph, entity->pads);
 	while ((entity = media_graph_walk_next(&graph))) {
 		if (entity == &video->video_dev.entity)
 			continue;
@@ -303,7 +303,7 @@ static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
 	ret = media_graph_walk_init(&pipe->graph, mdev);
 	if (ret)
 		goto out;
-	media_graph_walk_start(&pipe->graph, entity);
+	media_graph_walk_start(&pipe->graph, entity->pads);
 	while ((entity = media_graph_walk_next(&pipe->graph))) {
 
 		if (!is_media_entity_v4l2_subdev(entity))
@@ -345,7 +345,7 @@ static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
 
 	mdev = entity->graph_obj.mdev;
 	mutex_lock(&mdev->graph_mutex);
-	media_graph_walk_start(&pipe->graph, entity);
+	media_graph_walk_start(&pipe->graph, entity->pads);
 
 	while ((entity = media_graph_walk_next(&pipe->graph))) {
 
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index c1322aeaf01eb951..6f72c02c8054f496 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -217,7 +217,7 @@ iss_video_far_end(struct iss_video *video)
 		return NULL;
 	}
 
-	media_graph_walk_start(&graph, entity);
+	media_graph_walk_start(&graph, entity->pads);
 
 	while ((entity = media_graph_walk_next(&graph))) {
 		if (entity == &video->video.entity)
@@ -897,7 +897,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 	if (ret < 0)
 		goto err_media_pipeline_start;
 
-	media_graph_walk_start(&graph, entity);
+	media_graph_walk_start(&graph, entity->pads);
 	while ((entity = media_graph_walk_next(&graph)))
 		media_entity_enum_set(&pipe->ent_enum, entity);
 
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index e5f6960d92f6cdd4..07ab141e739ef5ff 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -928,22 +928,20 @@ void media_graph_walk_cleanup(struct media_graph *graph);
 void media_entity_put(struct media_entity *entity);
 
 /**
- * media_graph_walk_start - Start walking the media graph at a
- *	given entity
+ * media_graph_walk_start - Start walking the media graph at a given pad
  *
  * @graph: Media graph structure that will be used to walk the graph
- * @entity: Starting entity
+ * @pad: Starting pad
  *
  * Before using this function, media_graph_walk_init() must be
  * used to allocate resources used for walking the graph. This
  * function initializes the graph traversal structure to walk the
- * entities graph starting at the given entity. The traversal
+ * entities graph starting at the given pad. The traversal
  * structure must not be modified by the caller during graph
  * traversal. After the graph walk, the resources must be released
  * using media_graph_walk_cleanup().
  */
-void media_graph_walk_start(struct media_graph *graph,
-			    struct media_entity *entity);
+void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad);
 
 /**
  * media_graph_walk_next - Get the next entity in the graph
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 02/30] media: entity: Use pads instead of entities in the media graph walk stack
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 01/30] media: entity: Use pad as a starting point for graph walk Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 22:03   ` Laurent Pinchart
  2019-01-15 22:07   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 03/30] media: entity: Walk the graph based on pads Niklas Söderlund
                   ` (28 subsequent siblings)
  30 siblings, 2 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

Change the media graph walk stack structure to use media pads instead of
using media entities. In addition to the entity, the pad contains the
information which pad in the entity are being dealt with.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/media-entity.c | 53 ++++++++++++++++++------------------
 include/media/media-entity.h |  6 ++--
 2 files changed, 29 insertions(+), 30 deletions(-)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 2bbc07de71aa5e6d..892e64a0a9d8ec42 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -237,40 +237,39 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init);
  * Graph traversal
  */
 
-static struct media_entity *
-media_entity_other(struct media_entity *entity, struct media_link *link)
+static struct media_pad *
+media_entity_other(struct media_pad *pad, struct media_link *link)
 {
-	if (link->source->entity == entity)
-		return link->sink->entity;
+	if (link->source == pad)
+		return link->sink;
 	else
-		return link->source->entity;
+		return link->source;
 }
 
 /* push an entity to traversal stack */
-static void stack_push(struct media_graph *graph,
-		       struct media_entity *entity)
+static void stack_push(struct media_graph *graph, struct media_pad *pad)
 {
 	if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
 		WARN_ON(1);
 		return;
 	}
 	graph->top++;
-	graph->stack[graph->top].link = entity->links.next;
-	graph->stack[graph->top].entity = entity;
+	graph->stack[graph->top].link = pad->entity->links.next;
+	graph->stack[graph->top].pad = pad;
 }
 
-static struct media_entity *stack_pop(struct media_graph *graph)
+static struct media_pad *stack_pop(struct media_graph *graph)
 {
-	struct media_entity *entity;
+	struct media_pad *pad;
 
-	entity = graph->stack[graph->top].entity;
+	pad = graph->stack[graph->top].pad;
 	graph->top--;
 
-	return entity;
+	return pad;
 }
 
 #define link_top(en)	((en)->stack[(en)->top].link)
-#define stack_top(en)	((en)->stack[(en)->top].entity)
+#define stack_top(en)	((en)->stack[(en)->top].pad)
 
 /**
  * media_graph_walk_init - Allocate resources for graph walk
@@ -306,8 +305,8 @@ void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad)
 	media_entity_enum_set(&graph->ent_enum, pad->entity);
 
 	graph->top = 0;
-	graph->stack[graph->top].entity = NULL;
-	stack_push(graph, pad->entity);
+	graph->stack[graph->top].pad = NULL;
+	stack_push(graph, pad);
 	dev_dbg(pad->graph_obj.mdev->dev,
 		"begin graph walk at '%s':%u\n", pad->entity->name, pad->index);
 }
@@ -315,16 +314,16 @@ EXPORT_SYMBOL_GPL(media_graph_walk_start);
 
 static void media_graph_walk_iter(struct media_graph *graph)
 {
-	struct media_entity *entity = stack_top(graph);
+	struct media_pad *pad = stack_top(graph);
 	struct media_link *link;
-	struct media_entity *next;
+	struct media_pad *next;
 
 	link = list_entry(link_top(graph), typeof(*link), list);
 
 	/* The link is not enabled so we do not follow. */
 	if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
 		link_top(graph) = link_top(graph)->next;
-		dev_dbg(entity->graph_obj.mdev->dev,
+		dev_dbg(pad->graph_obj.mdev->dev,
 			"walk: skipping disabled link '%s':%u -> '%s':%u\n",
 			link->source->entity->name, link->source->index,
 			link->sink->entity->name, link->sink->index);
@@ -332,22 +331,22 @@ static void media_graph_walk_iter(struct media_graph *graph)
 	}
 
 	/* Get the entity in the other end of the link . */
-	next = media_entity_other(entity, link);
+	next = media_entity_other(pad, link);
 
 	/* Has the entity already been visited? */
-	if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
+	if (media_entity_enum_test_and_set(&graph->ent_enum, next->entity)) {
 		link_top(graph) = link_top(graph)->next;
-		dev_dbg(entity->graph_obj.mdev->dev,
+		dev_dbg(pad->graph_obj.mdev->dev,
 			"walk: skipping entity '%s' (already seen)\n",
-			next->name);
+			next->entity->name);
 		return;
 	}
 
 	/* Push the new entity to stack and start over. */
 	link_top(graph) = link_top(graph)->next;
 	stack_push(graph, next);
-	dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n",
-		next->name);
+	dev_dbg(next->graph_obj.mdev->dev, "walk: pushing '%s':%u on stack\n",
+		next->entity->name, next->index);
 }
 
 struct media_entity *media_graph_walk_next(struct media_graph *graph)
@@ -362,10 +361,10 @@ struct media_entity *media_graph_walk_next(struct media_graph *graph)
 	 * top of the stack until no more entities on the level can be
 	 * found.
 	 */
-	while (link_top(graph) != &stack_top(graph)->links)
+	while (link_top(graph) != &stack_top(graph)->entity->links)
 		media_graph_walk_iter(graph);
 
-	entity = stack_pop(graph);
+	entity = stack_pop(graph)->entity;
 	dev_dbg(entity->graph_obj.mdev->dev,
 		"walk: returning entity '%s'\n", entity->name);
 
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 07ab141e739ef5ff..99c7606f01317741 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -86,16 +86,16 @@ struct media_entity_enum {
  * struct media_graph - Media graph traversal state
  *
  * @stack:		Graph traversal stack; the stack contains information
- *			on the path the media entities to be walked and the
+ *			on the path the media pads to be walked and the
  *			links through which they were reached.
- * @stack.entity:	pointer to &struct media_entity at the graph.
+ * @stack.pad:		pointer to &struct media_pad at the graph.
  * @stack.link:		pointer to &struct list_head.
  * @ent_enum:		Visited entities
  * @top:		The top of the stack
  */
 struct media_graph {
 	struct {
-		struct media_entity *entity;
+		struct media_pad *pad;
 		struct list_head *link;
 	} stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
 
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 03/30] media: entity: Walk the graph based on pads
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 01/30] media: entity: Use pad as a starting point for graph walk Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 02/30] media: entity: Use pads instead of entities in the media graph walk stack Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 22:21   ` Laurent Pinchart
  2019-02-14 15:15   ` Jacopo Mondi
  2018-11-01 23:31 ` [PATCH v2 04/30] v4l: mc: Start walk from a specific pad in use count calculation Niklas Söderlund
                   ` (27 subsequent siblings)
  30 siblings, 2 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

Instead of iterating over graph entities during the walk, iterate the pads
through which the entity was first reached. This is required in order to
make the entity pipeline pad-based rather than entity based.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 Documentation/media/kapi/mc-core.rst          |  7 ++-
 drivers/media/media-entity.c                  | 46 ++++++++++--------
 drivers/media/platform/exynos4-is/media-dev.c | 20 ++++----
 drivers/media/platform/omap3isp/ispvideo.c    | 17 +++----
 drivers/media/platform/vsp1/vsp1_video.c      | 12 ++---
 drivers/media/platform/xilinx/xilinx-dma.c    | 12 ++---
 drivers/media/v4l2-core/v4l2-mc.c             | 25 +++++-----
 .../staging/media/davinci_vpfe/vpfe_video.c   | 47 ++++++++++---------
 drivers/staging/media/omap4iss/iss_video.c    | 34 +++++++-------
 include/media/media-entity.h                  |  7 +--
 10 files changed, 122 insertions(+), 105 deletions(-)

diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
index 27aefb9a778b2ad6..849b87439b7a9772 100644
--- a/Documentation/media/kapi/mc-core.rst
+++ b/Documentation/media/kapi/mc-core.rst
@@ -167,8 +167,11 @@ Drivers initiate a graph traversal by calling
 The graph structure, provided by the caller, is initialized to start graph
 traversal at the given pad in an entity.
 
-Drivers can then retrieve the next entity by calling
-:c:func:`media_graph_walk_next()`
+Drivers can then retrieve the next pad by calling
+:c:func:`media_graph_walk_next()`. Only the pad through which the entity
+is first reached is returned. If the caller is interested in knowing which
+further pads would be connected, the :c:func:`media_entity_has_route()`
+function can be used for that.
 
 When the graph traversal is complete the function will return ``NULL``.
 
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 892e64a0a9d8ec42..70db03fa33a21db1 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -349,9 +349,9 @@ static void media_graph_walk_iter(struct media_graph *graph)
 		next->entity->name, next->index);
 }
 
-struct media_entity *media_graph_walk_next(struct media_graph *graph)
+struct media_pad *media_graph_walk_next(struct media_graph *graph)
 {
-	struct media_entity *entity;
+	struct media_pad *pad;
 
 	if (stack_top(graph) == NULL)
 		return NULL;
@@ -364,11 +364,11 @@ struct media_entity *media_graph_walk_next(struct media_graph *graph)
 	while (link_top(graph) != &stack_top(graph)->entity->links)
 		media_graph_walk_iter(graph);
 
-	entity = stack_pop(graph)->entity;
-	dev_dbg(entity->graph_obj.mdev->dev,
-		"walk: returning entity '%s'\n", entity->name);
+	pad = stack_pop(graph);
+	dev_dbg(pad->graph_obj.mdev->dev,
+		"walk: returning pad '%s':%u\n", pad->entity->name, pad->index);
 
-	return entity;
+	return pad;
 }
 EXPORT_SYMBOL_GPL(media_graph_walk_next);
 
@@ -416,7 +416,8 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 {
 	struct media_device *mdev = entity->graph_obj.mdev;
 	struct media_graph *graph = &pipe->graph;
-	struct media_entity *entity_err = entity;
+	struct media_pad *pad = entity->pads;
+	struct media_pad *pad_err = pad;
 	struct media_link *link;
 	int ret;
 
@@ -426,9 +427,11 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 			goto error_graph_walk_start;
 	}
 
-	media_graph_walk_start(&pipe->graph, entity->pads);
+	media_graph_walk_start(&pipe->graph, pad);
+
+	while ((pad = media_graph_walk_next(graph))) {
+		struct media_entity *entity = pad->entity;
 
-	while ((entity = media_graph_walk_next(graph))) {
 		DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
 		DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
 
@@ -452,11 +455,11 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 		bitmap_fill(has_no_links, entity->num_pads);
 
 		list_for_each_entry(link, &entity->links, list) {
-			struct media_pad *pad = link->sink->entity == entity
-						? link->sink : link->source;
+			struct media_pad *other_pad = link->sink->entity == entity
+				? link->sink : link->source;
 
 			/* Mark that a pad is connected by a link. */
-			bitmap_clear(has_no_links, pad->index, 1);
+			bitmap_clear(has_no_links, other_pad->index, 1);
 
 			/*
 			 * Pads that either do not need to connect or
@@ -465,13 +468,13 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 			 */
 			if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) ||
 			    link->flags & MEDIA_LNK_FL_ENABLED)
-				bitmap_set(active, pad->index, 1);
+				bitmap_set(active, other_pad->index, 1);
 
 			/*
 			 * Link validation will only take place for
 			 * sink ends of the link that are enabled.
 			 */
-			if (link->sink != pad ||
+			if (link->sink != other_pad ||
 			    !(link->flags & MEDIA_LNK_FL_ENABLED))
 				continue;
 
@@ -507,9 +510,11 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 	 * Link validation on graph failed. We revert what we did and
 	 * return the error.
 	 */
-	media_graph_walk_start(graph, entity_err->pads);
+	media_graph_walk_start(graph, pad_err);
+
+	while ((pad_err = media_graph_walk_next(graph))) {
+		struct media_entity *entity_err = pad_err->entity;
 
-	while ((entity_err = media_graph_walk_next(graph))) {
 		/* Sanity check for negative stream_count */
 		if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) {
 			entity_err->stream_count--;
@@ -521,7 +526,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 		 * We haven't increased stream_count further than this
 		 * so we quit here.
 		 */
-		if (entity_err == entity)
+		if (pad_err == pad)
 			break;
 	}
 
@@ -548,8 +553,9 @@ EXPORT_SYMBOL_GPL(media_pipeline_start);
 
 void __media_pipeline_stop(struct media_entity *entity)
 {
-	struct media_graph *graph = &entity->pipe->graph;
 	struct media_pipeline *pipe = entity->pipe;
+	struct media_graph *graph = &pipe->graph;
+	struct media_pad *pad;
 
 	/*
 	 * If the following check fails, the driver has performed an
@@ -560,7 +566,9 @@ void __media_pipeline_stop(struct media_entity *entity)
 
 	media_graph_walk_start(graph, entity->pads);
 
-	while ((entity = media_graph_walk_next(graph))) {
+	while ((pad = media_graph_walk_next(graph))) {
+		struct media_entity *entity = pad->entity;
+
 		/* Sanity check for negative stream_count */
 		if (!WARN_ON_ONCE(entity->stream_count <= 0)) {
 			entity->stream_count--;
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 51d2a571c06db6a3..5813639c63b56a2c 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -1135,7 +1135,7 @@ static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable)
 static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
 				      struct media_graph *graph)
 {
-	struct media_entity *entity_err = entity;
+	struct media_pad *pad, *pad_err = entity->pads;
 	int ret;
 
 	/*
@@ -1144,13 +1144,13 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
 	 * through active links. This is needed as we cannot power on/off the
 	 * subdevs in random order.
 	 */
-	media_graph_walk_start(graph, entity->pads);
+	media_graph_walk_start(graph, pad_err);
 
-	while ((entity = media_graph_walk_next(graph))) {
-		if (!is_media_entity_v4l2_video_device(entity))
+	while ((pad = media_graph_walk_next(graph))) {
+		if (!is_media_entity_v4l2_video_device(pad->entity))
 			continue;
 
-		ret  = __fimc_md_modify_pipeline(entity, enable);
+		ret  = __fimc_md_modify_pipeline(pad->entity, enable);
 
 		if (ret < 0)
 			goto err;
@@ -1159,15 +1159,15 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
 	return 0;
 
 err:
-	media_graph_walk_start(graph, entity_err->pads);
+	media_graph_walk_start(graph, pad_err);
 
-	while ((entity_err = media_graph_walk_next(graph))) {
-		if (!is_media_entity_v4l2_video_device(entity_err))
+	while ((pad_err = media_graph_walk_next(graph))) {
+		if (!is_media_entity_v4l2_video_device(pad_err->entity))
 			continue;
 
-		__fimc_md_modify_pipeline(entity_err, !enable);
+		__fimc_md_modify_pipeline(pad_err->entity, !enable);
 
-		if (entity_err == entity)
+		if (pad_err == pad)
 			break;
 	}
 
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 50ad35bc644eae29..dc11b732dc05b00b 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -226,8 +226,8 @@ static int isp_video_get_graph_data(struct isp_video *video,
 				    struct isp_pipeline *pipe)
 {
 	struct media_graph graph;
-	struct media_entity *entity = &video->video.entity;
-	struct media_device *mdev = entity->graph_obj.mdev;
+	struct media_pad *pad = video->video.entity.pads;
+	struct media_device *mdev = pad->entity->graph_obj.mdev;
 	struct isp_video *far_end = NULL;
 	int ret;
 
@@ -238,23 +238,24 @@ static int isp_video_get_graph_data(struct isp_video *video,
 		return ret;
 	}
 
-	media_graph_walk_start(&graph, entity->pads);
+	media_graph_walk_start(&graph, pad);
 
-	while ((entity = media_graph_walk_next(&graph))) {
+	while ((pad = media_graph_walk_next(&graph))) {
 		struct isp_video *__video;
 
-		media_entity_enum_set(&pipe->ent_enum, entity);
+		media_entity_enum_set(&pipe->ent_enum, pad->entity);
 
 		if (far_end != NULL)
 			continue;
 
-		if (entity == &video->video.entity)
+		if (pad == video->video.entity.pads)
 			continue;
 
-		if (!is_media_entity_v4l2_video_device(entity))
+		if (!is_media_entity_v4l2_video_device(pad->entity))
 			continue;
 
-		__video = to_isp_video(media_entity_to_video_device(entity));
+		__video = to_isp_video(media_entity_to_video_device(
+					       pad->entity));
 		if (__video->type != video->type)
 			far_end = __video;
 	}
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index e35b2e2340b82f00..806825bd3484167a 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -570,8 +570,8 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
 				     struct vsp1_video *video)
 {
 	struct media_graph graph;
-	struct media_entity *entity = &video->video.entity;
-	struct media_device *mdev = entity->graph_obj.mdev;
+	struct media_pad *pad = video->video.entity.pads;
+	struct media_device *mdev = pad->entity->graph_obj.mdev;
 	unsigned int i;
 	int ret;
 
@@ -580,17 +580,17 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
 	if (ret)
 		return ret;
 
-	media_graph_walk_start(&graph, entity->pads);
+	media_graph_walk_start(&graph, pad);
 
-	while ((entity = media_graph_walk_next(&graph))) {
+	while ((pad = media_graph_walk_next(&graph))) {
 		struct v4l2_subdev *subdev;
 		struct vsp1_rwpf *rwpf;
 		struct vsp1_entity *e;
 
-		if (!is_media_entity_v4l2_subdev(entity))
+		if (!is_media_entity_v4l2_subdev(pad->entity))
 			continue;
 
-		subdev = media_entity_to_v4l2_subdev(entity);
+		subdev = media_entity_to_v4l2_subdev(pad->entity);
 		e = to_vsp1_entity(subdev);
 		list_add_tail(&e->list_pipe, &pipe->entities);
 		e->pipe = pipe;
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index 566c2d0fb97dc162..a2a329336243bdc7 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -178,8 +178,8 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
 				  struct xvip_dma *start)
 {
 	struct media_graph graph;
-	struct media_entity *entity = &start->video.entity;
-	struct media_device *mdev = entity->graph_obj.mdev;
+	struct media_pad *pad = start->video.entity.pads;
+	struct media_device *mdev = pad->entity->graph_obj.mdev;
 	unsigned int num_inputs = 0;
 	unsigned int num_outputs = 0;
 	int ret;
@@ -193,15 +193,15 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
 		return ret;
 	}
 
-	media_graph_walk_start(&graph, entity->pads);
+	media_graph_walk_start(&graph, pad);
 
-	while ((entity = media_graph_walk_next(&graph))) {
+	while ((pad = media_graph_walk_next(&graph))) {
 		struct xvip_dma *dma;
 
-		if (entity->function != MEDIA_ENT_F_IO_V4L)
+		if (pad->entity->function != MEDIA_ENT_F_IO_V4L)
 			continue;
 
-		dma = to_xvip_dma(media_entity_to_video_device(entity));
+		dma = to_xvip_dma(media_entity_to_video_device(pad->entity));
 
 		if (dma->pad.flags & MEDIA_PAD_FL_SINK) {
 			pipe->output = dma;
diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
index 9ed480fe5b6e4762..98edd47b2f0ae747 100644
--- a/drivers/media/v4l2-core/v4l2-mc.c
+++ b/drivers/media/v4l2-core/v4l2-mc.c
@@ -339,13 +339,14 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
 static int pipeline_pm_use_count(struct media_entity *entity,
 	struct media_graph *graph)
 {
+	struct media_pad *pad;
 	int use = 0;
 
 	media_graph_walk_start(graph, entity->pads);
 
-	while ((entity = media_graph_walk_next(graph))) {
-		if (is_media_entity_v4l2_video_device(entity))
-			use += entity->use_count;
+	while ((pad = media_graph_walk_next(graph))) {
+		if (is_media_entity_v4l2_video_device(pad->entity))
+			use += pad->entity->use_count;
 	}
 
 	return use;
@@ -398,7 +399,7 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
 static int pipeline_pm_power(struct media_entity *entity, int change,
 	struct media_graph *graph)
 {
-	struct media_entity *first = entity;
+	struct media_pad *tmp_pad, *pad;
 	int ret = 0;
 
 	if (!change)
@@ -406,19 +407,19 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
 
 	media_graph_walk_start(graph, entity->pads);
 
-	while (!ret && (entity = media_graph_walk_next(graph)))
-		if (is_media_entity_v4l2_subdev(entity))
-			ret = pipeline_pm_power_one(entity, change);
+	while (!ret && (pad = media_graph_walk_next(graph)))
+		if (is_media_entity_v4l2_subdev(pad->entity))
+			ret = pipeline_pm_power_one(pad->entity, change);
 
 	if (!ret)
 		return ret;
 
-	media_graph_walk_start(graph, first->pads);
+	media_graph_walk_start(graph, entity->pads);
 
-	while ((first = media_graph_walk_next(graph))
-	       && first != entity)
-		if (is_media_entity_v4l2_subdev(first))
-			pipeline_pm_power_one(first, -change);
+	while ((tmp_pad = media_graph_walk_next(graph))
+	       && tmp_pad != pad)
+		if (is_media_entity_v4l2_subdev(tmp_pad->entity))
+			pipeline_pm_power_one(tmp_pad->entity, -change);
 
 	return ret;
 }
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index 912d93fc7a483cd4..5219a0372d140f4a 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -130,8 +130,8 @@ __vpfe_video_get_format(struct vpfe_video_device *video,
 static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
 {
 	struct media_graph graph;
-	struct media_entity *entity = &video->video_dev.entity;
-	struct media_device *mdev = entity->graph_obj.mdev;
+	struct media_pad *pad = video->video_dev.entity.pads;
+	struct media_device *mdev = pad->entity->graph_obj.mdev;
 	struct vpfe_pipeline *pipe = &video->pipe;
 	struct vpfe_video_device *far_end = NULL;
 	int ret;
@@ -150,13 +150,14 @@ static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
 		mutex_unlock(&mdev->graph_mutex);
 		return -ENOMEM;
 	}
-	media_graph_walk_start(&graph, entity->pads);
-	while ((entity = media_graph_walk_next(&graph))) {
-		if (entity == &video->video_dev.entity)
+	media_graph_walk_start(&graph, pad);
+	while ((pad = media_graph_walk_next(&graph))) {
+		if (pad->entity == &video->video_dev.entity)
 			continue;
-		if (!is_media_entity_v4l2_video_device(entity))
+		if (!is_media_entity_v4l2_video_device(pad->entity))
 			continue;
-		far_end = to_vpfe_video(media_entity_to_video_device(entity));
+		far_end = to_vpfe_video(media_entity_to_video_device(
+						pad->entity));
 		if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
 			pipe->inputs[pipe->input_num++] = far_end;
 		else
@@ -288,27 +289,27 @@ static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe)
  */
 static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
 {
-	struct media_entity *entity;
+	struct media_pad *pad;
 	struct v4l2_subdev *subdev;
 	struct media_device *mdev;
 	int ret;
 
 	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
-		entity = vpfe_get_input_entity(pipe->outputs[0]);
+		pad = vpfe_get_input_entity(pipe->outputs[0])->pads;
 	else
-		entity = &pipe->inputs[0]->video_dev.entity;
+		pad = pipe->inputs[0]->video_dev.entity.pads;
 
-	mdev = entity->graph_obj.mdev;
+	mdev = pad->graph_obj.mdev;
 	mutex_lock(&mdev->graph_mutex);
 	ret = media_graph_walk_init(&pipe->graph, mdev);
 	if (ret)
 		goto out;
-	media_graph_walk_start(&pipe->graph, entity->pads);
-	while ((entity = media_graph_walk_next(&pipe->graph))) {
+	media_graph_walk_start(&pipe->graph, pad);
+	while ((pad = media_graph_walk_next(&pipe->graph))) {
 
-		if (!is_media_entity_v4l2_subdev(entity))
+		if (!is_media_entity_v4l2_subdev(pad->entity))
 			continue;
-		subdev = media_entity_to_v4l2_subdev(entity);
+		subdev = media_entity_to_v4l2_subdev(pad->entity);
 		ret = v4l2_subdev_call(subdev, video, s_stream, 1);
 		if (ret < 0 && ret != -ENOIOCTLCMD)
 			break;
@@ -333,25 +334,25 @@ static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
  */
 static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
 {
-	struct media_entity *entity;
+	struct media_pad *pad;
 	struct v4l2_subdev *subdev;
 	struct media_device *mdev;
 	int ret = 0;
 
 	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
-		entity = vpfe_get_input_entity(pipe->outputs[0]);
+		pad = vpfe_get_input_entity(pipe->outputs[0])->pads;
 	else
-		entity = &pipe->inputs[0]->video_dev.entity;
+		pad = pipe->inputs[0]->video_dev.entity.pads;
 
-	mdev = entity->graph_obj.mdev;
+	mdev = pad->graph_obj.mdev;
 	mutex_lock(&mdev->graph_mutex);
-	media_graph_walk_start(&pipe->graph, entity->pads);
+	media_graph_walk_start(&pipe->graph, pad);
 
-	while ((entity = media_graph_walk_next(&pipe->graph))) {
+	while ((pad = media_graph_walk_next(&pipe->graph))) {
 
-		if (!is_media_entity_v4l2_subdev(entity))
+		if (!is_media_entity_v4l2_subdev(pad->entity))
 			continue;
-		subdev = media_entity_to_v4l2_subdev(entity);
+		subdev = media_entity_to_v4l2_subdev(pad->entity);
 		ret = v4l2_subdev_call(subdev, video, s_stream, 0);
 		if (ret < 0 && ret != -ENOIOCTLCMD)
 			break;
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 6f72c02c8054f496..1271bbacf9e7bdeb 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -206,8 +206,8 @@ static struct iss_video *
 iss_video_far_end(struct iss_video *video)
 {
 	struct media_graph graph;
-	struct media_entity *entity = &video->video.entity;
-	struct media_device *mdev = entity->graph_obj.mdev;
+	struct media_pad *pad = video->video.entity.pads;
+	struct media_device *mdev = pad->entity->graph_obj.mdev;
 	struct iss_video *far_end = NULL;
 
 	mutex_lock(&mdev->graph_mutex);
@@ -217,16 +217,17 @@ iss_video_far_end(struct iss_video *video)
 		return NULL;
 	}
 
-	media_graph_walk_start(&graph, entity->pads);
+	media_graph_walk_start(&graph, pad);
 
-	while ((entity = media_graph_walk_next(&graph))) {
-		if (entity == &video->video.entity)
+	while ((pad = media_graph_walk_next(&graph))) {
+		if (pad->entity == &video->video.entity)
 			continue;
 
-		if (!is_media_entity_v4l2_video_device(entity))
+		if (!is_media_entity_v4l2_video_device(pad->entity))
 			continue;
 
-		far_end = to_iss_video(media_entity_to_video_device(entity));
+		far_end = to_iss_video(media_entity_to_video_device(
+						pad->entity));
 		if (far_end->type != video->type)
 			break;
 
@@ -860,7 +861,7 @@ 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_graph graph;
-	struct media_entity *entity = &video->video.entity;
+	struct media_pad *pad = video->video.entity.pads;
 	enum iss_pipeline_state state;
 	struct iss_pipeline *pipe;
 	struct iss_video *far_end;
@@ -876,30 +877,31 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 	 * Start streaming on the pipeline. No link touching an entity in the
 	 * pipeline can be activated or deactivated once streaming is started.
 	 */
-	pipe = entity->pipe
-	     ? to_iss_pipeline(entity) : &video->pipe;
+	pipe = pad->entity->pipe
+	     ? to_iss_pipeline(pad->entity) : &video->pipe;
 	pipe->external = NULL;
 	pipe->external_rate = 0;
 	pipe->external_bpp = 0;
 
-	ret = media_entity_enum_init(&pipe->ent_enum, entity->graph_obj.mdev);
+	ret = media_entity_enum_init(&pipe->ent_enum,
+				     pad->entity->graph_obj.mdev);
 	if (ret)
 		goto err_graph_walk_init;
 
-	ret = media_graph_walk_init(&graph, entity->graph_obj.mdev);
+	ret = media_graph_walk_init(&graph, pad->entity->graph_obj.mdev);
 	if (ret)
 		goto err_graph_walk_init;
 
 	if (video->iss->pdata->set_constraints)
 		video->iss->pdata->set_constraints(video->iss, true);
 
-	ret = media_pipeline_start(entity, &pipe->pipe);
+	ret = media_pipeline_start(pad->entity, &pipe->pipe);
 	if (ret < 0)
 		goto err_media_pipeline_start;
 
-	media_graph_walk_start(&graph, entity->pads);
-	while ((entity = media_graph_walk_next(&graph)))
-		media_entity_enum_set(&pipe->ent_enum, entity);
+	media_graph_walk_start(&graph, pad);
+	while ((pad = media_graph_walk_next(&graph)))
+		media_entity_enum_set(&pipe->ent_enum, pad->entity);
 
 	/*
 	 * Verify that the currently configured format matches the output of
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 99c7606f01317741..cde6350d752bb0ae 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -952,10 +952,11 @@ void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad);
  * The graph structure must have been previously initialized with a call to
  * media_graph_walk_start().
  *
- * Return: returns the next entity in the graph or %NULL if the whole graph
- * have been traversed.
+ * Return: returns the next pad in the graph or %NULL if the whole
+ * graph have been traversed. The pad which is returned is the pad
+ * through which a new entity is reached when parsing the graph.
  */
-struct media_entity *media_graph_walk_next(struct media_graph *graph);
+struct media_pad *media_graph_walk_next(struct media_graph *graph);
 
 /**
  * media_pipeline_start - Mark a pipeline as streaming
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 04/30] v4l: mc: Start walk from a specific pad in use count calculation
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (2 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 03/30] media: entity: Walk the graph based on pads Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 22:24   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 05/30] media: entity: Move the pipeline from entity to pads Niklas Söderlund
                   ` (26 subsequent siblings)
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

With the addition of the recent has_route() media entity op, the pads of a
media entity are no longer all interconnected. This has to be taken into
account in power management.

Prepare for the addition of a helper function supporting S_ROUTING.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/v4l2-core/v4l2-mc.c | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
index 98edd47b2f0ae747..208cd91ce57ff211 100644
--- a/drivers/media/v4l2-core/v4l2-mc.c
+++ b/drivers/media/v4l2-core/v4l2-mc.c
@@ -332,17 +332,16 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
 
 /*
  * pipeline_pm_use_count - Count the number of users of a pipeline
- * @entity: The entity
+ * @pad: The pad
  *
  * Return the total number of users of all video device nodes in the pipeline.
  */
-static int pipeline_pm_use_count(struct media_entity *entity,
-	struct media_graph *graph)
+static int pipeline_pm_use_count(struct media_pad *pad,
+				 struct media_graph *graph)
 {
-	struct media_pad *pad;
 	int use = 0;
 
-	media_graph_walk_start(graph, entity->pads);
+	media_graph_walk_start(graph, pad);
 
 	while ((pad = media_graph_walk_next(graph))) {
 		if (is_media_entity_v4l2_video_device(pad->entity))
@@ -388,7 +387,7 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
 
 /*
  * pipeline_pm_power - Apply power change to all entities in a pipeline
- * @entity: The entity
+ * @pad: The pad
  * @change: Use count change
  *
  * Walk the pipeline to update the use count and the power state of all non-node
@@ -396,16 +395,16 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
  *
  * Return 0 on success or a negative error code on failure.
  */
-static int pipeline_pm_power(struct media_entity *entity, int change,
+static int pipeline_pm_power(struct media_pad *pad, int change,
 	struct media_graph *graph)
 {
-	struct media_pad *tmp_pad, *pad;
+	struct media_pad *tmp_pad, *first = pad;
 	int ret = 0;
 
 	if (!change)
 		return 0;
 
-	media_graph_walk_start(graph, entity->pads);
+	media_graph_walk_start(graph, pad);
 
 	while (!ret && (pad = media_graph_walk_next(graph)))
 		if (is_media_entity_v4l2_subdev(pad->entity))
@@ -414,7 +413,7 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
 	if (!ret)
 		return ret;
 
-	media_graph_walk_start(graph, entity->pads);
+	media_graph_walk_start(graph, first);
 
 	while ((tmp_pad = media_graph_walk_next(graph))
 	       && tmp_pad != pad)
@@ -437,7 +436,7 @@ int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
 	WARN_ON(entity->use_count < 0);
 
 	/* Apply power change to connected non-nodes. */
-	ret = pipeline_pm_power(entity, change, &mdev->pm_count_walk);
+	ret = pipeline_pm_power(entity->pads, change, &mdev->pm_count_walk);
 	if (ret < 0)
 		entity->use_count -= change;
 
@@ -451,8 +450,8 @@ int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
 			      unsigned int notification)
 {
 	struct media_graph *graph = &link->graph_obj.mdev->pm_count_walk;
-	struct media_entity *source = link->source->entity;
-	struct media_entity *sink = link->sink->entity;
+	struct media_pad *source = link->source;
+	struct media_pad *sink = link->sink;
 	int source_use;
 	int sink_use;
 	int ret = 0;
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 05/30] media: entity: Move the pipeline from entity to pads
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (3 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 04/30] v4l: mc: Start walk from a specific pad in use count calculation Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 22:38   ` Laurent Pinchart
  2019-02-14 15:53   ` Jacopo Mondi
  2018-11-01 23:31 ` [PATCH v2 06/30] media: entity: Use pad as the starting point for a pipeline Niklas Söderlund
                   ` (25 subsequent siblings)
  30 siblings, 2 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

This moves the pipe and stream_count fields from struct media_entity to
struct media_pad. Effectively streams become pad-specific rather than
being stream specific, allowing several independent streams to traverse a
single entity.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/media-entity.c                  | 61 ++++++++++++-------
 drivers/media/platform/exynos4-is/fimc-isp.c  |  2 +-
 drivers/media/platform/exynos4-is/fimc-lite.c |  2 +-
 drivers/media/platform/omap3isp/isp.c         |  2 +-
 drivers/media/platform/omap3isp/ispvideo.c    |  2 +-
 drivers/media/platform/omap3isp/ispvideo.h    |  2 +-
 drivers/media/platform/rcar-vin/rcar-dma.c    |  2 +-
 drivers/media/platform/xilinx/xilinx-dma.c    |  2 +-
 drivers/media/platform/xilinx/xilinx-dma.h    |  2 +-
 drivers/staging/media/imx/imx-media-utils.c   |  2 +-
 drivers/staging/media/omap4iss/iss.c          |  2 +-
 drivers/staging/media/omap4iss/iss_video.c    |  2 +-
 drivers/staging/media/omap4iss/iss_video.h    |  2 +-
 include/media/media-entity.h                  | 17 ++++--
 14 files changed, 61 insertions(+), 41 deletions(-)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 70db03fa33a21db1..13260149c4dfc90c 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -419,7 +419,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 	struct media_pad *pad = entity->pads;
 	struct media_pad *pad_err = pad;
 	struct media_link *link;
-	int ret;
+	int ret = 0;
 
 	if (!pipe->streaming_count++) {
 		ret = media_graph_walk_init(&pipe->graph, mdev);
@@ -431,21 +431,27 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 
 	while ((pad = media_graph_walk_next(graph))) {
 		struct media_entity *entity = pad->entity;
+		unsigned int i;
+		bool skip_validation = pad->pipe;
 
 		DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
 		DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
 
-		entity->stream_count++;
+		for (i = 0; i < entity->num_pads; i++) {
+			struct media_pad *iter = &entity->pads[i];
 
-		if (WARN_ON(entity->pipe && entity->pipe != pipe)) {
-			ret = -EBUSY;
-			goto error;
+			if (iter->pipe && WARN_ON(iter->pipe != pipe))
+				ret = -EBUSY;
+			else
+				iter->pipe = pipe;
+			iter->stream_count++;
 		}
 
-		entity->pipe = pipe;
+		if (ret)
+			goto error;
 
 		/* Already streaming --- no need to check. */
-		if (entity->stream_count > 1)
+		if (skip_validation)
 			continue;
 
 		if (!entity->ops || !entity->ops->link_validate)
@@ -514,19 +520,24 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 
 	while ((pad_err = media_graph_walk_next(graph))) {
 		struct media_entity *entity_err = pad_err->entity;
+		unsigned int i;
+
+		for (i = 0; i < entity_err->num_pads; i++) {
+			struct media_pad *iter = &entity_err->pads[i];
 
-		/* Sanity check for negative stream_count */
-		if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) {
-			entity_err->stream_count--;
-			if (entity_err->stream_count == 0)
-				entity_err->pipe = NULL;
+			/* Sanity check for negative stream_count */
+			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
+				--iter->stream_count;
+				if (iter->stream_count == 0)
+					iter->pipe = NULL;
+			}
 		}
 
 		/*
 		 * We haven't increased stream_count further than this
 		 * so we quit here.
 		 */
-		if (pad_err == pad)
+		if (pad_err->entity == pad->entity)
 			break;
 	}
 
@@ -553,7 +564,7 @@ EXPORT_SYMBOL_GPL(media_pipeline_start);
 
 void __media_pipeline_stop(struct media_entity *entity)
 {
-	struct media_pipeline *pipe = entity->pipe;
+	struct media_pipeline *pipe = entity->pads->pipe;
 	struct media_graph *graph = &pipe->graph;
 	struct media_pad *pad;
 
@@ -567,13 +578,17 @@ void __media_pipeline_stop(struct media_entity *entity)
 	media_graph_walk_start(graph, entity->pads);
 
 	while ((pad = media_graph_walk_next(graph))) {
-		struct media_entity *entity = pad->entity;
+		unsigned int i;
 
-		/* Sanity check for negative stream_count */
-		if (!WARN_ON_ONCE(entity->stream_count <= 0)) {
-			entity->stream_count--;
-			if (entity->stream_count == 0)
-				entity->pipe = NULL;
+		for (i = 0; i < entity->num_pads; i++) {
+			struct media_pad *iter = &entity->pads[i];
+
+			/* Sanity check for negative stream_count */
+			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
+				iter->stream_count--;
+				if (iter->stream_count == 0)
+					iter->pipe = NULL;
+			}
 		}
 	}
 
@@ -865,7 +880,7 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
 {
 	const u32 mask = MEDIA_LNK_FL_ENABLED;
 	struct media_device *mdev;
-	struct media_entity *source, *sink;
+	struct media_pad *source, *sink;
 	int ret = -EBUSY;
 
 	if (link == NULL)
@@ -881,8 +896,8 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
 	if (link->flags == flags)
 		return 0;
 
-	source = link->source->entity;
-	sink = link->sink->entity;
+	source = link->source;
+	sink = link->sink;
 
 	if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
 	    (source->stream_count || sink->stream_count))
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index 9a48c0f69320ba35..79d128a57e87fd58 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -229,7 +229,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
 			}
 		}
 	} else {
-		if (sd->entity.stream_count == 0) {
+		if (sd->entity.pads->stream_count == 0) {
 			if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
 				struct v4l2_subdev_format format = *fmt;
 
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 96f0a8a0dcae591f..dbadcba6739a286b 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -1096,7 +1096,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
 	mutex_lock(&fimc->lock);
 
 	if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP &&
-	    sd->entity.stream_count > 0) ||
+	    sd->entity.pads->stream_count > 0) ||
 	    (atomic_read(&fimc->out_path) == FIMC_IO_DMA &&
 	    vb2_is_busy(&fimc->vb_queue))) {
 		mutex_unlock(&fimc->lock);
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 77fb7987b42f33cd..3663dfd00cadc2f0 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -927,7 +927,7 @@ static int isp_pipeline_is_last(struct media_entity *me)
 	struct isp_pipeline *pipe;
 	struct media_pad *pad;
 
-	if (!me->pipe)
+	if (!me->pads->pipe)
 		return 0;
 	pipe = to_isp_pipeline(me);
 	if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index dc11b732dc05b00b..f354cd7ceb8ffce5 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -1102,7 +1102,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 	/* Start streaming on the pipeline. No link touching an entity in the
 	 * pipeline can be activated or deactivated once streaming is started.
 	 */
-	pipe = video->video.entity.pipe
+	pipe = video->video.entity.pads->pipe
 	     ? to_isp_pipeline(&video->video.entity) : &video->pipe;
 
 	ret = media_entity_enum_init(&pipe->ent_enum, &video->isp->media_dev);
diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
index f6a2082b4a0a7708..8f4146c25a1b1293 100644
--- a/drivers/media/platform/omap3isp/ispvideo.h
+++ b/drivers/media/platform/omap3isp/ispvideo.h
@@ -103,7 +103,7 @@ struct isp_pipeline {
 };
 
 #define to_isp_pipeline(__e) \
-	container_of((__e)->pipe, struct isp_pipeline, pipe)
+	container_of((__e)->pads->pipe, struct isp_pipeline, pipe)
 
 static inline int isp_pipeline_ready(struct isp_pipeline *pipe)
 {
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index 92323310f7352147..e749096926f34d4a 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -1128,7 +1128,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on)
 	 */
 	mdev = vin->vdev.entity.graph_obj.mdev;
 	mutex_lock(&mdev->graph_mutex);
-	pipe = sd->entity.pipe ? sd->entity.pipe : &vin->vdev.pipe;
+	pipe = sd->entity.pads->pipe ? sd->entity.pads->pipe : &vin->vdev.pipe;
 	ret = __media_pipeline_start(&vin->vdev.entity, pipe);
 	mutex_unlock(&mdev->graph_mutex);
 	if (ret)
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index a2a329336243bdc7..f27a7be5f5d0f0b5 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -406,7 +406,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
 	 * Use the pipeline object embedded in the first DMA object that starts
 	 * streaming.
 	 */
-	pipe = dma->video.entity.pipe
+	pipe = dma->video.entity.pads->pipe
 	     ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe;
 
 	ret = media_pipeline_start(&dma->video.entity, &pipe->pipe);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
index e95d136c153a8f5f..c12e053ff41eed1c 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.h
+++ b/drivers/media/platform/xilinx/xilinx-dma.h
@@ -50,7 +50,7 @@ struct xvip_pipeline {
 
 static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
 {
-	return container_of(e->pipe, struct xvip_pipeline, pipe);
+	return container_of(e->pads->pipe, struct xvip_pipeline, pipe);
 }
 
 /**
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index 0eaa353d5cb39768..ba9d9a8337cb159e 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -917,7 +917,7 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
 			__media_pipeline_stop(entity);
 	} else {
 		v4l2_subdev_call(sd, video, s_stream, 0);
-		if (entity->pipe)
+		if (entity->pads->pipe)
 			__media_pipeline_stop(entity);
 	}
 
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index c8be1db532ab2555..030808b222cf3ae5 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -543,7 +543,7 @@ static int iss_pipeline_is_last(struct media_entity *me)
 	struct iss_pipeline *pipe;
 	struct media_pad *pad;
 
-	if (!me->pipe)
+	if (!me->pads->pipe)
 		return 0;
 	pipe = to_iss_pipeline(me);
 	if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED)
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 1271bbacf9e7bdeb..65f1e358271b3743 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -877,7 +877,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 	 * Start streaming on the pipeline. No link touching an entity in the
 	 * pipeline can be activated or deactivated once streaming is started.
 	 */
-	pipe = pad->entity->pipe
+	pipe = pad->pipe
 	     ? to_iss_pipeline(pad->entity) : &video->pipe;
 	pipe->external = NULL;
 	pipe->external_rate = 0;
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
index f22489edb5624af2..cdea8543b3f93ecf 100644
--- a/drivers/staging/media/omap4iss/iss_video.h
+++ b/drivers/staging/media/omap4iss/iss_video.h
@@ -94,7 +94,7 @@ struct iss_pipeline {
 };
 
 #define to_iss_pipeline(__e) \
-	container_of((__e)->pipe, struct iss_pipeline, pipe)
+	container_of((__e)->pads->pipe, struct iss_pipeline, pipe)
 
 static inline int iss_pipeline_ready(struct iss_pipeline *pipe)
 {
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index cde6350d752bb0ae..ca0b79288ea7fd11 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -188,15 +188,25 @@ enum media_pad_signal_type {
  *
  * @graph_obj:	Embedded structure containing the media object common data
  * @entity:	Entity this pad belongs to
+ * @pipe:	Pipeline this entity belongs to.
+ * @stream_count: Stream count for the entity.
  * @index:	Pad index in the entity pads array, numbered from 0 to n
  * @sig_type:	Type of the signal inside a media pad
  * @flags:	Pad flags, as defined in
  *		:ref:`include/uapi/linux/media.h <media_header>`
  *		(seek for ``MEDIA_PAD_FL_*``)
+ * .. note::
+ *
+ *    @stream_count reference counts must never be negative, but are
+ *    signed integers on purpose: a simple ``WARN_ON(<0)`` check can
+ *    be used to detect reference count bugs that would make them
+ *    negative.
  */
 struct media_pad {
 	struct media_gobj graph_obj;	/* must be first field in struct */
 	struct media_entity *entity;
+	struct media_pipeline *pipe;
+	int stream_count;
 	u16 index;
 	enum media_pad_signal_type sig_type;
 	unsigned long flags;
@@ -274,9 +284,7 @@ enum media_entity_type {
  * @pads:	Pads array with the size defined by @num_pads.
  * @links:	List of data links.
  * @ops:	Entity operations.
- * @stream_count: Stream count for the entity.
  * @use_count:	Use count for the entity.
- * @pipe:	Pipeline this entity belongs to.
  * @info:	Union with devnode information.  Kept just for backward
  *		compatibility.
  * @info.dev:	Contains device major and minor info.
@@ -289,7 +297,7 @@ enum media_entity_type {
  *
  * .. note::
  *
- *    @stream_count and @use_count reference counts must never be
+ *    @use_count reference counts must never be
  *    negative, but are signed integers on purpose: a simple ``WARN_ON(<0)``
  *    check can be used to detect reference count bugs that would make them
  *    negative.
@@ -311,11 +319,8 @@ struct media_entity {
 
 	const struct media_entity_operations *ops;
 
-	int stream_count;
 	int use_count;
 
-	struct media_pipeline *pipe;
-
 	union {
 		struct {
 			u32 major;
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 06/30] media: entity: Use pad as the starting point for a pipeline
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (4 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 05/30] media: entity: Move the pipeline from entity to pads Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 22:54   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 07/30] media: entity: Add has_route entity operation Niklas Söderlund
                   ` (24 subsequent siblings)
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

The pipeline will be moved from the entity to the pads; reflect this in
the media pipeline function API.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 Documentation/media/kapi/mc-core.rst          |  6 ++--
 drivers/media/media-entity.c                  | 25 +++++++-------
 drivers/media/pci/intel/ipu3/ipu3-cio2.c      |  6 ++--
 .../media/platform/exynos4-is/fimc-capture.c  |  8 ++---
 .../platform/exynos4-is/fimc-isp-video.c      |  8 ++---
 drivers/media/platform/exynos4-is/fimc-lite.c |  8 ++---
 drivers/media/platform/omap3isp/ispvideo.c    |  6 ++--
 .../media/platform/qcom/camss/camss-video.c   |  6 ++--
 drivers/media/platform/rcar-vin/rcar-dma.c    |  6 ++--
 .../media/platform/s3c-camif/camif-capture.c  |  6 ++--
 drivers/media/platform/vimc/vimc-capture.c    |  6 ++--
 drivers/media/platform/vsp1/vsp1_video.c      |  6 ++--
 drivers/media/platform/xilinx/xilinx-dma.c    |  6 ++--
 drivers/media/usb/au0828/au0828-core.c        |  4 +--
 drivers/staging/media/imx/imx-media-utils.c   |  6 ++--
 drivers/staging/media/omap4iss/iss_video.c    |  6 ++--
 include/media/media-entity.h                  | 33 ++++++++++---------
 17 files changed, 76 insertions(+), 76 deletions(-)

diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
index 849b87439b7a9772..ede7e946f6a82ac0 100644
--- a/Documentation/media/kapi/mc-core.rst
+++ b/Documentation/media/kapi/mc-core.rst
@@ -211,11 +211,11 @@ When starting streaming, drivers must notify all entities in the pipeline to
 prevent link states from being modified during streaming by calling
 :c:func:`media_pipeline_start()`.
 
-The function will mark all entities connected to the given entity through
-enabled links, either directly or indirectly, as streaming.
+The function will mark all entities connected to the given pad through
+enabled routes and links, either directly or indirectly, as streaming.
 
 The struct :c:type:`media_pipeline` instance pointed to by
-the pipe argument will be stored in every entity in the pipeline.
+the pipe argument will be stored in every pad in the pipeline.
 Drivers should embed the struct :c:type:`media_pipeline`
 in higher-level pipeline structures and can then access the
 pipeline through the struct :c:type:`media_entity`
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 13260149c4dfc90c..f2fa0b7826dbc2f3 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -411,12 +411,11 @@ EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad);
  * Pipeline management
  */
 
-__must_check int __media_pipeline_start(struct media_entity *entity,
+__must_check int __media_pipeline_start(struct media_pad *pad,
 					struct media_pipeline *pipe)
 {
-	struct media_device *mdev = entity->graph_obj.mdev;
+	struct media_device *mdev = pad->graph_obj.mdev;
 	struct media_graph *graph = &pipe->graph;
-	struct media_pad *pad = entity->pads;
 	struct media_pad *pad_err = pad;
 	struct media_link *link;
 	int ret = 0;
@@ -549,24 +548,23 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
 }
 EXPORT_SYMBOL_GPL(__media_pipeline_start);
 
-__must_check int media_pipeline_start(struct media_entity *entity,
+__must_check int media_pipeline_start(struct media_pad *pad,
 				      struct media_pipeline *pipe)
 {
-	struct media_device *mdev = entity->graph_obj.mdev;
+	struct media_device *mdev = pad->graph_obj.mdev;
 	int ret;
 
 	mutex_lock(&mdev->graph_mutex);
-	ret = __media_pipeline_start(entity, pipe);
+	ret = __media_pipeline_start(pad, pipe);
 	mutex_unlock(&mdev->graph_mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(media_pipeline_start);
 
-void __media_pipeline_stop(struct media_entity *entity)
+void __media_pipeline_stop(struct media_pad *pad)
 {
-	struct media_pipeline *pipe = entity->pads->pipe;
+	struct media_pipeline *pipe = pad->pipe;
 	struct media_graph *graph = &pipe->graph;
-	struct media_pad *pad;
 
 	/*
 	 * If the following check fails, the driver has performed an
@@ -575,9 +573,10 @@ void __media_pipeline_stop(struct media_entity *entity)
 	if (WARN_ON(!pipe))
 		return;
 
-	media_graph_walk_start(graph, entity->pads);
+	media_graph_walk_start(graph, pad);
 
 	while ((pad = media_graph_walk_next(graph))) {
+		struct media_entity *entity = pad->entity;
 		unsigned int i;
 
 		for (i = 0; i < entity->num_pads; i++) {
@@ -598,12 +597,12 @@ void __media_pipeline_stop(struct media_entity *entity)
 }
 EXPORT_SYMBOL_GPL(__media_pipeline_stop);
 
-void media_pipeline_stop(struct media_entity *entity)
+void media_pipeline_stop(struct media_pad *pad)
 {
-	struct media_device *mdev = entity->graph_obj.mdev;
+	struct media_device *mdev = pad->graph_obj.mdev;
 
 	mutex_lock(&mdev->graph_mutex);
-	__media_pipeline_stop(entity);
+	__media_pipeline_stop(pad);
 	mutex_unlock(&mdev->graph_mutex);
 }
 EXPORT_SYMBOL_GPL(media_pipeline_stop);
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index 452eb9b42140bb92..3e17a3a546ee5458 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -1000,7 +1000,7 @@ static int cio2_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
 		return r;
 	}
 
-	r = media_pipeline_start(&q->vdev.entity, &q->pipe);
+	r = media_pipeline_start(q->vdev.entity.pads, &q->pipe);
 	if (r)
 		goto fail_pipeline;
 
@@ -1020,7 +1020,7 @@ static int cio2_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
 fail_csi2_subdev:
 	cio2_hw_exit(cio2, q);
 fail_hw:
-	media_pipeline_stop(&q->vdev.entity);
+	media_pipeline_stop(q->vdev.entity.pads);
 fail_pipeline:
 	dev_dbg(&cio2->pci_dev->dev, "failed to start streaming (%d)\n", r);
 	cio2_vb2_return_all_buffers(q, VB2_BUF_STATE_QUEUED);
@@ -1041,7 +1041,7 @@ static void cio2_vb2_stop_streaming(struct vb2_queue *vq)
 	cio2_hw_exit(cio2, q);
 	synchronize_irq(cio2->pci_dev->irq);
 	cio2_vb2_return_all_buffers(q, VB2_BUF_STATE_ERROR);
-	media_pipeline_stop(&q->vdev.entity);
+	media_pipeline_stop(q->vdev.entity.pads);
 	pm_runtime_put(&cio2->pci_dev->dev);
 	cio2->streaming = false;
 }
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index f56220e549bb9511..04fa01caa3aba5f8 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -537,7 +537,7 @@ static int fimc_capture_release(struct file *file)
 	mutex_lock(&fimc->lock);
 
 	if (close && vc->streaming) {
-		media_pipeline_stop(&vc->ve.vdev.entity);
+		media_pipeline_stop(vc->ve.vdev.entity.pads);
 		vc->streaming = false;
 	}
 
@@ -1201,7 +1201,7 @@ static int fimc_cap_streamon(struct file *file, void *priv,
 	if (fimc_capture_active(fimc))
 		return -EBUSY;
 
-	ret = media_pipeline_start(entity, &vc->ve.pipe->mp);
+	ret = media_pipeline_start(entity->pads, &vc->ve.pipe->mp);
 	if (ret < 0)
 		return ret;
 
@@ -1235,7 +1235,7 @@ static int fimc_cap_streamon(struct file *file, void *priv,
 	}
 
 err_p_stop:
-	media_pipeline_stop(entity);
+	media_pipeline_stop(entity->pads);
 	return ret;
 }
 
@@ -1250,7 +1250,7 @@ static int fimc_cap_streamoff(struct file *file, void *priv,
 	if (ret < 0)
 		return ret;
 
-	media_pipeline_stop(&vc->ve.vdev.entity);
+	media_pipeline_stop(vc->ve.vdev.entity.pads);
 	vc->streaming = false;
 	return 0;
 }
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c
index de6bd28f7e313d20..af25aa85fa647ca3 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -312,7 +312,7 @@ static int isp_video_release(struct file *file)
 	mutex_lock(&isp->video_lock);
 
 	if (v4l2_fh_is_singular_file(file) && ivc->streaming) {
-		media_pipeline_stop(entity);
+		media_pipeline_stop(entity->pads);
 		ivc->streaming = 0;
 	}
 
@@ -494,7 +494,7 @@ static int isp_video_streamon(struct file *file, void *priv,
 	struct media_entity *me = &ve->vdev.entity;
 	int ret;
 
-	ret = media_pipeline_start(me, &ve->pipe->mp);
+	ret = media_pipeline_start(me->pads, &ve->pipe->mp);
 	if (ret < 0)
 		return ret;
 
@@ -509,7 +509,7 @@ static int isp_video_streamon(struct file *file, void *priv,
 	isp->video_capture.streaming = 1;
 	return 0;
 p_stop:
-	media_pipeline_stop(me);
+	media_pipeline_stop(me->pads);
 	return ret;
 }
 
@@ -524,7 +524,7 @@ static int isp_video_streamoff(struct file *file, void *priv,
 	if (ret < 0)
 		return ret;
 
-	media_pipeline_stop(&video->ve.vdev.entity);
+	media_pipeline_stop(video->ve.vdev.entity.pads);
 	video->streaming = 0;
 	return 0;
 }
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index dbadcba6739a286b..1d6858e5abb0b9f3 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -524,7 +524,7 @@ static int fimc_lite_release(struct file *file)
 	if (v4l2_fh_is_singular_file(file) &&
 	    atomic_read(&fimc->out_path) == FIMC_IO_DMA) {
 		if (fimc->streaming) {
-			media_pipeline_stop(entity);
+			media_pipeline_stop(entity->pads);
 			fimc->streaming = false;
 		}
 		fimc_lite_stop_capture(fimc, false);
@@ -832,7 +832,7 @@ static int fimc_lite_streamon(struct file *file, void *priv,
 	if (fimc_lite_active(fimc))
 		return -EBUSY;
 
-	ret = media_pipeline_start(entity, &fimc->ve.pipe->mp);
+	ret = media_pipeline_start(entity->pads, &fimc->ve.pipe->mp);
 	if (ret < 0)
 		return ret;
 
@@ -849,7 +849,7 @@ static int fimc_lite_streamon(struct file *file, void *priv,
 	}
 
 err_p_stop:
-	media_pipeline_stop(entity);
+	media_pipeline_stop(entity->pads);
 	return 0;
 }
 
@@ -863,7 +863,7 @@ static int fimc_lite_streamoff(struct file *file, void *priv,
 	if (ret < 0)
 		return ret;
 
-	media_pipeline_stop(&fimc->ve.vdev.entity);
+	media_pipeline_stop(fimc->ve.vdev.entity.pads);
 	fimc->streaming = false;
 	return 0;
 }
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index f354cd7ceb8ffce5..6a85a8323a113869 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -1113,7 +1113,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 	pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
 	pipe->max_rate = pipe->l3_ick;
 
-	ret = media_pipeline_start(&video->video.entity, &pipe->pipe);
+	ret = media_pipeline_start(video->video.entity.pads, &pipe->pipe);
 	if (ret < 0)
 		goto err_pipeline_start;
 
@@ -1170,7 +1170,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 	return 0;
 
 err_check_format:
-	media_pipeline_stop(&video->video.entity);
+	media_pipeline_stop(video->video.entity.pads);
 err_pipeline_start:
 	/* TODO: Implement PM QoS */
 	/* The DMA queue must be emptied here, otherwise CCDC interrupts that
@@ -1237,7 +1237,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
 	video->error = false;
 
 	/* TODO: Implement PM QoS */
-	media_pipeline_stop(&video->video.entity);
+	media_pipeline_stop(video->video.entity.pads);
 
 	media_entity_enum_cleanup(&pipe->ent_enum);
 
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index 58aebe7114cd7dc5..3ec24286e38d6856 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -436,7 +436,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count)
 	struct v4l2_subdev *subdev;
 	int ret;
 
-	ret = media_pipeline_start(&vdev->entity, &video->pipe);
+	ret = media_pipeline_start(vdev->entity.pads, &video->pipe);
 	if (ret < 0)
 		return ret;
 
@@ -465,7 +465,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count)
 	return 0;
 
 error:
-	media_pipeline_stop(&vdev->entity);
+	media_pipeline_stop(vdev->entity.pads);
 
 	video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
 
@@ -496,7 +496,7 @@ static void video_stop_streaming(struct vb2_queue *q)
 		v4l2_subdev_call(subdev, video, s_stream, 0);
 	}
 
-	media_pipeline_stop(&vdev->entity);
+	media_pipeline_stop(vdev->entity.pads);
 
 	video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
 }
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index e749096926f34d4a..57c2087f7ad472f3 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -1112,7 +1112,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on)
 	sd = media_entity_to_v4l2_subdev(pad->entity);
 
 	if (!on) {
-		media_pipeline_stop(&vin->vdev.entity);
+		media_pipeline_stop(vin->vdev.entity.pads);
 		return v4l2_subdev_call(sd, video, s_stream, 0);
 	}
 
@@ -1129,7 +1129,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on)
 	mdev = vin->vdev.entity.graph_obj.mdev;
 	mutex_lock(&mdev->graph_mutex);
 	pipe = sd->entity.pads->pipe ? sd->entity.pads->pipe : &vin->vdev.pipe;
-	ret = __media_pipeline_start(&vin->vdev.entity, pipe);
+	ret = __media_pipeline_start(vin->vdev.entity.pads, pipe);
 	mutex_unlock(&mdev->graph_mutex);
 	if (ret)
 		return ret;
@@ -1138,7 +1138,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on)
 	if (ret == -ENOIOCTLCMD)
 		ret = 0;
 	if (ret)
-		media_pipeline_stop(&vin->vdev.entity);
+		media_pipeline_stop(vin->vdev.entity.pads);
 
 	return ret;
 }
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index 23b008d1a47bb9d1..21f407985afaedfc 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -858,13 +858,13 @@ static int s3c_camif_streamon(struct file *file, void *priv,
 	if (s3c_vp_active(vp))
 		return 0;
 
-	ret = media_pipeline_start(sensor, camif->m_pipeline);
+	ret = media_pipeline_start(sensor->pads, camif->m_pipeline);
 	if (ret < 0)
 		return ret;
 
 	ret = camif_pipeline_validate(camif);
 	if (ret < 0) {
-		media_pipeline_stop(sensor);
+		media_pipeline_stop(sensor->pads);
 		return ret;
 	}
 
@@ -888,7 +888,7 @@ static int s3c_camif_streamoff(struct file *file, void *priv,
 
 	ret = vb2_streamoff(&vp->vb_queue, type);
 	if (ret == 0)
-		media_pipeline_stop(&camif->sensor.sd->entity);
+		media_pipeline_stop(camif->sensor.sd->entity.pads);
 	return ret;
 }
 
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c
index 3f7e9ed5663376df..55e72fcd97c54f7c 100644
--- a/drivers/media/platform/vimc/vimc-capture.c
+++ b/drivers/media/platform/vimc/vimc-capture.c
@@ -248,7 +248,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
 	vcap->sequence = 0;
 
 	/* Start the media pipeline */
-	ret = media_pipeline_start(entity, &vcap->pipe);
+	ret = media_pipeline_start(entity->pads, &vcap->pipe);
 	if (ret) {
 		vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED);
 		return ret;
@@ -257,7 +257,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
 	/* Enable streaming from the pipe */
 	ret = vimc_pipeline_s_stream(&vcap->vdev.entity, 1);
 	if (ret) {
-		media_pipeline_stop(entity);
+		media_pipeline_stop(entity->pads);
 		vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED);
 		return ret;
 	}
@@ -277,7 +277,7 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq)
 	vimc_pipeline_s_stream(&vcap->vdev.entity, 0);
 
 	/* Stop the media pipeline */
-	media_pipeline_stop(&vcap->vdev.entity);
+	media_pipeline_stop(vcap->vdev.entity.pads);
 
 	/* Release all active buffers */
 	vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_ERROR);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 806825bd3484167a..1209d2622fca646b 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -937,7 +937,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
 	}
 	mutex_unlock(&pipe->lock);
 
-	media_pipeline_stop(&video->video.entity);
+	media_pipeline_stop(video->video.entity.pads);
 	vsp1_video_release_buffers(video);
 	vsp1_video_pipeline_put(pipe);
 }
@@ -1064,7 +1064,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 		return PTR_ERR(pipe);
 	}
 
-	ret = __media_pipeline_start(&video->video.entity, &pipe->pipe);
+	ret = __media_pipeline_start(video->video.entity.pads, &pipe->pipe);
 	if (ret < 0) {
 		mutex_unlock(&mdev->graph_mutex);
 		goto err_pipe;
@@ -1088,7 +1088,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 	return 0;
 
 err_stop:
-	media_pipeline_stop(&video->video.entity);
+	media_pipeline_stop(video->video.entity.pads);
 err_pipe:
 	vsp1_video_pipeline_put(pipe);
 	return ret;
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index f27a7be5f5d0f0b5..d171925168745e45 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -409,7 +409,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
 	pipe = dma->video.entity.pads->pipe
 	     ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe;
 
-	ret = media_pipeline_start(&dma->video.entity, &pipe->pipe);
+	ret = media_pipeline_start(dma->video.entity.pads, &pipe->pipe);
 	if (ret < 0)
 		goto error;
 
@@ -435,7 +435,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
 	return 0;
 
 error_stop:
-	media_pipeline_stop(&dma->video.entity);
+	media_pipeline_stop(dma->video.entity.pads);
 
 error:
 	/* Give back all queued buffers to videobuf2. */
@@ -463,7 +463,7 @@ static void xvip_dma_stop_streaming(struct vb2_queue *vq)
 
 	/* Cleanup the pipeline and mark it as being stopped. */
 	xvip_pipeline_cleanup(pipe);
-	media_pipeline_stop(&dma->video.entity);
+	media_pipeline_stop(dma->video.entity.pads);
 
 	/* Give back all queued buffers to videobuf2. */
 	spin_lock_irq(&dma->queued_lock);
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 1fdb1601dc653e64..32c2fe808113ea0b 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -396,7 +396,7 @@ static int au0828_enable_source(struct media_entity *entity,
 		goto end;
 	}
 
-	ret = __media_pipeline_start(entity, pipe);
+	ret = __media_pipeline_start(entity->pads, pipe);
 	if (ret) {
 		pr_err("Start Pipeline: %s->%s Error %d\n",
 			source->name, entity->name, ret);
@@ -447,7 +447,7 @@ static void au0828_disable_source(struct media_entity *entity)
 		*/
 		if (dev->active_link_owner != entity)
 			return;
-		__media_pipeline_stop(entity);
+		__media_pipeline_stop(entity->pads);
 		ret = __media_entity_setup_link(dev->active_link, 0);
 		if (ret)
 			pr_err("Deactivate link Error %d\n", ret);
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index ba9d9a8337cb159e..44bc20068876f15b 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -909,16 +909,16 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
 	mutex_lock(&imxmd->md.graph_mutex);
 
 	if (on) {
-		ret = __media_pipeline_start(entity, &imxmd->pipe);
+		ret = __media_pipeline_start(entity->pads, &imxmd->pipe);
 		if (ret)
 			goto out;
 		ret = v4l2_subdev_call(sd, video, s_stream, 1);
 		if (ret)
-			__media_pipeline_stop(entity);
+			__media_pipeline_stop(entity->pads);
 	} else {
 		v4l2_subdev_call(sd, video, s_stream, 0);
 		if (entity->pads->pipe)
-			__media_pipeline_stop(entity);
+			__media_pipeline_stop(entity->pads);
 	}
 
 out:
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 65f1e358271b3743..87f5d16b3a822692 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -895,7 +895,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 	if (video->iss->pdata->set_constraints)
 		video->iss->pdata->set_constraints(video->iss, true);
 
-	ret = media_pipeline_start(pad->entity, &pipe->pipe);
+	ret = media_pipeline_start(pad, &pipe->pipe);
 	if (ret < 0)
 		goto err_media_pipeline_start;
 
@@ -984,7 +984,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 err_omap4iss_set_stream:
 	vb2_streamoff(&vfh->queue, type);
 err_iss_video_check_format:
-	media_pipeline_stop(&video->video.entity);
+	media_pipeline_stop(video->video.entity.pads);
 err_media_pipeline_start:
 	if (video->iss->pdata->set_constraints)
 		video->iss->pdata->set_constraints(video->iss, false);
@@ -1038,7 +1038,7 @@ iss_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
 
 	if (video->iss->pdata->set_constraints)
 		video->iss->pdata->set_constraints(video->iss, false);
-	media_pipeline_stop(&video->video.entity);
+	media_pipeline_stop(video->video.entity.pads);
 
 done:
 	mutex_unlock(&video->stream_lock);
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index ca0b79288ea7fd11..8378f700389635ea 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -965,53 +965,54 @@ struct media_pad *media_graph_walk_next(struct media_graph *graph);
 
 /**
  * media_pipeline_start - Mark a pipeline as streaming
- * @entity: Starting entity
- * @pipe: Media pipeline to be assigned to all entities in the pipeline.
+ * @pad: Starting pad
+ * @pipe: Media pipeline to be assigned to all pads in the pipeline.
  *
- * Mark all entities connected to a given entity through enabled links, either
- * directly or indirectly, as streaming. The given pipeline object is assigned
- * to every entity in the pipeline and stored in the media_entity pipe field.
+ * Mark all pads connected to a given pad through enabled
+ * routes or links, either directly or indirectly, as streaming. The
+ * given pipeline object is assigned to every pad in the pipeline
+ * and stored in the media_pad pipe field.
  *
  * Calls to this function can be nested, in which case the same number of
  * media_pipeline_stop() calls will be required to stop streaming. The
  * pipeline pointer must be identical for all nested calls to
  * media_pipeline_start().
  */
-__must_check int media_pipeline_start(struct media_entity *entity,
+__must_check int media_pipeline_start(struct media_pad *pad,
 				      struct media_pipeline *pipe);
 /**
  * __media_pipeline_start - Mark a pipeline as streaming
  *
- * @entity: Starting entity
- * @pipe: Media pipeline to be assigned to all entities in the pipeline.
+ * @pad: Starting pad
+ * @pipe: Media pipeline to be assigned to all pads in the pipeline.
  *
  * ..note:: This is the non-locking version of media_pipeline_start()
  */
-__must_check int __media_pipeline_start(struct media_entity *entity,
+__must_check int __media_pipeline_start(struct media_pad *pad,
 					struct media_pipeline *pipe);
 
 /**
  * media_pipeline_stop - Mark a pipeline as not streaming
- * @entity: Starting entity
+ * @pad: Starting pad
  *
- * Mark all entities connected to a given entity through enabled links, either
- * directly or indirectly, as not streaming. The media_entity pipe field is
- * reset to %NULL.
+ * Mark all pads connected to a given pad through enabled routes or
+ * links, either directly or indirectly, as not streaming. The
+ * media_pad pipe field is reset to %NULL.
  *
  * If multiple calls to media_pipeline_start() have been made, the same
  * number of calls to this function are required to mark the pipeline as not
  * streaming.
  */
-void media_pipeline_stop(struct media_entity *entity);
+void media_pipeline_stop(struct media_pad *pad);
 
 /**
  * __media_pipeline_stop - Mark a pipeline as not streaming
  *
- * @entity: Starting entity
+ * @pad: Starting pad
  *
  * .. note:: This is the non-locking version of media_pipeline_stop()
  */
-void __media_pipeline_stop(struct media_entity *entity);
+void __media_pipeline_stop(struct media_pad *pad);
 
 /**
  * media_devnode_create() - creates and initializes a device node interface
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 07/30] media: entity: Add has_route entity operation
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (5 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 06/30] media: entity: Use pad as the starting point for a pipeline Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 08/30] media: entity: Add media_has_route() function Niklas Söderlund
                   ` (23 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Michal Simek

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

The optional operation can be used by entities to report whether two
pads are internally connected.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 include/media/media-entity.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 8378f700389635ea..cd482814654616b5 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -223,6 +223,9 @@ struct media_pad {
  * @link_validate:	Return whether a link is valid from the entity point of
  *			view. The media_pipeline_start() function
  *			validates all links by calling this operation. Optional.
+ * @has_route:		Return whether a route exists inside the entity between
+ *			two given pads. Optional. If the operation isn't
+ *			implemented all pads will be considered as connected.
  *
  * .. note::
  *
@@ -235,6 +238,8 @@ struct media_entity_operations {
 			  const struct media_pad *local,
 			  const struct media_pad *remote, u32 flags);
 	int (*link_validate)(struct media_link *link);
+	bool (*has_route)(struct media_entity *entity, unsigned int pad0,
+			  unsigned int pad1);
 };
 
 /**
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 08/30] media: entity: Add media_has_route() function
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (6 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 07/30] media: entity: Add has_route entity operation Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink Niklas Söderlund
                   ` (22 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Michal Simek

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

This is a wrapper around the media entity has_route operation.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/media-entity.c | 16 ++++++++++++++++
 include/media/media-entity.h | 17 +++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index f2fa0b7826dbc2f3..3c0e7425c8983b45 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -237,6 +237,22 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init);
  * Graph traversal
  */
 
+bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
+			    unsigned int pad1)
+{
+	if (pad0 >= entity->num_pads || pad1 >= entity->num_pads)
+		return false;
+
+	if (pad0 == pad1)
+		return true;
+
+	if (!entity->ops || !entity->ops->has_route)
+		return true;
+
+	return entity->ops->has_route(entity, pad0, pad1);
+}
+EXPORT_SYMBOL_GPL(media_entity_has_route);
+
 static struct media_pad *
 media_entity_other(struct media_pad *pad, struct media_link *link)
 {
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index cd482814654616b5..9540d2af80f19805 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -919,6 +919,23 @@ int media_entity_get_fwnode_pad(struct media_entity *entity,
 __must_check int media_graph_walk_init(
 	struct media_graph *graph, struct media_device *mdev);
 
+/**
+ * media_entity_has_route - Check if two entity pads are connected internally
+ *
+ * @entity: The entity
+ * @pad0: The first pad index
+ * @pad1: The second pad index
+ *
+ * This function can be used to check whether two pads of an entity are
+ * connected internally in the entity.
+ *
+ * The caller must hold entity->graph_obj.mdev->mutex.
+ *
+ * Return: true if the pads are connected internally and false otherwise.
+ */
+bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
+			    unsigned int pad1);
+
 /**
  * media_graph_walk_cleanup - Release resources used by graph walk.
  *
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (7 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 08/30] media: entity: Add media_has_route() function Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 22:57   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 10/30] media: entity: Use routing information during graph traversal Niklas Söderlund
                   ` (21 subsequent siblings)
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

This way the pads are always passed to the has_route() op sink pad first.
Makes sense.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/media-entity.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 3c0e7425c8983b45..33f00e35ccd92c6f 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -249,6 +249,10 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
 	if (!entity->ops || !entity->ops->has_route)
 		return true;
 
+	if (entity->pads[pad0].flags & MEDIA_PAD_FL_SOURCE
+	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
+		swap(pad0, pad1);
+
 	return entity->ops->has_route(entity, pad0, pad1);
 }
 EXPORT_SYMBOL_GPL(media_entity_has_route);
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 10/30] media: entity: Use routing information during graph traversal
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (8 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 11/30] media: entity: Skip link validation for pads to which there is no route to Niklas Söderlund
                   ` (20 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Michal Simek

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Take internal routing information as reported by the entity has_route
operation into account during graph traversal to avoid following
unrelated links.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/media-entity.c | 44 ++++++++++++++++++++++--------------
 1 file changed, 27 insertions(+), 17 deletions(-)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 33f00e35ccd92c6f..4d10bc186e1e7a10 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -257,15 +257,6 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
 }
 EXPORT_SYMBOL_GPL(media_entity_has_route);
 
-static struct media_pad *
-media_entity_other(struct media_pad *pad, struct media_link *link)
-{
-	if (link->source == pad)
-		return link->sink;
-	else
-		return link->source;
-}
-
 /* push an entity to traversal stack */
 static void stack_push(struct media_graph *graph, struct media_pad *pad)
 {
@@ -336,7 +327,8 @@ static void media_graph_walk_iter(struct media_graph *graph)
 {
 	struct media_pad *pad = stack_top(graph);
 	struct media_link *link;
-	struct media_pad *next;
+	struct media_pad *remote;
+	struct media_pad *local;
 
 	link = list_entry(link_top(graph), typeof(*link), list);
 
@@ -350,23 +342,41 @@ static void media_graph_walk_iter(struct media_graph *graph)
 		return;
 	}
 
-	/* Get the entity in the other end of the link . */
-	next = media_entity_other(pad, link);
+	/*
+	 * Get the local pad, the remote pad and the entity at the other
+	 * end of the link.
+	 */
+	if (link->source->entity == pad->entity) {
+		remote = link->sink;
+		local = link->source;
+	} else {
+		remote = link->source;
+		local = link->sink;
+	}
+
+	/*
+	 * Are the local pad and the pad we came from connected
+	 * internally in the entity ?
+	 */
+	if (!media_entity_has_route(pad->entity, pad->index, local->index)) {
+		link_top(graph) = link_top(graph)->next;
+		return;
+	}
 
 	/* Has the entity already been visited? */
-	if (media_entity_enum_test_and_set(&graph->ent_enum, next->entity)) {
+	if (media_entity_enum_test_and_set(&graph->ent_enum, remote->entity)) {
 		link_top(graph) = link_top(graph)->next;
 		dev_dbg(pad->graph_obj.mdev->dev,
 			"walk: skipping entity '%s' (already seen)\n",
-			next->entity->name);
+			remote->entity->name);
 		return;
 	}
 
 	/* Push the new entity to stack and start over. */
 	link_top(graph) = link_top(graph)->next;
-	stack_push(graph, next);
-	dev_dbg(next->graph_obj.mdev->dev, "walk: pushing '%s':%u on stack\n",
-		next->entity->name, next->index);
+	stack_push(graph, remote);
+	dev_dbg(remote->graph_obj.mdev->dev, "walk: pushing '%s':%u on stack\n",
+		remote->entity->name, remote->index);
 }
 
 struct media_pad *media_graph_walk_next(struct media_graph *graph)
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 11/30] media: entity: Skip link validation for pads to which there is no route to
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (9 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 10/30] media: entity: Use routing information during graph traversal Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 23:13   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 12/30] media: entity: Add an iterator helper for connected pads Niklas Söderlund
                   ` (19 subsequent siblings)
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

Links are validated along the pipeline which is about to start streaming.
Not all the pads in entities that are traversed along that pipeline are
part of the pipeline, however. Skip the link validation for such pads.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/media-entity.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 4d10bc186e1e7a10..cdf3805dec755ec5 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -493,6 +493,11 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
 			struct media_pad *other_pad = link->sink->entity == entity
 				? link->sink : link->source;
 
+			/* Ignore pads to which there is no route. */
+			if (!media_entity_has_route(entity, pad->index,
+						    other_pad->index))
+				continue;
+
 			/* Mark that a pad is connected by a link. */
 			bitmap_clear(has_no_links, other_pad->index, 1);
 
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 12/30] media: entity: Add an iterator helper for connected pads
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (10 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 11/30] media: entity: Skip link validation for pads to which there is no route to Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 23:24   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 13/30] media: entity: Add only connected pads to the pipeline Niklas Söderlund
                   ` (18 subsequent siblings)
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

Add a helper macro for iterating over pads that are connected through
enabled routes. This can be used to find all the connected pads within an
entity, for instance starting from the pad which has been obtained during
the graph walk.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 include/media/media-entity.h | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 9540d2af80f19805..4bb1b568e1ac4795 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -936,6 +936,33 @@ __must_check int media_graph_walk_init(
 bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
 			    unsigned int pad1);
 
+static inline struct media_pad *__media_entity_for_routed_pads_next(
+	struct media_pad *start, struct media_pad *iter)
+{
+	struct media_entity *entity = start->entity;
+
+	while (iter < &entity->pads[entity->num_pads] &&
+	       !media_entity_has_route(entity, start->index, iter->index))
+		iter++;
+
+	return iter;
+}
+
+/**
+ * media_entity_for_routed_pads - Iterate over entity pads connected by routes
+ *
+ * @start: The stating pad
+ * @iter: The iterator pad
+ *
+ * Iterate over all pads connected through routes from a given pad
+ * within an entity. The iteration will include the starting pad itself.
+ */
+#define media_entity_for_routed_pads(start, iter)			\
+	for (iter = __media_entity_for_routed_pads_next(		\
+		     start, (start)->entity->pads);			\
+	     iter < &(start)->entity->pads[(start)->entity->num_pads];	\
+	     iter = __media_entity_for_routed_pads_next(start, iter + 1))
+
 /**
  * media_graph_walk_cleanup - Release resources used by graph walk.
  *
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 13/30] media: entity: Add only connected pads to the pipeline
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (11 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 12/30] media: entity: Add an iterator helper for connected pads Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 23:33   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 14/30] media: entity: Add debug information in graph walk route check Niklas Söderlund
                   ` (17 subsequent siblings)
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

A single entity may contain multiple pipelines. Only add pads that were
connected to the pad through which the entity was reached to the pipeline.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/media-entity.c | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index cdf3805dec755ec5..a5bb257d5a68f755 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -460,15 +460,13 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
 
 	while ((pad = media_graph_walk_next(graph))) {
 		struct media_entity *entity = pad->entity;
-		unsigned int i;
+		struct media_pad *iter;
 		bool skip_validation = pad->pipe;
 
 		DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
 		DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
 
-		for (i = 0; i < entity->num_pads; i++) {
-			struct media_pad *iter = &entity->pads[i];
-
+		media_entity_for_routed_pads(pad, iter) {
 			if (iter->pipe && WARN_ON(iter->pipe != pipe))
 				ret = -EBUSY;
 			else
@@ -553,12 +551,9 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
 	media_graph_walk_start(graph, pad_err);
 
 	while ((pad_err = media_graph_walk_next(graph))) {
-		struct media_entity *entity_err = pad_err->entity;
-		unsigned int i;
-
-		for (i = 0; i < entity_err->num_pads; i++) {
-			struct media_pad *iter = &entity_err->pads[i];
+		struct media_pad *iter;
 
+		media_entity_for_routed_pads(pad_err, iter) {
 			/* Sanity check for negative stream_count */
 			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
 				--iter->stream_count;
@@ -611,12 +606,9 @@ void __media_pipeline_stop(struct media_pad *pad)
 	media_graph_walk_start(graph, pad);
 
 	while ((pad = media_graph_walk_next(graph))) {
-		struct media_entity *entity = pad->entity;
-		unsigned int i;
-
-		for (i = 0; i < entity->num_pads; i++) {
-			struct media_pad *iter = &entity->pads[i];
+		struct media_pad *iter;
 
+		media_entity_for_routed_pads(pad, iter) {
 			/* Sanity check for negative stream_count */
 			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
 				iter->stream_count--;
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 14/30] media: entity: Add debug information in graph walk route check
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (12 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 13/30] media: entity: Add only connected pads to the pipeline Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 23:35   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 15/30] media: entity: Look for indirect routes Niklas Söderlund
                   ` (16 subsequent siblings)
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/media-entity.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index a5bb257d5a68f755..42977634d7102852 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -360,6 +360,9 @@ static void media_graph_walk_iter(struct media_graph *graph)
 	 */
 	if (!media_entity_has_route(pad->entity, pad->index, local->index)) {
 		link_top(graph) = link_top(graph)->next;
+		dev_dbg(pad->graph_obj.mdev->dev,
+			"walk: skipping \"%s\":%u -> %u (no route)\n",
+			pad->entity->name, pad->index, local->index);
 		return;
 	}
 
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 15/30] media: entity: Look for indirect routes
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (13 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 14/30] media: entity: Add debug information in graph walk route check Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 23:41   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations Niklas Söderlund
                   ` (15 subsequent siblings)
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

Two pads are considered having an active route for the purpose of
has_route() if an indirect active route can be found between the two pads.
An simple example of this is that a source pad has an active route to
another source pad if both of the pads have an active route to the same
sink pad.

Make media_entity_has_route() return true in that case, and do not rely on
drivers performing this by themselves.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/media-entity.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 42977634d7102852..e45fc2549017615a 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -240,6 +240,9 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init);
 bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
 			    unsigned int pad1)
 {
+	unsigned int i;
+	bool has_route;
+
 	if (pad0 >= entity->num_pads || pad1 >= entity->num_pads)
 		return false;
 
@@ -253,7 +256,34 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
 	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
 		swap(pad0, pad1);
 
-	return entity->ops->has_route(entity, pad0, pad1);
+	has_route = entity->ops->has_route(entity, pad0, pad1);
+	/* A direct route is returned immediately */
+	if (has_route ||
+	    (entity->pads[pad0].flags & MEDIA_PAD_FL_SINK &&
+	     entity->pads[pad1].flags & MEDIA_PAD_FL_SOURCE))
+		return true;
+
+	/* Look for indirect routes */
+	for (i = 0; i < entity->num_pads; i++) {
+		if (i == pad0 || i == pad1)
+			continue;
+
+		/*
+		 * There are no direct routes between same types of
+		 * pads, so skip checking this route
+		 */
+		if (!((entity->pads[pad0].flags ^ entity->pads[i].flags) &
+		      (MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_SINK)))
+			continue;
+
+		/* Is there an indirect route? */
+		if (entity->ops->has_route(entity, i, pad0) &&
+		    entity->ops->has_route(entity, i, pad1))
+			return true;
+	}
+
+	return false;
+
 }
 EXPORT_SYMBOL_GPL(media_entity_has_route);
 
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (14 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 15/30] media: entity: Look for indirect routes Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-15 23:51   ` Laurent Pinchart
  2019-02-21 14:39   ` Jacopo Mondi
  2018-11-01 23:31 ` [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING Niklas Söderlund
                   ` (14 subsequent siblings)
  30 siblings, 2 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Michal Simek

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>

- Add sink and source streams for multiplexed links
- Copy the argument back in case of an error. This is needed to let the
  caller know the number of routes.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
 drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
 include/media/v4l2-subdev.h           |  7 +++++
 include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
 4 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 7de041bae84fb2f2..40406acb51ec0906 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/version.h>
 
+#include <linux/v4l2-subdev.h>
 #include <linux/videodev2.h>
 
 #include <media/v4l2-common.h>
@@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
 		}
 		break;
 	}
+
+	case VIDIOC_SUBDEV_G_ROUTING:
+	case VIDIOC_SUBDEV_S_ROUTING: {
+		struct v4l2_subdev_routing *route = parg;
+
+		if (route->num_routes > 0) {
+			if (route->num_routes > 256)
+				return -EINVAL;
+
+			*user_ptr = (void __user *)route->routes;
+			*kernel_ptr = (void *)&route->routes;
+			*array_size = sizeof(struct v4l2_subdev_route)
+				    * route->num_routes;
+			ret = 1;
+		}
+		break;
+	}
 	}
 
 	return ret;
@@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
 	 * Some ioctls can return an error, but still have valid
 	 * results that must be returned.
 	 */
-	if (err < 0 && !always_copy)
+	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
 		goto out;
 
 out_array_args:
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 792f41dffe2329b9..1d3b37cf548fa533 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
 	case VIDIOC_SUBDEV_QUERYSTD:
 		return v4l2_subdev_call(sd, video, querystd, arg);
+
+	case VIDIOC_SUBDEV_G_ROUTING:
+		return v4l2_subdev_call(sd, pad, get_routing, arg);
+
+	case VIDIOC_SUBDEV_S_ROUTING: {
+		struct v4l2_subdev_routing *route = arg;
+		unsigned int i;
+
+		if (route->num_routes > sd->entity.num_pads)
+			return -EINVAL;
+
+		for (i = 0; i < route->num_routes; ++i) {
+			unsigned int sink = route->routes[i].sink_pad;
+			unsigned int source = route->routes[i].source_pad;
+			struct media_pad *pads = sd->entity.pads;
+
+			if (sink >= sd->entity.num_pads ||
+			    source >= sd->entity.num_pads)
+				return -EINVAL;
+
+			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
+			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
+				return -EINVAL;
+		}
+
+		return v4l2_subdev_call(sd, pad, set_routing, route);
+	}
 #endif
+
 	default:
 		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
 	}
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
  *
  * @set_frame_desc: set the low level media bus frame parameters, @fd array
  *                  may be adjusted by the subdev driver to device capabilities.
+ *
+ * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
+ * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
  */
 struct v4l2_subdev_pad_ops {
 	int (*init_cfg)(struct v4l2_subdev *sd,
@@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
 			      struct v4l2_mbus_frame_desc *fd);
 	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
 			      struct v4l2_mbus_frame_desc *fd);
+	int (*get_routing)(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_routing *route);
+	int (*set_routing)(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_routing *route);
 };
 
 /**
diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index 03970ce3074193e6..af069bfb10ca23a5 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
 	__u32 reserved[8];
 };
 
+#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
+#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
+
+/**
+ * struct v4l2_subdev_route - A signal route inside a subdev
+ * @sink_pad: the sink pad
+ * @sink_stream: the sink stream
+ * @source_pad: the source pad
+ * @source_stream: the source stream
+ * @flags: route flags:
+ *
+ *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
+ *	active stream will start when streaming is enabled on a video
+ *	node. Set by the user.
+ *
+ *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
+ *	can it be activated and inactivated? Set by the driver.
+ */
+struct v4l2_subdev_route {
+	__u32 sink_pad;
+	__u32 sink_stream;
+	__u32 source_pad;
+	__u32 source_stream;
+	__u32 flags;
+	__u32 reserved[5];
+};
+
+/**
+ * struct v4l2_subdev_routing - Routing information
+ * @routes: the routes array
+ * @num_routes: the total number of routes in the routes array
+ */
+struct v4l2_subdev_routing {
+	struct v4l2_subdev_route *routes;
+	__u32 num_routes;
+	__u32 reserved[5];
+};
+
 /* Backwards compatibility define --- to be removed */
 #define v4l2_subdev_edid v4l2_edid
 
@@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
 #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
 #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
 #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
+#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
+#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
 
 #endif
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (15 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-01-08 10:04   ` Geert Uytterhoeven
  2019-01-15 23:53   ` Laurent Pinchart
  2018-11-01 23:31 ` [PATCH v2 18/30] v4l: subdev: Take routing information into account in link validation Niklas Söderlund
                   ` (13 subsequent siblings)
  30 siblings, 2 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Niklas Söderlund

From: Sakari Ailus <sakari.ailus@linux.intel.com>

Implement compat IOCTL handling for VIDIOC_SUBDEV_G_ROUTING and
VIDIOC_SUBDEV_S_ROUTING IOCTLs.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 77 +++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 6481212fda772c73..83af332763f41a6b 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -1045,6 +1045,66 @@ static int put_v4l2_event32(struct v4l2_event __user *p64,
 	return 0;
 }
 
+struct v4l2_subdev_routing32 {
+	compat_caddr_t routes;
+	__u32 num_routes;
+	__u32 reserved[5];
+};
+
+static int get_v4l2_subdev_routing(struct v4l2_subdev_routing __user *p64,
+				   struct v4l2_subdev_routing32 __user *p32)
+{
+	struct v4l2_subdev_route __user *routes;
+	compat_caddr_t p;
+	u32 num_routes;
+
+	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+	    get_user(p, &p32->routes) ||
+	    get_user(num_routes, &p32->num_routes) ||
+	    put_user(num_routes, &p64->num_routes) ||
+	    copy_in_user(&p64->reserved, &p32->reserved,
+			 sizeof(p64->reserved)) ||
+	    num_routes > U32_MAX / sizeof(*p64->routes))
+		return -EFAULT;
+
+	routes = compat_ptr(p);
+
+	if (!access_ok(VERIFY_READ, routes,
+		       num_routes * sizeof(*p64->routes)))
+		return -EFAULT;
+
+	if (put_user((__force struct v4l2_subdev_route *)routes,
+		     &p64->routes))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int put_v4l2_subdev_routing(struct v4l2_subdev_routing __user *p64,
+				   struct v4l2_subdev_routing32 __user *p32)
+{
+	struct v4l2_subdev_route __user *routes;
+	compat_caddr_t p;
+	u32 num_routes;
+
+	if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
+	    get_user(p, &p32->routes) ||
+	    get_user(num_routes, &p64->num_routes) ||
+	    put_user(num_routes, &p32->num_routes) ||
+	    copy_in_user(&p32->reserved, &p64->reserved,
+			 sizeof(p64->reserved)) ||
+	    num_routes > U32_MAX / sizeof(*p64->routes))
+		return -EFAULT;
+
+	routes = compat_ptr(p);
+
+	if (!access_ok(VERIFY_WRITE, routes,
+		       num_routes * sizeof(*p64->routes)))
+		return -EFAULT;
+
+	return 0;
+}
+
 struct v4l2_edid32 {
 	__u32 pad;
 	__u32 start_block;
@@ -1117,6 +1177,8 @@ static int put_v4l2_edid32(struct v4l2_edid __user *p64,
 #define VIDIOC_STREAMOFF32	_IOW ('V', 19, s32)
 #define VIDIOC_G_INPUT32	_IOR ('V', 38, s32)
 #define VIDIOC_S_INPUT32	_IOWR('V', 39, s32)
+#define VIDIOC_SUBDEV_G_ROUTING32 _IOWR('V', 38, struct v4l2_subdev_routing32)
+#define VIDIOC_SUBDEV_S_ROUTING32 _IOWR('V', 39, struct v4l2_subdev_routing32)
 #define VIDIOC_G_OUTPUT32	_IOR ('V', 46, s32)
 #define VIDIOC_S_OUTPUT32	_IOWR('V', 47, s32)
 
@@ -1195,6 +1257,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
 	case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
 	case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
 	case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
+	case VIDIOC_SUBDEV_G_ROUTING32: cmd = VIDIOC_SUBDEV_G_ROUTING; break;
+	case VIDIOC_SUBDEV_S_ROUTING32: cmd = VIDIOC_SUBDEV_S_ROUTING; break;
 	case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
 	case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
 	case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
@@ -1227,6 +1291,15 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
 		compatible_arg = 0;
 		break;
 
+	case VIDIOC_SUBDEV_G_ROUTING:
+	case VIDIOC_SUBDEV_S_ROUTING:
+		err = alloc_userspace(sizeof(struct v4l2_subdev_routing),
+				      0, &new_p64);
+		if (!err)
+			err = get_v4l2_subdev_routing(new_p64, p32);
+		compatible_arg = 0;
+		break;
+
 	case VIDIOC_G_EDID:
 	case VIDIOC_S_EDID:
 		err = alloc_userspace(sizeof(struct v4l2_edid), 0, &new_p64);
@@ -1368,6 +1441,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
 		if (put_v4l2_edid32(new_p64, p32))
 			err = -EFAULT;
 		break;
+	case VIDIOC_SUBDEV_G_ROUTING:
+	case VIDIOC_SUBDEV_S_ROUTING:
+		err = put_v4l2_subdev_routing(new_p64, p32);
+		break;
 	}
 	if (err)
 		return err;
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 18/30] v4l: subdev: Take routing information into account in link validation
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (16 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 19/30] v4l: subdev: Improve link format validation debug messages Niklas Söderlund
                   ` (12 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

The routing information is essential in link validation for multiplexed
links: the pads at the ends of a multiplexed link have no single format
defined for them. Instead, the format is accessible in the sink (or
source) pads of the sub-devices at both ends of that link.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/v4l2-core/v4l2-subdev.c | 217 ++++++++++++++++++++++++--
 1 file changed, 203 insertions(+), 14 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 1d3b37cf548fa533..05684c796b184272 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -640,12 +640,17 @@ static int
 v4l2_subdev_link_validate_get_format(struct media_pad *pad,
 				     struct v4l2_subdev_format *fmt)
 {
+	dev_dbg(pad->entity->graph_obj.mdev->dev,
+		"obtaining format on \"%s\":%u\n", pad->entity->name,
+		pad->index);
+
 	if (is_media_entity_v4l2_subdev(pad->entity)) {
 		struct v4l2_subdev *sd =
 			media_entity_to_v4l2_subdev(pad->entity);
 
 		fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
 		fmt->pad = pad->index;
+
 		return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
 	}
 
@@ -656,31 +661,215 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad,
 	return -EINVAL;
 }
 
-int v4l2_subdev_link_validate(struct media_link *link)
+static int v4l2_subdev_link_validate_one(struct media_link *link,
+					 struct v4l2_subdev_format *source_fmt,
+					 struct v4l2_subdev_format *sink_fmt)
 {
 	struct v4l2_subdev *sink;
-	struct v4l2_subdev_format sink_fmt, source_fmt;
 	int rval;
 
-	rval = v4l2_subdev_link_validate_get_format(
-		link->source, &source_fmt);
-	if (rval < 0)
-		return 0;
-
-	rval = v4l2_subdev_link_validate_get_format(
-		link->sink, &sink_fmt);
-	if (rval < 0)
-		return 0;
-
 	sink = media_entity_to_v4l2_subdev(link->sink->entity);
 
 	rval = v4l2_subdev_call(sink, pad, link_validate, link,
-				&source_fmt, &sink_fmt);
+				source_fmt, sink_fmt);
 	if (rval != -ENOIOCTLCMD)
 		return rval;
 
 	return v4l2_subdev_link_validate_default(
-		sink, link, &source_fmt, &sink_fmt);
+		sink, link, source_fmt, sink_fmt);
+}
+
+/* How many routes to assume there can be per a sub-device? */
+#define LINK_VALIDATE_ROUTES	8
+
+#define R_SRC	0
+#define R_SINK	1
+#define NR_R	2
+
+int v4l2_subdev_link_validate(struct media_link *link)
+{
+	struct v4l2_subdev *sink;
+	struct route_info {
+		struct v4l2_subdev_route routes[LINK_VALIDATE_ROUTES];
+		struct v4l2_subdev_routing routing;
+		bool has_route;
+		struct media_pad *pad;
+		/* Format for a non-multiplexed pad. */
+		struct v4l2_subdev_format fmt;
+	} r[NR_R] = {
+		{
+			/* Source end of the link */
+			.routing = {
+				.routes = r[R_SRC].routes,
+				.num_routes = ARRAY_SIZE(r[R_SRC].routes),
+			},
+			.pad = link->source,
+		},
+		{
+			/* Sink end of the link */
+			.routing = {
+				.routes = r[R_SINK].routes,
+				.num_routes = ARRAY_SIZE(r[R_SINK].routes),
+			},
+			.pad = link->sink,
+		},
+	};
+	unsigned int i, j;
+	int rval;
+
+	sink = media_entity_to_v4l2_subdev(link->sink->entity);
+
+	dev_dbg(sink->entity.graph_obj.mdev->dev,
+		"validating link \"%s\":%u -> \"%s\":%u\n",
+		link->source->entity->name, link->source->index,
+		sink->entity.name, link->sink->index);
+
+	for (i = 0; i < NR_R; i++) {
+		struct route_info *ri = &r[i];
+
+		ri->has_route = true;
+
+		rval = v4l2_subdev_call(
+			media_entity_to_v4l2_subdev(ri->pad->entity),
+			pad, get_routing, &ri->routing);
+
+		switch (rval) {
+		case 0:
+			break;
+		case -ENOIOCTLCMD:
+			dev_dbg(sink->entity.graph_obj.mdev->dev,
+				"no routing information on \"%s\":%u\n",
+				ri->pad->entity->name, ri->pad->index);
+			ri->has_route = false;
+			break;
+		default:
+			dev_dbg(sink->entity.graph_obj.mdev->dev,
+				"error %d in get_routing() on \"%s\":%u\n",
+				rval, ri->pad->entity->name, ri->pad->index);
+			return rval;
+		}
+
+		rval = v4l2_subdev_link_validate_get_format(ri->pad,
+							    &ri->fmt);
+
+		if (!rval) {
+			dev_dbg(sink->entity.graph_obj.mdev->dev,
+				"format information available on \"%s\":%u\n",
+				ri->pad->entity->name, ri->pad->index);
+			ri->has_route = false;
+		}
+
+		if (!ri->has_route) {
+			ri->routing.num_routes = 1;
+		} else {
+			dev_dbg(sink->entity.graph_obj.mdev->dev,
+				"routes on \"%s\":%u:\n",
+				ri->pad->entity->name, ri->pad->index);
+			for (j = 0; j < ri->routing.num_routes; j++)
+				dev_dbg(sink->entity.graph_obj.mdev->dev,
+					"\t%u: %u/%u -> %u/%u\n", j,
+					ri->routing.routes[j].sink_pad,
+					ri->routing.routes[j].sink_stream,
+					ri->routing.routes[j].source_pad,
+					ri->routing.routes[j].source_stream);
+		}
+	}
+
+	for (i = 0, j = 0;
+	     i < r[R_SRC].routing.num_routes &&
+		     j < r[R_SINK].routing.num_routes; ) {
+		unsigned int *ro[] = { &i, &j };
+		unsigned int k;
+
+		/* Get the first active route for the sink pad. */
+		if (r[R_SINK].has_route &&
+		    (r[R_SINK].routes[j].sink_pad != link->sink->index ||
+		     !(r[R_SINK].routes[j].flags
+		       & V4L2_SUBDEV_ROUTE_FL_ACTIVE))) {
+			dev_dbg(sink->entity.graph_obj.mdev->dev,
+				"skipping route %u/%u -> %u/%u[%u]\n",
+				r[R_SINK].routes[j].sink_pad,
+				r[R_SINK].routes[j].sink_stream,
+				r[R_SINK].routes[j].source_pad,
+				r[R_SINK].routes[j].source_stream,
+				(bool)(r[R_SINK].routes[j].flags
+				       & V4L2_SUBDEV_ROUTE_FL_ACTIVE));
+			j++;
+			continue;
+		}
+
+		/*
+		 * Get the corresponding route for the source pad.
+		 * It's ok for the source pad to have routes active
+		 * where the sink pad does not, but the routes that
+		 * are active on the sink pad have to be active on
+		 * the source pad as well.
+		 */
+		if (r[R_SRC].has_route &&
+		    (r[R_SRC].routes[i].source_pad != link->source->index ||
+		     r[R_SRC].routes[i].source_stream
+		     != r[R_SINK].routes[j].sink_stream)) {
+			dev_dbg(sink->entity.graph_obj.mdev->dev,
+				"skipping source route %u/%u -> %u/%u\n",
+				r[R_SRC].routes[i].sink_pad,
+				r[R_SRC].routes[i].sink_stream,
+				r[R_SRC].routes[i].source_pad,
+				r[R_SRC].routes[i].source_stream);
+			i++;
+			continue;
+		}
+
+		/* The source route must be active. */
+		if (r[R_SRC].has_route &&
+		    !(r[R_SRC].routes[i].flags
+		      & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) {
+			dev_dbg(sink->entity.graph_obj.mdev->dev,
+				"source route not active\n");
+			return -EINVAL;
+		}
+
+		for (k = 0; k < NR_R; k++) {
+			if (r[k].has_route) {
+				dev_dbg(sink->entity.graph_obj.mdev->dev,
+					"validating %s route \"%s\": %u/%u -> %u/%u\n",
+					k == R_SINK ? "sink" : "source",
+					r[k].pad->entity->name,
+					r[k].routes[*ro[k]].sink_pad,
+					r[k].routes[*ro[k]].sink_stream,
+					r[k].routes[*ro[k]].source_pad,
+					r[k].routes[*ro[k]].source_stream);
+				rval = v4l2_subdev_link_validate_get_format(
+					&r[k].pad->entity->pads[
+						k == R_SINK
+						? r[k].routes[*ro[k]].source_pad
+						: r[k].routes[*ro[k]].sink_pad],
+					&r[k].fmt);
+			} else {
+				dev_dbg(sink->entity.graph_obj.mdev->dev,
+					"routing not supported by \"%s\":%u",
+					r[k].pad->entity->name,
+					r[k].pad->index);
+			}
+		}
+
+		rval = v4l2_subdev_link_validate_one(
+			link, &r[R_SRC].fmt, &r[R_SINK].fmt);
+		if (rval) {
+			dev_dbg(sink->entity.graph_obj.mdev->dev,
+				"error %d in link validation\n", rval);
+			return rval;
+		}
+
+		i++, j++;
+	}
+
+	if (j < r[R_SINK].routing.num_routes) {
+		dev_dbg(sink->entity.graph_obj.mdev->dev,
+			"not all sink routes verified; out of source routes\n");
+		return -EINVAL;
+	}
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
 
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 19/30] v4l: subdev: Improve link format validation debug messages
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (17 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 18/30] v4l: subdev: Take routing information into account in link validation Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 20/30] v4l: mc: Add an S_ROUTING helper function for power state changes Niklas Söderlund
                   ` (11 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

The existing link format validation failure debug message in media-entity.c
helped to poinpoint the point of failure but provided no additional
information what's wrong. Tell the user exactly why the validation failed.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/v4l2-core/v4l2-subdev.c | 40 ++++++++++++++++++++++-----
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 05684c796b184272..5c1459d3661e1de6 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -618,21 +618,47 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
 				      struct v4l2_subdev_format *source_fmt,
 				      struct v4l2_subdev_format *sink_fmt)
 {
+	bool pass = true;
+
 	/* The width, height and code must match. */
-	if (source_fmt->format.width != sink_fmt->format.width
-	    || source_fmt->format.height != sink_fmt->format.height
-	    || source_fmt->format.code != sink_fmt->format.code)
-		return -EPIPE;
+	if (source_fmt->format.width != sink_fmt->format.width) {
+		dev_dbg(sd->entity.graph_obj.mdev->dev,
+			"%s: width does not match (source %u, sink %u)\n",
+			__func__,
+			source_fmt->format.width, sink_fmt->format.width);
+		pass = false;
+	}
+
+	if (source_fmt->format.height != sink_fmt->format.height) {
+		dev_dbg(sd->entity.graph_obj.mdev->dev,
+			"%s: height does not match (source %u, sink %u)\n",
+			__func__,
+			source_fmt->format.height, sink_fmt->format.height);
+		pass = false;
+	}
+
+	if (source_fmt->format.code != sink_fmt->format.code) {
+		dev_dbg(sd->entity.graph_obj.mdev->dev,
+			"%s: media bus code does not match (source 0x%8.8x, sink 0x%8.8x)\n",
+			__func__,
+			source_fmt->format.code, sink_fmt->format.code);
+		pass = false;
+	}
 
 	/* The field order must match, or the sink field order must be NONE
 	 * to support interlaced hardware connected to bridges that support
 	 * progressive formats only.
 	 */
 	if (source_fmt->format.field != sink_fmt->format.field &&
-	    sink_fmt->format.field != V4L2_FIELD_NONE)
-		return -EPIPE;
+	    sink_fmt->format.field != V4L2_FIELD_NONE) {
+		dev_dbg(sd->entity.graph_obj.mdev->dev,
+			"%s: field does not match (source %u, sink %u)\n",
+			__func__,
+			source_fmt->format.field, sink_fmt->format.field);
+		pass = false;
+	}
 
-	return 0;
+	return pass ? 0 : -EPIPE;
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
 
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 20/30] v4l: mc: Add an S_ROUTING helper function for power state changes
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (18 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 19/30] v4l: subdev: Improve link format validation debug messages Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 21/30] v4l: Add bus type to frame descriptors Niklas Söderlund
                   ` (10 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

With the addition of the has_route() media entity operation, all pads of an
entity are no longer interconnected. The S_ROUTING IOCTL for sub-devices can
be used to enable and disable routes for an entity. The consequence is that
the routing information has to be taken into account in use count
calculation: disabling a route has a very similar effect on use counts as
has disabling a link.

Add a helper function for drivers implementing VIDIOC_SUBDEV_S_ROUTING
IOCTL to take the change into account.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/v4l2-core/v4l2-mc.c | 34 +++++++++++++++++++++++++++++++
 include/media/v4l2-mc.h           | 22 ++++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
index 208cd91ce57ff211..534c5ea4fab42244 100644
--- a/drivers/media/v4l2-core/v4l2-mc.c
+++ b/drivers/media/v4l2-core/v4l2-mc.c
@@ -482,3 +482,37 @@ int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(v4l2_pipeline_link_notify);
+
+int v4l2_subdev_routing_pm_use(struct media_entity *entity,
+			       struct v4l2_subdev_route *route)
+{
+	struct media_graph *graph =
+		&entity->graph_obj.mdev->pm_count_walk;
+	struct media_pad *source = &entity->pads[route->source_pad];
+	struct media_pad *sink = &entity->pads[route->sink_pad];
+	int source_use;
+	int sink_use;
+	int ret;
+
+	source_use = pipeline_pm_use_count(source, graph);
+	sink_use = pipeline_pm_use_count(sink, graph);
+
+	if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) {
+		/* Route disabled. */
+		pipeline_pm_power(source, -sink_use, graph);
+		pipeline_pm_power(sink, -source_use, graph);
+		return 0;
+	}
+
+	/* Route enabled. */
+	ret = pipeline_pm_power(source, sink_use, graph);
+	if (ret < 0)
+		return ret;
+
+	ret = pipeline_pm_power(sink, source_use, graph);
+	if (ret < 0)
+		pipeline_pm_power(source, -sink_use, graph);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_routing_pm_use);
diff --git a/include/media/v4l2-mc.h b/include/media/v4l2-mc.h
index bf5043c1ab6b3a32..730922636579a5fe 100644
--- a/include/media/v4l2-mc.h
+++ b/include/media/v4l2-mc.h
@@ -26,6 +26,7 @@
 /* We don't need to include pci.h or usb.h here */
 struct pci_dev;
 struct usb_device;
+struct v4l2_subdev_route;
 
 #ifdef CONFIG_MEDIA_CONTROLLER
 /**
@@ -132,6 +133,22 @@ int v4l2_pipeline_pm_use(struct media_entity *entity, int use);
 int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
 			      unsigned int notification);
 
+/**
+ * v4l2_subdev_routing_pm_use - Handle power state changes due to S_ROUTING
+ * @entity: The entity
+ * @route: The new state of the route
+ *
+ * Propagate the use count across a route in a pipeline whenever the
+ * route is enabled or disabled. The function is called before
+ * changing the route state when enabling a route, and after changing
+ * the route state when disabling a route.
+ *
+ * Return 0 on success or a negative error code on failure. Powering entities
+ * off is assumed to never fail. This function will not fail for disconnection
+ * events.
+ */
+int v4l2_subdev_routing_pm_use(struct media_entity *entity,
+			       struct v4l2_subdev_route *route);
 #else /* CONFIG_MEDIA_CONTROLLER */
 
 static inline int v4l2_mc_create_media_graph(struct media_device *mdev)
@@ -164,5 +181,10 @@ static inline int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
 	return 0;
 }
 
+static inline int v4l2_subdev_routing_pm_use(struct media_entity *entity,
+					     struct v4l2_subdev_route *route)
+{
+	return 0;
+}
 #endif /* CONFIG_MEDIA_CONTROLLER */
 #endif /* _V4L2_MC_H */
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 21/30] v4l: Add bus type to frame descriptors
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (19 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 20/30] v4l: mc: Add an S_ROUTING helper function for power state changes Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 22/30] v4l: Add CSI-2 bus configuration " Niklas Söderlund
                   ` (9 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 include/media/v4l2-subdev.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 5acaeeb9b3cacefa..ac1f7ee4cdb978ad 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -349,12 +349,21 @@ struct v4l2_mbus_frame_desc_entry {
 
 #define V4L2_FRAME_DESC_ENTRY_MAX	4
 
+enum {
+	V4L2_MBUS_FRAME_DESC_TYPE_PLATFORM,
+	V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL,
+	V4L2_MBUS_FRAME_DESC_TYPE_CCP2,
+	V4L2_MBUS_FRAME_DESC_TYPE_CSI2,
+};
+
 /**
  * struct v4l2_mbus_frame_desc - media bus data frame description
+ * @type: type of the bus (V4L2_MBUS_FRAME_DESC_TYPE_*)
  * @entry: frame descriptors array
  * @num_entries: number of entries in @entry array
  */
 struct v4l2_mbus_frame_desc {
+	u32 type;
 	struct v4l2_mbus_frame_desc_entry entry[V4L2_FRAME_DESC_ENTRY_MAX];
 	unsigned short num_entries;
 };
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 22/30] v4l: Add CSI-2 bus configuration to frame descriptors
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (20 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 21/30] v4l: Add bus type to frame descriptors Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 23/30] v4l: Add stream to frame descriptor Niklas Söderlund
                   ` (8 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

Add CSI-2 bus specific configuration to the frame descriptors. This allows
obtaining the virtual channel and data type information for each stream
the transmitter is sending.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 include/media/v4l2-subdev.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index ac1f7ee4cdb978ad..ffd98e4f368358a6 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -317,6 +317,17 @@ struct v4l2_subdev_audio_ops {
 	int (*s_stream)(struct v4l2_subdev *sd, int enable);
 };
 
+/**
+ * struct v4l2_mbus_frame_desc_entry_csi2
+ *
+ * @channel: CSI-2 virtual channel
+ * @data_type: CSI-2 data type ID
+ */
+struct v4l2_mbus_frame_desc_entry_csi2 {
+	u8 channel;
+	u8 data_type;
+};
+
 /**
  * enum v4l2_mbus_frame_desc_entry - media bus frame description flags
  *
@@ -340,11 +351,16 @@ enum v4l2_mbus_frame_desc_flags {
  *		%FRAME_DESC_FL_BLOB is not set.
  * @length:	number of octets per frame, valid if @flags
  *		%V4L2_MBUS_FRAME_DESC_FL_LEN_MAX is set.
+ * @bus:	Bus specific frame descriptor parameters
+ * @bus.csi2:	CSI-2 specific bus configuration
  */
 struct v4l2_mbus_frame_desc_entry {
 	enum v4l2_mbus_frame_desc_flags flags;
 	u32 pixelcode;
 	u32 length;
+	union {
+		struct v4l2_mbus_frame_desc_entry_csi2 csi2;
+	} bus;
 };
 
 #define V4L2_FRAME_DESC_ENTRY_MAX	4
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 23/30] v4l: Add stream to frame descriptor
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (21 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 22/30] v4l: Add CSI-2 bus configuration " Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 24/30] adv748x: csi2: add translation from pixelcode to CSI-2 datatype Niklas Söderlund
                   ` (7 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc

From: Sakari Ailus <sakari.ailus@linux.intel.com>

The stream field identifies the stream this frame descriptor applies to in
routing configuration across a multiplexed link.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 include/media/v4l2-subdev.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index ffd98e4f368358a6..5fbce1932107a990 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -347,6 +347,7 @@ enum v4l2_mbus_frame_desc_flags {
  * struct v4l2_mbus_frame_desc_entry - media bus frame description structure
  *
  * @flags:	bitmask flags, as defined by &enum v4l2_mbus_frame_desc_flags.
+ * @stream:	stream in routing configuration
  * @pixelcode:	media bus pixel code, valid if @flags
  *		%FRAME_DESC_FL_BLOB is not set.
  * @length:	number of octets per frame, valid if @flags
@@ -356,6 +357,7 @@ enum v4l2_mbus_frame_desc_flags {
  */
 struct v4l2_mbus_frame_desc_entry {
 	enum v4l2_mbus_frame_desc_flags flags;
+	u32 stream;
 	u32 pixelcode;
 	u32 length;
 	union {
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 24/30] adv748x: csi2: add translation from pixelcode to CSI-2 datatype
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (22 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 23/30] v4l: Add stream to frame descriptor Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 25/30] adv748x: csi2: only allow formats on sink pads Niklas Söderlund
                   ` (6 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Niklas Söderlund

Prepare to implement frame descriptors to support multiplexed streams by
adding a function to map pixelcode to CSI-2 datatype. This is needed to
properly be able to fill out the struct v4l2_mbus_frame_desc.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/i2c/adv748x/adv748x-csi2.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 6ce21542ed485811..8a7cc713c7adfcc1 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -14,6 +14,28 @@
 
 #include "adv748x.h"
 
+struct adv748x_csi2_format {
+	unsigned int code;
+	unsigned int datatype;
+};
+
+static const struct adv748x_csi2_format adv748x_csi2_formats[] = {
+	{ .code = MEDIA_BUS_FMT_RGB888_1X24,    .datatype = 0x24, },
+	{ .code = MEDIA_BUS_FMT_UYVY8_1X16,     .datatype = 0x1e, },
+	{ .code = MEDIA_BUS_FMT_UYVY8_2X8,      .datatype = 0x1e, },
+	{ .code = MEDIA_BUS_FMT_YUYV10_2X10,    .datatype = 0x1e, },
+};
+
+static unsigned int adv748x_csi2_code_to_datatype(unsigned int code)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(adv748x_csi2_formats); i++)
+		if (adv748x_csi2_formats[i].code == code)
+			return adv748x_csi2_formats[i].datatype;
+	return 0;
+}
+
 static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx,
 					    unsigned int vc)
 {
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 25/30] adv748x: csi2: only allow formats on sink pads
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (23 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 24/30] adv748x: csi2: add translation from pixelcode to CSI-2 datatype Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2019-02-21 14:18   ` Jacopo Mondi
  2018-11-01 23:31 ` [PATCH v2 26/30] adv748x: csi2: describe the multiplexed stream Niklas Söderlund
                   ` (5 subsequent siblings)
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Niklas Söderlund

Once the CSI-2 subdevice of the ADV748X becomes aware of multiplexed
streams the format of the source pad is of no value as it carries
multiple streams. Prepare for this by explicitly denying setting a
format on anything but the sink pad.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/i2c/adv748x/adv748x-csi2.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 8a7cc713c7adfcc1..9f2c49221a8ddebc 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -163,6 +163,9 @@ static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
 	struct adv748x_state *state = tx->state;
 	struct v4l2_mbus_framefmt *mbusformat;
 
+	if (sdformat->pad != ADV748X_CSI2_SINK)
+		return -EINVAL;
+
 	mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
 						 sdformat->which);
 	if (!mbusformat)
@@ -186,6 +189,9 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
 	struct v4l2_mbus_framefmt *mbusformat;
 	int ret = 0;
 
+	if (sdformat->pad != ADV748X_CSI2_SINK)
+		return -EINVAL;
+
 	mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
 						 sdformat->which);
 	if (!mbusformat)
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 26/30] adv748x: csi2: describe the multiplexed stream
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (24 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 25/30] adv748x: csi2: only allow formats on sink pads Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 27/30] adv748x: csi2: add internal routing configuration Niklas Söderlund
                   ` (4 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Niklas Söderlund

The adv748x CSI-2 transmitter can only transmit one stream over the
CSI-2 link, however it can choose which virtual channel is used. This
choice effects the CSI-2 receiver and needs to be captured in the frame
descriptor information, solve this by implementing .get_frame_desc().

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/i2c/adv748x/adv748x-csi2.c | 31 +++++++++++++++++++++++-
 drivers/media/i2c/adv748x/adv748x.h      |  1 +
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 9f2c49221a8ddebc..d83ae8e5d802a3bd 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -222,9 +222,37 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
 	return ret;
 }
 
+static int adv748x_csi2_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+				       struct v4l2_mbus_frame_desc *fd)
+{
+	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
+	struct v4l2_mbus_framefmt *mbusformat;
+
+	memset(fd, 0, sizeof(*fd));
+
+	if (pad != ADV748X_CSI2_SOURCE)
+		return -EINVAL;
+
+	mbusformat = adv748x_csi2_get_pad_format(sd, NULL, ADV748X_CSI2_SINK,
+						 V4L2_SUBDEV_FORMAT_ACTIVE);
+	if (!mbusformat)
+		return -EINVAL;
+
+	fd->entry->stream = tx->vc;
+	fd->entry->bus.csi2.channel = tx->vc;
+	fd->entry->bus.csi2.data_type =
+		adv748x_csi2_code_to_datatype(mbusformat->code);
+
+	fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+	fd->num_entries = 1;
+
+	return 0;
+}
+
 static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
 	.get_fmt = adv748x_csi2_get_format,
 	.set_fmt = adv748x_csi2_set_format,
+	.get_frame_desc = adv748x_csi2_get_frame_desc,
 };
 
 /* -----------------------------------------------------------------------------
@@ -291,7 +319,8 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
 		return 0;
 
 	/* Initialise the virtual channel */
-	adv748x_csi2_set_virtual_channel(tx, 0);
+	tx->vc = 0;
+	adv748x_csi2_set_virtual_channel(tx, tx->vc);
 
 	adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
 			    MEDIA_ENT_F_VID_IF_BRIDGE,
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index 39c2fdc3b41667d8..b24e5ea1fe0f8c8d 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -76,6 +76,7 @@ enum adv748x_csi2_pads {
 
 struct adv748x_csi2 {
 	struct adv748x_state *state;
+	unsigned int vc;
 	struct v4l2_mbus_framefmt format;
 	unsigned int page;
 	unsigned int port;
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 27/30] adv748x: csi2: add internal routing configuration
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (25 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 26/30] adv748x: csi2: describe the multiplexed stream Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 28/30] adv748x: afe: add routing support Niklas Söderlund
                   ` (3 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Niklas Söderlund

Add support to get and set the internal routing between the adv748x
CSI-2 transmitters sink pad and its multiplexed source pad. This routing
includes which stream of the multiplexed pad to use, allowing the user
to select which CSI-2 virtual channel to use when transmitting the
stream.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/i2c/adv748x/adv748x-csi2.c | 65 ++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index d83ae8e5d802a3bd..ef588567313574c7 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -14,6 +14,8 @@
 
 #include "adv748x.h"
 
+#define ADV748X_CSI2_ROUTES_MAX 4
+
 struct adv748x_csi2_format {
 	unsigned int code;
 	unsigned int datatype;
@@ -249,10 +251,73 @@ static int adv748x_csi2_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
 	return 0;
 }
 
+static int adv748x_csi2_get_routing(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_routing *routing)
+{
+	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
+	struct v4l2_subdev_route *r = routing->routes;
+	unsigned int vc;
+
+	if (routing->num_routes < ADV748X_CSI2_ROUTES_MAX) {
+		routing->num_routes = ADV748X_CSI2_ROUTES_MAX;
+		return -ENOSPC;
+	}
+
+	routing->num_routes = ADV748X_CSI2_ROUTES_MAX;
+
+	for (vc = 0; vc < ADV748X_CSI2_ROUTES_MAX; vc++) {
+		r->sink_pad = ADV748X_CSI2_SINK;
+		r->sink_stream = 0;
+		r->source_pad = ADV748X_CSI2_SOURCE;
+		r->source_stream = vc;
+		r->flags = vc == tx->vc ? V4L2_SUBDEV_ROUTE_FL_ACTIVE : 0;
+		r++;
+	}
+
+	return 0;
+}
+
+static int adv748x_csi2_set_routing(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_routing *routing)
+{
+	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
+	struct v4l2_subdev_route *r = routing->routes;
+	unsigned int i;
+	int vc = -1;
+
+	if (routing->num_routes > ADV748X_CSI2_ROUTES_MAX)
+		return -ENOSPC;
+
+	for (i = 0; i < routing->num_routes; i++) {
+		if (r->sink_pad != ADV748X_CSI2_SINK ||
+		    r->sink_stream != 0 ||
+		    r->source_pad != ADV748X_CSI2_SOURCE ||
+		    r->source_stream >= ADV748X_CSI2_ROUTES_MAX)
+			return -EINVAL;
+
+		if (r->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE) {
+			if (vc != -1)
+				return -EMLINK;
+
+			vc = r->source_stream;
+		}
+		r++;
+	}
+
+	if (vc != -1)
+		tx->vc = vc;
+
+	adv748x_csi2_set_virtual_channel(tx, tx->vc);
+
+	return 0;
+}
+
 static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
 	.get_fmt = adv748x_csi2_get_format,
 	.set_fmt = adv748x_csi2_set_format,
 	.get_frame_desc = adv748x_csi2_get_frame_desc,
+	.get_routing = adv748x_csi2_get_routing,
+	.set_routing = adv748x_csi2_set_routing,
 };
 
 /* -----------------------------------------------------------------------------
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 28/30] adv748x: afe: add routing support
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (26 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 27/30] adv748x: csi2: add internal routing configuration Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 29/30] rcar-csi2: use frame description information to configure CSI-2 bus Niklas Söderlund
                   ` (2 subsequent siblings)
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Niklas Söderlund

The adv748x afe has eight analog sink pads, currently one of them is
chosen to be the active route based on device tree configuration. With
the new routing API it's possible to expose and change which of the
eight sink pads are routed to the source pad.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/i2c/adv748x/adv748x-afe.c | 65 +++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c
index 71714634efb08bd4..6b7fd4685aa4c177 100644
--- a/drivers/media/i2c/adv748x/adv748x-afe.c
+++ b/drivers/media/i2c/adv748x/adv748x-afe.c
@@ -39,6 +39,9 @@
 #define ADV748X_AFE_STD_PAL_SECAM			0xe
 #define ADV748X_AFE_STD_PAL_SECAM_PED			0xf
 
+#define ADV748X_AFE_ROUTES_MAX ((ADV748X_AFE_SINK_AIN7 - \
+				ADV748X_AFE_SINK_AIN0) + 1)
+
 static int adv748x_afe_read_ro_map(struct adv748x_state *state, u8 reg)
 {
 	int ret;
@@ -383,10 +386,72 @@ static int adv748x_afe_set_format(struct v4l2_subdev *sd,
 	return 0;
 }
 
+static int adv748x_afe_get_routing(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_routing *routing)
+{
+	struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
+	struct v4l2_subdev_route *r = routing->routes;
+	unsigned int i;
+
+	/* There is one possible route from each sink */
+	if (routing->num_routes < ADV748X_AFE_ROUTES_MAX) {
+		routing->num_routes = ADV748X_AFE_ROUTES_MAX;
+		return -ENOSPC;
+	}
+
+	routing->num_routes = ADV748X_AFE_ROUTES_MAX;
+
+	for (i = ADV748X_AFE_SINK_AIN0; i <= ADV748X_AFE_SINK_AIN7; i++) {
+		r->sink_pad = i;
+		r->sink_stream = 0;
+		r->source_pad = ADV748X_AFE_SOURCE;
+		r->source_stream = 0;
+		r->flags = afe->input == i ? V4L2_SUBDEV_ROUTE_FL_ACTIVE : 0;
+		r++;
+	}
+
+	return 0;
+}
+
+static int adv748x_afe_set_routing(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_routing *routing)
+{
+	struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
+	struct v4l2_subdev_route *r = routing->routes;
+	int input = -1;
+	unsigned int i;
+
+	if (routing->num_routes > ADV748X_AFE_ROUTES_MAX)
+		return -ENOSPC;
+
+	for (i = 0; i < routing->num_routes; i++) {
+		if (r->sink_pad > ADV748X_AFE_SINK_AIN7 ||
+		    r->sink_stream != 0 ||
+		    r->source_pad != ADV748X_AFE_SOURCE ||
+		    r->source_stream != 0)
+			return -EINVAL;
+
+		if (r->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE) {
+			if (input != -1)
+				return -EMLINK;
+
+			input = r->sink_pad;
+		}
+		r++;
+	}
+
+	if (input != -1)
+		afe->input = input;
+
+	return 0;
+}
+
 static const struct v4l2_subdev_pad_ops adv748x_afe_pad_ops = {
 	.enum_mbus_code = adv748x_afe_enum_mbus_code,
 	.set_fmt = adv748x_afe_set_format,
 	.get_fmt = adv748x_afe_get_format,
+	.get_routing = adv748x_afe_get_routing,
+	.set_routing = adv748x_afe_set_routing,
 };
 
 /* -----------------------------------------------------------------------------
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 29/30] rcar-csi2: use frame description information to configure CSI-2 bus
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (27 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 28/30] adv748x: afe: add routing support Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-01 23:31 ` [PATCH v2 30/30] rcar-csi2: expose the subdevice internal routing Niklas Söderlund
  2018-12-03 22:16 ` [PATCH v2 00/30] v4l: add support for multiplexed streams Sakari Ailus
  30 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Niklas Söderlund

The driver can now access frame descriptor information, use it when
configuring the CSI-2 bus. Only enable the virtual channels which are
described in the frame descriptor and calculate the link based on all
enabled streams.

With multiplexed stream supported it's now meaningful to have different
formats on the different source pads. Make source formats independent
off each other and disallowing a format on the multiplexed sink pad.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/platform/rcar-vin/rcar-csi2.c | 135 ++++++++++++++------
 1 file changed, 98 insertions(+), 37 deletions(-)

diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index b0044a08e71ed017..00564c969dd021db 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -304,25 +304,22 @@ static const struct rcsi2_mbps_reg hsfreqrange_m3w_h3es1[] = {
 #define CSI0CLKFREQRANGE(n)		((n & 0x3f) << 16)
 
 struct rcar_csi2_format {
-	u32 code;
 	unsigned int datatype;
 	unsigned int bpp;
 };
 
 static const struct rcar_csi2_format rcar_csi2_formats[] = {
-	{ .code = MEDIA_BUS_FMT_RGB888_1X24,	.datatype = 0x24, .bpp = 24 },
-	{ .code = MEDIA_BUS_FMT_UYVY8_1X16,	.datatype = 0x1e, .bpp = 16 },
-	{ .code = MEDIA_BUS_FMT_YUYV8_1X16,	.datatype = 0x1e, .bpp = 16 },
-	{ .code = MEDIA_BUS_FMT_UYVY8_2X8,	.datatype = 0x1e, .bpp = 16 },
-	{ .code = MEDIA_BUS_FMT_YUYV10_2X10,	.datatype = 0x1e, .bpp = 20 },
+	{ .datatype = 0x1e, .bpp = 16 },
+	{ .datatype = 0x24, .bpp = 24 },
 };
 
-static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code)
+static const struct rcar_csi2_format
+*rcsi2_datatype_to_fmt(unsigned int datatype)
 {
 	unsigned int i;
 
 	for (i = 0; i < ARRAY_SIZE(rcar_csi2_formats); i++)
-		if (rcar_csi2_formats[i].code == code)
+		if (rcar_csi2_formats[i].datatype == datatype)
 			return &rcar_csi2_formats[i];
 
 	return NULL;
@@ -337,6 +334,14 @@ enum rcar_csi2_pads {
 	NR_OF_RCAR_CSI2_PAD,
 };
 
+static int rcsi2_pad_to_vc(unsigned int pad)
+{
+	if (pad < RCAR_CSI2_SOURCE_VC0 || pad > RCAR_CSI2_SOURCE_VC3)
+		return -EINVAL;
+
+	return pad - RCAR_CSI2_SOURCE_VC0;
+}
+
 struct rcar_csi2_info {
 	int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps);
 	int (*confirm_start)(struct rcar_csi2 *priv);
@@ -357,7 +362,7 @@ struct rcar_csi2 {
 	struct v4l2_async_subdev asd;
 	struct v4l2_subdev *remote;
 
-	struct v4l2_mbus_framefmt mf;
+	struct v4l2_mbus_framefmt mf[4];
 
 	struct mutex lock;
 	int stream_count;
@@ -393,6 +398,32 @@ static void rcsi2_reset(struct rcar_csi2 *priv)
 	rcsi2_write(priv, SRST_REG, 0);
 }
 
+static int rcsi2_get_remote_frame_desc(struct rcar_csi2 *priv,
+				       struct v4l2_mbus_frame_desc *fd)
+{
+	struct media_pad *pad;
+	int ret;
+
+	if (!priv->remote)
+		return -ENODEV;
+
+	pad = media_entity_remote_pad(&priv->pads[RCAR_CSI2_SINK]);
+	if (!pad)
+		return -ENODEV;
+
+	ret = v4l2_subdev_call(priv->remote, pad, get_frame_desc,
+			       pad->index, fd);
+	if (ret)
+		return -ENODEV;
+
+	if (fd->type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+		dev_err(priv->dev, "Frame desc do not describe CSI-2 link");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int rcsi2_wait_phy_start(struct rcar_csi2 *priv)
 {
 	unsigned int timeout;
@@ -431,10 +462,12 @@ static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps)
 	return 0;
 }
 
-static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp)
+static int rcsi2_calc_mbps(struct rcar_csi2 *priv,
+			   struct v4l2_mbus_frame_desc *fd)
 {
 	struct v4l2_subdev *source;
 	struct v4l2_ctrl *ctrl;
+	unsigned int i, bpp = 0;
 	u64 mbps;
 
 	if (!priv->remote)
@@ -450,6 +483,21 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp)
 		return -EINVAL;
 	}
 
+	/* Calculate total bpp */
+	for (i = 0; i < fd->num_entries; i++) {
+		const struct rcar_csi2_format *format;
+
+		format = rcsi2_datatype_to_fmt(
+					fd->entry[i].bus.csi2.data_type);
+		if (!format) {
+			dev_err(priv->dev, "Unknown data type: %d\n",
+				fd->entry[i].bus.csi2.data_type);
+			return -EINVAL;
+		}
+
+		bpp += format->bpp;
+	}
+
 	/*
 	 * Calculate the phypll in mbps.
 	 * link_freq = (pixel_rate * bits_per_sample) / (2 * nr_of_lanes)
@@ -463,42 +511,40 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp)
 
 static int rcsi2_start(struct rcar_csi2 *priv)
 {
-	const struct rcar_csi2_format *format;
+	struct v4l2_mbus_frame_desc fd;
 	u32 phycnt, vcdt = 0, vcdt2 = 0;
 	unsigned int i;
 	int mbps, ret;
 
-	dev_dbg(priv->dev, "Input size (%ux%u%c)\n",
-		priv->mf.width, priv->mf.height,
-		priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i');
-
-	/* Code is validated in set_fmt. */
-	format = rcsi2_code_to_fmt(priv->mf.code);
+	/* Get information about multiplexed link. */
+	ret = rcsi2_get_remote_frame_desc(priv, &fd);
+	if (ret)
+		return ret;
 
-	/*
-	 * Enable all Virtual Channels.
-	 *
-	 * NOTE: It's not possible to get individual datatype for each
-	 *       source virtual channel. Once this is possible in V4L2
-	 *       it should be used here.
-	 */
-	for (i = 0; i < 4; i++) {
+	for (i = 0; i < fd.num_entries; i++) {
+		struct v4l2_mbus_frame_desc_entry *entry = &fd.entry[i];
 		u32 vcdt_part;
 
-		vcdt_part = VCDT_SEL_VC(i) | VCDT_VCDTN_EN | VCDT_SEL_DTN_ON |
-			VCDT_SEL_DT(format->datatype);
+		vcdt_part = VCDT_SEL_VC(entry->bus.csi2.channel) |
+			VCDT_VCDTN_EN | VCDT_SEL_DTN_ON |
+			VCDT_SEL_DT(entry->bus.csi2.data_type);
 
 		/* Store in correct reg and offset. */
-		if (i < 2)
-			vcdt |= vcdt_part << ((i % 2) * 16);
+		if (entry->bus.csi2.channel < 2)
+			vcdt |= vcdt_part <<
+				((entry->bus.csi2.channel % 2) * 16);
 		else
-			vcdt2 |= vcdt_part << ((i % 2) * 16);
+			vcdt2 |= vcdt_part <<
+				((entry->bus.csi2.channel % 2) * 16);
+
+		dev_dbg(priv->dev, "VC%d datatype: 0x%x\n",
+			entry->bus.csi2.channel, entry->bus.csi2.data_type);
 	}
 
 	phycnt = PHYCNT_ENABLECLK;
 	phycnt |= (1 << priv->lanes) - 1;
 
-	mbps = rcsi2_calc_mbps(priv, format->bpp);
+	mbps = rcsi2_calc_mbps(priv, &fd);
 	if (mbps < 0)
 		return mbps;
 
@@ -619,14 +665,16 @@ static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
 {
 	struct rcar_csi2 *priv = sd_to_csi2(sd);
 	struct v4l2_mbus_framefmt *framefmt;
+	int vc;
 
-	if (!rcsi2_code_to_fmt(format->format.code))
-		format->format.code = rcar_csi2_formats[0].code;
+	vc = rcsi2_pad_to_vc(format->pad);
+	if (vc < 0)
+		return vc;
 
 	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
-		priv->mf = format->format;
+		priv->mf[vc] = format->format;
 	} else {
-		framefmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+		framefmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
 		*framefmt = format->format;
 	}
 
@@ -638,11 +686,17 @@ static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
 				struct v4l2_subdev_format *format)
 {
 	struct rcar_csi2 *priv = sd_to_csi2(sd);
+	int vc;
+
+	vc = rcsi2_pad_to_vc(format->pad);
+	if (vc < 0)
+		return vc;
 
 	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-		format->format = priv->mf;
+		format->format = priv->mf[vc];
 	else
-		format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
+		format->format = *v4l2_subdev_get_try_format(sd, cfg,
+							     format->pad);
 
 	return 0;
 }
@@ -672,6 +726,13 @@ static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier,
 	struct rcar_csi2 *priv = notifier_to_csi2(notifier);
 	int pad;
 
+	if (!v4l2_subdev_has_op(subdev, pad, get_frame_desc)) {
+		dev_err(priv->dev,
+			"Failed as '%s' do not support frame descriptors\n",
+			subdev->name);
+		return -EINVAL;
+	}
+
 	pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
 					  MEDIA_PAD_FL_SOURCE);
 	if (pad < 0) {
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v2 30/30] rcar-csi2: expose the subdevice internal routing
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (28 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 29/30] rcar-csi2: use frame description information to configure CSI-2 bus Niklas Söderlund
@ 2018-11-01 23:31 ` Niklas Söderlund
  2018-11-14 13:10   ` Nikita Yushchenko
  2018-12-03 22:16 ` [PATCH v2 00/30] v4l: add support for multiplexed streams Sakari Ailus
  30 siblings, 1 reply; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-01 23:31 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media
  Cc: linux-renesas-soc, Niklas Söderlund

Expose the subdevice internal routing from the single multiplexed sink
pad to its source pads by implementing .get_routing(). This information
is used to do link validation at stream start and allows user-space to
view the route configuration.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/platform/rcar-vin/rcar-csi2.c | 53 +++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index 00564c969dd021db..f51b6fbc6042ac1d 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -342,6 +342,14 @@ static int rcsi2_pad_to_vc(unsigned int pad)
 	return pad - RCAR_CSI2_SOURCE_VC0;
 }
 
+static int rcsi2_vc_to_pad(unsigned int vc)
+{
+	if (vc > 3)
+		return -EINVAL;
+
+	return vc + RCAR_CSI2_SOURCE_VC0;
+}
+
 struct rcar_csi2_info {
 	int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps);
 	int (*confirm_start)(struct rcar_csi2 *priv);
@@ -705,9 +713,54 @@ static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = {
 	.s_stream = rcsi2_s_stream,
 };
 
+static int rcsi2_get_routing(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_routing *routing)
+{
+	struct rcar_csi2 *priv = sd_to_csi2(sd);
+	struct v4l2_mbus_frame_desc fd;
+	struct v4l2_subdev_route *r = routing->routes;
+	unsigned int i;
+	int ret;
+
+	/* Get information about multiplexed link */
+	ret = rcsi2_get_remote_frame_desc(priv, &fd);
+	if (ret)
+		return ret;
+
+	if (routing->num_routes < fd.num_entries) {
+		routing->num_routes = fd.num_entries;
+		return -ENOSPC;
+	}
+
+	routing->num_routes = fd.num_entries;
+
+	for (i = 0; i < fd.num_entries; i++) {
+		struct v4l2_mbus_frame_desc_entry *entry = &fd.entry[i];
+		int source_pad;
+
+		source_pad = rcsi2_vc_to_pad(entry->bus.csi2.channel);
+		if (source_pad < 0) {
+			dev_err(priv->dev, "Virtual Channel out of range: %u\n",
+				entry->bus.csi2.channel);
+			return -ENOSPC;
+		}
+
+		r->sink_pad = RCAR_CSI2_SINK;
+		r->sink_stream = entry->stream;
+		r->source_pad = source_pad;
+		r->source_stream = 0;
+		r->flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE |
+			V4L2_SUBDEV_ROUTE_FL_IMMUTABLE;
+		r++;
+	}
+
+	return 0;
+}
+
 static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = {
 	.set_fmt = rcsi2_set_pad_format,
 	.get_fmt = rcsi2_get_pad_format,
+	.get_routing = rcsi2_get_routing,
 };
 
 static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 30/30] rcar-csi2: expose the subdevice internal routing
  2018-11-01 23:31 ` [PATCH v2 30/30] rcar-csi2: expose the subdevice internal routing Niklas Söderlund
@ 2018-11-14 13:10   ` Nikita Yushchenko
  2018-11-14 19:45     ` Niklas Söderlund
  0 siblings, 1 reply; 90+ messages in thread
From: Nikita Yushchenko @ 2018-11-14 13:10 UTC (permalink / raw)
  To: Niklas Söderlund, Laurent Pinchart, Sakari Ailus,
	Benoit Parrot, linux-media
  Cc: linux-renesas-soc

> +	for (i = 0; i < fd.num_entries; i++) {
> +		struct v4l2_mbus_frame_desc_entry *entry = &fd.entry[i];
> +		int source_pad;
> +
> +		source_pad = rcsi2_vc_to_pad(entry->bus.csi2.channel);
> +		if (source_pad < 0) {
> +			dev_err(priv->dev, "Virtual Channel out of range: %u\n",
> +				entry->bus.csi2.channel);
> +			return -ENOSPC;

Why -ENOSPC here?

AFAIU negative source_pad here means driver internal error (frame desc
returned from rcsi2_get_remote_frame_desc() is invalid).  Then I think
error return should be -EIO.

Nikita

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 30/30] rcar-csi2: expose the subdevice internal routing
  2018-11-14 13:10   ` Nikita Yushchenko
@ 2018-11-14 19:45     ` Niklas Söderlund
  0 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-11-14 19:45 UTC (permalink / raw)
  To: Nikita Yushchenko
  Cc: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media,
	linux-renesas-soc

Hi Nikita,

Thanks for your feedback.

On 2018-11-14 16:10:37 +0300, Nikita Yushchenko wrote:
> > +	for (i = 0; i < fd.num_entries; i++) {
> > +		struct v4l2_mbus_frame_desc_entry *entry = &fd.entry[i];
> > +		int source_pad;
> > +
> > +		source_pad = rcsi2_vc_to_pad(entry->bus.csi2.channel);
> > +		if (source_pad < 0) {
> > +			dev_err(priv->dev, "Virtual Channel out of range: %u\n",
> > +				entry->bus.csi2.channel);
> > +			return -ENOSPC;
> 
> Why -ENOSPC here?
> 
> AFAIU negative source_pad here means driver internal error (frame desc
> returned from rcsi2_get_remote_frame_desc() is invalid).  Then I think
> error return should be -EIO.

Wops, I agree with you this should not be -ENOSPC. Looking at the code 
this seems I just reused the same error code as if there is no space in 
the routes array check above this chunk, my bad. I will fix this for the 
next version.

-- 
Regards,
Niklas S�derlund

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 00/30] v4l: add support for multiplexed streams
  2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
                   ` (29 preceding siblings ...)
  2018-11-01 23:31 ` [PATCH v2 30/30] rcar-csi2: expose the subdevice internal routing Niklas Söderlund
@ 2018-12-03 22:16 ` Sakari Ailus
  2018-12-05 22:09   ` Niklas Söderlund
  30 siblings, 1 reply; 90+ messages in thread
From: Sakari Ailus @ 2018-12-03 22:16 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Laurent Pinchart, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

On Fri, Nov 02, 2018 at 12:31:14AM +0100, Niklas S�derlund wrote:
> Hi all,
> 
> This series adds support for multiplexed streams within a media device
> link. The use-case addressed in this series covers CSI-2 Virtual
> Channels on the Renesas R-Car Gen3 platforms. The v4l2 changes have been
> a joint effort between Sakari and Laurent and floating around for some
> time [1].
> 
> I have added driver support for the devices used on the Renesas Gen3
> platforms, a ADV7482 connected to the R-Car CSI-2 receiver. With these
> changes I can control which of the analog inputs of the ADV7482 the
> video source is captured from and on which CSI-2 virtual channel the
> video is transmitted on to the R-Car CSI-2 receiver.
> 
> The series adds two new subdev IOCTLs [GS]_ROUTING which allows
> user-space to get and set routes inside a subdevice. I have added RFC
> support for these to v4l-utils [2] which can be used to test this
> series, example:
> 
>     Check the internal routing of the adv748x csi-2 transmitter:
>     v4l2-ctl -d /dev/v4l-subdev24 --get-routing
>     0/0 -> 1/0 [ENABLED]
>     0/0 -> 1/1 []
>     0/0 -> 1/2 []
>     0/0 -> 1/3 []
> 
> 
>     Select that video should be outputed on VC 2 and check the result:
>     $ v4l2-ctl -d /dev/v4l-subdev24 --set-routing '0/0 -> 1/2 [1]'
> 
>     $ v4l2-ctl -d /dev/v4l-subdev24 --get-routing
>     0/0 -> 1/0 []
>     0/0 -> 1/1 []
>     0/0 -> 1/2 [ENABLED]
>     0/0 -> 1/3 []
> 
> This series is tested on R-Car M3-N and for your testing needs this
> series is available at
> 
>     git://git.ragnatech.se/linux v4l2/mux
> 
> * Changes since v1
> - Rebased on latest media-tree.
> - Incorporated changes to patch 'v4l: subdev: compat: Implement handling 
>   for VIDIOC_SUBDEV_[GS]_ROUTING' by Sakari.
> - Added review tags.

I was looking at the patches and they seem very nice to me. It's not that
I've written most of them, but I still. X-)

I noticed that the new [GS]_ROUTING interface has no documentation
currently. Could you write it?

Also what I'd like to see is the media graph of a device that is driven by
these drivers. That'd help to better understand the use case also for those
who haven't worked with the patches.

Thanks.

-- 
Kind regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 00/30] v4l: add support for multiplexed streams
  2018-12-03 22:16 ` [PATCH v2 00/30] v4l: add support for multiplexed streams Sakari Ailus
@ 2018-12-05 22:09   ` Niklas Söderlund
  0 siblings, 0 replies; 90+ messages in thread
From: Niklas Söderlund @ 2018-12-05 22:09 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Laurent Pinchart, Benoit Parrot, linux-media, linux-renesas-soc

Hi Sakari,

Thanks for your feedback.

On 2018-12-04 00:16:29 +0200, Sakari Ailus wrote:
> Hi Niklas,
> 
> On Fri, Nov 02, 2018 at 12:31:14AM +0100, Niklas S�derlund wrote:
> > Hi all,
> > 
> > This series adds support for multiplexed streams within a media device
> > link. The use-case addressed in this series covers CSI-2 Virtual
> > Channels on the Renesas R-Car Gen3 platforms. The v4l2 changes have been
> > a joint effort between Sakari and Laurent and floating around for some
> > time [1].
> > 
> > I have added driver support for the devices used on the Renesas Gen3
> > platforms, a ADV7482 connected to the R-Car CSI-2 receiver. With these
> > changes I can control which of the analog inputs of the ADV7482 the
> > video source is captured from and on which CSI-2 virtual channel the
> > video is transmitted on to the R-Car CSI-2 receiver.
> > 
> > The series adds two new subdev IOCTLs [GS]_ROUTING which allows
> > user-space to get and set routes inside a subdevice. I have added RFC
> > support for these to v4l-utils [2] which can be used to test this
> > series, example:
> > 
> >     Check the internal routing of the adv748x csi-2 transmitter:
> >     v4l2-ctl -d /dev/v4l-subdev24 --get-routing
> >     0/0 -> 1/0 [ENABLED]
> >     0/0 -> 1/1 []
> >     0/0 -> 1/2 []
> >     0/0 -> 1/3 []
> > 
> > 
> >     Select that video should be outputed on VC 2 and check the result:
> >     $ v4l2-ctl -d /dev/v4l-subdev24 --set-routing '0/0 -> 1/2 [1]'
> > 
> >     $ v4l2-ctl -d /dev/v4l-subdev24 --get-routing
> >     0/0 -> 1/0 []
> >     0/0 -> 1/1 []
> >     0/0 -> 1/2 [ENABLED]
> >     0/0 -> 1/3 []
> > 
> > This series is tested on R-Car M3-N and for your testing needs this
> > series is available at
> > 
> >     git://git.ragnatech.se/linux v4l2/mux
> > 
> > * Changes since v1
> > - Rebased on latest media-tree.
> > - Incorporated changes to patch 'v4l: subdev: compat: Implement handling 
> >   for VIDIOC_SUBDEV_[GS]_ROUTING' by Sakari.
> > - Added review tags.
> 
> I was looking at the patches and they seem very nice to me. It's not that
> I've written most of them, but I still. X-)

:-)

> 
> I noticed that the new [GS]_ROUTING interface has no documentation
> currently. Could you write it?

Will add it for the next version. Thanks for pointing this out.

> 
> Also what I'd like to see is the media graph of a device that is driven by
> these drivers. That'd help to better understand the use case also for those
> who haven't worked with the patches.

I will attach the media graph for this simple use-case with the adv7482 
and a more complex case using 8 cameras and GMSL in the next version.

-- 
Regards,
Niklas S�derlund

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING
  2018-11-01 23:31 ` [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING Niklas Söderlund
@ 2019-01-08 10:04   ` Geert Uytterhoeven
  2019-01-15 23:53   ` Laurent Pinchart
  1 sibling, 0 replies; 90+ messages in thread
From: Geert Uytterhoeven @ 2019-01-08 10:04 UTC (permalink / raw)
  To: Niklas Söderlund, Sakari Ailus
  Cc: Laurent Pinchart, Benoit Parrot, Linux Media Mailing List, Linux-Renesas

Hi Niklas, Sakari,

On Fri, Nov 2, 2018 at 12:33 AM Niklas Söderlund
<niklas.soderlund+renesas@ragnatech.se> wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
>
> Implement compat IOCTL handling for VIDIOC_SUBDEV_G_ROUTING and
> VIDIOC_SUBDEV_S_ROUTING IOCTLs.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> @@ -1045,6 +1045,66 @@ static int put_v4l2_event32(struct v4l2_event __user *p64,
>         return 0;
>  }
>
> +struct v4l2_subdev_routing32 {
> +       compat_caddr_t routes;
> +       __u32 num_routes;
> +       __u32 reserved[5];
> +};
> +
> +static int get_v4l2_subdev_routing(struct v4l2_subdev_routing __user *p64,
> +                                  struct v4l2_subdev_routing32 __user *p32)
> +{
> +       struct v4l2_subdev_route __user *routes;
> +       compat_caddr_t p;
> +       u32 num_routes;
> +
> +       if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||

Please drop the first parameter of all newly-added access_ok() calls, as
it has been removed in commit 96d4f267e40f9509 ("Remove 'type' argument
from access_ok() function").

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 01/30] media: entity: Use pad as a starting point for graph walk
  2018-11-01 23:31 ` [PATCH v2 01/30] media: entity: Use pad as a starting point for graph walk Niklas Söderlund
@ 2019-01-15 21:43   ` Laurent Pinchart
  0 siblings, 0 replies; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 21:43 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hello Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:15AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> With the upcoming use of the recently added has_route() media entity op, all
> the pads in an entity will no longer be considered interconnected. This has
> an effect where the media graph is traversed: the starting pad does make a
> difference.
> 
> Prepare for this change by using pad instead of the entity as an argument
> for the graph walk operations. The actual graph traversal algorithm change
> is in further patches.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
>  Documentation/media/kapi/mc-core.rst            |  2 +-
>  drivers/media/media-entity.c                    | 17 ++++++++---------
>  drivers/media/platform/exynos4-is/media-dev.c   |  4 ++--
>  drivers/media/platform/omap3isp/ispvideo.c      |  2 +-
>  drivers/media/platform/vsp1/vsp1_video.c        |  2 +-
>  drivers/media/platform/xilinx/xilinx-dma.c      |  2 +-
>  drivers/media/v4l2-core/v4l2-mc.c               |  6 +++---
>  drivers/staging/media/davinci_vpfe/vpfe_video.c |  6 +++---
>  drivers/staging/media/omap4iss/iss_video.c      |  4 ++--
>  include/media/media-entity.h                    | 10 ++++------
>  10 files changed, 26 insertions(+), 29 deletions(-)
> 
> diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
> index 0c05503eaf1fa6c7..27aefb9a778b2ad6 100644
> --- a/Documentation/media/kapi/mc-core.rst
> +++ b/Documentation/media/kapi/mc-core.rst
> @@ -165,7 +165,7 @@ Drivers initiate a graph traversal by calling
>  :c:func:`media_graph_walk_start()`
>  
>  The graph structure, provided by the caller, is initialized to start graph
> -traversal at the given entity.
> +traversal at the given pad in an entity.
>  
>  Drivers can then retrieve the next entity by calling
>  :c:func:`media_graph_walk_next()`
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index 0b1cb3559140a1fe..2bbc07de71aa5e6d 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -300,17 +300,16 @@ void media_graph_walk_cleanup(struct media_graph *graph)
>  }
>  EXPORT_SYMBOL_GPL(media_graph_walk_cleanup);
>  
> -void media_graph_walk_start(struct media_graph *graph,
> -			    struct media_entity *entity)
> +void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad)
>  {
>  	media_entity_enum_zero(&graph->ent_enum);
> -	media_entity_enum_set(&graph->ent_enum, entity);
> +	media_entity_enum_set(&graph->ent_enum, pad->entity);
>  
>  	graph->top = 0;
>  	graph->stack[graph->top].entity = NULL;
> -	stack_push(graph, entity);
> -	dev_dbg(entity->graph_obj.mdev->dev,
> -		"begin graph walk at '%s'\n", entity->name);
> +	stack_push(graph, pad->entity);
> +	dev_dbg(pad->graph_obj.mdev->dev,
> +		"begin graph walk at '%s':%u\n", pad->entity->name, pad->index);
>  }
>  EXPORT_SYMBOL_GPL(media_graph_walk_start);
>  
> @@ -428,7 +427,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  			goto error_graph_walk_start;
>  	}
>  
> -	media_graph_walk_start(&pipe->graph, entity);
> +	media_graph_walk_start(&pipe->graph, entity->pads);
>  
>  	while ((entity = media_graph_walk_next(graph))) {
>  		DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
> @@ -509,7 +508,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  	 * Link validation on graph failed. We revert what we did and
>  	 * return the error.
>  	 */
> -	media_graph_walk_start(graph, entity_err);
> +	media_graph_walk_start(graph, entity_err->pads);
>  
>  	while ((entity_err = media_graph_walk_next(graph))) {
>  		/* Sanity check for negative stream_count */
> @@ -560,7 +559,7 @@ void __media_pipeline_stop(struct media_entity *entity)
>  	if (WARN_ON(!pipe))
>  		return;
>  
> -	media_graph_walk_start(graph, entity);
> +	media_graph_walk_start(graph, entity->pads);
>  
>  	while ((entity = media_graph_walk_next(graph))) {
>  		/* Sanity check for negative stream_count */
> diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
> index 870501b0f351addb..51d2a571c06db6a3 100644
> --- a/drivers/media/platform/exynos4-is/media-dev.c
> +++ b/drivers/media/platform/exynos4-is/media-dev.c
> @@ -1144,7 +1144,7 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
>  	 * through active links. This is needed as we cannot power on/off the
>  	 * subdevs in random order.
>  	 */
> -	media_graph_walk_start(graph, entity);
> +	media_graph_walk_start(graph, entity->pads);
>  
>  	while ((entity = media_graph_walk_next(graph))) {
>  		if (!is_media_entity_v4l2_video_device(entity))
> @@ -1159,7 +1159,7 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
>  	return 0;
>  
>  err:
> -	media_graph_walk_start(graph, entity_err);
> +	media_graph_walk_start(graph, entity_err->pads);
>  
>  	while ((entity_err = media_graph_walk_next(graph))) {
>  		if (!is_media_entity_v4l2_video_device(entity_err))
> diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
> index 5658f6a326f77f66..50ad35bc644eae29 100644
> --- a/drivers/media/platform/omap3isp/ispvideo.c
> +++ b/drivers/media/platform/omap3isp/ispvideo.c
> @@ -238,7 +238,7 @@ static int isp_video_get_graph_data(struct isp_video *video,
>  		return ret;
>  	}
>  
> -	media_graph_walk_start(&graph, entity);
> +	media_graph_walk_start(&graph, entity->pads);
>  
>  	while ((entity = media_graph_walk_next(&graph))) {
>  		struct isp_video *__video;
> diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
> index 771dfe1f7c20e526..e35b2e2340b82f00 100644
> --- a/drivers/media/platform/vsp1/vsp1_video.c
> +++ b/drivers/media/platform/vsp1/vsp1_video.c
> @@ -580,7 +580,7 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
>  	if (ret)
>  		return ret;
>  
> -	media_graph_walk_start(&graph, entity);
> +	media_graph_walk_start(&graph, entity->pads);
>  
>  	while ((entity = media_graph_walk_next(&graph))) {
>  		struct v4l2_subdev *subdev;
> diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
> index 4ae9d38c94332fa4..566c2d0fb97dc162 100644
> --- a/drivers/media/platform/xilinx/xilinx-dma.c
> +++ b/drivers/media/platform/xilinx/xilinx-dma.c
> @@ -193,7 +193,7 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
>  		return ret;
>  	}
>  
> -	media_graph_walk_start(&graph, entity);
> +	media_graph_walk_start(&graph, entity->pads);
>  
>  	while ((entity = media_graph_walk_next(&graph))) {
>  		struct xvip_dma *dma;
> diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
> index 014a2a97cadd8706..9ed480fe5b6e4762 100644
> --- a/drivers/media/v4l2-core/v4l2-mc.c
> +++ b/drivers/media/v4l2-core/v4l2-mc.c
> @@ -341,7 +341,7 @@ static int pipeline_pm_use_count(struct media_entity *entity,
>  {
>  	int use = 0;
>  
> -	media_graph_walk_start(graph, entity);
> +	media_graph_walk_start(graph, entity->pads);
>  
>  	while ((entity = media_graph_walk_next(graph))) {
>  		if (is_media_entity_v4l2_video_device(entity))
> @@ -404,7 +404,7 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
>  	if (!change)
>  		return 0;
>  
> -	media_graph_walk_start(graph, entity);
> +	media_graph_walk_start(graph, entity->pads);
>  
>  	while (!ret && (entity = media_graph_walk_next(graph)))
>  		if (is_media_entity_v4l2_subdev(entity))
> @@ -413,7 +413,7 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
>  	if (!ret)
>  		return ret;
>  
> -	media_graph_walk_start(graph, first);
> +	media_graph_walk_start(graph, first->pads);
>  
>  	while ((first = media_graph_walk_next(graph))
>  	       && first != entity)
> diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
> index 5e42490331b7620f..912d93fc7a483cd4 100644
> --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
> +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
> @@ -150,7 +150,7 @@ static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
>  		mutex_unlock(&mdev->graph_mutex);
>  		return -ENOMEM;
>  	}
> -	media_graph_walk_start(&graph, entity);
> +	media_graph_walk_start(&graph, entity->pads);
>  	while ((entity = media_graph_walk_next(&graph))) {
>  		if (entity == &video->video_dev.entity)
>  			continue;
> @@ -303,7 +303,7 @@ static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
>  	ret = media_graph_walk_init(&pipe->graph, mdev);
>  	if (ret)
>  		goto out;
> -	media_graph_walk_start(&pipe->graph, entity);
> +	media_graph_walk_start(&pipe->graph, entity->pads);
>  	while ((entity = media_graph_walk_next(&pipe->graph))) {
>  
>  		if (!is_media_entity_v4l2_subdev(entity))
> @@ -345,7 +345,7 @@ static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
>  
>  	mdev = entity->graph_obj.mdev;
>  	mutex_lock(&mdev->graph_mutex);
> -	media_graph_walk_start(&pipe->graph, entity);
> +	media_graph_walk_start(&pipe->graph, entity->pads);
>  
>  	while ((entity = media_graph_walk_next(&pipe->graph))) {
>  
> diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
> index c1322aeaf01eb951..6f72c02c8054f496 100644
> --- a/drivers/staging/media/omap4iss/iss_video.c
> +++ b/drivers/staging/media/omap4iss/iss_video.c
> @@ -217,7 +217,7 @@ iss_video_far_end(struct iss_video *video)
>  		return NULL;
>  	}
>  
> -	media_graph_walk_start(&graph, entity);
> +	media_graph_walk_start(&graph, entity->pads);
>  
>  	while ((entity = media_graph_walk_next(&graph))) {
>  		if (entity == &video->video.entity)
> @@ -897,7 +897,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
>  	if (ret < 0)
>  		goto err_media_pipeline_start;
>  
> -	media_graph_walk_start(&graph, entity);
> +	media_graph_walk_start(&graph, entity->pads);
>  	while ((entity = media_graph_walk_next(&graph)))
>  		media_entity_enum_set(&pipe->ent_enum, entity);
>  
> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index e5f6960d92f6cdd4..07ab141e739ef5ff 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -928,22 +928,20 @@ void media_graph_walk_cleanup(struct media_graph *graph);
>  void media_entity_put(struct media_entity *entity);
>  
>  /**
> - * media_graph_walk_start - Start walking the media graph at a
> - *	given entity
> + * media_graph_walk_start - Start walking the media graph at a given pad
>   *
>   * @graph: Media graph structure that will be used to walk the graph
> - * @entity: Starting entity
> + * @pad: Starting pad
>   *
>   * Before using this function, media_graph_walk_init() must be
>   * used to allocate resources used for walking the graph. This
>   * function initializes the graph traversal structure to walk the
> - * entities graph starting at the given entity. The traversal
> + * entities graph starting at the given pad. The traversal
>   * structure must not be modified by the caller during graph
>   * traversal. After the graph walk, the resources must be released
>   * using media_graph_walk_cleanup().
>   */
> -void media_graph_walk_start(struct media_graph *graph,
> -			    struct media_entity *entity);
> +void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad);
>  
>  /**
>   * media_graph_walk_next - Get the next entity in the graph

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 02/30] media: entity: Use pads instead of entities in the media graph walk stack
  2018-11-01 23:31 ` [PATCH v2 02/30] media: entity: Use pads instead of entities in the media graph walk stack Niklas Söderlund
@ 2019-01-15 22:03   ` Laurent Pinchart
  2019-01-15 22:13     ` Sakari Ailus
  2019-01-15 22:07   ` Laurent Pinchart
  1 sibling, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 22:03 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:16AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> Change the media graph walk stack structure to use media pads instead of
> using media entities. In addition to the entity, the pad contains the
> information which pad in the entity are being dealt with.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/media-entity.c | 53 ++++++++++++++++++------------------
>  include/media/media-entity.h |  6 ++--
>  2 files changed, 29 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index 2bbc07de71aa5e6d..892e64a0a9d8ec42 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -237,40 +237,39 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init);
>   * Graph traversal
>   */
>  
> -static struct media_entity *
> -media_entity_other(struct media_entity *entity, struct media_link *link)
> +static struct media_pad *
> +media_entity_other(struct media_pad *pad, struct media_link *link)
>  {
> -	if (link->source->entity == entity)
> -		return link->sink->entity;
> +	if (link->source == pad)
> +		return link->sink;
>  	else
> -		return link->source->entity;
> +		return link->source;
>  }
>  
>  /* push an entity to traversal stack */
> -static void stack_push(struct media_graph *graph,
> -		       struct media_entity *entity)
> +static void stack_push(struct media_graph *graph, struct media_pad *pad)
>  {
>  	if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
>  		WARN_ON(1);
>  		return;
>  	}
>  	graph->top++;
> -	graph->stack[graph->top].link = entity->links.next;
> -	graph->stack[graph->top].entity = entity;
> +	graph->stack[graph->top].link = pad->entity->links.next;
> +	graph->stack[graph->top].pad = pad;
>  }
>  
> -static struct media_entity *stack_pop(struct media_graph *graph)
> +static struct media_pad *stack_pop(struct media_graph *graph)
>  {
> -	struct media_entity *entity;
> +	struct media_pad *pad;
>  
> -	entity = graph->stack[graph->top].entity;
> +	pad = graph->stack[graph->top].pad;
>  	graph->top--;
>  
> -	return entity;
> +	return pad;
>  }
>  
>  #define link_top(en)	((en)->stack[(en)->top].link)
> -#define stack_top(en)	((en)->stack[(en)->top].entity)
> +#define stack_top(en)	((en)->stack[(en)->top].pad)
>  
>  /**
>   * media_graph_walk_init - Allocate resources for graph walk
> @@ -306,8 +305,8 @@ void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad)
>  	media_entity_enum_set(&graph->ent_enum, pad->entity);
>  
>  	graph->top = 0;
> -	graph->stack[graph->top].entity = NULL;
> -	stack_push(graph, pad->entity);
> +	graph->stack[graph->top].pad = NULL;
> +	stack_push(graph, pad);
>  	dev_dbg(pad->graph_obj.mdev->dev,
>  		"begin graph walk at '%s':%u\n", pad->entity->name, pad->index);
>  }
> @@ -315,16 +314,16 @@ EXPORT_SYMBOL_GPL(media_graph_walk_start);
>  
>  static void media_graph_walk_iter(struct media_graph *graph)
>  {
> -	struct media_entity *entity = stack_top(graph);
> +	struct media_pad *pad = stack_top(graph);
>  	struct media_link *link;
> -	struct media_entity *next;
> +	struct media_pad *next;
>  
>  	link = list_entry(link_top(graph), typeof(*link), list);
>  
>  	/* The link is not enabled so we do not follow. */
>  	if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
>  		link_top(graph) = link_top(graph)->next;
> -		dev_dbg(entity->graph_obj.mdev->dev,
> +		dev_dbg(pad->graph_obj.mdev->dev,
>  			"walk: skipping disabled link '%s':%u -> '%s':%u\n",
>  			link->source->entity->name, link->source->index,
>  			link->sink->entity->name, link->sink->index);
> @@ -332,22 +331,22 @@ static void media_graph_walk_iter(struct media_graph *graph)
>  	}
>  
>  	/* Get the entity in the other end of the link . */

s/entity/pad/

> -	next = media_entity_other(entity, link);
> +	next = media_entity_other(pad, link);
>  
>  	/* Has the entity already been visited? */

s/entity/pad's entity/

> -	if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
> +	if (media_entity_enum_test_and_set(&graph->ent_enum, next->entity)) {
>  		link_top(graph) = link_top(graph)->next;
> -		dev_dbg(entity->graph_obj.mdev->dev,
> +		dev_dbg(pad->graph_obj.mdev->dev,
>  			"walk: skipping entity '%s' (already seen)\n",
> -			next->name);
> +			next->entity->name);
>  		return;
>  	}
>  
>  	/* Push the new entity to stack and start over. */

s/entity/pad/

>  	link_top(graph) = link_top(graph)->next;
>  	stack_push(graph, next);
> -	dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n",
> -		next->name);
> +	dev_dbg(next->graph_obj.mdev->dev, "walk: pushing '%s':%u on stack\n",
> +		next->entity->name, next->index);
>  }
>  
>  struct media_entity *media_graph_walk_next(struct media_graph *graph)
> @@ -362,10 +361,10 @@ struct media_entity *media_graph_walk_next(struct media_graph *graph)
>  	 * top of the stack until no more entities on the level can be
>  	 * found.
>  	 */
> -	while (link_top(graph) != &stack_top(graph)->links)
> +	while (link_top(graph) != &stack_top(graph)->entity->links)
>  		media_graph_walk_iter(graph);
>  
> -	entity = stack_pop(graph);
> +	entity = stack_pop(graph)->entity;
>  	dev_dbg(entity->graph_obj.mdev->dev,
>  		"walk: returning entity '%s'\n", entity->name);
>  
> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index 07ab141e739ef5ff..99c7606f01317741 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -86,16 +86,16 @@ struct media_entity_enum {
>   * struct media_graph - Media graph traversal state
>   *
>   * @stack:		Graph traversal stack; the stack contains information
> - *			on the path the media entities to be walked and the
> + *			on the path the media pads to be walked and the

This sentence doesn't make too much sense to me, are we missing
something ?

The rest looks OK to me, so with this fixed,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

>   *			links through which they were reached.
> - * @stack.entity:	pointer to &struct media_entity at the graph.
> + * @stack.pad:		pointer to &struct media_pad at the graph.
>   * @stack.link:		pointer to &struct list_head.
>   * @ent_enum:		Visited entities
>   * @top:		The top of the stack
>   */
>  struct media_graph {
>  	struct {
> -		struct media_entity *entity;
> +		struct media_pad *pad;
>  		struct list_head *link;
>  	} stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
>  

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 02/30] media: entity: Use pads instead of entities in the media graph walk stack
  2018-11-01 23:31 ` [PATCH v2 02/30] media: entity: Use pads instead of entities in the media graph walk stack Niklas Söderlund
  2019-01-15 22:03   ` Laurent Pinchart
@ 2019-01-15 22:07   ` Laurent Pinchart
  1 sibling, 0 replies; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 22:07 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Another small comment.

On Fri, Nov 02, 2018 at 12:31:16AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> Change the media graph walk stack structure to use media pads instead of
> using media entities. In addition to the entity, the pad contains the
> information which pad in the entity are being dealt with.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/media-entity.c | 53 ++++++++++++++++++------------------
>  include/media/media-entity.h |  6 ++--
>  2 files changed, 29 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index 2bbc07de71aa5e6d..892e64a0a9d8ec42 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -237,40 +237,39 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init);
>   * Graph traversal
>   */
>  
> -static struct media_entity *
> -media_entity_other(struct media_entity *entity, struct media_link *link)
> +static struct media_pad *
> +media_entity_other(struct media_pad *pad, struct media_link *link)

Shouldn't this now be called media_pad_other() ?

>  {
> -	if (link->source->entity == entity)
> -		return link->sink->entity;
> +	if (link->source == pad)
> +		return link->sink;
>  	else
> -		return link->source->entity;
> +		return link->source;
>  }

[snip]

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 02/30] media: entity: Use pads instead of entities in the media graph walk stack
  2019-01-15 22:03   ` Laurent Pinchart
@ 2019-01-15 22:13     ` Sakari Ailus
  0 siblings, 0 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-01-15 22:13 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

Hi Laurent,

On Wed, Jan 16, 2019 at 12:03:13AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thank you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:16AM +0100, Niklas Söderlund wrote:
> > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > 
> > Change the media graph walk stack structure to use media pads instead of
> > using media entities. In addition to the entity, the pad contains the
> > information which pad in the entity are being dealt with.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/media-entity.c | 53 ++++++++++++++++++------------------
> >  include/media/media-entity.h |  6 ++--
> >  2 files changed, 29 insertions(+), 30 deletions(-)
> > 
> > diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> > index 2bbc07de71aa5e6d..892e64a0a9d8ec42 100644
> > --- a/drivers/media/media-entity.c
> > +++ b/drivers/media/media-entity.c
> > @@ -237,40 +237,39 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init);
> >   * Graph traversal
> >   */
> >  
> > -static struct media_entity *
> > -media_entity_other(struct media_entity *entity, struct media_link *link)
> > +static struct media_pad *
> > +media_entity_other(struct media_pad *pad, struct media_link *link)
> >  {
> > -	if (link->source->entity == entity)
> > -		return link->sink->entity;
> > +	if (link->source == pad)
> > +		return link->sink;
> >  	else
> > -		return link->source->entity;
> > +		return link->source;
> >  }
> >  
> >  /* push an entity to traversal stack */
> > -static void stack_push(struct media_graph *graph,
> > -		       struct media_entity *entity)
> > +static void stack_push(struct media_graph *graph, struct media_pad *pad)
> >  {
> >  	if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
> >  		WARN_ON(1);
> >  		return;
> >  	}
> >  	graph->top++;
> > -	graph->stack[graph->top].link = entity->links.next;
> > -	graph->stack[graph->top].entity = entity;
> > +	graph->stack[graph->top].link = pad->entity->links.next;
> > +	graph->stack[graph->top].pad = pad;
> >  }
> >  
> > -static struct media_entity *stack_pop(struct media_graph *graph)
> > +static struct media_pad *stack_pop(struct media_graph *graph)
> >  {
> > -	struct media_entity *entity;
> > +	struct media_pad *pad;
> >  
> > -	entity = graph->stack[graph->top].entity;
> > +	pad = graph->stack[graph->top].pad;
> >  	graph->top--;
> >  
> > -	return entity;
> > +	return pad;
> >  }
> >  
> >  #define link_top(en)	((en)->stack[(en)->top].link)
> > -#define stack_top(en)	((en)->stack[(en)->top].entity)
> > +#define stack_top(en)	((en)->stack[(en)->top].pad)
> >  
> >  /**
> >   * media_graph_walk_init - Allocate resources for graph walk
> > @@ -306,8 +305,8 @@ void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad)
> >  	media_entity_enum_set(&graph->ent_enum, pad->entity);
> >  
> >  	graph->top = 0;
> > -	graph->stack[graph->top].entity = NULL;
> > -	stack_push(graph, pad->entity);
> > +	graph->stack[graph->top].pad = NULL;
> > +	stack_push(graph, pad);
> >  	dev_dbg(pad->graph_obj.mdev->dev,
> >  		"begin graph walk at '%s':%u\n", pad->entity->name, pad->index);
> >  }
> > @@ -315,16 +314,16 @@ EXPORT_SYMBOL_GPL(media_graph_walk_start);
> >  
> >  static void media_graph_walk_iter(struct media_graph *graph)
> >  {
> > -	struct media_entity *entity = stack_top(graph);
> > +	struct media_pad *pad = stack_top(graph);
> >  	struct media_link *link;
> > -	struct media_entity *next;
> > +	struct media_pad *next;
> >  
> >  	link = list_entry(link_top(graph), typeof(*link), list);
> >  
> >  	/* The link is not enabled so we do not follow. */
> >  	if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
> >  		link_top(graph) = link_top(graph)->next;
> > -		dev_dbg(entity->graph_obj.mdev->dev,
> > +		dev_dbg(pad->graph_obj.mdev->dev,
> >  			"walk: skipping disabled link '%s':%u -> '%s':%u\n",
> >  			link->source->entity->name, link->source->index,
> >  			link->sink->entity->name, link->sink->index);
> > @@ -332,22 +331,22 @@ static void media_graph_walk_iter(struct media_graph *graph)
> >  	}
> >  
> >  	/* Get the entity in the other end of the link . */
> 
> s/entity/pad/
> 
> > -	next = media_entity_other(entity, link);
> > +	next = media_entity_other(pad, link);
> >  
> >  	/* Has the entity already been visited? */
> 
> s/entity/pad's entity/
> 
> > -	if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
> > +	if (media_entity_enum_test_and_set(&graph->ent_enum, next->entity)) {
> >  		link_top(graph) = link_top(graph)->next;
> > -		dev_dbg(entity->graph_obj.mdev->dev,
> > +		dev_dbg(pad->graph_obj.mdev->dev,
> >  			"walk: skipping entity '%s' (already seen)\n",
> > -			next->name);
> > +			next->entity->name);
> >  		return;
> >  	}
> >  
> >  	/* Push the new entity to stack and start over. */
> 
> s/entity/pad/
> 
> >  	link_top(graph) = link_top(graph)->next;
> >  	stack_push(graph, next);
> > -	dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n",
> > -		next->name);
> > +	dev_dbg(next->graph_obj.mdev->dev, "walk: pushing '%s':%u on stack\n",
> > +		next->entity->name, next->index);
> >  }
> >  
> >  struct media_entity *media_graph_walk_next(struct media_graph *graph)
> > @@ -362,10 +361,10 @@ struct media_entity *media_graph_walk_next(struct media_graph *graph)
> >  	 * top of the stack until no more entities on the level can be
> >  	 * found.
> >  	 */
> > -	while (link_top(graph) != &stack_top(graph)->links)
> > +	while (link_top(graph) != &stack_top(graph)->entity->links)
> >  		media_graph_walk_iter(graph);
> >  
> > -	entity = stack_pop(graph);
> > +	entity = stack_pop(graph)->entity;
> >  	dev_dbg(entity->graph_obj.mdev->dev,
> >  		"walk: returning entity '%s'\n", entity->name);
> >  
> > diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> > index 07ab141e739ef5ff..99c7606f01317741 100644
> > --- a/include/media/media-entity.h
> > +++ b/include/media/media-entity.h
> > @@ -86,16 +86,16 @@ struct media_entity_enum {
> >   * struct media_graph - Media graph traversal state
> >   *
> >   * @stack:		Graph traversal stack; the stack contains information
> > - *			on the path the media entities to be walked and the
> > + *			on the path the media pads to be walked and the
> 
> This sentence doesn't make too much sense to me, are we missing
> something ?

I think this should have been "the stack contains information on the media
entities to be walked and the links through which they were reached". So
just replace "entities" by "pads" here.

> 
> The rest looks OK to me, so with this fixed,
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> >   *			links through which they were reached.
> > - * @stack.entity:	pointer to &struct media_entity at the graph.
> > + * @stack.pad:		pointer to &struct media_pad at the graph.
> >   * @stack.link:		pointer to &struct list_head.
> >   * @ent_enum:		Visited entities
> >   * @top:		The top of the stack
> >   */
> >  struct media_graph {
> >  	struct {
> > -		struct media_entity *entity;
> > +		struct media_pad *pad;
> >  		struct list_head *link;
> >  	} stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
> >  
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 03/30] media: entity: Walk the graph based on pads
  2018-11-01 23:31 ` [PATCH v2 03/30] media: entity: Walk the graph based on pads Niklas Söderlund
@ 2019-01-15 22:21   ` Laurent Pinchart
       [not found]     ` <20190115223406.mxgzl36cp54gb7nv@kekkonen.localdomain>
  2019-02-14 15:15   ` Jacopo Mondi
  1 sibling, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 22:21 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:17AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> Instead of iterating over graph entities during the walk, iterate the pads
> through which the entity was first reached. This is required in order to
> make the entity pipeline pad-based rather than entity based.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  Documentation/media/kapi/mc-core.rst          |  7 ++-
>  drivers/media/media-entity.c                  | 46 ++++++++++--------
>  drivers/media/platform/exynos4-is/media-dev.c | 20 ++++----
>  drivers/media/platform/omap3isp/ispvideo.c    | 17 +++----
>  drivers/media/platform/vsp1/vsp1_video.c      | 12 ++---
>  drivers/media/platform/xilinx/xilinx-dma.c    | 12 ++---
>  drivers/media/v4l2-core/v4l2-mc.c             | 25 +++++-----
>  .../staging/media/davinci_vpfe/vpfe_video.c   | 47 ++++++++++---------
>  drivers/staging/media/omap4iss/iss_video.c    | 34 +++++++-------
>  include/media/media-entity.h                  |  7 +--
>  10 files changed, 122 insertions(+), 105 deletions(-)

[snip]

> diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
> index 51d2a571c06db6a3..5813639c63b56a2c 100644
> --- a/drivers/media/platform/exynos4-is/media-dev.c
> +++ b/drivers/media/platform/exynos4-is/media-dev.c
> @@ -1135,7 +1135,7 @@ static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable)
>  static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
>  				      struct media_graph *graph)
>  {
> -	struct media_entity *entity_err = entity;
> +	struct media_pad *pad, *pad_err = entity->pads;
>  	int ret;
>  
>  	/*
> @@ -1144,13 +1144,13 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
>  	 * through active links. This is needed as we cannot power on/off the
>  	 * subdevs in random order.
>  	 */
> -	media_graph_walk_start(graph, entity->pads);
> +	media_graph_walk_start(graph, pad_err);

I would keep entity->pads here as we're not dealing with an error path.

>  
> -	while ((entity = media_graph_walk_next(graph))) {
> -		if (!is_media_entity_v4l2_video_device(entity))
> +	while ((pad = media_graph_walk_next(graph))) {
> +		if (!is_media_entity_v4l2_video_device(pad->entity))
>  			continue;
>  
> -		ret  = __fimc_md_modify_pipeline(entity, enable);
> +		ret  = __fimc_md_modify_pipeline(pad->entity, enable);
>  
>  		if (ret < 0)
>  			goto err;
> @@ -1159,15 +1159,15 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
>  	return 0;
>  
>  err:
> -	media_graph_walk_start(graph, entity_err->pads);
> +	media_graph_walk_start(graph, pad_err);
>  
> -	while ((entity_err = media_graph_walk_next(graph))) {
> -		if (!is_media_entity_v4l2_video_device(entity_err))
> +	while ((pad_err = media_graph_walk_next(graph))) {
> +		if (!is_media_entity_v4l2_video_device(pad_err->entity))
>  			continue;
>  
> -		__fimc_md_modify_pipeline(entity_err, !enable);
> +		__fimc_md_modify_pipeline(pad_err->entity, !enable);
>  
> -		if (entity_err == entity)
> +		if (pad_err == pad)
>  			break;
>  	}
>  

[snip]

> diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
> index 9ed480fe5b6e4762..98edd47b2f0ae747 100644
> --- a/drivers/media/v4l2-core/v4l2-mc.c
> +++ b/drivers/media/v4l2-core/v4l2-mc.c
> @@ -339,13 +339,14 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
>  static int pipeline_pm_use_count(struct media_entity *entity,
>  	struct media_graph *graph)
>  {
> +	struct media_pad *pad;
>  	int use = 0;
>  
>  	media_graph_walk_start(graph, entity->pads);
>  
> -	while ((entity = media_graph_walk_next(graph))) {
> -		if (is_media_entity_v4l2_video_device(entity))
> -			use += entity->use_count;
> +	while ((pad = media_graph_walk_next(graph))) {
> +		if (is_media_entity_v4l2_video_device(pad->entity))
> +			use += pad->entity->use_count;
>  	}
>  
>  	return use;
> @@ -398,7 +399,7 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
>  static int pipeline_pm_power(struct media_entity *entity, int change,
>  	struct media_graph *graph)
>  {
> -	struct media_entity *first = entity;
> +	struct media_pad *tmp_pad, *pad;

How about pad_err instead of tmp_pad, like in the exynos driver ? Or
possible first_pad to retain the "first" name ?

>  	int ret = 0;
>  
>  	if (!change)
> @@ -406,19 +407,19 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
>  
>  	media_graph_walk_start(graph, entity->pads);
>  
> -	while (!ret && (entity = media_graph_walk_next(graph)))
> -		if (is_media_entity_v4l2_subdev(entity))
> -			ret = pipeline_pm_power_one(entity, change);
> +	while (!ret && (pad = media_graph_walk_next(graph)))
> +		if (is_media_entity_v4l2_subdev(pad->entity))
> +			ret = pipeline_pm_power_one(pad->entity, change);
>  
>  	if (!ret)
>  		return ret;
>  
> -	media_graph_walk_start(graph, first->pads);
> +	media_graph_walk_start(graph, entity->pads);
>  
> -	while ((first = media_graph_walk_next(graph))
> -	       && first != entity)
> -		if (is_media_entity_v4l2_subdev(first))
> -			pipeline_pm_power_one(first, -change);
> +	while ((tmp_pad = media_graph_walk_next(graph))
> +	       && tmp_pad != pad)
> +		if (is_media_entity_v4l2_subdev(tmp_pad->entity))
> +			pipeline_pm_power_one(tmp_pad->entity, -change);
>  
>  	return ret;
>  }

[snip]

> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index 99c7606f01317741..cde6350d752bb0ae 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -952,10 +952,11 @@ void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad);
>   * The graph structure must have been previously initialized with a call to
>   * media_graph_walk_start().
>   *
> - * Return: returns the next entity in the graph or %NULL if the whole graph
> - * have been traversed.
> + * Return: returns the next pad in the graph or %NULL if the whole
> + * graph have been traversed. The pad which is returned is the pad

s/have been/has/been/
s/The pad which is returned/The returned pad/

> + * through which a new entity is reached when parsing the graph.

through which the entity was reached when walking the graph.

With these addressed,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

>   */
> -struct media_entity *media_graph_walk_next(struct media_graph *graph);
> +struct media_pad *media_graph_walk_next(struct media_graph *graph);
>  
>  /**
>   * media_pipeline_start - Mark a pipeline as streaming

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 04/30] v4l: mc: Start walk from a specific pad in use count calculation
  2018-11-01 23:31 ` [PATCH v2 04/30] v4l: mc: Start walk from a specific pad in use count calculation Niklas Söderlund
@ 2019-01-15 22:24   ` Laurent Pinchart
  2019-01-15 22:36     ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 22:24 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:18AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> With the addition of the recent has_route() media entity op, the pads of a
> media entity are no longer all interconnected. This has to be taken into
> account in power management.
> 
> Prepare for the addition of a helper function supporting S_ROUTING.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/v4l2-core/v4l2-mc.c | 25 ++++++++++++-------------
>  1 file changed, 12 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
> index 98edd47b2f0ae747..208cd91ce57ff211 100644
> --- a/drivers/media/v4l2-core/v4l2-mc.c
> +++ b/drivers/media/v4l2-core/v4l2-mc.c
> @@ -332,17 +332,16 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
>  
>  /*
>   * pipeline_pm_use_count - Count the number of users of a pipeline
> - * @entity: The entity
> + * @pad: The pad

That's not very descriptive (I know it wasn't to start with either). How
about "Any pad part of the pipeline" ?

>   *
>   * Return the total number of users of all video device nodes in the pipeline.
>   */
> -static int pipeline_pm_use_count(struct media_entity *entity,
> -	struct media_graph *graph)
> +static int pipeline_pm_use_count(struct media_pad *pad,
> +				 struct media_graph *graph)
>  {
> -	struct media_pad *pad;
>  	int use = 0;
>  
> -	media_graph_walk_start(graph, entity->pads);
> +	media_graph_walk_start(graph, pad);
>  
>  	while ((pad = media_graph_walk_next(graph))) {
>  		if (is_media_entity_v4l2_video_device(pad->entity))
> @@ -388,7 +387,7 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
>  
>  /*
>   * pipeline_pm_power - Apply power change to all entities in a pipeline
> - * @entity: The entity
> + * @pad: The pad

Same here.

With this fixed,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

>   * @change: Use count change
>   *
>   * Walk the pipeline to update the use count and the power state of all non-node
> @@ -396,16 +395,16 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
>   *
>   * Return 0 on success or a negative error code on failure.
>   */
> -static int pipeline_pm_power(struct media_entity *entity, int change,
> +static int pipeline_pm_power(struct media_pad *pad, int change,
>  	struct media_graph *graph)
>  {
> -	struct media_pad *tmp_pad, *pad;
> +	struct media_pad *tmp_pad, *first = pad;
>  	int ret = 0;
>  
>  	if (!change)
>  		return 0;
>  
> -	media_graph_walk_start(graph, entity->pads);
> +	media_graph_walk_start(graph, pad);
>  
>  	while (!ret && (pad = media_graph_walk_next(graph)))
>  		if (is_media_entity_v4l2_subdev(pad->entity))
> @@ -414,7 +413,7 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
>  	if (!ret)
>  		return ret;
>  
> -	media_graph_walk_start(graph, entity->pads);
> +	media_graph_walk_start(graph, first);
>  
>  	while ((tmp_pad = media_graph_walk_next(graph))
>  	       && tmp_pad != pad)
> @@ -437,7 +436,7 @@ int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
>  	WARN_ON(entity->use_count < 0);
>  
>  	/* Apply power change to connected non-nodes. */
> -	ret = pipeline_pm_power(entity, change, &mdev->pm_count_walk);
> +	ret = pipeline_pm_power(entity->pads, change, &mdev->pm_count_walk);
>  	if (ret < 0)
>  		entity->use_count -= change;
>  
> @@ -451,8 +450,8 @@ int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
>  			      unsigned int notification)
>  {
>  	struct media_graph *graph = &link->graph_obj.mdev->pm_count_walk;
> -	struct media_entity *source = link->source->entity;
> -	struct media_entity *sink = link->sink->entity;
> +	struct media_pad *source = link->source;
> +	struct media_pad *sink = link->sink;
>  	int source_use;
>  	int sink_use;
>  	int ret = 0;

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 04/30] v4l: mc: Start walk from a specific pad in use count calculation
  2019-01-15 22:24   ` Laurent Pinchart
@ 2019-01-15 22:36     ` Sakari Ailus
  0 siblings, 0 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-01-15 22:36 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

On Wed, Jan 16, 2019 at 12:24:32AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thank you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:18AM +0100, Niklas Söderlund wrote:
> > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > 
> > With the addition of the recent has_route() media entity op, the pads of a
> > media entity are no longer all interconnected. This has to be taken into
> > account in power management.
> > 
> > Prepare for the addition of a helper function supporting S_ROUTING.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/v4l2-core/v4l2-mc.c | 25 ++++++++++++-------------
> >  1 file changed, 12 insertions(+), 13 deletions(-)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
> > index 98edd47b2f0ae747..208cd91ce57ff211 100644
> > --- a/drivers/media/v4l2-core/v4l2-mc.c
> > +++ b/drivers/media/v4l2-core/v4l2-mc.c
> > @@ -332,17 +332,16 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
> >  
> >  /*
> >   * pipeline_pm_use_count - Count the number of users of a pipeline
> > - * @entity: The entity
> > + * @pad: The pad
> 
> That's not very descriptive (I know it wasn't to start with either). How
> about "Any pad part of the pipeline" ?

How about: "Any pad along the pipeline"?

> 
> >   *
> >   * Return the total number of users of all video device nodes in the pipeline.
> >   */
> > -static int pipeline_pm_use_count(struct media_entity *entity,
> > -	struct media_graph *graph)
> > +static int pipeline_pm_use_count(struct media_pad *pad,
> > +				 struct media_graph *graph)
> >  {
> > -	struct media_pad *pad;
> >  	int use = 0;
> >  
> > -	media_graph_walk_start(graph, entity->pads);
> > +	media_graph_walk_start(graph, pad);
> >  
> >  	while ((pad = media_graph_walk_next(graph))) {
> >  		if (is_media_entity_v4l2_video_device(pad->entity))
> > @@ -388,7 +387,7 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
> >  
> >  /*
> >   * pipeline_pm_power - Apply power change to all entities in a pipeline
> > - * @entity: The entity
> > + * @pad: The pad
> 
> Same here.
> 
> With this fixed,
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> >   * @change: Use count change
> >   *
> >   * Walk the pipeline to update the use count and the power state of all non-node
> > @@ -396,16 +395,16 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
> >   *
> >   * Return 0 on success or a negative error code on failure.
> >   */
> > -static int pipeline_pm_power(struct media_entity *entity, int change,
> > +static int pipeline_pm_power(struct media_pad *pad, int change,
> >  	struct media_graph *graph)
> >  {
> > -	struct media_pad *tmp_pad, *pad;
> > +	struct media_pad *tmp_pad, *first = pad;
> >  	int ret = 0;
> >  
> >  	if (!change)
> >  		return 0;
> >  
> > -	media_graph_walk_start(graph, entity->pads);
> > +	media_graph_walk_start(graph, pad);
> >  
> >  	while (!ret && (pad = media_graph_walk_next(graph)))
> >  		if (is_media_entity_v4l2_subdev(pad->entity))
> > @@ -414,7 +413,7 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
> >  	if (!ret)
> >  		return ret;
> >  
> > -	media_graph_walk_start(graph, entity->pads);
> > +	media_graph_walk_start(graph, first);
> >  
> >  	while ((tmp_pad = media_graph_walk_next(graph))
> >  	       && tmp_pad != pad)
> > @@ -437,7 +436,7 @@ int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
> >  	WARN_ON(entity->use_count < 0);
> >  
> >  	/* Apply power change to connected non-nodes. */
> > -	ret = pipeline_pm_power(entity, change, &mdev->pm_count_walk);
> > +	ret = pipeline_pm_power(entity->pads, change, &mdev->pm_count_walk);
> >  	if (ret < 0)
> >  		entity->use_count -= change;
> >  
> > @@ -451,8 +450,8 @@ int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
> >  			      unsigned int notification)
> >  {
> >  	struct media_graph *graph = &link->graph_obj.mdev->pm_count_walk;
> > -	struct media_entity *source = link->source->entity;
> > -	struct media_entity *sink = link->sink->entity;
> > +	struct media_pad *source = link->source;
> > +	struct media_pad *sink = link->sink;
> >  	int source_use;
> >  	int sink_use;
> >  	int ret = 0;
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 05/30] media: entity: Move the pipeline from entity to pads
  2018-11-01 23:31 ` [PATCH v2 05/30] media: entity: Move the pipeline from entity to pads Niklas Söderlund
@ 2019-01-15 22:38   ` Laurent Pinchart
  2019-01-15 22:48     ` Sakari Ailus
  2019-02-14 15:53   ` Jacopo Mondi
  1 sibling, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 22:38 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thanks you for the patch.

On Fri, Nov 02, 2018 at 12:31:19AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> This moves the pipe and stream_count fields from struct media_entity to
> struct media_pad. Effectively streams become pad-specific rather than
> being stream specific, allowing several independent streams to traverse a

Should this be "entity-specific" instead of "stream specific" ?

> single entity.

"and the entity to be part of multiple pipelines" ?

> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/media-entity.c                  | 61 ++++++++++++-------
>  drivers/media/platform/exynos4-is/fimc-isp.c  |  2 +-
>  drivers/media/platform/exynos4-is/fimc-lite.c |  2 +-
>  drivers/media/platform/omap3isp/isp.c         |  2 +-
>  drivers/media/platform/omap3isp/ispvideo.c    |  2 +-
>  drivers/media/platform/omap3isp/ispvideo.h    |  2 +-
>  drivers/media/platform/rcar-vin/rcar-dma.c    |  2 +-
>  drivers/media/platform/xilinx/xilinx-dma.c    |  2 +-
>  drivers/media/platform/xilinx/xilinx-dma.h    |  2 +-
>  drivers/staging/media/imx/imx-media-utils.c   |  2 +-
>  drivers/staging/media/omap4iss/iss.c          |  2 +-
>  drivers/staging/media/omap4iss/iss_video.c    |  2 +-
>  drivers/staging/media/omap4iss/iss_video.h    |  2 +-
>  include/media/media-entity.h                  | 17 ++++--
>  14 files changed, 61 insertions(+), 41 deletions(-)
> 
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index 70db03fa33a21db1..13260149c4dfc90c 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -419,7 +419,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  	struct media_pad *pad = entity->pads;
>  	struct media_pad *pad_err = pad;
>  	struct media_link *link;
> -	int ret;
> +	int ret = 0;

Is this needed ?

>  
>  	if (!pipe->streaming_count++) {
>  		ret = media_graph_walk_init(&pipe->graph, mdev);
> @@ -431,21 +431,27 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  
>  	while ((pad = media_graph_walk_next(graph))) {
>  		struct media_entity *entity = pad->entity;
> +		unsigned int i;
> +		bool skip_validation = pad->pipe;
>  
>  		DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
>  		DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
>  
> -		entity->stream_count++;
> +		for (i = 0; i < entity->num_pads; i++) {
> +			struct media_pad *iter = &entity->pads[i];

Unrelated to this patch, a for_each_pad() would be nice.

>  
> -		if (WARN_ON(entity->pipe && entity->pipe != pipe)) {
> -			ret = -EBUSY;
> -			goto error;
> +			if (iter->pipe && WARN_ON(iter->pipe != pipe))
> +				ret = -EBUSY;
> +			else
> +				iter->pipe = pipe;
> +			iter->stream_count++;

How about keeping a similar construct as currently exists ?

		iter->stream_count++;
		if (WARN_ON(iter->pipe && iter->pipe != pipe) {
			ret = -EBUSY;
			goto error;
		}

		iter->pipe = pipe;

>  		}
>  
> -		entity->pipe = pipe;
> +		if (ret)
> +			goto error;
>  
>  		/* Already streaming --- no need to check. */

Maybe "Already part of the pipeline" to match the condition ?

> -		if (entity->stream_count > 1)
> +		if (skip_validation)
>  			continue;
>  
>  		if (!entity->ops || !entity->ops->link_validate)
> @@ -514,19 +520,24 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  
>  	while ((pad_err = media_graph_walk_next(graph))) {
>  		struct media_entity *entity_err = pad_err->entity;
> +		unsigned int i;
> +
> +		for (i = 0; i < entity_err->num_pads; i++) {
> +			struct media_pad *iter = &entity_err->pads[i];
>  
> -		/* Sanity check for negative stream_count */
> -		if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) {
> -			entity_err->stream_count--;
> -			if (entity_err->stream_count == 0)
> -				entity_err->pipe = NULL;
> +			/* Sanity check for negative stream_count */
> +			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
> +				--iter->stream_count;
> +				if (iter->stream_count == 0)
> +					iter->pipe = NULL;
> +			}
>  		}
>  
>  		/*
>  		 * We haven't increased stream_count further than this
>  		 * so we quit here.
>  		 */
> -		if (pad_err == pad)
> +		if (pad_err->entity == pad->entity)

Is this needed ?

>  			break;
>  	}
>  
> @@ -553,7 +564,7 @@ EXPORT_SYMBOL_GPL(media_pipeline_start);
>  
>  void __media_pipeline_stop(struct media_entity *entity)
>  {
> -	struct media_pipeline *pipe = entity->pipe;
> +	struct media_pipeline *pipe = entity->pads->pipe;
>  	struct media_graph *graph = &pipe->graph;
>  	struct media_pad *pad;
>  
> @@ -567,13 +578,17 @@ void __media_pipeline_stop(struct media_entity *entity)
>  	media_graph_walk_start(graph, entity->pads);
>  
>  	while ((pad = media_graph_walk_next(graph))) {
> -		struct media_entity *entity = pad->entity;
> +		unsigned int i;
>  
> -		/* Sanity check for negative stream_count */
> -		if (!WARN_ON_ONCE(entity->stream_count <= 0)) {
> -			entity->stream_count--;
> -			if (entity->stream_count == 0)
> -				entity->pipe = NULL;
> +		for (i = 0; i < entity->num_pads; i++) {
> +			struct media_pad *iter = &entity->pads[i];
> +
> +			/* Sanity check for negative stream_count */
> +			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
> +				iter->stream_count--;
> +				if (iter->stream_count == 0)
> +					iter->pipe = NULL;
> +			}
>  		}
>  	}
>  
> @@ -865,7 +880,7 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
>  {
>  	const u32 mask = MEDIA_LNK_FL_ENABLED;
>  	struct media_device *mdev;
> -	struct media_entity *source, *sink;
> +	struct media_pad *source, *sink;
>  	int ret = -EBUSY;
>  
>  	if (link == NULL)
> @@ -881,8 +896,8 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
>  	if (link->flags == flags)
>  		return 0;
>  
> -	source = link->source->entity;
> -	sink = link->sink->entity;
> +	source = link->source;
> +	sink = link->sink;
>  
>  	if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
>  	    (source->stream_count || sink->stream_count))
> diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
> index 9a48c0f69320ba35..79d128a57e87fd58 100644
> --- a/drivers/media/platform/exynos4-is/fimc-isp.c
> +++ b/drivers/media/platform/exynos4-is/fimc-isp.c
> @@ -229,7 +229,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
>  			}
>  		}
>  	} else {
> -		if (sd->entity.stream_count == 0) {
> +		if (sd->entity.pads->stream_count == 0) {
>  			if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
>  				struct v4l2_subdev_format format = *fmt;
>  
> diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
> index 96f0a8a0dcae591f..dbadcba6739a286b 100644
> --- a/drivers/media/platform/exynos4-is/fimc-lite.c
> +++ b/drivers/media/platform/exynos4-is/fimc-lite.c
> @@ -1096,7 +1096,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
>  	mutex_lock(&fimc->lock);
>  
>  	if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP &&
> -	    sd->entity.stream_count > 0) ||
> +	    sd->entity.pads->stream_count > 0) ||
>  	    (atomic_read(&fimc->out_path) == FIMC_IO_DMA &&
>  	    vb2_is_busy(&fimc->vb_queue))) {
>  		mutex_unlock(&fimc->lock);
> diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
> index 77fb7987b42f33cd..3663dfd00cadc2f0 100644
> --- a/drivers/media/platform/omap3isp/isp.c
> +++ b/drivers/media/platform/omap3isp/isp.c
> @@ -927,7 +927,7 @@ static int isp_pipeline_is_last(struct media_entity *me)
>  	struct isp_pipeline *pipe;
>  	struct media_pad *pad;
>  
> -	if (!me->pipe)
> +	if (!me->pads->pipe)
>  		return 0;
>  	pipe = to_isp_pipeline(me);
>  	if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
> diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
> index dc11b732dc05b00b..f354cd7ceb8ffce5 100644
> --- a/drivers/media/platform/omap3isp/ispvideo.c
> +++ b/drivers/media/platform/omap3isp/ispvideo.c
> @@ -1102,7 +1102,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
>  	/* Start streaming on the pipeline. No link touching an entity in the
>  	 * pipeline can be activated or deactivated once streaming is started.
>  	 */
> -	pipe = video->video.entity.pipe
> +	pipe = video->video.entity.pads->pipe
>  	     ? to_isp_pipeline(&video->video.entity) : &video->pipe;
>  
>  	ret = media_entity_enum_init(&pipe->ent_enum, &video->isp->media_dev);
> diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
> index f6a2082b4a0a7708..8f4146c25a1b1293 100644
> --- a/drivers/media/platform/omap3isp/ispvideo.h
> +++ b/drivers/media/platform/omap3isp/ispvideo.h
> @@ -103,7 +103,7 @@ struct isp_pipeline {
>  };
>  
>  #define to_isp_pipeline(__e) \
> -	container_of((__e)->pipe, struct isp_pipeline, pipe)
> +	container_of((__e)->pads->pipe, struct isp_pipeline, pipe)
>  
>  static inline int isp_pipeline_ready(struct isp_pipeline *pipe)
>  {
> diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
> index 92323310f7352147..e749096926f34d4a 100644
> --- a/drivers/media/platform/rcar-vin/rcar-dma.c
> +++ b/drivers/media/platform/rcar-vin/rcar-dma.c
> @@ -1128,7 +1128,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on)
>  	 */
>  	mdev = vin->vdev.entity.graph_obj.mdev;
>  	mutex_lock(&mdev->graph_mutex);
> -	pipe = sd->entity.pipe ? sd->entity.pipe : &vin->vdev.pipe;
> +	pipe = sd->entity.pads->pipe ? sd->entity.pads->pipe : &vin->vdev.pipe;
>  	ret = __media_pipeline_start(&vin->vdev.entity, pipe);
>  	mutex_unlock(&mdev->graph_mutex);
>  	if (ret)
> diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
> index a2a329336243bdc7..f27a7be5f5d0f0b5 100644
> --- a/drivers/media/platform/xilinx/xilinx-dma.c
> +++ b/drivers/media/platform/xilinx/xilinx-dma.c
> @@ -406,7 +406,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
>  	 * Use the pipeline object embedded in the first DMA object that starts
>  	 * streaming.
>  	 */
> -	pipe = dma->video.entity.pipe
> +	pipe = dma->video.entity.pads->pipe
>  	     ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe;
>  
>  	ret = media_pipeline_start(&dma->video.entity, &pipe->pipe);
> diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
> index e95d136c153a8f5f..c12e053ff41eed1c 100644
> --- a/drivers/media/platform/xilinx/xilinx-dma.h
> +++ b/drivers/media/platform/xilinx/xilinx-dma.h
> @@ -50,7 +50,7 @@ struct xvip_pipeline {
>  
>  static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
>  {
> -	return container_of(e->pipe, struct xvip_pipeline, pipe);
> +	return container_of(e->pads->pipe, struct xvip_pipeline, pipe);
>  }
>  
>  /**
> diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
> index 0eaa353d5cb39768..ba9d9a8337cb159e 100644
> --- a/drivers/staging/media/imx/imx-media-utils.c
> +++ b/drivers/staging/media/imx/imx-media-utils.c
> @@ -917,7 +917,7 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
>  			__media_pipeline_stop(entity);
>  	} else {
>  		v4l2_subdev_call(sd, video, s_stream, 0);
> -		if (entity->pipe)
> +		if (entity->pads->pipe)
>  			__media_pipeline_stop(entity);
>  	}
>  
> diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
> index c8be1db532ab2555..030808b222cf3ae5 100644
> --- a/drivers/staging/media/omap4iss/iss.c
> +++ b/drivers/staging/media/omap4iss/iss.c
> @@ -543,7 +543,7 @@ static int iss_pipeline_is_last(struct media_entity *me)
>  	struct iss_pipeline *pipe;
>  	struct media_pad *pad;
>  
> -	if (!me->pipe)
> +	if (!me->pads->pipe)
>  		return 0;
>  	pipe = to_iss_pipeline(me);
>  	if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED)
> diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
> index 1271bbacf9e7bdeb..65f1e358271b3743 100644
> --- a/drivers/staging/media/omap4iss/iss_video.c
> +++ b/drivers/staging/media/omap4iss/iss_video.c
> @@ -877,7 +877,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
>  	 * Start streaming on the pipeline. No link touching an entity in the
>  	 * pipeline can be activated or deactivated once streaming is started.
>  	 */
> -	pipe = pad->entity->pipe
> +	pipe = pad->pipe
>  	     ? to_iss_pipeline(pad->entity) : &video->pipe;
>  	pipe->external = NULL;
>  	pipe->external_rate = 0;
> diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
> index f22489edb5624af2..cdea8543b3f93ecf 100644
> --- a/drivers/staging/media/omap4iss/iss_video.h
> +++ b/drivers/staging/media/omap4iss/iss_video.h
> @@ -94,7 +94,7 @@ struct iss_pipeline {
>  };
>  
>  #define to_iss_pipeline(__e) \
> -	container_of((__e)->pipe, struct iss_pipeline, pipe)
> +	container_of((__e)->pads->pipe, struct iss_pipeline, pipe)
>  
>  static inline int iss_pipeline_ready(struct iss_pipeline *pipe)
>  {
> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index cde6350d752bb0ae..ca0b79288ea7fd11 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -188,15 +188,25 @@ enum media_pad_signal_type {
>   *
>   * @graph_obj:	Embedded structure containing the media object common data
>   * @entity:	Entity this pad belongs to
> + * @pipe:	Pipeline this entity belongs to.

s/entity/pad/

> + * @stream_count: Stream count for the entity.

Ditto.

>   * @index:	Pad index in the entity pads array, numbered from 0 to n
>   * @sig_type:	Type of the signal inside a media pad
>   * @flags:	Pad flags, as defined in
>   *		:ref:`include/uapi/linux/media.h <media_header>`
>   *		(seek for ``MEDIA_PAD_FL_*``)
> + * .. note::
> + *
> + *    @stream_count reference counts must never be negative, but are
> + *    signed integers on purpose: a simple ``WARN_ON(<0)`` check can
> + *    be used to detect reference count bugs that would make them
> + *    negative.
>   */
>  struct media_pad {
>  	struct media_gobj graph_obj;	/* must be first field in struct */
>  	struct media_entity *entity;
> +	struct media_pipeline *pipe;
> +	int stream_count;
>  	u16 index;
>  	enum media_pad_signal_type sig_type;
>  	unsigned long flags;
> @@ -274,9 +284,7 @@ enum media_entity_type {
>   * @pads:	Pads array with the size defined by @num_pads.
>   * @links:	List of data links.
>   * @ops:	Entity operations.
> - * @stream_count: Stream count for the entity.
>   * @use_count:	Use count for the entity.
> - * @pipe:	Pipeline this entity belongs to.
>   * @info:	Union with devnode information.  Kept just for backward
>   *		compatibility.
>   * @info.dev:	Contains device major and minor info.
> @@ -289,7 +297,7 @@ enum media_entity_type {
>   *
>   * .. note::
>   *
> - *    @stream_count and @use_count reference counts must never be
> + *    @use_count reference counts must never be
>   *    negative, but are signed integers on purpose: a simple ``WARN_ON(<0)``
>   *    check can be used to detect reference count bugs that would make them

I would rewrap the text.

With the above comments addressed,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

>   *    negative.
> @@ -311,11 +319,8 @@ struct media_entity {
>  
>  	const struct media_entity_operations *ops;
>  
> -	int stream_count;
>  	int use_count;
>  
> -	struct media_pipeline *pipe;
> -
>  	union {
>  		struct {
>  			u32 major;

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 05/30] media: entity: Move the pipeline from entity to pads
  2019-01-15 22:38   ` Laurent Pinchart
@ 2019-01-15 22:48     ` Sakari Ailus
  0 siblings, 0 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-01-15 22:48 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

On Wed, Jan 16, 2019 at 12:38:42AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thanks you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:19AM +0100, Niklas Söderlund wrote:
> > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > 
> > This moves the pipe and stream_count fields from struct media_entity to
> > struct media_pad. Effectively streams become pad-specific rather than
> > being stream specific, allowing several independent streams to traverse a
> 
> Should this be "entity-specific" instead of "stream specific" ?

Yes.

> 
> > single entity.
> 
> "and the entity to be part of multiple pipelines" ?

Sounds good.

> 
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/media-entity.c                  | 61 ++++++++++++-------
> >  drivers/media/platform/exynos4-is/fimc-isp.c  |  2 +-
> >  drivers/media/platform/exynos4-is/fimc-lite.c |  2 +-
> >  drivers/media/platform/omap3isp/isp.c         |  2 +-
> >  drivers/media/platform/omap3isp/ispvideo.c    |  2 +-
> >  drivers/media/platform/omap3isp/ispvideo.h    |  2 +-
> >  drivers/media/platform/rcar-vin/rcar-dma.c    |  2 +-
> >  drivers/media/platform/xilinx/xilinx-dma.c    |  2 +-
> >  drivers/media/platform/xilinx/xilinx-dma.h    |  2 +-
> >  drivers/staging/media/imx/imx-media-utils.c   |  2 +-
> >  drivers/staging/media/omap4iss/iss.c          |  2 +-
> >  drivers/staging/media/omap4iss/iss_video.c    |  2 +-
> >  drivers/staging/media/omap4iss/iss_video.h    |  2 +-
> >  include/media/media-entity.h                  | 17 ++++--
> >  14 files changed, 61 insertions(+), 41 deletions(-)
> > 
> > diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> > index 70db03fa33a21db1..13260149c4dfc90c 100644
> > --- a/drivers/media/media-entity.c
> > +++ b/drivers/media/media-entity.c
> > @@ -419,7 +419,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
> >  	struct media_pad *pad = entity->pads;
> >  	struct media_pad *pad_err = pad;
> >  	struct media_link *link;
> > -	int ret;
> > +	int ret = 0;
> 
> Is this needed ?
> 
> >  
> >  	if (!pipe->streaming_count++) {
> >  		ret = media_graph_walk_init(&pipe->graph, mdev);
> > @@ -431,21 +431,27 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
> >  
> >  	while ((pad = media_graph_walk_next(graph))) {
> >  		struct media_entity *entity = pad->entity;
> > +		unsigned int i;
> > +		bool skip_validation = pad->pipe;
> >  
> >  		DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
> >  		DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
> >  
> > -		entity->stream_count++;
> > +		for (i = 0; i < entity->num_pads; i++) {
> > +			struct media_pad *iter = &entity->pads[i];
> 
> Unrelated to this patch, a for_each_pad() would be nice.
> 
> >  
> > -		if (WARN_ON(entity->pipe && entity->pipe != pipe)) {
> > -			ret = -EBUSY;
> > -			goto error;
> > +			if (iter->pipe && WARN_ON(iter->pipe != pipe))
> > +				ret = -EBUSY;
> > +			else
> > +				iter->pipe = pipe;
> > +			iter->stream_count++;
> 
> How about keeping a similar construct as currently exists ?

That would complicate the error handling there. Now it's enough to figure
out on which entity the failure happened, not the pad.

> 
> 		iter->stream_count++;
> 		if (WARN_ON(iter->pipe && iter->pipe != pipe) {
> 			ret = -EBUSY;
> 			goto error;
> 		}
> 
> 		iter->pipe = pipe;
> 
> >  		}
> >  
> > -		entity->pipe = pipe;
> > +		if (ret)
> > +			goto error;
> >  
> >  		/* Already streaming --- no need to check. */
> 
> Maybe "Already part of the pipeline" to match the condition ?

Fine with me.

> 
> > -		if (entity->stream_count > 1)
> > +		if (skip_validation)
> >  			continue;
> >  
> >  		if (!entity->ops || !entity->ops->link_validate)
> > @@ -514,19 +520,24 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
> >  
> >  	while ((pad_err = media_graph_walk_next(graph))) {
> >  		struct media_entity *entity_err = pad_err->entity;
> > +		unsigned int i;
> > +
> > +		for (i = 0; i < entity_err->num_pads; i++) {
> > +			struct media_pad *iter = &entity_err->pads[i];
> >  
> > -		/* Sanity check for negative stream_count */
> > -		if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) {
> > -			entity_err->stream_count--;
> > -			if (entity_err->stream_count == 0)
> > -				entity_err->pipe = NULL;
> > +			/* Sanity check for negative stream_count */
> > +			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
> > +				--iter->stream_count;
> > +				if (iter->stream_count == 0)
> > +					iter->pipe = NULL;
> > +			}
> >  		}
> >  
> >  		/*
> >  		 * We haven't increased stream_count further than this
> >  		 * so we quit here.
> >  		 */
> > -		if (pad_err == pad)
> > +		if (pad_err->entity == pad->entity)
> 
> Is this needed ?

See above².

> 
> >  			break;
> >  	}
> >  
> > @@ -553,7 +564,7 @@ EXPORT_SYMBOL_GPL(media_pipeline_start);
> >  
> >  void __media_pipeline_stop(struct media_entity *entity)
> >  {
> > -	struct media_pipeline *pipe = entity->pipe;
> > +	struct media_pipeline *pipe = entity->pads->pipe;
> >  	struct media_graph *graph = &pipe->graph;
> >  	struct media_pad *pad;
> >  
> > @@ -567,13 +578,17 @@ void __media_pipeline_stop(struct media_entity *entity)
> >  	media_graph_walk_start(graph, entity->pads);
> >  
> >  	while ((pad = media_graph_walk_next(graph))) {
> > -		struct media_entity *entity = pad->entity;
> > +		unsigned int i;
> >  
> > -		/* Sanity check for negative stream_count */
> > -		if (!WARN_ON_ONCE(entity->stream_count <= 0)) {
> > -			entity->stream_count--;
> > -			if (entity->stream_count == 0)
> > -				entity->pipe = NULL;
> > +		for (i = 0; i < entity->num_pads; i++) {
> > +			struct media_pad *iter = &entity->pads[i];
> > +
> > +			/* Sanity check for negative stream_count */
> > +			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
> > +				iter->stream_count--;
> > +				if (iter->stream_count == 0)
> > +					iter->pipe = NULL;
> > +			}
> >  		}
> >  	}
> >  
> > @@ -865,7 +880,7 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
> >  {
> >  	const u32 mask = MEDIA_LNK_FL_ENABLED;
> >  	struct media_device *mdev;
> > -	struct media_entity *source, *sink;
> > +	struct media_pad *source, *sink;
> >  	int ret = -EBUSY;
> >  
> >  	if (link == NULL)
> > @@ -881,8 +896,8 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
> >  	if (link->flags == flags)
> >  		return 0;
> >  
> > -	source = link->source->entity;
> > -	sink = link->sink->entity;
> > +	source = link->source;
> > +	sink = link->sink;
> >  
> >  	if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
> >  	    (source->stream_count || sink->stream_count))
> > diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
> > index 9a48c0f69320ba35..79d128a57e87fd58 100644
> > --- a/drivers/media/platform/exynos4-is/fimc-isp.c
> > +++ b/drivers/media/platform/exynos4-is/fimc-isp.c
> > @@ -229,7 +229,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
> >  			}
> >  		}
> >  	} else {
> > -		if (sd->entity.stream_count == 0) {
> > +		if (sd->entity.pads->stream_count == 0) {
> >  			if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
> >  				struct v4l2_subdev_format format = *fmt;
> >  
> > diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
> > index 96f0a8a0dcae591f..dbadcba6739a286b 100644
> > --- a/drivers/media/platform/exynos4-is/fimc-lite.c
> > +++ b/drivers/media/platform/exynos4-is/fimc-lite.c
> > @@ -1096,7 +1096,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
> >  	mutex_lock(&fimc->lock);
> >  
> >  	if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP &&
> > -	    sd->entity.stream_count > 0) ||
> > +	    sd->entity.pads->stream_count > 0) ||
> >  	    (atomic_read(&fimc->out_path) == FIMC_IO_DMA &&
> >  	    vb2_is_busy(&fimc->vb_queue))) {
> >  		mutex_unlock(&fimc->lock);
> > diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
> > index 77fb7987b42f33cd..3663dfd00cadc2f0 100644
> > --- a/drivers/media/platform/omap3isp/isp.c
> > +++ b/drivers/media/platform/omap3isp/isp.c
> > @@ -927,7 +927,7 @@ static int isp_pipeline_is_last(struct media_entity *me)
> >  	struct isp_pipeline *pipe;
> >  	struct media_pad *pad;
> >  
> > -	if (!me->pipe)
> > +	if (!me->pads->pipe)
> >  		return 0;
> >  	pipe = to_isp_pipeline(me);
> >  	if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
> > diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
> > index dc11b732dc05b00b..f354cd7ceb8ffce5 100644
> > --- a/drivers/media/platform/omap3isp/ispvideo.c
> > +++ b/drivers/media/platform/omap3isp/ispvideo.c
> > @@ -1102,7 +1102,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
> >  	/* Start streaming on the pipeline. No link touching an entity in the
> >  	 * pipeline can be activated or deactivated once streaming is started.
> >  	 */
> > -	pipe = video->video.entity.pipe
> > +	pipe = video->video.entity.pads->pipe
> >  	     ? to_isp_pipeline(&video->video.entity) : &video->pipe;
> >  
> >  	ret = media_entity_enum_init(&pipe->ent_enum, &video->isp->media_dev);
> > diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
> > index f6a2082b4a0a7708..8f4146c25a1b1293 100644
> > --- a/drivers/media/platform/omap3isp/ispvideo.h
> > +++ b/drivers/media/platform/omap3isp/ispvideo.h
> > @@ -103,7 +103,7 @@ struct isp_pipeline {
> >  };
> >  
> >  #define to_isp_pipeline(__e) \
> > -	container_of((__e)->pipe, struct isp_pipeline, pipe)
> > +	container_of((__e)->pads->pipe, struct isp_pipeline, pipe)
> >  
> >  static inline int isp_pipeline_ready(struct isp_pipeline *pipe)
> >  {
> > diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
> > index 92323310f7352147..e749096926f34d4a 100644
> > --- a/drivers/media/platform/rcar-vin/rcar-dma.c
> > +++ b/drivers/media/platform/rcar-vin/rcar-dma.c
> > @@ -1128,7 +1128,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on)
> >  	 */
> >  	mdev = vin->vdev.entity.graph_obj.mdev;
> >  	mutex_lock(&mdev->graph_mutex);
> > -	pipe = sd->entity.pipe ? sd->entity.pipe : &vin->vdev.pipe;
> > +	pipe = sd->entity.pads->pipe ? sd->entity.pads->pipe : &vin->vdev.pipe;
> >  	ret = __media_pipeline_start(&vin->vdev.entity, pipe);
> >  	mutex_unlock(&mdev->graph_mutex);
> >  	if (ret)
> > diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
> > index a2a329336243bdc7..f27a7be5f5d0f0b5 100644
> > --- a/drivers/media/platform/xilinx/xilinx-dma.c
> > +++ b/drivers/media/platform/xilinx/xilinx-dma.c
> > @@ -406,7 +406,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
> >  	 * Use the pipeline object embedded in the first DMA object that starts
> >  	 * streaming.
> >  	 */
> > -	pipe = dma->video.entity.pipe
> > +	pipe = dma->video.entity.pads->pipe
> >  	     ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe;
> >  
> >  	ret = media_pipeline_start(&dma->video.entity, &pipe->pipe);
> > diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
> > index e95d136c153a8f5f..c12e053ff41eed1c 100644
> > --- a/drivers/media/platform/xilinx/xilinx-dma.h
> > +++ b/drivers/media/platform/xilinx/xilinx-dma.h
> > @@ -50,7 +50,7 @@ struct xvip_pipeline {
> >  
> >  static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
> >  {
> > -	return container_of(e->pipe, struct xvip_pipeline, pipe);
> > +	return container_of(e->pads->pipe, struct xvip_pipeline, pipe);
> >  }
> >  
> >  /**
> > diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
> > index 0eaa353d5cb39768..ba9d9a8337cb159e 100644
> > --- a/drivers/staging/media/imx/imx-media-utils.c
> > +++ b/drivers/staging/media/imx/imx-media-utils.c
> > @@ -917,7 +917,7 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
> >  			__media_pipeline_stop(entity);
> >  	} else {
> >  		v4l2_subdev_call(sd, video, s_stream, 0);
> > -		if (entity->pipe)
> > +		if (entity->pads->pipe)
> >  			__media_pipeline_stop(entity);
> >  	}
> >  
> > diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
> > index c8be1db532ab2555..030808b222cf3ae5 100644
> > --- a/drivers/staging/media/omap4iss/iss.c
> > +++ b/drivers/staging/media/omap4iss/iss.c
> > @@ -543,7 +543,7 @@ static int iss_pipeline_is_last(struct media_entity *me)
> >  	struct iss_pipeline *pipe;
> >  	struct media_pad *pad;
> >  
> > -	if (!me->pipe)
> > +	if (!me->pads->pipe)
> >  		return 0;
> >  	pipe = to_iss_pipeline(me);
> >  	if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED)
> > diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
> > index 1271bbacf9e7bdeb..65f1e358271b3743 100644
> > --- a/drivers/staging/media/omap4iss/iss_video.c
> > +++ b/drivers/staging/media/omap4iss/iss_video.c
> > @@ -877,7 +877,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
> >  	 * Start streaming on the pipeline. No link touching an entity in the
> >  	 * pipeline can be activated or deactivated once streaming is started.
> >  	 */
> > -	pipe = pad->entity->pipe
> > +	pipe = pad->pipe
> >  	     ? to_iss_pipeline(pad->entity) : &video->pipe;
> >  	pipe->external = NULL;
> >  	pipe->external_rate = 0;
> > diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
> > index f22489edb5624af2..cdea8543b3f93ecf 100644
> > --- a/drivers/staging/media/omap4iss/iss_video.h
> > +++ b/drivers/staging/media/omap4iss/iss_video.h
> > @@ -94,7 +94,7 @@ struct iss_pipeline {
> >  };
> >  
> >  #define to_iss_pipeline(__e) \
> > -	container_of((__e)->pipe, struct iss_pipeline, pipe)
> > +	container_of((__e)->pads->pipe, struct iss_pipeline, pipe)
> >  
> >  static inline int iss_pipeline_ready(struct iss_pipeline *pipe)
> >  {
> > diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> > index cde6350d752bb0ae..ca0b79288ea7fd11 100644
> > --- a/include/media/media-entity.h
> > +++ b/include/media/media-entity.h
> > @@ -188,15 +188,25 @@ enum media_pad_signal_type {
> >   *
> >   * @graph_obj:	Embedded structure containing the media object common data
> >   * @entity:	Entity this pad belongs to
> > + * @pipe:	Pipeline this entity belongs to.
> 
> s/entity/pad/
> 
> > + * @stream_count: Stream count for the entity.
> 
> Ditto.

Agreed.

> 
> >   * @index:	Pad index in the entity pads array, numbered from 0 to n
> >   * @sig_type:	Type of the signal inside a media pad
> >   * @flags:	Pad flags, as defined in
> >   *		:ref:`include/uapi/linux/media.h <media_header>`
> >   *		(seek for ``MEDIA_PAD_FL_*``)
> > + * .. note::
> > + *
> > + *    @stream_count reference counts must never be negative, but are
> > + *    signed integers on purpose: a simple ``WARN_ON(<0)`` check can
> > + *    be used to detect reference count bugs that would make them
> > + *    negative.
> >   */
> >  struct media_pad {
> >  	struct media_gobj graph_obj;	/* must be first field in struct */
> >  	struct media_entity *entity;
> > +	struct media_pipeline *pipe;
> > +	int stream_count;
> >  	u16 index;
> >  	enum media_pad_signal_type sig_type;
> >  	unsigned long flags;
> > @@ -274,9 +284,7 @@ enum media_entity_type {
> >   * @pads:	Pads array with the size defined by @num_pads.
> >   * @links:	List of data links.
> >   * @ops:	Entity operations.
> > - * @stream_count: Stream count for the entity.
> >   * @use_count:	Use count for the entity.
> > - * @pipe:	Pipeline this entity belongs to.
> >   * @info:	Union with devnode information.  Kept just for backward
> >   *		compatibility.
> >   * @info.dev:	Contains device major and minor info.
> > @@ -289,7 +297,7 @@ enum media_entity_type {
> >   *
> >   * .. note::
> >   *
> > - *    @stream_count and @use_count reference counts must never be
> > + *    @use_count reference counts must never be
> >   *    negative, but are signed integers on purpose: a simple ``WARN_ON(<0)``
> >   *    check can be used to detect reference count bugs that would make them
> 
> I would rewrap the text.
> 
> With the above comments addressed,
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> >   *    negative.
> > @@ -311,11 +319,8 @@ struct media_entity {
> >  
> >  	const struct media_entity_operations *ops;
> >  
> > -	int stream_count;
> >  	int use_count;
> >  
> > -	struct media_pipeline *pipe;
> > -
> >  	union {
> >  		struct {
> >  			u32 major;
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 06/30] media: entity: Use pad as the starting point for a pipeline
  2018-11-01 23:31 ` [PATCH v2 06/30] media: entity: Use pad as the starting point for a pipeline Niklas Söderlund
@ 2019-01-15 22:54   ` Laurent Pinchart
  2019-01-22 15:31     ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 22:54 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:20AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> The pipeline will be moved from the entity to the pads; reflect this in
> the media pipeline function API.

Will be moved, or has been moved ?

> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  Documentation/media/kapi/mc-core.rst          |  6 ++--
>  drivers/media/media-entity.c                  | 25 +++++++-------
>  drivers/media/pci/intel/ipu3/ipu3-cio2.c      |  6 ++--
>  .../media/platform/exynos4-is/fimc-capture.c  |  8 ++---
>  .../platform/exynos4-is/fimc-isp-video.c      |  8 ++---
>  drivers/media/platform/exynos4-is/fimc-lite.c |  8 ++---
>  drivers/media/platform/omap3isp/ispvideo.c    |  6 ++--
>  .../media/platform/qcom/camss/camss-video.c   |  6 ++--
>  drivers/media/platform/rcar-vin/rcar-dma.c    |  6 ++--
>  .../media/platform/s3c-camif/camif-capture.c  |  6 ++--
>  drivers/media/platform/vimc/vimc-capture.c    |  6 ++--
>  drivers/media/platform/vsp1/vsp1_video.c      |  6 ++--
>  drivers/media/platform/xilinx/xilinx-dma.c    |  6 ++--
>  drivers/media/usb/au0828/au0828-core.c        |  4 +--
>  drivers/staging/media/imx/imx-media-utils.c   |  6 ++--
>  drivers/staging/media/omap4iss/iss_video.c    |  6 ++--
>  include/media/media-entity.h                  | 33 ++++++++++---------
>  17 files changed, 76 insertions(+), 76 deletions(-)
> 
> diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
> index 849b87439b7a9772..ede7e946f6a82ac0 100644
> --- a/Documentation/media/kapi/mc-core.rst
> +++ b/Documentation/media/kapi/mc-core.rst
> @@ -211,11 +211,11 @@ When starting streaming, drivers must notify all entities in the pipeline to
>  prevent link states from being modified during streaming by calling
>  :c:func:`media_pipeline_start()`.
>  
> -The function will mark all entities connected to the given entity through
> -enabled links, either directly or indirectly, as streaming.
> +The function will mark all entities connected to the given pad through
> +enabled routes and links, either directly or indirectly, as streaming.

That's not really correct, it doesn't mark entities, but pads. I think
this section of the documentation needs to be rewritten based on the new
model of an entity being part of multiple pipelines. s/entity/pad/ isn't
enough, there's a whole new semantics.

>  The struct :c:type:`media_pipeline` instance pointed to by
> -the pipe argument will be stored in every entity in the pipeline.
> +the pipe argument will be stored in every pad in the pipeline.
>  Drivers should embed the struct :c:type:`media_pipeline`
>  in higher-level pipeline structures and can then access the
>  pipeline through the struct :c:type:`media_entity`
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index 13260149c4dfc90c..f2fa0b7826dbc2f3 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -411,12 +411,11 @@ EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad);
>   * Pipeline management
>   */
>  
> -__must_check int __media_pipeline_start(struct media_entity *entity,
> +__must_check int __media_pipeline_start(struct media_pad *pad,
>  					struct media_pipeline *pipe)
>  {
> -	struct media_device *mdev = entity->graph_obj.mdev;
> +	struct media_device *mdev = pad->graph_obj.mdev;
>  	struct media_graph *graph = &pipe->graph;
> -	struct media_pad *pad = entity->pads;
>  	struct media_pad *pad_err = pad;
>  	struct media_link *link;
>  	int ret = 0;
> @@ -549,24 +548,23 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  }
>  EXPORT_SYMBOL_GPL(__media_pipeline_start);
>  
> -__must_check int media_pipeline_start(struct media_entity *entity,
> +__must_check int media_pipeline_start(struct media_pad *pad,
>  				      struct media_pipeline *pipe)
>  {
> -	struct media_device *mdev = entity->graph_obj.mdev;
> +	struct media_device *mdev = pad->graph_obj.mdev;
>  	int ret;
>  
>  	mutex_lock(&mdev->graph_mutex);
> -	ret = __media_pipeline_start(entity, pipe);
> +	ret = __media_pipeline_start(pad, pipe);
>  	mutex_unlock(&mdev->graph_mutex);
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(media_pipeline_start);
>  
> -void __media_pipeline_stop(struct media_entity *entity)
> +void __media_pipeline_stop(struct media_pad *pad)
>  {
> -	struct media_pipeline *pipe = entity->pads->pipe;
> +	struct media_pipeline *pipe = pad->pipe;
>  	struct media_graph *graph = &pipe->graph;
> -	struct media_pad *pad;
>  
>  	/*
>  	 * If the following check fails, the driver has performed an
> @@ -575,9 +573,10 @@ void __media_pipeline_stop(struct media_entity *entity)
>  	if (WARN_ON(!pipe))
>  		return;
>  
> -	media_graph_walk_start(graph, entity->pads);
> +	media_graph_walk_start(graph, pad);
>  
>  	while ((pad = media_graph_walk_next(graph))) {
> +		struct media_entity *entity = pad->entity;

It looks like this line is a bug fix for a previous patch in the series.

>  		unsigned int i;
>  
>  		for (i = 0; i < entity->num_pads; i++) {
> @@ -598,12 +597,12 @@ void __media_pipeline_stop(struct media_entity *entity)
>  }
>  EXPORT_SYMBOL_GPL(__media_pipeline_stop);
>  
> -void media_pipeline_stop(struct media_entity *entity)
> +void media_pipeline_stop(struct media_pad *pad)
>  {
> -	struct media_device *mdev = entity->graph_obj.mdev;
> +	struct media_device *mdev = pad->graph_obj.mdev;
>  
>  	mutex_lock(&mdev->graph_mutex);
> -	__media_pipeline_stop(entity);
> +	__media_pipeline_stop(pad);
>  	mutex_unlock(&mdev->graph_mutex);
>  }
>  EXPORT_SYMBOL_GPL(media_pipeline_stop);

[snip]

> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index ca0b79288ea7fd11..8378f700389635ea 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -965,53 +965,54 @@ struct media_pad *media_graph_walk_next(struct media_graph *graph);
>  
>  /**
>   * media_pipeline_start - Mark a pipeline as streaming
> - * @entity: Starting entity
> - * @pipe: Media pipeline to be assigned to all entities in the pipeline.
> + * @pad: Starting pad
> + * @pipe: Media pipeline to be assigned to all pads in the pipeline.
>   *
> - * Mark all entities connected to a given entity through enabled links, either
> - * directly or indirectly, as streaming. The given pipeline object is assigned
> - * to every entity in the pipeline and stored in the media_entity pipe field.
> + * Mark all pads connected to a given pad through enabled
> + * routes or links, either directly or indirectly, as streaming. The
> + * given pipeline object is assigned to every pad in the pipeline
> + * and stored in the media_pad pipe field.

Reflowing text to the 80 columns limit ?

>   *
>   * Calls to this function can be nested, in which case the same number of
>   * media_pipeline_stop() calls will be required to stop streaming. The
>   * pipeline pointer must be identical for all nested calls to
>   * media_pipeline_start().
>   */
> -__must_check int media_pipeline_start(struct media_entity *entity,
> +__must_check int media_pipeline_start(struct media_pad *pad,
>  				      struct media_pipeline *pipe);
>  /**
>   * __media_pipeline_start - Mark a pipeline as streaming
>   *
> - * @entity: Starting entity
> - * @pipe: Media pipeline to be assigned to all entities in the pipeline.
> + * @pad: Starting pad
> + * @pipe: Media pipeline to be assigned to all pads in the pipeline.
>   *
>   * ..note:: This is the non-locking version of media_pipeline_start()
>   */
> -__must_check int __media_pipeline_start(struct media_entity *entity,
> +__must_check int __media_pipeline_start(struct media_pad *pad,
>  					struct media_pipeline *pipe);
>  
>  /**
>   * media_pipeline_stop - Mark a pipeline as not streaming
> - * @entity: Starting entity
> + * @pad: Starting pad
>   *
> - * Mark all entities connected to a given entity through enabled links, either
> - * directly or indirectly, as not streaming. The media_entity pipe field is
> - * reset to %NULL.
> + * Mark all pads connected to a given pad through enabled routes or
> + * links, either directly or indirectly, as not streaming. The
> + * media_pad pipe field is reset to %NULL.

Ditto.

With the above fixed,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

>   *
>   * If multiple calls to media_pipeline_start() have been made, the same
>   * number of calls to this function are required to mark the pipeline as not
>   * streaming.
>   */
> -void media_pipeline_stop(struct media_entity *entity);
> +void media_pipeline_stop(struct media_pad *pad);
>  
>  /**
>   * __media_pipeline_stop - Mark a pipeline as not streaming
>   *
> - * @entity: Starting entity
> + * @pad: Starting pad
>   *
>   * .. note:: This is the non-locking version of media_pipeline_stop()
>   */
> -void __media_pipeline_stop(struct media_entity *entity);
> +void __media_pipeline_stop(struct media_pad *pad);
>  
>  /**
>   * media_devnode_create() - creates and initializes a device node interface

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink
  2018-11-01 23:31 ` [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink Niklas Söderlund
@ 2019-01-15 22:57   ` Laurent Pinchart
  2019-01-22 15:15     ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 22:57 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Sakari,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:23AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> This way the pads are always passed to the has_route() op sink pad first.
> Makes sense.

Is there anything in the API that mandates one pad to be a sink and the
other pad to the a source ? I had designed the operation to allow
sink-sink and source-source connections to be checked too.

If your goal is to simplify the implementation of the .has_route()
operation in drivers, I would instead sort pad0 and pad1 by value.

> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/media-entity.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index 3c0e7425c8983b45..33f00e35ccd92c6f 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -249,6 +249,10 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
>  	if (!entity->ops || !entity->ops->has_route)
>  		return true;
>  
> +	if (entity->pads[pad0].flags & MEDIA_PAD_FL_SOURCE
> +	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
> +		swap(pad0, pad1);
> +
>  	return entity->ops->has_route(entity, pad0, pad1);
>  }
>  EXPORT_SYMBOL_GPL(media_entity_has_route);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 11/30] media: entity: Skip link validation for pads to which there is no route to
  2018-11-01 23:31 ` [PATCH v2 11/30] media: entity: Skip link validation for pads to which there is no route to Niklas Söderlund
@ 2019-01-15 23:13   ` Laurent Pinchart
  0 siblings, 0 replies; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 23:13 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:25AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> Links are validated along the pipeline which is about to start streaming.
> Not all the pads in entities that are traversed along that pipeline are
> part of the pipeline, however. Skip the link validation for such pads.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
>  drivers/media/media-entity.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index 4d10bc186e1e7a10..cdf3805dec755ec5 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -493,6 +493,11 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
>  			struct media_pad *other_pad = link->sink->entity == entity
>  				? link->sink : link->source;
>  
> +			/* Ignore pads to which there is no route. */
> +			if (!media_entity_has_route(entity, pad->index,
> +						    other_pad->index))
> +				continue;
> +
>  			/* Mark that a pad is connected by a link. */
>  			bitmap_clear(has_no_links, other_pad->index, 1);
>  

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 12/30] media: entity: Add an iterator helper for connected pads
  2018-11-01 23:31 ` [PATCH v2 12/30] media: entity: Add an iterator helper for connected pads Niklas Söderlund
@ 2019-01-15 23:24   ` Laurent Pinchart
  2019-01-22 15:36     ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 23:24 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:26AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> Add a helper macro for iterating over pads that are connected through
> enabled routes. This can be used to find all the connected pads within an
> entity, for instance starting from the pad which has been obtained during
> the graph walk.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  include/media/media-entity.h | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
> 
> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index 9540d2af80f19805..4bb1b568e1ac4795 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -936,6 +936,33 @@ __must_check int media_graph_walk_init(
>  bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
>  			    unsigned int pad1);
>  
> +static inline struct media_pad *__media_entity_for_routed_pads_next(
> +	struct media_pad *start, struct media_pad *iter)
> +{
> +	struct media_entity *entity = start->entity;
> +
> +	while (iter < &entity->pads[entity->num_pads] &&
> +	       !media_entity_has_route(entity, start->index, iter->index))
> +		iter++;
> +
> +	return iter;

Returning a pointer past the end of the array is asking for trouble. I
think we should return NULL in that case, and adapt the check in
media_entity_for_routed_pads() accordingly.

> +}
> +
> +/**
> + * media_entity_for_routed_pads - Iterate over entity pads connected by routes
> + *
> + * @start: The stating pad

s/stating/starting/

> + * @iter: The iterator pad
> + *
> + * Iterate over all pads connected through routes from a given pad
> + * within an entity. The iteration will include the starting pad itself.
> + */
> +#define media_entity_for_routed_pads(start, iter)			\

Maybe media_entity_for_each_routed_pad() ? Or just
for_each_entity_routed_pad() ?

> +	for (iter = __media_entity_for_routed_pads_next(		\

And how about __media_entity_next_routed_pad() ?

> +		     start, (start)->entity->pads);			\
> +	     iter < &(start)->entity->pads[(start)->entity->num_pads];	\
> +	     iter = __media_entity_for_routed_pads_next(start, iter + 1))
> +
>  /**
>   * media_graph_walk_cleanup - Release resources used by graph walk.
>   *

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 03/30] media: entity: Walk the graph based on pads
       [not found]     ` <20190115223406.mxgzl36cp54gb7nv@kekkonen.localdomain>
@ 2019-01-15 23:28       ` Laurent Pinchart
  2019-01-22 14:50         ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 23:28 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

Hi Sakari,

On Wed, Jan 16, 2019 at 12:34:07AM +0200, Sakari Ailus wrote:
> On Wed, Jan 16, 2019 at 12:21:36AM +0200, Laurent Pinchart wrote:
> > On Fri, Nov 02, 2018 at 12:31:17AM +0100, Niklas Söderlund wrote:
> >> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> 
> >> Instead of iterating over graph entities during the walk, iterate the pads
> >> through which the entity was first reached. This is required in order to
> >> make the entity pipeline pad-based rather than entity based.
> >> 
> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >> ---
> >>  Documentation/media/kapi/mc-core.rst          |  7 ++-
> >>  drivers/media/media-entity.c                  | 46 ++++++++++--------
> >>  drivers/media/platform/exynos4-is/media-dev.c | 20 ++++----
> >>  drivers/media/platform/omap3isp/ispvideo.c    | 17 +++----
> >>  drivers/media/platform/vsp1/vsp1_video.c      | 12 ++---
> >>  drivers/media/platform/xilinx/xilinx-dma.c    | 12 ++---
> >>  drivers/media/v4l2-core/v4l2-mc.c             | 25 +++++-----
> >>  .../staging/media/davinci_vpfe/vpfe_video.c   | 47 ++++++++++---------
> >>  drivers/staging/media/omap4iss/iss_video.c    | 34 +++++++-------
> >>  include/media/media-entity.h                  |  7 +--
> >>  10 files changed, 122 insertions(+), 105 deletions(-)
> > 
> > [snip]
> > 
> >> diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
> >> index 51d2a571c06db6a3..5813639c63b56a2c 100644
> >> --- a/drivers/media/platform/exynos4-is/media-dev.c
> >> +++ b/drivers/media/platform/exynos4-is/media-dev.c
> >> @@ -1135,7 +1135,7 @@ static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable)
> >>  static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
> >>  				      struct media_graph *graph)
> >>  {
> >> -	struct media_entity *entity_err = entity;
> >> +	struct media_pad *pad, *pad_err = entity->pads;
> >>  	int ret;
> >>  
> >>  	/*
> >> @@ -1144,13 +1144,13 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
> >>  	 * through active links. This is needed as we cannot power on/off the
> >>  	 * subdevs in random order.
> >>  	 */
> >> -	media_graph_walk_start(graph, entity->pads);
> >> +	media_graph_walk_start(graph, pad_err);
> > 
> > I would keep entity->pads here as we're not dealing with an error path.
> > 
> >>  
> >> -	while ((entity = media_graph_walk_next(graph))) {
> >> -		if (!is_media_entity_v4l2_video_device(entity))
> >> +	while ((pad = media_graph_walk_next(graph))) {
> >> +		if (!is_media_entity_v4l2_video_device(pad->entity))
> >>  			continue;
> >>  
> >> -		ret  = __fimc_md_modify_pipeline(entity, enable);
> >> +		ret  = __fimc_md_modify_pipeline(pad->entity, enable);
> >>  
> >>  		if (ret < 0)
> >>  			goto err;
> >> @@ -1159,15 +1159,15 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
> >>  	return 0;
> >>  
> >>  err:
> >> -	media_graph_walk_start(graph, entity_err->pads);
> >> +	media_graph_walk_start(graph, pad_err);
> >>  
> >> -	while ((entity_err = media_graph_walk_next(graph))) {
> >> -		if (!is_media_entity_v4l2_video_device(entity_err))
> >> +	while ((pad_err = media_graph_walk_next(graph))) {
> >> +		if (!is_media_entity_v4l2_video_device(pad_err->entity))
> >>  			continue;
> >>  
> >> -		__fimc_md_modify_pipeline(entity_err, !enable);
> >> +		__fimc_md_modify_pipeline(pad_err->entity, !enable);
> >>  
> >> -		if (entity_err == entity)
> >> +		if (pad_err == pad)
> >>  			break;
> >>  	}
> >>  
> > 
> > [snip]
> > 
> >> diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
> >> index 9ed480fe5b6e4762..98edd47b2f0ae747 100644
> >> --- a/drivers/media/v4l2-core/v4l2-mc.c
> >> +++ b/drivers/media/v4l2-core/v4l2-mc.c
> >> @@ -339,13 +339,14 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
> >>  static int pipeline_pm_use_count(struct media_entity *entity,
> >>  	struct media_graph *graph)
> >>  {
> >> +	struct media_pad *pad;
> >>  	int use = 0;
> >>  
> >>  	media_graph_walk_start(graph, entity->pads);
> >>  
> >> -	while ((entity = media_graph_walk_next(graph))) {
> >> -		if (is_media_entity_v4l2_video_device(entity))
> >> -			use += entity->use_count;
> >> +	while ((pad = media_graph_walk_next(graph))) {
> >> +		if (is_media_entity_v4l2_video_device(pad->entity))
> >> +			use += pad->entity->use_count;
> >>  	}
> >>  
> >>  	return use;
> >> @@ -398,7 +399,7 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
> >>  static int pipeline_pm_power(struct media_entity *entity, int change,
> >>  	struct media_graph *graph)
> >>  {
> >> -	struct media_entity *first = entity;
> >> +	struct media_pad *tmp_pad, *pad;
> > 
> > How about pad_err instead of tmp_pad, like in the exynos driver ? Or
> > possible first_pad to retain the "first" name ?
> 
> Why? This is just a pad. It's an iterator. first_pad or pad_err are
> misleading as such. If you don't like tmp_pad, how about "pad2"? The "pad"
> variable is still used for a similar purpose.

The variable is a pad iterator used in the error path, which can't use
the pad pointer as we need to stop iterating when we reach it. first_pad
is a bad idea, but pad_err would convey the meaning.

> > 
> >>  	int ret = 0;
> >>  
> >>  	if (!change)
> >> @@ -406,19 +407,19 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
> >>  
> >>  	media_graph_walk_start(graph, entity->pads);
> >>  
> >> -	while (!ret && (entity = media_graph_walk_next(graph)))
> >> -		if (is_media_entity_v4l2_subdev(entity))
> >> -			ret = pipeline_pm_power_one(entity, change);
> >> +	while (!ret && (pad = media_graph_walk_next(graph)))
> >> +		if (is_media_entity_v4l2_subdev(pad->entity))
> >> +			ret = pipeline_pm_power_one(pad->entity, change);
> >>  
> >>  	if (!ret)
> >>  		return ret;
> >>  
> >> -	media_graph_walk_start(graph, first->pads);
> >> +	media_graph_walk_start(graph, entity->pads);
> >>  
> >> -	while ((first = media_graph_walk_next(graph))
> >> -	       && first != entity)
> >> -		if (is_media_entity_v4l2_subdev(first))
> >> -			pipeline_pm_power_one(first, -change);
> >> +	while ((tmp_pad = media_graph_walk_next(graph))
> >> +	       && tmp_pad != pad)
> >> +		if (is_media_entity_v4l2_subdev(tmp_pad->entity))
> >> +			pipeline_pm_power_one(tmp_pad->entity, -change);
> >>  
> >>  	return ret;
> >>  }
> > 
> > [snip]
> > 
> >> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> >> index 99c7606f01317741..cde6350d752bb0ae 100644
> >> --- a/include/media/media-entity.h
> >> +++ b/include/media/media-entity.h
> >> @@ -952,10 +952,11 @@ void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad);
> >>   * The graph structure must have been previously initialized with a call to
> >>   * media_graph_walk_start().
> >>   *
> >> - * Return: returns the next entity in the graph or %NULL if the whole graph
> >> - * have been traversed.
> >> + * Return: returns the next pad in the graph or %NULL if the whole
> >> + * graph have been traversed. The pad which is returned is the pad
> > 
> > s/have been/has/been/
> > s/The pad which is returned/The returned pad/
> > 
> >> + * through which a new entity is reached when parsing the graph.
> > 
> > through which the entity was reached when walking the graph.
> 
> I'd keep "new", as the intent is to underline that it's a new entity not
> yet reached while walking the graph.

"through which the new entity was reached when walking the graph" then ?

> > 
> > With these addressed,
> > 
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > 
> >>   */
> >> -struct media_entity *media_graph_walk_next(struct media_graph *graph);
> >> +struct media_pad *media_graph_walk_next(struct media_graph *graph);
> >>  
> >>  /**
> >>   * media_pipeline_start - Mark a pipeline as streaming

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 13/30] media: entity: Add only connected pads to the pipeline
  2018-11-01 23:31 ` [PATCH v2 13/30] media: entity: Add only connected pads to the pipeline Niklas Söderlund
@ 2019-01-15 23:33   ` Laurent Pinchart
  0 siblings, 0 replies; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 23:33 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:27AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> A single entity may contain multiple pipelines. Only add pads that were
> connected to the pad through which the entity was reached to the pipeline.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
>  drivers/media/media-entity.c | 20 ++++++--------------
>  1 file changed, 6 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index cdf3805dec755ec5..a5bb257d5a68f755 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -460,15 +460,13 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
>  
>  	while ((pad = media_graph_walk_next(graph))) {
>  		struct media_entity *entity = pad->entity;
> -		unsigned int i;
> +		struct media_pad *iter;
>  		bool skip_validation = pad->pipe;
>  
>  		DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
>  		DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
>  
> -		for (i = 0; i < entity->num_pads; i++) {
> -			struct media_pad *iter = &entity->pads[i];
> -
> +		media_entity_for_routed_pads(pad, iter) {
>  			if (iter->pipe && WARN_ON(iter->pipe != pipe))
>  				ret = -EBUSY;
>  			else
> @@ -553,12 +551,9 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
>  	media_graph_walk_start(graph, pad_err);
>  
>  	while ((pad_err = media_graph_walk_next(graph))) {
> -		struct media_entity *entity_err = pad_err->entity;
> -		unsigned int i;
> -
> -		for (i = 0; i < entity_err->num_pads; i++) {
> -			struct media_pad *iter = &entity_err->pads[i];
> +		struct media_pad *iter;
>  
> +		media_entity_for_routed_pads(pad_err, iter) {
>  			/* Sanity check for negative stream_count */
>  			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
>  				--iter->stream_count;
> @@ -611,12 +606,9 @@ void __media_pipeline_stop(struct media_pad *pad)
>  	media_graph_walk_start(graph, pad);
>  
>  	while ((pad = media_graph_walk_next(graph))) {
> -		struct media_entity *entity = pad->entity;
> -		unsigned int i;
> -
> -		for (i = 0; i < entity->num_pads; i++) {
> -			struct media_pad *iter = &entity->pads[i];
> +		struct media_pad *iter;
>  
> +		media_entity_for_routed_pads(pad, iter) {
>  			/* Sanity check for negative stream_count */
>  			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
>  				iter->stream_count--;

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 14/30] media: entity: Add debug information in graph walk route check
  2018-11-01 23:31 ` [PATCH v2 14/30] media: entity: Add debug information in graph walk route check Niklas Söderlund
@ 2019-01-15 23:35   ` Laurent Pinchart
  2019-01-22 15:38     ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 23:35 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:28AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/media-entity.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index a5bb257d5a68f755..42977634d7102852 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -360,6 +360,9 @@ static void media_graph_walk_iter(struct media_graph *graph)
>  	 */
>  	if (!media_entity_has_route(pad->entity, pad->index, local->index)) {
>  		link_top(graph) = link_top(graph)->next;
> +		dev_dbg(pad->graph_obj.mdev->dev,
> +			"walk: skipping \"%s\":%u -> %u (no route)\n",
> +			pad->entity->name, pad->index, local->index);

Maybe "%s: skipping...", __func__, ?

Apart from that,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

>  		return;
>  	}
>  

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 15/30] media: entity: Look for indirect routes
  2018-11-01 23:31 ` [PATCH v2 15/30] media: entity: Look for indirect routes Niklas Söderlund
@ 2019-01-15 23:41   ` Laurent Pinchart
  2019-01-22 15:56     ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 23:41 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:29AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> Two pads are considered having an active route for the purpose of
> has_route() if an indirect active route can be found between the two pads.
> An simple example of this is that a source pad has an active route to
> another source pad if both of the pads have an active route to the same
> sink pad.
> 
> Make media_entity_has_route() return true in that case, and do not rely on
> drivers performing this by themselves.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/media-entity.c | 32 +++++++++++++++++++++++++++++++-
>  1 file changed, 31 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index 42977634d7102852..e45fc2549017615a 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -240,6 +240,9 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init);
>  bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
>  			    unsigned int pad1)
>  {
> +	unsigned int i;
> +	bool has_route;
> +
>  	if (pad0 >= entity->num_pads || pad1 >= entity->num_pads)
>  		return false;
>  
> @@ -253,7 +256,34 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
>  	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
>  		swap(pad0, pad1);
>  
> -	return entity->ops->has_route(entity, pad0, pad1);
> +	has_route = entity->ops->has_route(entity, pad0, pad1);
> +	/* A direct route is returned immediately */
> +	if (has_route ||
> +	    (entity->pads[pad0].flags & MEDIA_PAD_FL_SINK &&
> +	     entity->pads[pad1].flags & MEDIA_PAD_FL_SOURCE))
> +		return true;

This will return true if pad0 is a sink and pad1 a source, regardless of
has_route. I don't think that was intended. return has_route; would be
an easy fix.

> +
> +	/* Look for indirect routes */
> +	for (i = 0; i < entity->num_pads; i++) {
> +		if (i == pad0 || i == pad1)
> +			continue;
> +
> +		/*
> +		 * There are no direct routes between same types of
> +		 * pads, so skip checking this route
> +		 */
> +		if (!((entity->pads[pad0].flags ^ entity->pads[i].flags) &
> +		      (MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_SINK)))
> +			continue;
> +
> +		/* Is there an indirect route? */
> +		if (entity->ops->has_route(entity, i, pad0) &&
> +		    entity->ops->has_route(entity, i, pad1))
> +			return true;
> +	}

Isn't this best implemented in drivers ? I fear the complexity you need
here isn't worth it, especially given that you would also need to
support cases such as

Pads 0, 1 and 2 are sink, pads 3 and 4 are sources. has_route(0, 3),
has_route(1, 3), has_route(1, 4) and has_route(2, 4) are all true,
has_route(0, 4) and has_route(2, 3) are all false.
media_entity_has_route(0, 2) should return true.

> +	return false;
> +
>  }
>  EXPORT_SYMBOL_GPL(media_entity_has_route);
>  

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2018-11-01 23:31 ` [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations Niklas Söderlund
@ 2019-01-15 23:51   ` Laurent Pinchart
  2019-01-22 16:14     ` Sakari Ailus
  2019-02-21 14:59     ` Jacopo Mondi
  2019-02-21 14:39   ` Jacopo Mondi
  1 sibling, 2 replies; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 23:51 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc,
	Michal Simek

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> 
> - Add sink and source streams for multiplexed links
> - Copy the argument back in case of an error. This is needed to let the
>   caller know the number of routes.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
>  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
>  include/media/v4l2-subdev.h           |  7 +++++
>  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++

Missing documentation :-(

>  4 files changed, 94 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index 7de041bae84fb2f2..40406acb51ec0906 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -19,6 +19,7 @@
>  #include <linux/kernel.h>
>  #include <linux/version.h>
>  
> +#include <linux/v4l2-subdev.h>
>  #include <linux/videodev2.h>
>  
>  #include <media/v4l2-common.h>
> @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
>  		}
>  		break;
>  	}
> +
> +	case VIDIOC_SUBDEV_G_ROUTING:
> +	case VIDIOC_SUBDEV_S_ROUTING: {
> +		struct v4l2_subdev_routing *route = parg;
> +
> +		if (route->num_routes > 0) {
> +			if (route->num_routes > 256)
> +				return -EINVAL;
> +
> +			*user_ptr = (void __user *)route->routes;
> +			*kernel_ptr = (void *)&route->routes;
> +			*array_size = sizeof(struct v4l2_subdev_route)
> +				    * route->num_routes;
> +			ret = 1;
> +		}
> +		break;
> +	}
>  	}
>  
>  	return ret;
> @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
>  	 * Some ioctls can return an error, but still have valid
>  	 * results that must be returned.
>  	 */
> -	if (err < 0 && !always_copy)
> +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)

This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
always_copy instead ?

>  		goto out;
>  
>  out_array_args:
> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> index 792f41dffe2329b9..1d3b37cf548fa533 100644
> --- a/drivers/media/v4l2-core/v4l2-subdev.c
> +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
>  
>  	case VIDIOC_SUBDEV_QUERYSTD:
>  		return v4l2_subdev_call(sd, video, querystd, arg);
> +
> +	case VIDIOC_SUBDEV_G_ROUTING:
> +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> +
> +	case VIDIOC_SUBDEV_S_ROUTING: {
> +		struct v4l2_subdev_routing *route = arg;
> +		unsigned int i;
> +
> +		if (route->num_routes > sd->entity.num_pads)
> +			return -EINVAL;
> +
> +		for (i = 0; i < route->num_routes; ++i) {
> +			unsigned int sink = route->routes[i].sink_pad;
> +			unsigned int source = route->routes[i].source_pad;
> +			struct media_pad *pads = sd->entity.pads;
> +
> +			if (sink >= sd->entity.num_pads ||
> +			    source >= sd->entity.num_pads)
> +				return -EINVAL;
> +
> +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> +				return -EINVAL;
> +		}
> +
> +		return v4l2_subdev_call(sd, pad, set_routing, route);
> +	}
>  #endif
> +
>  	default:
>  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
>  	}
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
>   *
>   * @set_frame_desc: set the low level media bus frame parameters, @fd array
>   *                  may be adjusted by the subdev driver to device capabilities.
> + *
> + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.

Please define the purpose of those operations instead of just pointing
to the userspace API.

>   */
>  struct v4l2_subdev_pad_ops {
>  	int (*init_cfg)(struct v4l2_subdev *sd,
> @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
>  			      struct v4l2_mbus_frame_desc *fd);
>  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
>  			      struct v4l2_mbus_frame_desc *fd);
> +	int (*get_routing)(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_routing *route);
> +	int (*set_routing)(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_routing *route);
>  };
>  
>  /**
> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> index 03970ce3074193e6..af069bfb10ca23a5 100644
> --- a/include/uapi/linux/v4l2-subdev.h
> +++ b/include/uapi/linux/v4l2-subdev.h
> @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
>  	__u32 reserved[8];
>  };
>  
> +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> +
> +/**
> + * struct v4l2_subdev_route - A signal route inside a subdev
> + * @sink_pad: the sink pad
> + * @sink_stream: the sink stream
> + * @source_pad: the source pad
> + * @source_stream: the source stream

At this point in the series there's no concept of multiplexed streams,
so the two fields don't make sense. You may want to reorder patches, or
split this in two.

> + * @flags: route flags:
> + *
> + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> + *	active stream will start when streaming is enabled on a video
> + *	node. Set by the user.

This is very confusing as "stream" isn't defined. The documentation
needs a rewrite with more details.

> + *
> + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> + *	can it be activated and inactivated? Set by the driver.
> + */
> +struct v4l2_subdev_route {
> +	__u32 sink_pad;
> +	__u32 sink_stream;
> +	__u32 source_pad;
> +	__u32 source_stream;
> +	__u32 flags;
> +	__u32 reserved[5];
> +};
> +
> +/**
> + * struct v4l2_subdev_routing - Routing information
> + * @routes: the routes array
> + * @num_routes: the total number of routes in the routes array
> + */
> +struct v4l2_subdev_routing {
> +	struct v4l2_subdev_route *routes;

Missing __user ?

> +	__u32 num_routes;
> +	__u32 reserved[5];
> +};
> +
>  /* Backwards compatibility define --- to be removed */
>  #define v4l2_subdev_edid v4l2_edid
>  
> @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
>  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
>  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
>  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
>  
>  #endif
> -- 
> 2.19.1
> 

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING
  2018-11-01 23:31 ` [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING Niklas Söderlund
  2019-01-08 10:04   ` Geert Uytterhoeven
@ 2019-01-15 23:53   ` Laurent Pinchart
  2019-01-22 15:57     ` Sakari Ailus
  2019-02-18 11:21     ` Jacopo Mondi
  1 sibling, 2 replies; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-15 23:53 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, Benoit Parrot, linux-media, linux-renesas-soc

Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:31AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> Implement compat IOCTL handling for VIDIOC_SUBDEV_G_ROUTING and
> VIDIOC_SUBDEV_S_ROUTING IOCTLs.

Let's instead design the ioctl in a way that doesn't require compat
handling.

> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 77 +++++++++++++++++++
>  1 file changed, 77 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> index 6481212fda772c73..83af332763f41a6b 100644
> --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> @@ -1045,6 +1045,66 @@ static int put_v4l2_event32(struct v4l2_event __user *p64,
>  	return 0;
>  }
>  
> +struct v4l2_subdev_routing32 {
> +	compat_caddr_t routes;
> +	__u32 num_routes;
> +	__u32 reserved[5];
> +};
> +
> +static int get_v4l2_subdev_routing(struct v4l2_subdev_routing __user *p64,
> +				   struct v4l2_subdev_routing32 __user *p32)
> +{
> +	struct v4l2_subdev_route __user *routes;
> +	compat_caddr_t p;
> +	u32 num_routes;
> +
> +	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
> +	    get_user(p, &p32->routes) ||
> +	    get_user(num_routes, &p32->num_routes) ||
> +	    put_user(num_routes, &p64->num_routes) ||
> +	    copy_in_user(&p64->reserved, &p32->reserved,
> +			 sizeof(p64->reserved)) ||
> +	    num_routes > U32_MAX / sizeof(*p64->routes))
> +		return -EFAULT;
> +
> +	routes = compat_ptr(p);
> +
> +	if (!access_ok(VERIFY_READ, routes,
> +		       num_routes * sizeof(*p64->routes)))
> +		return -EFAULT;
> +
> +	if (put_user((__force struct v4l2_subdev_route *)routes,
> +		     &p64->routes))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static int put_v4l2_subdev_routing(struct v4l2_subdev_routing __user *p64,
> +				   struct v4l2_subdev_routing32 __user *p32)
> +{
> +	struct v4l2_subdev_route __user *routes;
> +	compat_caddr_t p;
> +	u32 num_routes;
> +
> +	if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
> +	    get_user(p, &p32->routes) ||
> +	    get_user(num_routes, &p64->num_routes) ||
> +	    put_user(num_routes, &p32->num_routes) ||
> +	    copy_in_user(&p32->reserved, &p64->reserved,
> +			 sizeof(p64->reserved)) ||
> +	    num_routes > U32_MAX / sizeof(*p64->routes))
> +		return -EFAULT;
> +
> +	routes = compat_ptr(p);
> +
> +	if (!access_ok(VERIFY_WRITE, routes,
> +		       num_routes * sizeof(*p64->routes)))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
>  struct v4l2_edid32 {
>  	__u32 pad;
>  	__u32 start_block;
> @@ -1117,6 +1177,8 @@ static int put_v4l2_edid32(struct v4l2_edid __user *p64,
>  #define VIDIOC_STREAMOFF32	_IOW ('V', 19, s32)
>  #define VIDIOC_G_INPUT32	_IOR ('V', 38, s32)
>  #define VIDIOC_S_INPUT32	_IOWR('V', 39, s32)
> +#define VIDIOC_SUBDEV_G_ROUTING32 _IOWR('V', 38, struct v4l2_subdev_routing32)
> +#define VIDIOC_SUBDEV_S_ROUTING32 _IOWR('V', 39, struct v4l2_subdev_routing32)
>  #define VIDIOC_G_OUTPUT32	_IOR ('V', 46, s32)
>  #define VIDIOC_S_OUTPUT32	_IOWR('V', 47, s32)
>  
> @@ -1195,6 +1257,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
>  	case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
>  	case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
>  	case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
> +	case VIDIOC_SUBDEV_G_ROUTING32: cmd = VIDIOC_SUBDEV_G_ROUTING; break;
> +	case VIDIOC_SUBDEV_S_ROUTING32: cmd = VIDIOC_SUBDEV_S_ROUTING; break;
>  	case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
>  	case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
>  	case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
> @@ -1227,6 +1291,15 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
>  		compatible_arg = 0;
>  		break;
>  
> +	case VIDIOC_SUBDEV_G_ROUTING:
> +	case VIDIOC_SUBDEV_S_ROUTING:
> +		err = alloc_userspace(sizeof(struct v4l2_subdev_routing),
> +				      0, &new_p64);
> +		if (!err)
> +			err = get_v4l2_subdev_routing(new_p64, p32);
> +		compatible_arg = 0;
> +		break;
> +
>  	case VIDIOC_G_EDID:
>  	case VIDIOC_S_EDID:
>  		err = alloc_userspace(sizeof(struct v4l2_edid), 0, &new_p64);
> @@ -1368,6 +1441,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
>  		if (put_v4l2_edid32(new_p64, p32))
>  			err = -EFAULT;
>  		break;
> +	case VIDIOC_SUBDEV_G_ROUTING:
> +	case VIDIOC_SUBDEV_S_ROUTING:
> +		err = put_v4l2_subdev_routing(new_p64, p32);
> +		break;
>  	}
>  	if (err)
>  		return err;

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 03/30] media: entity: Walk the graph based on pads
  2019-01-15 23:28       ` Laurent Pinchart
@ 2019-01-22 14:50         ` Sakari Ailus
  0 siblings, 0 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-01-22 14:50 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

Hi Laurent,

On Wed, Jan 16, 2019 at 01:28:22AM +0200, Laurent Pinchart wrote:
> Hi Sakari,
> 
> On Wed, Jan 16, 2019 at 12:34:07AM +0200, Sakari Ailus wrote:
> > On Wed, Jan 16, 2019 at 12:21:36AM +0200, Laurent Pinchart wrote:
> > > On Fri, Nov 02, 2018 at 12:31:17AM +0100, Niklas Söderlund wrote:
> > >> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >> 
> > >> Instead of iterating over graph entities during the walk, iterate the pads
> > >> through which the entity was first reached. This is required in order to
> > >> make the entity pipeline pad-based rather than entity based.
> > >> 
> > >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > >> ---
> > >>  Documentation/media/kapi/mc-core.rst          |  7 ++-
> > >>  drivers/media/media-entity.c                  | 46 ++++++++++--------
> > >>  drivers/media/platform/exynos4-is/media-dev.c | 20 ++++----
> > >>  drivers/media/platform/omap3isp/ispvideo.c    | 17 +++----
> > >>  drivers/media/platform/vsp1/vsp1_video.c      | 12 ++---
> > >>  drivers/media/platform/xilinx/xilinx-dma.c    | 12 ++---
> > >>  drivers/media/v4l2-core/v4l2-mc.c             | 25 +++++-----
> > >>  .../staging/media/davinci_vpfe/vpfe_video.c   | 47 ++++++++++---------
> > >>  drivers/staging/media/omap4iss/iss_video.c    | 34 +++++++-------
> > >>  include/media/media-entity.h                  |  7 +--
> > >>  10 files changed, 122 insertions(+), 105 deletions(-)
> > > 
> > > [snip]
> > > 
> > >> diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
> > >> index 51d2a571c06db6a3..5813639c63b56a2c 100644
> > >> --- a/drivers/media/platform/exynos4-is/media-dev.c
> > >> +++ b/drivers/media/platform/exynos4-is/media-dev.c
> > >> @@ -1135,7 +1135,7 @@ static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable)
> > >>  static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
> > >>  				      struct media_graph *graph)
> > >>  {
> > >> -	struct media_entity *entity_err = entity;
> > >> +	struct media_pad *pad, *pad_err = entity->pads;
> > >>  	int ret;
> > >>  
> > >>  	/*
> > >> @@ -1144,13 +1144,13 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
> > >>  	 * through active links. This is needed as we cannot power on/off the
> > >>  	 * subdevs in random order.
> > >>  	 */
> > >> -	media_graph_walk_start(graph, entity->pads);
> > >> +	media_graph_walk_start(graph, pad_err);
> > > 
> > > I would keep entity->pads here as we're not dealing with an error path.
> > > 
> > >>  
> > >> -	while ((entity = media_graph_walk_next(graph))) {
> > >> -		if (!is_media_entity_v4l2_video_device(entity))
> > >> +	while ((pad = media_graph_walk_next(graph))) {
> > >> +		if (!is_media_entity_v4l2_video_device(pad->entity))
> > >>  			continue;
> > >>  
> > >> -		ret  = __fimc_md_modify_pipeline(entity, enable);
> > >> +		ret  = __fimc_md_modify_pipeline(pad->entity, enable);
> > >>  
> > >>  		if (ret < 0)
> > >>  			goto err;
> > >> @@ -1159,15 +1159,15 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
> > >>  	return 0;
> > >>  
> > >>  err:
> > >> -	media_graph_walk_start(graph, entity_err->pads);
> > >> +	media_graph_walk_start(graph, pad_err);
> > >>  
> > >> -	while ((entity_err = media_graph_walk_next(graph))) {
> > >> -		if (!is_media_entity_v4l2_video_device(entity_err))
> > >> +	while ((pad_err = media_graph_walk_next(graph))) {
> > >> +		if (!is_media_entity_v4l2_video_device(pad_err->entity))
> > >>  			continue;
> > >>  
> > >> -		__fimc_md_modify_pipeline(entity_err, !enable);
> > >> +		__fimc_md_modify_pipeline(pad_err->entity, !enable);
> > >>  
> > >> -		if (entity_err == entity)
> > >> +		if (pad_err == pad)
> > >>  			break;
> > >>  	}
> > >>  
> > > 
> > > [snip]
> > > 
> > >> diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
> > >> index 9ed480fe5b6e4762..98edd47b2f0ae747 100644
> > >> --- a/drivers/media/v4l2-core/v4l2-mc.c
> > >> +++ b/drivers/media/v4l2-core/v4l2-mc.c
> > >> @@ -339,13 +339,14 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
> > >>  static int pipeline_pm_use_count(struct media_entity *entity,
> > >>  	struct media_graph *graph)
> > >>  {
> > >> +	struct media_pad *pad;
> > >>  	int use = 0;
> > >>  
> > >>  	media_graph_walk_start(graph, entity->pads);
> > >>  
> > >> -	while ((entity = media_graph_walk_next(graph))) {
> > >> -		if (is_media_entity_v4l2_video_device(entity))
> > >> -			use += entity->use_count;
> > >> +	while ((pad = media_graph_walk_next(graph))) {
> > >> +		if (is_media_entity_v4l2_video_device(pad->entity))
> > >> +			use += pad->entity->use_count;
> > >>  	}
> > >>  
> > >>  	return use;
> > >> @@ -398,7 +399,7 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
> > >>  static int pipeline_pm_power(struct media_entity *entity, int change,
> > >>  	struct media_graph *graph)
> > >>  {
> > >> -	struct media_entity *first = entity;
> > >> +	struct media_pad *tmp_pad, *pad;
> > > 
> > > How about pad_err instead of tmp_pad, like in the exynos driver ? Or
> > > possible first_pad to retain the "first" name ?
> > 
> > Why? This is just a pad. It's an iterator. first_pad or pad_err are
> > misleading as such. If you don't like tmp_pad, how about "pad2"? The "pad"
> > variable is still used for a similar purpose.
> 
> The variable is a pad iterator used in the error path, which can't use
> the pad pointer as we need to stop iterating when we reach it. first_pad
> is a bad idea, but pad_err would convey the meaning.

I'm sure it'd convey a meaning but it's not the right meaning: this is an
iterator, not where the error happened. It'd require a code change as well
to change the meaning.

I'm not opposed to that necessarily, but I think it's more simple to grasp
as-is (with rename to e.g. pad2).

> 
> > > 
> > >>  	int ret = 0;
> > >>  
> > >>  	if (!change)
> > >> @@ -406,19 +407,19 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
> > >>  
> > >>  	media_graph_walk_start(graph, entity->pads);
> > >>  
> > >> -	while (!ret && (entity = media_graph_walk_next(graph)))
> > >> -		if (is_media_entity_v4l2_subdev(entity))
> > >> -			ret = pipeline_pm_power_one(entity, change);
> > >> +	while (!ret && (pad = media_graph_walk_next(graph)))
> > >> +		if (is_media_entity_v4l2_subdev(pad->entity))
> > >> +			ret = pipeline_pm_power_one(pad->entity, change);
> > >>  
> > >>  	if (!ret)
> > >>  		return ret;
> > >>  
> > >> -	media_graph_walk_start(graph, first->pads);
> > >> +	media_graph_walk_start(graph, entity->pads);
> > >>  
> > >> -	while ((first = media_graph_walk_next(graph))
> > >> -	       && first != entity)
> > >> -		if (is_media_entity_v4l2_subdev(first))
> > >> -			pipeline_pm_power_one(first, -change);
> > >> +	while ((tmp_pad = media_graph_walk_next(graph))
> > >> +	       && tmp_pad != pad)
> > >> +		if (is_media_entity_v4l2_subdev(tmp_pad->entity))
> > >> +			pipeline_pm_power_one(tmp_pad->entity, -change);
> > >>  
> > >>  	return ret;
> > >>  }
> > > 
> > > [snip]
> > > 
> > >> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> > >> index 99c7606f01317741..cde6350d752bb0ae 100644
> > >> --- a/include/media/media-entity.h
> > >> +++ b/include/media/media-entity.h
> > >> @@ -952,10 +952,11 @@ void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad);
> > >>   * The graph structure must have been previously initialized with a call to
> > >>   * media_graph_walk_start().
> > >>   *
> > >> - * Return: returns the next entity in the graph or %NULL if the whole graph
> > >> - * have been traversed.
> > >> + * Return: returns the next pad in the graph or %NULL if the whole
> > >> + * graph have been traversed. The pad which is returned is the pad
> > > 
> > > s/have been/has/been/
> > > s/The pad which is returned/The returned pad/
> > > 
> > >> + * through which a new entity is reached when parsing the graph.
> > > 
> > > through which the entity was reached when walking the graph.
> > 
> > I'd keep "new", as the intent is to underline that it's a new entity not
> > yet reached while walking the graph.
> 
> "through which the new entity was reached when walking the graph" then ?

Yes, please!

> 
> > > 
> > > With these addressed,
> > > 
> > > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > 
> > >>   */
> > >> -struct media_entity *media_graph_walk_next(struct media_graph *graph);
> > >> +struct media_pad *media_graph_walk_next(struct media_graph *graph);
> > >>  
> > >>  /**
> > >>   * media_pipeline_start - Mark a pipeline as streaming
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink
  2019-01-15 22:57   ` Laurent Pinchart
@ 2019-01-22 15:15     ` Sakari Ailus
  2019-01-22 15:20       ` Laurent Pinchart
  0 siblings, 1 reply; 90+ messages in thread
From: Sakari Ailus @ 2019-01-22 15:15 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

Hi Laurent,

On Wed, Jan 16, 2019 at 12:57:43AM +0200, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:23AM +0100, Niklas Söderlund wrote:
> > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > 
> > This way the pads are always passed to the has_route() op sink pad first.
> > Makes sense.
> 
> Is there anything in the API that mandates one pad to be a sink and the
> other pad to the a source ? I had designed the operation to allow
> sink-sink and source-source connections to be checked too.

Do you have a use case in mind for sink--sink or source--source routes? The
routes are about flows of data, so I'd presume only source--sink or
sink--source routes are meaningful.

If you did, then the driver would have to handle that by itself. This still
simplifies the implementation for drivers that do not.

> 
> If your goal is to simplify the implementation of the .has_route()
> operation in drivers, I would instead sort pad0 and pad1 by value.

That'd be another option to make the order deterministic for the driver.
I'm fine with that as well.

> 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/media-entity.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> > index 3c0e7425c8983b45..33f00e35ccd92c6f 100644
> > --- a/drivers/media/media-entity.c
> > +++ b/drivers/media/media-entity.c
> > @@ -249,6 +249,10 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> >  	if (!entity->ops || !entity->ops->has_route)
> >  		return true;
> >  
> > +	if (entity->pads[pad0].flags & MEDIA_PAD_FL_SOURCE
> > +	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
> > +		swap(pad0, pad1);
> > +
> >  	return entity->ops->has_route(entity, pad0, pad1);
> >  }
> >  EXPORT_SYMBOL_GPL(media_entity_has_route);
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink
  2019-01-22 15:15     ` Sakari Ailus
@ 2019-01-22 15:20       ` Laurent Pinchart
  2019-02-18  9:21         ` Jacopo Mondi
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-22 15:20 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

Hi Sakari,

On Tue, Jan 22, 2019 at 05:15:06PM +0200, Sakari Ailus wrote:
> On Wed, Jan 16, 2019 at 12:57:43AM +0200, Laurent Pinchart wrote:
> >> 
> >> This way the pads are always passed to the has_route() op sink pad first.
> >> Makes sense.
> > 
> > Is there anything in the API that mandates one pad to be a sink and the
> > other pad to the a source ? I had designed the operation to allow
> > sink-sink and source-source connections to be checked too.
> 
> Do you have a use case in mind for sink--sink or source--source routes? The
> routes are about flows of data, so I'd presume only source--sink or
> sink--source routes are meaningful.
> 
> If you did, then the driver would have to handle that by itself. This still
> simplifies the implementation for drivers that do not.

I don't have use cases for such routes, but we use the has_route
operation when traversing pipelines, and at that point we need to get
all the internally connected pads. In another patch in this series you
implement a helper function that handles this, but its implementation
isn't complete. I explained in my review of that patch that I fear a
correct generic implementation would become quite complex, while the
complexity should be easy to handle on the driver side as the code can
then be specialized for the case at hand.

> > If your goal is to simplify the implementation of the .has_route()
> > operation in drivers, I would instead sort pad0 and pad1 by value.
> 
> That'd be another option to make the order deterministic for the driver.
> I'm fine with that as well.
> 
> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >> ---
> >>  drivers/media/media-entity.c | 4 ++++
> >>  1 file changed, 4 insertions(+)
> >> 
> >> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> >> index 3c0e7425c8983b45..33f00e35ccd92c6f 100644
> >> --- a/drivers/media/media-entity.c
> >> +++ b/drivers/media/media-entity.c
> >> @@ -249,6 +249,10 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> >>  	if (!entity->ops || !entity->ops->has_route)
> >>  		return true;
> >>  
> >> +	if (entity->pads[pad0].flags & MEDIA_PAD_FL_SOURCE
> >> +	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
> >> +		swap(pad0, pad1);
> >> +
> >>  	return entity->ops->has_route(entity, pad0, pad1);
> >>  }
> >>  EXPORT_SYMBOL_GPL(media_entity_has_route);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 06/30] media: entity: Use pad as the starting point for a pipeline
  2019-01-15 22:54   ` Laurent Pinchart
@ 2019-01-22 15:31     ` Sakari Ailus
  2019-01-22 15:37       ` Laurent Pinchart
  0 siblings, 1 reply; 90+ messages in thread
From: Sakari Ailus @ 2019-01-22 15:31 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

Hi Laurent,

On Wed, Jan 16, 2019 at 12:54:20AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thank you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:20AM +0100, Niklas Söderlund wrote:
> > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > 
> > The pipeline will be moved from the entity to the pads; reflect this in
> > the media pipeline function API.
> 
> Will be moved, or has been moved ?

Will be, as it's not yet in this patch.

> 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  Documentation/media/kapi/mc-core.rst          |  6 ++--
> >  drivers/media/media-entity.c                  | 25 +++++++-------
> >  drivers/media/pci/intel/ipu3/ipu3-cio2.c      |  6 ++--
> >  .../media/platform/exynos4-is/fimc-capture.c  |  8 ++---
> >  .../platform/exynos4-is/fimc-isp-video.c      |  8 ++---
> >  drivers/media/platform/exynos4-is/fimc-lite.c |  8 ++---
> >  drivers/media/platform/omap3isp/ispvideo.c    |  6 ++--
> >  .../media/platform/qcom/camss/camss-video.c   |  6 ++--
> >  drivers/media/platform/rcar-vin/rcar-dma.c    |  6 ++--
> >  .../media/platform/s3c-camif/camif-capture.c  |  6 ++--
> >  drivers/media/platform/vimc/vimc-capture.c    |  6 ++--
> >  drivers/media/platform/vsp1/vsp1_video.c      |  6 ++--
> >  drivers/media/platform/xilinx/xilinx-dma.c    |  6 ++--
> >  drivers/media/usb/au0828/au0828-core.c        |  4 +--
> >  drivers/staging/media/imx/imx-media-utils.c   |  6 ++--
> >  drivers/staging/media/omap4iss/iss_video.c    |  6 ++--
> >  include/media/media-entity.h                  | 33 ++++++++++---------
> >  17 files changed, 76 insertions(+), 76 deletions(-)
> > 
> > diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
> > index 849b87439b7a9772..ede7e946f6a82ac0 100644
> > --- a/Documentation/media/kapi/mc-core.rst
> > +++ b/Documentation/media/kapi/mc-core.rst
> > @@ -211,11 +211,11 @@ When starting streaming, drivers must notify all entities in the pipeline to
> >  prevent link states from being modified during streaming by calling
> >  :c:func:`media_pipeline_start()`.
> >  
> > -The function will mark all entities connected to the given entity through
> > -enabled links, either directly or indirectly, as streaming.
> > +The function will mark all entities connected to the given pad through
> > +enabled routes and links, either directly or indirectly, as streaming.
> 
> That's not really correct, it doesn't mark entities, but pads. I think
> this section of the documentation needs to be rewritten based on the new
> model of an entity being part of multiple pipelines. s/entity/pad/ isn't
> enough, there's a whole new semantics.

I'd say it's correct. Note that this function just beings the walk from a
given pad, it doesn't make other changes --- there are further patches
thought that do.

> 
> >  The struct :c:type:`media_pipeline` instance pointed to by
> > -the pipe argument will be stored in every entity in the pipeline.
> > +the pipe argument will be stored in every pad in the pipeline.
> >  Drivers should embed the struct :c:type:`media_pipeline`
> >  in higher-level pipeline structures and can then access the
> >  pipeline through the struct :c:type:`media_entity`
> > diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> > index 13260149c4dfc90c..f2fa0b7826dbc2f3 100644
> > --- a/drivers/media/media-entity.c
> > +++ b/drivers/media/media-entity.c
> > @@ -411,12 +411,11 @@ EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad);
> >   * Pipeline management
> >   */
> >  
> > -__must_check int __media_pipeline_start(struct media_entity *entity,
> > +__must_check int __media_pipeline_start(struct media_pad *pad,
> >  					struct media_pipeline *pipe)
> >  {
> > -	struct media_device *mdev = entity->graph_obj.mdev;
> > +	struct media_device *mdev = pad->graph_obj.mdev;
> >  	struct media_graph *graph = &pipe->graph;
> > -	struct media_pad *pad = entity->pads;
> >  	struct media_pad *pad_err = pad;
> >  	struct media_link *link;
> >  	int ret = 0;
> > @@ -549,24 +548,23 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
> >  }
> >  EXPORT_SYMBOL_GPL(__media_pipeline_start);
> >  
> > -__must_check int media_pipeline_start(struct media_entity *entity,
> > +__must_check int media_pipeline_start(struct media_pad *pad,
> >  				      struct media_pipeline *pipe)
> >  {
> > -	struct media_device *mdev = entity->graph_obj.mdev;
> > +	struct media_device *mdev = pad->graph_obj.mdev;
> >  	int ret;
> >  
> >  	mutex_lock(&mdev->graph_mutex);
> > -	ret = __media_pipeline_start(entity, pipe);
> > +	ret = __media_pipeline_start(pad, pipe);
> >  	mutex_unlock(&mdev->graph_mutex);
> >  	return ret;
> >  }
> >  EXPORT_SYMBOL_GPL(media_pipeline_start);
> >  
> > -void __media_pipeline_stop(struct media_entity *entity)
> > +void __media_pipeline_stop(struct media_pad *pad)
> >  {
> > -	struct media_pipeline *pipe = entity->pads->pipe;
> > +	struct media_pipeline *pipe = pad->pipe;
> >  	struct media_graph *graph = &pipe->graph;
> > -	struct media_pad *pad;
> >  
> >  	/*
> >  	 * If the following check fails, the driver has performed an
> > @@ -575,9 +573,10 @@ void __media_pipeline_stop(struct media_entity *entity)
> >  	if (WARN_ON(!pipe))
> >  		return;
> >  
> > -	media_graph_walk_start(graph, entity->pads);
> > +	media_graph_walk_start(graph, pad);
> >  
> >  	while ((pad = media_graph_walk_next(graph))) {
> > +		struct media_entity *entity = pad->entity;
> 
> It looks like this line is a bug fix for a previous patch in the series.

Yes, so it seems to be. The previous patch appears to remove it.

> 
> >  		unsigned int i;
> >  
> >  		for (i = 0; i < entity->num_pads; i++) {
> > @@ -598,12 +597,12 @@ void __media_pipeline_stop(struct media_entity *entity)
> >  }
> >  EXPORT_SYMBOL_GPL(__media_pipeline_stop);
> >  
> > -void media_pipeline_stop(struct media_entity *entity)
> > +void media_pipeline_stop(struct media_pad *pad)
> >  {
> > -	struct media_device *mdev = entity->graph_obj.mdev;
> > +	struct media_device *mdev = pad->graph_obj.mdev;
> >  
> >  	mutex_lock(&mdev->graph_mutex);
> > -	__media_pipeline_stop(entity);
> > +	__media_pipeline_stop(pad);
> >  	mutex_unlock(&mdev->graph_mutex);
> >  }
> >  EXPORT_SYMBOL_GPL(media_pipeline_stop);
> 
> [snip]
> 
> > diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> > index ca0b79288ea7fd11..8378f700389635ea 100644
> > --- a/include/media/media-entity.h
> > +++ b/include/media/media-entity.h
> > @@ -965,53 +965,54 @@ struct media_pad *media_graph_walk_next(struct media_graph *graph);
> >  
> >  /**
> >   * media_pipeline_start - Mark a pipeline as streaming
> > - * @entity: Starting entity
> > - * @pipe: Media pipeline to be assigned to all entities in the pipeline.
> > + * @pad: Starting pad
> > + * @pipe: Media pipeline to be assigned to all pads in the pipeline.
> >   *
> > - * Mark all entities connected to a given entity through enabled links, either
> > - * directly or indirectly, as streaming. The given pipeline object is assigned
> > - * to every entity in the pipeline and stored in the media_entity pipe field.
> > + * Mark all pads connected to a given pad through enabled
> > + * routes or links, either directly or indirectly, as streaming. The
> > + * given pipeline object is assigned to every pad in the pipeline
> > + * and stored in the media_pad pipe field.
> 
> Reflowing text to the 80 columns limit ?

Agreed.

> 
> >   *
> >   * Calls to this function can be nested, in which case the same number of
> >   * media_pipeline_stop() calls will be required to stop streaming. The
> >   * pipeline pointer must be identical for all nested calls to
> >   * media_pipeline_start().
> >   */
> > -__must_check int media_pipeline_start(struct media_entity *entity,
> > +__must_check int media_pipeline_start(struct media_pad *pad,
> >  				      struct media_pipeline *pipe);
> >  /**
> >   * __media_pipeline_start - Mark a pipeline as streaming
> >   *
> > - * @entity: Starting entity
> > - * @pipe: Media pipeline to be assigned to all entities in the pipeline.
> > + * @pad: Starting pad
> > + * @pipe: Media pipeline to be assigned to all pads in the pipeline.
> >   *
> >   * ..note:: This is the non-locking version of media_pipeline_start()
> >   */
> > -__must_check int __media_pipeline_start(struct media_entity *entity,
> > +__must_check int __media_pipeline_start(struct media_pad *pad,
> >  					struct media_pipeline *pipe);
> >  
> >  /**
> >   * media_pipeline_stop - Mark a pipeline as not streaming
> > - * @entity: Starting entity
> > + * @pad: Starting pad
> >   *
> > - * Mark all entities connected to a given entity through enabled links, either
> > - * directly or indirectly, as not streaming. The media_entity pipe field is
> > - * reset to %NULL.
> > + * Mark all pads connected to a given pad through enabled routes or
> > + * links, either directly or indirectly, as not streaming. The
> > + * media_pad pipe field is reset to %NULL.
> 
> Ditto.
> 
> With the above fixed,
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> >   *
> >   * If multiple calls to media_pipeline_start() have been made, the same
> >   * number of calls to this function are required to mark the pipeline as not
> >   * streaming.
> >   */
> > -void media_pipeline_stop(struct media_entity *entity);
> > +void media_pipeline_stop(struct media_pad *pad);
> >  
> >  /**
> >   * __media_pipeline_stop - Mark a pipeline as not streaming
> >   *
> > - * @entity: Starting entity
> > + * @pad: Starting pad
> >   *
> >   * .. note:: This is the non-locking version of media_pipeline_stop()
> >   */
> > -void __media_pipeline_stop(struct media_entity *entity);
> > +void __media_pipeline_stop(struct media_pad *pad);
> >  
> >  /**
> >   * media_devnode_create() - creates and initializes a device node interface
> 

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 12/30] media: entity: Add an iterator helper for connected pads
  2019-01-15 23:24   ` Laurent Pinchart
@ 2019-01-22 15:36     ` Sakari Ailus
  2019-01-22 15:38       ` Laurent Pinchart
  0 siblings, 1 reply; 90+ messages in thread
From: Sakari Ailus @ 2019-01-22 15:36 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

Hi Laurent,

On Wed, Jan 16, 2019 at 01:24:05AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thank you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:26AM +0100, Niklas Söderlund wrote:
> > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > 
> > Add a helper macro for iterating over pads that are connected through
> > enabled routes. This can be used to find all the connected pads within an
> > entity, for instance starting from the pad which has been obtained during
> > the graph walk.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  include/media/media-entity.h | 27 +++++++++++++++++++++++++++
> >  1 file changed, 27 insertions(+)
> > 
> > diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> > index 9540d2af80f19805..4bb1b568e1ac4795 100644
> > --- a/include/media/media-entity.h
> > +++ b/include/media/media-entity.h
> > @@ -936,6 +936,33 @@ __must_check int media_graph_walk_init(
> >  bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> >  			    unsigned int pad1);
> >  
> > +static inline struct media_pad *__media_entity_for_routed_pads_next(
> > +	struct media_pad *start, struct media_pad *iter)
> > +{
> > +	struct media_entity *entity = start->entity;
> > +
> > +	while (iter < &entity->pads[entity->num_pads] &&
> > +	       !media_entity_has_route(entity, start->index, iter->index))
> > +		iter++;
> > +
> > +	return iter;
> 
> Returning a pointer past the end of the array is asking for trouble. I
> think we should return NULL in that case, and adapt the check in
> media_entity_for_routed_pads() accordingly.

Well, that pointer never gets used, in a similar manner than simply looping
over an array. I wouldn't change that --- this function is also integrally
a part of media_entity_for_each_routed_pad() implementation below.

> 
> > +}
> > +
> > +/**
> > + * media_entity_for_routed_pads - Iterate over entity pads connected by routes
> > + *
> > + * @start: The stating pad
> 
> s/stating/starting/
> 
> > + * @iter: The iterator pad
> > + *
> > + * Iterate over all pads connected through routes from a given pad
> > + * within an entity. The iteration will include the starting pad itself.
> > + */
> > +#define media_entity_for_routed_pads(start, iter)			\
> 
> Maybe media_entity_for_each_routed_pad() ? Or just

I'd prefer this one: we have media_entity_ prefix for pretty much
everything that handles entities.

> for_each_entity_routed_pad() ?
> 
> > +	for (iter = __media_entity_for_routed_pads_next(		\
> 
> And how about __media_entity_next_routed_pad() ?

Yes.

> 
> > +		     start, (start)->entity->pads);			\
> > +	     iter < &(start)->entity->pads[(start)->entity->num_pads];	\
> > +	     iter = __media_entity_for_routed_pads_next(start, iter + 1))
> > +
> >  /**
> >   * media_graph_walk_cleanup - Release resources used by graph walk.
> >   *
> 

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 06/30] media: entity: Use pad as the starting point for a pipeline
  2019-01-22 15:31     ` Sakari Ailus
@ 2019-01-22 15:37       ` Laurent Pinchart
  2019-01-22 16:16         ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-22 15:37 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

Hi Sakari,

On Tue, Jan 22, 2019 at 05:31:34PM +0200, Sakari Ailus wrote:
> On Wed, Jan 16, 2019 at 12:54:20AM +0200, Laurent Pinchart wrote:
> > On Fri, Nov 02, 2018 at 12:31:20AM +0100, Niklas Söderlund wrote:
> >> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> 
> >> The pipeline will be moved from the entity to the pads; reflect this in
> >> the media pipeline function API.
> > 
> > Will be moved, or has been moved ?
> 
> Will be, as it's not yet in this patch.

[PATCH v2 05/30] media: entity: Move the pipeline from entity to pads

> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >> ---
> >>  Documentation/media/kapi/mc-core.rst          |  6 ++--
> >>  drivers/media/media-entity.c                  | 25 +++++++-------
> >>  drivers/media/pci/intel/ipu3/ipu3-cio2.c      |  6 ++--
> >>  .../media/platform/exynos4-is/fimc-capture.c  |  8 ++---
> >>  .../platform/exynos4-is/fimc-isp-video.c      |  8 ++---
> >>  drivers/media/platform/exynos4-is/fimc-lite.c |  8 ++---
> >>  drivers/media/platform/omap3isp/ispvideo.c    |  6 ++--
> >>  .../media/platform/qcom/camss/camss-video.c   |  6 ++--
> >>  drivers/media/platform/rcar-vin/rcar-dma.c    |  6 ++--
> >>  .../media/platform/s3c-camif/camif-capture.c  |  6 ++--
> >>  drivers/media/platform/vimc/vimc-capture.c    |  6 ++--
> >>  drivers/media/platform/vsp1/vsp1_video.c      |  6 ++--
> >>  drivers/media/platform/xilinx/xilinx-dma.c    |  6 ++--
> >>  drivers/media/usb/au0828/au0828-core.c        |  4 +--
> >>  drivers/staging/media/imx/imx-media-utils.c   |  6 ++--
> >>  drivers/staging/media/omap4iss/iss_video.c    |  6 ++--
> >>  include/media/media-entity.h                  | 33 ++++++++++---------
> >>  17 files changed, 76 insertions(+), 76 deletions(-)
> >> 
> >> diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
> >> index 849b87439b7a9772..ede7e946f6a82ac0 100644
> >> --- a/Documentation/media/kapi/mc-core.rst
> >> +++ b/Documentation/media/kapi/mc-core.rst
> >> @@ -211,11 +211,11 @@ When starting streaming, drivers must notify all entities in the pipeline to
> >>  prevent link states from being modified during streaming by calling
> >>  :c:func:`media_pipeline_start()`.
> >>  
> >> -The function will mark all entities connected to the given entity through
> >> -enabled links, either directly or indirectly, as streaming.
> >> +The function will mark all entities connected to the given pad through
> >> +enabled routes and links, either directly or indirectly, as streaming.
> > 
> > That's not really correct, it doesn't mark entities, but pads. I think
> > this section of the documentation needs to be rewritten based on the new
> > model of an entity being part of multiple pipelines. s/entity/pad/ isn't
> > enough, there's a whole new semantics.
> 
> I'd say it's correct. Note that this function just beings the walk from a
> given pad, it doesn't make other changes --- there are further patches
> thought that do.

OK, it might be a change in progress, but the documentation still has to
be rewritten to explain the new model. We need at least one or two new
paragraphs in addition to the s/entity/pad/.

> >>  The struct :c:type:`media_pipeline` instance pointed to by
> >> -the pipe argument will be stored in every entity in the pipeline.
> >> +the pipe argument will be stored in every pad in the pipeline.
> >>  Drivers should embed the struct :c:type:`media_pipeline`
> >>  in higher-level pipeline structures and can then access the
> >>  pipeline through the struct :c:type:`media_entity`
> >> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> >> index 13260149c4dfc90c..f2fa0b7826dbc2f3 100644
> >> --- a/drivers/media/media-entity.c
> >> +++ b/drivers/media/media-entity.c
> >> @@ -411,12 +411,11 @@ EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad);
> >>   * Pipeline management
> >>   */
> >>  
> >> -__must_check int __media_pipeline_start(struct media_entity *entity,
> >> +__must_check int __media_pipeline_start(struct media_pad *pad,
> >>  					struct media_pipeline *pipe)
> >>  {
> >> -	struct media_device *mdev = entity->graph_obj.mdev;
> >> +	struct media_device *mdev = pad->graph_obj.mdev;
> >>  	struct media_graph *graph = &pipe->graph;
> >> -	struct media_pad *pad = entity->pads;
> >>  	struct media_pad *pad_err = pad;
> >>  	struct media_link *link;
> >>  	int ret = 0;
> >> @@ -549,24 +548,23 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
> >>  }
> >>  EXPORT_SYMBOL_GPL(__media_pipeline_start);
> >>  
> >> -__must_check int media_pipeline_start(struct media_entity *entity,
> >> +__must_check int media_pipeline_start(struct media_pad *pad,
> >>  				      struct media_pipeline *pipe)
> >>  {
> >> -	struct media_device *mdev = entity->graph_obj.mdev;
> >> +	struct media_device *mdev = pad->graph_obj.mdev;
> >>  	int ret;
> >>  
> >>  	mutex_lock(&mdev->graph_mutex);
> >> -	ret = __media_pipeline_start(entity, pipe);
> >> +	ret = __media_pipeline_start(pad, pipe);
> >>  	mutex_unlock(&mdev->graph_mutex);
> >>  	return ret;
> >>  }
> >>  EXPORT_SYMBOL_GPL(media_pipeline_start);
> >>  
> >> -void __media_pipeline_stop(struct media_entity *entity)
> >> +void __media_pipeline_stop(struct media_pad *pad)
> >>  {
> >> -	struct media_pipeline *pipe = entity->pads->pipe;
> >> +	struct media_pipeline *pipe = pad->pipe;
> >>  	struct media_graph *graph = &pipe->graph;
> >> -	struct media_pad *pad;
> >>  
> >>  	/*
> >>  	 * If the following check fails, the driver has performed an
> >> @@ -575,9 +573,10 @@ void __media_pipeline_stop(struct media_entity *entity)
> >>  	if (WARN_ON(!pipe))
> >>  		return;
> >>  
> >> -	media_graph_walk_start(graph, entity->pads);
> >> +	media_graph_walk_start(graph, pad);
> >>  
> >>  	while ((pad = media_graph_walk_next(graph))) {
> >> +		struct media_entity *entity = pad->entity;
> > 
> > It looks like this line is a bug fix for a previous patch in the series.
> 
> Yes, so it seems to be. The previous patch appears to remove it.
> 
> >>  		unsigned int i;
> >>  
> >>  		for (i = 0; i < entity->num_pads; i++) {
> >> @@ -598,12 +597,12 @@ void __media_pipeline_stop(struct media_entity *entity)
> >>  }
> >>  EXPORT_SYMBOL_GPL(__media_pipeline_stop);
> >>  
> >> -void media_pipeline_stop(struct media_entity *entity)
> >> +void media_pipeline_stop(struct media_pad *pad)
> >>  {
> >> -	struct media_device *mdev = entity->graph_obj.mdev;
> >> +	struct media_device *mdev = pad->graph_obj.mdev;
> >>  
> >>  	mutex_lock(&mdev->graph_mutex);
> >> -	__media_pipeline_stop(entity);
> >> +	__media_pipeline_stop(pad);
> >>  	mutex_unlock(&mdev->graph_mutex);
> >>  }
> >>  EXPORT_SYMBOL_GPL(media_pipeline_stop);
> > 
> > [snip]
> > 
> >> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> >> index ca0b79288ea7fd11..8378f700389635ea 100644
> >> --- a/include/media/media-entity.h
> >> +++ b/include/media/media-entity.h
> >> @@ -965,53 +965,54 @@ struct media_pad *media_graph_walk_next(struct media_graph *graph);
> >>  
> >>  /**
> >>   * media_pipeline_start - Mark a pipeline as streaming
> >> - * @entity: Starting entity
> >> - * @pipe: Media pipeline to be assigned to all entities in the pipeline.
> >> + * @pad: Starting pad
> >> + * @pipe: Media pipeline to be assigned to all pads in the pipeline.
> >>   *
> >> - * Mark all entities connected to a given entity through enabled links, either
> >> - * directly or indirectly, as streaming. The given pipeline object is assigned
> >> - * to every entity in the pipeline and stored in the media_entity pipe field.
> >> + * Mark all pads connected to a given pad through enabled
> >> + * routes or links, either directly or indirectly, as streaming. The
> >> + * given pipeline object is assigned to every pad in the pipeline
> >> + * and stored in the media_pad pipe field.
> > 
> > Reflowing text to the 80 columns limit ?
> 
> Agreed.
> 
> >>   *
> >>   * Calls to this function can be nested, in which case the same number of
> >>   * media_pipeline_stop() calls will be required to stop streaming. The
> >>   * pipeline pointer must be identical for all nested calls to
> >>   * media_pipeline_start().
> >>   */
> >> -__must_check int media_pipeline_start(struct media_entity *entity,
> >> +__must_check int media_pipeline_start(struct media_pad *pad,
> >>  				      struct media_pipeline *pipe);
> >>  /**
> >>   * __media_pipeline_start - Mark a pipeline as streaming
> >>   *
> >> - * @entity: Starting entity
> >> - * @pipe: Media pipeline to be assigned to all entities in the pipeline.
> >> + * @pad: Starting pad
> >> + * @pipe: Media pipeline to be assigned to all pads in the pipeline.
> >>   *
> >>   * ..note:: This is the non-locking version of media_pipeline_start()
> >>   */
> >> -__must_check int __media_pipeline_start(struct media_entity *entity,
> >> +__must_check int __media_pipeline_start(struct media_pad *pad,
> >>  					struct media_pipeline *pipe);
> >>  
> >>  /**
> >>   * media_pipeline_stop - Mark a pipeline as not streaming
> >> - * @entity: Starting entity
> >> + * @pad: Starting pad
> >>   *
> >> - * Mark all entities connected to a given entity through enabled links, either
> >> - * directly or indirectly, as not streaming. The media_entity pipe field is
> >> - * reset to %NULL.
> >> + * Mark all pads connected to a given pad through enabled routes or
> >> + * links, either directly or indirectly, as not streaming. The
> >> + * media_pad pipe field is reset to %NULL.
> > 
> > Ditto.
> > 
> > With the above fixed,
> > 
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > 
> >>   *
> >>   * If multiple calls to media_pipeline_start() have been made, the same
> >>   * number of calls to this function are required to mark the pipeline as not
> >>   * streaming.
> >>   */
> >> -void media_pipeline_stop(struct media_entity *entity);
> >> +void media_pipeline_stop(struct media_pad *pad);
> >>  
> >>  /**
> >>   * __media_pipeline_stop - Mark a pipeline as not streaming
> >>   *
> >> - * @entity: Starting entity
> >> + * @pad: Starting pad
> >>   *
> >>   * .. note:: This is the non-locking version of media_pipeline_stop()
> >>   */
> >> -void __media_pipeline_stop(struct media_entity *entity);
> >> +void __media_pipeline_stop(struct media_pad *pad);
> >>  
> >>  /**
> >>   * media_devnode_create() - creates and initializes a device node interface

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 14/30] media: entity: Add debug information in graph walk route check
  2019-01-15 23:35   ` Laurent Pinchart
@ 2019-01-22 15:38     ` Sakari Ailus
  0 siblings, 0 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-01-22 15:38 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

On Wed, Jan 16, 2019 at 01:35:14AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thank you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:28AM +0100, Niklas Söderlund wrote:
> > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/media-entity.c | 3 +++
> >  1 file changed, 3 insertions(+)
> > 
> > diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> > index a5bb257d5a68f755..42977634d7102852 100644
> > --- a/drivers/media/media-entity.c
> > +++ b/drivers/media/media-entity.c
> > @@ -360,6 +360,9 @@ static void media_graph_walk_iter(struct media_graph *graph)
> >  	 */
> >  	if (!media_entity_has_route(pad->entity, pad->index, local->index)) {
> >  		link_top(graph) = link_top(graph)->next;
> > +		dev_dbg(pad->graph_obj.mdev->dev,
> > +			"walk: skipping \"%s\":%u -> %u (no route)\n",
> > +			pad->entity->name, pad->index, local->index);
> 
> Maybe "%s: skipping...", __func__, ?

We already have a similar format elsewhere for messages alike. I'd add the
function name to all of them rather than just this one. The message is also
informative and unique enough to be easily found.

> 
> Apart from that,
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> >  		return;
> >  	}
> >  
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 12/30] media: entity: Add an iterator helper for connected pads
  2019-01-22 15:36     ` Sakari Ailus
@ 2019-01-22 15:38       ` Laurent Pinchart
  2019-01-22 16:21         ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-22 15:38 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

Hi Sakari,

On Tue, Jan 22, 2019 at 05:36:55PM +0200, Sakari Ailus wrote:
> On Wed, Jan 16, 2019 at 01:24:05AM +0200, Laurent Pinchart wrote:
> > On Fri, Nov 02, 2018 at 12:31:26AM +0100, Niklas Söderlund wrote:
> >> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> 
> >> Add a helper macro for iterating over pads that are connected through
> >> enabled routes. This can be used to find all the connected pads within an
> >> entity, for instance starting from the pad which has been obtained during
> >> the graph walk.
> >> 
> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >> ---
> >>  include/media/media-entity.h | 27 +++++++++++++++++++++++++++
> >>  1 file changed, 27 insertions(+)
> >> 
> >> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> >> index 9540d2af80f19805..4bb1b568e1ac4795 100644
> >> --- a/include/media/media-entity.h
> >> +++ b/include/media/media-entity.h
> >> @@ -936,6 +936,33 @@ __must_check int media_graph_walk_init(
> >>  bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> >>  			    unsigned int pad1);
> >>  
> >> +static inline struct media_pad *__media_entity_for_routed_pads_next(
> >> +	struct media_pad *start, struct media_pad *iter)
> >> +{
> >> +	struct media_entity *entity = start->entity;
> >> +
> >> +	while (iter < &entity->pads[entity->num_pads] &&
> >> +	       !media_entity_has_route(entity, start->index, iter->index))
> >> +		iter++;
> >> +
> >> +	return iter;
> > 
> > Returning a pointer past the end of the array is asking for trouble. I
> > think we should return NULL in that case, and adapt the check in
> > media_entity_for_routed_pads() accordingly.
> 
> Well, that pointer never gets used, in a similar manner than simply looping
> over an array. I wouldn't change that --- this function is also integrally
> a part of media_entity_for_each_routed_pad() implementation below.

I know it doesn't get used, but it's still asking for trouble, it will
be easy to use it by mistake. Returning NULL would be clearer.

> >> +}
> >> +
> >> +/**
> >> + * media_entity_for_routed_pads - Iterate over entity pads connected by routes
> >> + *
> >> + * @start: The stating pad
> > 
> > s/stating/starting/
> > 
> >> + * @iter: The iterator pad
> >> + *
> >> + * Iterate over all pads connected through routes from a given pad
> >> + * within an entity. The iteration will include the starting pad itself.
> >> + */
> >> +#define media_entity_for_routed_pads(start, iter)			\
> > 
> > Maybe media_entity_for_each_routed_pad() ? Or just
> 
> I'd prefer this one: we have media_entity_ prefix for pretty much
> everything that handles entities.

It's a bit long, but OK.

> > for_each_entity_routed_pad() ?
> > 
> >> +	for (iter = __media_entity_for_routed_pads_next(		\
> > 
> > And how about __media_entity_next_routed_pad() ?
> 
> Yes.
> 
> > 
> >> +		     start, (start)->entity->pads);			\
> >> +	     iter < &(start)->entity->pads[(start)->entity->num_pads];	\
> >> +	     iter = __media_entity_for_routed_pads_next(start, iter + 1))
> >> +
> >>  /**
> >>   * media_graph_walk_cleanup - Release resources used by graph walk.
> >>   *

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 15/30] media: entity: Look for indirect routes
  2019-01-15 23:41   ` Laurent Pinchart
@ 2019-01-22 15:56     ` Sakari Ailus
  0 siblings, 0 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-01-22 15:56 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

Hi Laurent,

On Wed, Jan 16, 2019 at 01:41:08AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thank you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:29AM +0100, Niklas Söderlund wrote:
> > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > 
> > Two pads are considered having an active route for the purpose of
> > has_route() if an indirect active route can be found between the two pads.
> > An simple example of this is that a source pad has an active route to
> > another source pad if both of the pads have an active route to the same
> > sink pad.
> > 
> > Make media_entity_has_route() return true in that case, and do not rely on
> > drivers performing this by themselves.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/media-entity.c | 32 +++++++++++++++++++++++++++++++-
> >  1 file changed, 31 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> > index 42977634d7102852..e45fc2549017615a 100644
> > --- a/drivers/media/media-entity.c
> > +++ b/drivers/media/media-entity.c
> > @@ -240,6 +240,9 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init);
> >  bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> >  			    unsigned int pad1)
> >  {
> > +	unsigned int i;
> > +	bool has_route;
> > +
> >  	if (pad0 >= entity->num_pads || pad1 >= entity->num_pads)
> >  		return false;
> >  
> > @@ -253,7 +256,34 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> >  	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
> >  		swap(pad0, pad1);
> >  
> > -	return entity->ops->has_route(entity, pad0, pad1);
> > +	has_route = entity->ops->has_route(entity, pad0, pad1);
> > +	/* A direct route is returned immediately */
> > +	if (has_route ||
> > +	    (entity->pads[pad0].flags & MEDIA_PAD_FL_SINK &&
> > +	     entity->pads[pad1].flags & MEDIA_PAD_FL_SOURCE))
> > +		return true;
> 
> This will return true if pad0 is a sink and pad1 a source, regardless of
> has_route. I don't think that was intended. return has_route; would be
> an easy fix.

Good find. Yes, I think the condition apart from has_route itself is to be
dropped.

> 
> > +
> > +	/* Look for indirect routes */
> > +	for (i = 0; i < entity->num_pads; i++) {
> > +		if (i == pad0 || i == pad1)
> > +			continue;
> > +
> > +		/*
> > +		 * There are no direct routes between same types of
> > +		 * pads, so skip checking this route
> > +		 */
> > +		if (!((entity->pads[pad0].flags ^ entity->pads[i].flags) &
> > +		      (MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_SINK)))
> > +			continue;
> > +
> > +		/* Is there an indirect route? */
> > +		if (entity->ops->has_route(entity, i, pad0) &&
> > +		    entity->ops->has_route(entity, i, pad1))
> > +			return true;
> > +	}
> 
> Isn't this best implemented in drivers ? I fear the complexity you need
> here isn't worth it, especially given that you would also need to
> support cases such as
> 
> Pads 0, 1 and 2 are sink, pads 3 and 4 are sources. has_route(0, 3),
> has_route(1, 3), has_route(1, 4) and has_route(2, 4) are all true,
> has_route(0, 4) and has_route(2, 3) are all false.
> media_entity_has_route(0, 2) should return true.

Yes, this is not entirely generic, but it'd cover the vast majority of the
cases. It needs to be documented as such. I'd keep it, to avoid drivers
from having to cope with checks for two source pads when both are routed to
a common sink. I presume this is one of the most common cases. I'm also
fine with dropping it for now, to keep the API simple. But we should then
reconsider this if that'd simplify drivers.

> 
> > +	return false;
> > +
> >  }
> >  EXPORT_SYMBOL_GPL(media_entity_has_route);
> >  
> 

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING
  2019-01-15 23:53   ` Laurent Pinchart
@ 2019-01-22 15:57     ` Sakari Ailus
  2019-02-18 11:21     ` Jacopo Mondi
  1 sibling, 0 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-01-22 15:57 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

On Wed, Jan 16, 2019 at 01:53:03AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thank you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:31AM +0100, Niklas Söderlund wrote:
> > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > 
> > Implement compat IOCTL handling for VIDIOC_SUBDEV_G_ROUTING and
> > VIDIOC_SUBDEV_S_ROUTING IOCTLs.
> 
> Let's instead design the ioctl in a way that doesn't require compat
> handling.

Yeah, I wrote the patch back then when the practice hadn't changed yes. I
agree.

> 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 77 +++++++++++++++++++
> >  1 file changed, 77 insertions(+)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> > index 6481212fda772c73..83af332763f41a6b 100644
> > --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> > +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> > @@ -1045,6 +1045,66 @@ static int put_v4l2_event32(struct v4l2_event __user *p64,
> >  	return 0;
> >  }
> >  
> > +struct v4l2_subdev_routing32 {
> > +	compat_caddr_t routes;
> > +	__u32 num_routes;
> > +	__u32 reserved[5];
> > +};
> > +
> > +static int get_v4l2_subdev_routing(struct v4l2_subdev_routing __user *p64,
> > +				   struct v4l2_subdev_routing32 __user *p32)
> > +{
> > +	struct v4l2_subdev_route __user *routes;
> > +	compat_caddr_t p;
> > +	u32 num_routes;
> > +
> > +	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
> > +	    get_user(p, &p32->routes) ||
> > +	    get_user(num_routes, &p32->num_routes) ||
> > +	    put_user(num_routes, &p64->num_routes) ||
> > +	    copy_in_user(&p64->reserved, &p32->reserved,
> > +			 sizeof(p64->reserved)) ||
> > +	    num_routes > U32_MAX / sizeof(*p64->routes))
> > +		return -EFAULT;
> > +
> > +	routes = compat_ptr(p);
> > +
> > +	if (!access_ok(VERIFY_READ, routes,
> > +		       num_routes * sizeof(*p64->routes)))
> > +		return -EFAULT;
> > +
> > +	if (put_user((__force struct v4l2_subdev_route *)routes,
> > +		     &p64->routes))
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> > +static int put_v4l2_subdev_routing(struct v4l2_subdev_routing __user *p64,
> > +				   struct v4l2_subdev_routing32 __user *p32)
> > +{
> > +	struct v4l2_subdev_route __user *routes;
> > +	compat_caddr_t p;
> > +	u32 num_routes;
> > +
> > +	if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
> > +	    get_user(p, &p32->routes) ||
> > +	    get_user(num_routes, &p64->num_routes) ||
> > +	    put_user(num_routes, &p32->num_routes) ||
> > +	    copy_in_user(&p32->reserved, &p64->reserved,
> > +			 sizeof(p64->reserved)) ||
> > +	    num_routes > U32_MAX / sizeof(*p64->routes))
> > +		return -EFAULT;
> > +
> > +	routes = compat_ptr(p);
> > +
> > +	if (!access_ok(VERIFY_WRITE, routes,
> > +		       num_routes * sizeof(*p64->routes)))
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> >  struct v4l2_edid32 {
> >  	__u32 pad;
> >  	__u32 start_block;
> > @@ -1117,6 +1177,8 @@ static int put_v4l2_edid32(struct v4l2_edid __user *p64,
> >  #define VIDIOC_STREAMOFF32	_IOW ('V', 19, s32)
> >  #define VIDIOC_G_INPUT32	_IOR ('V', 38, s32)
> >  #define VIDIOC_S_INPUT32	_IOWR('V', 39, s32)
> > +#define VIDIOC_SUBDEV_G_ROUTING32 _IOWR('V', 38, struct v4l2_subdev_routing32)
> > +#define VIDIOC_SUBDEV_S_ROUTING32 _IOWR('V', 39, struct v4l2_subdev_routing32)
> >  #define VIDIOC_G_OUTPUT32	_IOR ('V', 46, s32)
> >  #define VIDIOC_S_OUTPUT32	_IOWR('V', 47, s32)
> >  
> > @@ -1195,6 +1257,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
> >  	case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
> >  	case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
> >  	case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
> > +	case VIDIOC_SUBDEV_G_ROUTING32: cmd = VIDIOC_SUBDEV_G_ROUTING; break;
> > +	case VIDIOC_SUBDEV_S_ROUTING32: cmd = VIDIOC_SUBDEV_S_ROUTING; break;
> >  	case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
> >  	case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
> >  	case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
> > @@ -1227,6 +1291,15 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
> >  		compatible_arg = 0;
> >  		break;
> >  
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +	case VIDIOC_SUBDEV_S_ROUTING:
> > +		err = alloc_userspace(sizeof(struct v4l2_subdev_routing),
> > +				      0, &new_p64);
> > +		if (!err)
> > +			err = get_v4l2_subdev_routing(new_p64, p32);
> > +		compatible_arg = 0;
> > +		break;
> > +
> >  	case VIDIOC_G_EDID:
> >  	case VIDIOC_S_EDID:
> >  		err = alloc_userspace(sizeof(struct v4l2_edid), 0, &new_p64);
> > @@ -1368,6 +1441,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
> >  		if (put_v4l2_edid32(new_p64, p32))
> >  			err = -EFAULT;
> >  		break;
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +	case VIDIOC_SUBDEV_S_ROUTING:
> > +		err = put_v4l2_subdev_routing(new_p64, p32);
> > +		break;
> >  	}
> >  	if (err)
> >  		return err;
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-01-15 23:51   ` Laurent Pinchart
@ 2019-01-22 16:14     ` Sakari Ailus
  2019-01-22 17:00       ` Laurent Pinchart
  2019-02-21 14:59     ` Jacopo Mondi
  1 sibling, 1 reply; 90+ messages in thread
From: Sakari Ailus @ 2019-01-22 16:14 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media,
	linux-renesas-soc, Michal Simek

On Wed, Jan 16, 2019 at 01:51:45AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thank you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > 
> > - Add sink and source streams for multiplexed links
> > - Copy the argument back in case of an error. This is needed to let the
> >   caller know the number of routes.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> >  include/media/v4l2-subdev.h           |  7 +++++
> >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> 
> Missing documentation :-(
> 
> >  4 files changed, 94 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/kernel.h>
> >  #include <linux/version.h>
> >  
> > +#include <linux/v4l2-subdev.h>
> >  #include <linux/videodev2.h>
> >  
> >  #include <media/v4l2-common.h>
> > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> >  		}
> >  		break;
> >  	}
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = parg;
> > +
> > +		if (route->num_routes > 0) {
> > +			if (route->num_routes > 256)
> > +				return -EINVAL;
> > +
> > +			*user_ptr = (void __user *)route->routes;
> > +			*kernel_ptr = (void *)&route->routes;
> > +			*array_size = sizeof(struct v4l2_subdev_route)
> > +				    * route->num_routes;
> > +			ret = 1;
> > +		}
> > +		break;
> > +	}
> >  	}
> >  
> >  	return ret;
> > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> >  	 * Some ioctls can return an error, but still have valid
> >  	 * results that must be returned.
> >  	 */
> > -	if (err < 0 && !always_copy)
> > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> 
> This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
> always_copy instead ?

Sub-device IOCTLs are partially handled in v4l2-subdev.c, not here. In
particular, __video_do_ioctl() that digs that information from v4l2_ioctls
array is not in the call path for sub-device IOCTLs. So, it'd take a
refactoring of IOCTL handling to change this, which I think should be a
different patchset --- we're already at 30 patches here.

> 
> >  		goto out;
> >  
> >  out_array_args:
> > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> >  
> >  	case VIDIOC_SUBDEV_QUERYSTD:
> >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > +
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = arg;
> > +		unsigned int i;
> > +
> > +		if (route->num_routes > sd->entity.num_pads)
> > +			return -EINVAL;
> > +
> > +		for (i = 0; i < route->num_routes; ++i) {
> > +			unsigned int sink = route->routes[i].sink_pad;
> > +			unsigned int source = route->routes[i].source_pad;
> > +			struct media_pad *pads = sd->entity.pads;
> > +
> > +			if (sink >= sd->entity.num_pads ||
> > +			    source >= sd->entity.num_pads)
> > +				return -EINVAL;
> > +
> > +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> > +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> > +				return -EINVAL;
> > +		}
> > +
> > +		return v4l2_subdev_call(sd, pad, set_routing, route);
> > +	}
> >  #endif
> > +
> >  	default:
> >  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> >  	}
> > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> > --- a/include/media/v4l2-subdev.h
> > +++ b/include/media/v4l2-subdev.h
> > @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> >   *
> >   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> >   *                  may be adjusted by the subdev driver to device capabilities.
> > + *
> > + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> > + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
> 
> Please define the purpose of those operations instead of just pointing
> to the userspace API.
> 
> >   */
> >  struct v4l2_subdev_pad_ops {
> >  	int (*init_cfg)(struct v4l2_subdev *sd,
> > @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> >  			      struct v4l2_mbus_frame_desc *fd);
> >  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> >  			      struct v4l2_mbus_frame_desc *fd);
> > +	int (*get_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> > +	int (*set_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> >  };
> >  
> >  /**
> > diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> > index 03970ce3074193e6..af069bfb10ca23a5 100644
> > --- a/include/uapi/linux/v4l2-subdev.h
> > +++ b/include/uapi/linux/v4l2-subdev.h
> > @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> >  	__u32 reserved[8];
> >  };
> >  
> > +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> > +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> > +
> > +/**
> > + * struct v4l2_subdev_route - A signal route inside a subdev
> > + * @sink_pad: the sink pad
> > + * @sink_stream: the sink stream
> > + * @source_pad: the source pad
> > + * @source_stream: the source stream
> 
> At this point in the series there's no concept of multiplexed streams,
> so the two fields don't make sense. You may want to reorder patches, or
> split this in two.

I think it would make sense to reorder, as adding an IOCTL and then
changing the argument struct would be something to avoid if possible.

> 
> > + * @flags: route flags:
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> > + *	active stream will start when streaming is enabled on a video
> > + *	node. Set by the user.
> 
> This is very confusing as "stream" isn't defined. The documentation
> needs a rewrite with more details.

Yes, we need a little more documentation on this.

> 
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> > + *	can it be activated and inactivated? Set by the driver.
> > + */
> > +struct v4l2_subdev_route {
> > +	__u32 sink_pad;
> > +	__u32 sink_stream;
> > +	__u32 source_pad;
> > +	__u32 source_stream;
> > +	__u32 flags;
> > +	__u32 reserved[5];
> > +};
> > +
> > +/**
> > + * struct v4l2_subdev_routing - Routing information
> > + * @routes: the routes array
> > + * @num_routes: the total number of routes in the routes array
> > + */
> > +struct v4l2_subdev_routing {
> > +	struct v4l2_subdev_route *routes;
> 
> Missing __user ?

We actually don't have any IOCTLs using __u64 pointer values in V4L2. I
wonder what Hans thinks, too. I guess it's the way to go. Compat code is so
awful. :-I

> 
> > +	__u32 num_routes;
> > +	__u32 reserved[5];
> > +};
> > +
> >  /* Backwards compatibility define --- to be removed */
> >  #define v4l2_subdev_edid v4l2_edid
> >  
> > @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
> >  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
> >  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
> >  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> > +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> > +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
> >  
> >  #endif

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 06/30] media: entity: Use pad as the starting point for a pipeline
  2019-01-22 15:37       ` Laurent Pinchart
@ 2019-01-22 16:16         ` Sakari Ailus
  0 siblings, 0 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-01-22 16:16 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

On Tue, Jan 22, 2019 at 05:37:15PM +0200, Laurent Pinchart wrote:
> Hi Sakari,
> 
> On Tue, Jan 22, 2019 at 05:31:34PM +0200, Sakari Ailus wrote:
> > On Wed, Jan 16, 2019 at 12:54:20AM +0200, Laurent Pinchart wrote:
> > > On Fri, Nov 02, 2018 at 12:31:20AM +0100, Niklas Söderlund wrote:
> > >> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >> 
> > >> The pipeline will be moved from the entity to the pads; reflect this in
> > >> the media pipeline function API.
> > > 
> > > Will be moved, or has been moved ?
> > 
> > Will be, as it's not yet in this patch.
> 
> [PATCH v2 05/30] media: entity: Move the pipeline from entity to pads

Oh, I thought it was the other way. Well, "has been" then? :-)

> 
> > >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > >> ---
> > >>  Documentation/media/kapi/mc-core.rst          |  6 ++--
> > >>  drivers/media/media-entity.c                  | 25 +++++++-------
> > >>  drivers/media/pci/intel/ipu3/ipu3-cio2.c      |  6 ++--
> > >>  .../media/platform/exynos4-is/fimc-capture.c  |  8 ++---
> > >>  .../platform/exynos4-is/fimc-isp-video.c      |  8 ++---
> > >>  drivers/media/platform/exynos4-is/fimc-lite.c |  8 ++---
> > >>  drivers/media/platform/omap3isp/ispvideo.c    |  6 ++--
> > >>  .../media/platform/qcom/camss/camss-video.c   |  6 ++--
> > >>  drivers/media/platform/rcar-vin/rcar-dma.c    |  6 ++--
> > >>  .../media/platform/s3c-camif/camif-capture.c  |  6 ++--
> > >>  drivers/media/platform/vimc/vimc-capture.c    |  6 ++--
> > >>  drivers/media/platform/vsp1/vsp1_video.c      |  6 ++--
> > >>  drivers/media/platform/xilinx/xilinx-dma.c    |  6 ++--
> > >>  drivers/media/usb/au0828/au0828-core.c        |  4 +--
> > >>  drivers/staging/media/imx/imx-media-utils.c   |  6 ++--
> > >>  drivers/staging/media/omap4iss/iss_video.c    |  6 ++--
> > >>  include/media/media-entity.h                  | 33 ++++++++++---------
> > >>  17 files changed, 76 insertions(+), 76 deletions(-)
> > >> 
> > >> diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
> > >> index 849b87439b7a9772..ede7e946f6a82ac0 100644
> > >> --- a/Documentation/media/kapi/mc-core.rst
> > >> +++ b/Documentation/media/kapi/mc-core.rst
> > >> @@ -211,11 +211,11 @@ When starting streaming, drivers must notify all entities in the pipeline to
> > >>  prevent link states from being modified during streaming by calling
> > >>  :c:func:`media_pipeline_start()`.
> > >>  
> > >> -The function will mark all entities connected to the given entity through
> > >> -enabled links, either directly or indirectly, as streaming.
> > >> +The function will mark all entities connected to the given pad through
> > >> +enabled routes and links, either directly or indirectly, as streaming.
> > > 
> > > That's not really correct, it doesn't mark entities, but pads. I think
> > > this section of the documentation needs to be rewritten based on the new
> > > model of an entity being part of multiple pipelines. s/entity/pad/ isn't
> > > enough, there's a whole new semantics.
> > 
> > I'd say it's correct. Note that this function just beings the walk from a
> > given pad, it doesn't make other changes --- there are further patches
> > thought that do.
> 
> OK, it might be a change in progress, but the documentation still has to
> be rewritten to explain the new model. We need at least one or two new
> paragraphs in addition to the s/entity/pad/.

There are several patches that would need to change the documentation "a
little". I wonder if it'd be better to just have one patch in the end
updating the documentation.

> 
> > >>  The struct :c:type:`media_pipeline` instance pointed to by
> > >> -the pipe argument will be stored in every entity in the pipeline.
> > >> +the pipe argument will be stored in every pad in the pipeline.
> > >>  Drivers should embed the struct :c:type:`media_pipeline`
> > >>  in higher-level pipeline structures and can then access the
> > >>  pipeline through the struct :c:type:`media_entity`
> > >> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> > >> index 13260149c4dfc90c..f2fa0b7826dbc2f3 100644
> > >> --- a/drivers/media/media-entity.c
> > >> +++ b/drivers/media/media-entity.c
> > >> @@ -411,12 +411,11 @@ EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad);
> > >>   * Pipeline management
> > >>   */
> > >>  
> > >> -__must_check int __media_pipeline_start(struct media_entity *entity,
> > >> +__must_check int __media_pipeline_start(struct media_pad *pad,
> > >>  					struct media_pipeline *pipe)
> > >>  {
> > >> -	struct media_device *mdev = entity->graph_obj.mdev;
> > >> +	struct media_device *mdev = pad->graph_obj.mdev;
> > >>  	struct media_graph *graph = &pipe->graph;
> > >> -	struct media_pad *pad = entity->pads;
> > >>  	struct media_pad *pad_err = pad;
> > >>  	struct media_link *link;
> > >>  	int ret = 0;
> > >> @@ -549,24 +548,23 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
> > >>  }
> > >>  EXPORT_SYMBOL_GPL(__media_pipeline_start);
> > >>  
> > >> -__must_check int media_pipeline_start(struct media_entity *entity,
> > >> +__must_check int media_pipeline_start(struct media_pad *pad,
> > >>  				      struct media_pipeline *pipe)
> > >>  {
> > >> -	struct media_device *mdev = entity->graph_obj.mdev;
> > >> +	struct media_device *mdev = pad->graph_obj.mdev;
> > >>  	int ret;
> > >>  
> > >>  	mutex_lock(&mdev->graph_mutex);
> > >> -	ret = __media_pipeline_start(entity, pipe);
> > >> +	ret = __media_pipeline_start(pad, pipe);
> > >>  	mutex_unlock(&mdev->graph_mutex);
> > >>  	return ret;
> > >>  }
> > >>  EXPORT_SYMBOL_GPL(media_pipeline_start);
> > >>  
> > >> -void __media_pipeline_stop(struct media_entity *entity)
> > >> +void __media_pipeline_stop(struct media_pad *pad)
> > >>  {
> > >> -	struct media_pipeline *pipe = entity->pads->pipe;
> > >> +	struct media_pipeline *pipe = pad->pipe;
> > >>  	struct media_graph *graph = &pipe->graph;
> > >> -	struct media_pad *pad;
> > >>  
> > >>  	/*
> > >>  	 * If the following check fails, the driver has performed an
> > >> @@ -575,9 +573,10 @@ void __media_pipeline_stop(struct media_entity *entity)
> > >>  	if (WARN_ON(!pipe))
> > >>  		return;
> > >>  
> > >> -	media_graph_walk_start(graph, entity->pads);
> > >> +	media_graph_walk_start(graph, pad);
> > >>  
> > >>  	while ((pad = media_graph_walk_next(graph))) {
> > >> +		struct media_entity *entity = pad->entity;
> > > 
> > > It looks like this line is a bug fix for a previous patch in the series.
> > 
> > Yes, so it seems to be. The previous patch appears to remove it.
> > 
> > >>  		unsigned int i;
> > >>  
> > >>  		for (i = 0; i < entity->num_pads; i++) {
> > >> @@ -598,12 +597,12 @@ void __media_pipeline_stop(struct media_entity *entity)
> > >>  }
> > >>  EXPORT_SYMBOL_GPL(__media_pipeline_stop);
> > >>  
> > >> -void media_pipeline_stop(struct media_entity *entity)
> > >> +void media_pipeline_stop(struct media_pad *pad)
> > >>  {
> > >> -	struct media_device *mdev = entity->graph_obj.mdev;
> > >> +	struct media_device *mdev = pad->graph_obj.mdev;
> > >>  
> > >>  	mutex_lock(&mdev->graph_mutex);
> > >> -	__media_pipeline_stop(entity);
> > >> +	__media_pipeline_stop(pad);
> > >>  	mutex_unlock(&mdev->graph_mutex);
> > >>  }
> > >>  EXPORT_SYMBOL_GPL(media_pipeline_stop);
> > > 
> > > [snip]
> > > 
> > >> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> > >> index ca0b79288ea7fd11..8378f700389635ea 100644
> > >> --- a/include/media/media-entity.h
> > >> +++ b/include/media/media-entity.h
> > >> @@ -965,53 +965,54 @@ struct media_pad *media_graph_walk_next(struct media_graph *graph);
> > >>  
> > >>  /**
> > >>   * media_pipeline_start - Mark a pipeline as streaming
> > >> - * @entity: Starting entity
> > >> - * @pipe: Media pipeline to be assigned to all entities in the pipeline.
> > >> + * @pad: Starting pad
> > >> + * @pipe: Media pipeline to be assigned to all pads in the pipeline.
> > >>   *
> > >> - * Mark all entities connected to a given entity through enabled links, either
> > >> - * directly or indirectly, as streaming. The given pipeline object is assigned
> > >> - * to every entity in the pipeline and stored in the media_entity pipe field.
> > >> + * Mark all pads connected to a given pad through enabled
> > >> + * routes or links, either directly or indirectly, as streaming. The
> > >> + * given pipeline object is assigned to every pad in the pipeline
> > >> + * and stored in the media_pad pipe field.
> > > 
> > > Reflowing text to the 80 columns limit ?
> > 
> > Agreed.
> > 
> > >>   *
> > >>   * Calls to this function can be nested, in which case the same number of
> > >>   * media_pipeline_stop() calls will be required to stop streaming. The
> > >>   * pipeline pointer must be identical for all nested calls to
> > >>   * media_pipeline_start().
> > >>   */
> > >> -__must_check int media_pipeline_start(struct media_entity *entity,
> > >> +__must_check int media_pipeline_start(struct media_pad *pad,
> > >>  				      struct media_pipeline *pipe);
> > >>  /**
> > >>   * __media_pipeline_start - Mark a pipeline as streaming
> > >>   *
> > >> - * @entity: Starting entity
> > >> - * @pipe: Media pipeline to be assigned to all entities in the pipeline.
> > >> + * @pad: Starting pad
> > >> + * @pipe: Media pipeline to be assigned to all pads in the pipeline.
> > >>   *
> > >>   * ..note:: This is the non-locking version of media_pipeline_start()
> > >>   */
> > >> -__must_check int __media_pipeline_start(struct media_entity *entity,
> > >> +__must_check int __media_pipeline_start(struct media_pad *pad,
> > >>  					struct media_pipeline *pipe);
> > >>  
> > >>  /**
> > >>   * media_pipeline_stop - Mark a pipeline as not streaming
> > >> - * @entity: Starting entity
> > >> + * @pad: Starting pad
> > >>   *
> > >> - * Mark all entities connected to a given entity through enabled links, either
> > >> - * directly or indirectly, as not streaming. The media_entity pipe field is
> > >> - * reset to %NULL.
> > >> + * Mark all pads connected to a given pad through enabled routes or
> > >> + * links, either directly or indirectly, as not streaming. The
> > >> + * media_pad pipe field is reset to %NULL.
> > > 
> > > Ditto.
> > > 
> > > With the above fixed,
> > > 
> > > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > 
> > >>   *
> > >>   * If multiple calls to media_pipeline_start() have been made, the same
> > >>   * number of calls to this function are required to mark the pipeline as not
> > >>   * streaming.
> > >>   */
> > >> -void media_pipeline_stop(struct media_entity *entity);
> > >> +void media_pipeline_stop(struct media_pad *pad);
> > >>  
> > >>  /**
> > >>   * __media_pipeline_stop - Mark a pipeline as not streaming
> > >>   *
> > >> - * @entity: Starting entity
> > >> + * @pad: Starting pad
> > >>   *
> > >>   * .. note:: This is the non-locking version of media_pipeline_stop()
> > >>   */
> > >> -void __media_pipeline_stop(struct media_entity *entity);
> > >> +void __media_pipeline_stop(struct media_pad *pad);
> > >>  
> > >>  /**
> > >>   * media_devnode_create() - creates and initializes a device node interface
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 12/30] media: entity: Add an iterator helper for connected pads
  2019-01-22 15:38       ` Laurent Pinchart
@ 2019-01-22 16:21         ` Sakari Ailus
  0 siblings, 0 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-01-22 16:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Benoit Parrot, linux-media, linux-renesas-soc

On Tue, Jan 22, 2019 at 05:38:48PM +0200, Laurent Pinchart wrote:
> Hi Sakari,
> 
> On Tue, Jan 22, 2019 at 05:36:55PM +0200, Sakari Ailus wrote:
> > On Wed, Jan 16, 2019 at 01:24:05AM +0200, Laurent Pinchart wrote:
> > > On Fri, Nov 02, 2018 at 12:31:26AM +0100, Niklas Söderlund wrote:
> > >> From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >> 
> > >> Add a helper macro for iterating over pads that are connected through
> > >> enabled routes. This can be used to find all the connected pads within an
> > >> entity, for instance starting from the pad which has been obtained during
> > >> the graph walk.
> > >> 
> > >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > >> ---
> > >>  include/media/media-entity.h | 27 +++++++++++++++++++++++++++
> > >>  1 file changed, 27 insertions(+)
> > >> 
> > >> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> > >> index 9540d2af80f19805..4bb1b568e1ac4795 100644
> > >> --- a/include/media/media-entity.h
> > >> +++ b/include/media/media-entity.h
> > >> @@ -936,6 +936,33 @@ __must_check int media_graph_walk_init(
> > >>  bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> > >>  			    unsigned int pad1);
> > >>  
> > >> +static inline struct media_pad *__media_entity_for_routed_pads_next(
> > >> +	struct media_pad *start, struct media_pad *iter)
> > >> +{
> > >> +	struct media_entity *entity = start->entity;
> > >> +
> > >> +	while (iter < &entity->pads[entity->num_pads] &&
> > >> +	       !media_entity_has_route(entity, start->index, iter->index))
> > >> +		iter++;
> > >> +
> > >> +	return iter;
> > > 
> > > Returning a pointer past the end of the array is asking for trouble. I
> > > think we should return NULL in that case, and adapt the check in
> > > media_entity_for_routed_pads() accordingly.
> > 
> > Well, that pointer never gets used, in a similar manner than simply looping
> > over an array. I wouldn't change that --- this function is also integrally
> > a part of media_entity_for_each_routed_pad() implementation below.
> 
> I know it doesn't get used, but it's still asking for trouble, it will
> be easy to use it by mistake. Returning NULL would be clearer.

Hmph. Well, that's a fair point, too... The caller must be also changed to
cope with NULL then. It'd be nice to see the end result of that for it's
already fairly complex.

> 
> > >> +}
> > >> +
> > >> +/**
> > >> + * media_entity_for_routed_pads - Iterate over entity pads connected by routes
> > >> + *
> > >> + * @start: The stating pad
> > > 
> > > s/stating/starting/
> > > 
> > >> + * @iter: The iterator pad
> > >> + *
> > >> + * Iterate over all pads connected through routes from a given pad
> > >> + * within an entity. The iteration will include the starting pad itself.
> > >> + */
> > >> +#define media_entity_for_routed_pads(start, iter)			\
> > > 
> > > Maybe media_entity_for_each_routed_pad() ? Or just
> > 
> > I'd prefer this one: we have media_entity_ prefix for pretty much
> > everything that handles entities.
> 
> It's a bit long, but OK.
> 
> > > for_each_entity_routed_pad() ?
> > > 
> > >> +	for (iter = __media_entity_for_routed_pads_next(		\
> > > 
> > > And how about __media_entity_next_routed_pad() ?
> > 
> > Yes.
> > 
> > > 
> > >> +		     start, (start)->entity->pads);			\
> > >> +	     iter < &(start)->entity->pads[(start)->entity->num_pads];	\
> > >> +	     iter = __media_entity_for_routed_pads_next(start, iter + 1))
> > >> +
> > >>  /**
> > >>   * media_graph_walk_cleanup - Release resources used by graph walk.
> > >>   *
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-01-22 16:14     ` Sakari Ailus
@ 2019-01-22 17:00       ` Laurent Pinchart
  0 siblings, 0 replies; 90+ messages in thread
From: Laurent Pinchart @ 2019-01-22 17:00 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Niklas Söderlund, Benoit Parrot, linux-media,
	linux-renesas-soc, Michal Simek

Hi Sakari,

On Tue, Jan 22, 2019 at 06:14:57PM +0200, Sakari Ailus wrote:
> On Wed, Jan 16, 2019 at 01:51:45AM +0200, Laurent Pinchart wrote:
> > On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> >> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >> 
> >> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> >> 
> >> - Add sink and source streams for multiplexed links
> >> - Copy the argument back in case of an error. This is needed to let the
> >>   caller know the number of routes.
> >> 
> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >> ---
> >>  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> >>  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> >>  include/media/v4l2-subdev.h           |  7 +++++
> >>  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> > 
> > Missing documentation :-(
> > 
> >>  4 files changed, 94 insertions(+), 1 deletion(-)
> >> 
> >> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> >> index 7de041bae84fb2f2..40406acb51ec0906 100644
> >> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> >> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> >> @@ -19,6 +19,7 @@
> >>  #include <linux/kernel.h>
> >>  #include <linux/version.h>
> >>  
> >> +#include <linux/v4l2-subdev.h>
> >>  #include <linux/videodev2.h>
> >>  
> >>  #include <media/v4l2-common.h>
> >> @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> >>  		}
> >>  		break;
> >>  	}
> >> +
> >> +	case VIDIOC_SUBDEV_G_ROUTING:
> >> +	case VIDIOC_SUBDEV_S_ROUTING: {
> >> +		struct v4l2_subdev_routing *route = parg;
> >> +
> >> +		if (route->num_routes > 0) {
> >> +			if (route->num_routes > 256)
> >> +				return -EINVAL;
> >> +
> >> +			*user_ptr = (void __user *)route->routes;
> >> +			*kernel_ptr = (void *)&route->routes;
> >> +			*array_size = sizeof(struct v4l2_subdev_route)
> >> +				    * route->num_routes;
> >> +			ret = 1;
> >> +		}
> >> +		break;
> >> +	}
> >>  	}
> >>  
> >>  	return ret;
> >> @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> >>  	 * Some ioctls can return an error, but still have valid
> >>  	 * results that must be returned.
> >>  	 */
> >> -	if (err < 0 && !always_copy)
> >> +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> > 
> > This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
> > always_copy instead ?
> 
> Sub-device IOCTLs are partially handled in v4l2-subdev.c, not here. In
> particular, __video_do_ioctl() that digs that information from v4l2_ioctls
> array is not in the call path for sub-device IOCTLs. So, it'd take a
> refactoring of IOCTL handling to change this, which I think should be a
> different patchset --- we're already at 30 patches here.

I'm OK with that. Could we add a FIXME comment ?

> >>  		goto out;
> >>  
> >>  out_array_args:
> >> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> >> index 792f41dffe2329b9..1d3b37cf548fa533 100644
> >> --- a/drivers/media/v4l2-core/v4l2-subdev.c
> >> +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> >> @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> >>  
> >>  	case VIDIOC_SUBDEV_QUERYSTD:
> >>  		return v4l2_subdev_call(sd, video, querystd, arg);
> >> +
> >> +	case VIDIOC_SUBDEV_G_ROUTING:
> >> +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> >> +
> >> +	case VIDIOC_SUBDEV_S_ROUTING: {
> >> +		struct v4l2_subdev_routing *route = arg;
> >> +		unsigned int i;
> >> +
> >> +		if (route->num_routes > sd->entity.num_pads)
> >> +			return -EINVAL;
> >> +
> >> +		for (i = 0; i < route->num_routes; ++i) {
> >> +			unsigned int sink = route->routes[i].sink_pad;
> >> +			unsigned int source = route->routes[i].source_pad;
> >> +			struct media_pad *pads = sd->entity.pads;
> >> +
> >> +			if (sink >= sd->entity.num_pads ||
> >> +			    source >= sd->entity.num_pads)
> >> +				return -EINVAL;
> >> +
> >> +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> >> +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> >> +				return -EINVAL;
> >> +		}
> >> +
> >> +		return v4l2_subdev_call(sd, pad, set_routing, route);
> >> +	}
> >>  #endif
> >> +
> >>  	default:
> >>  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> >>  	}
> >> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> >> index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> >> --- a/include/media/v4l2-subdev.h
> >> +++ b/include/media/v4l2-subdev.h
> >> @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> >>   *
> >>   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> >>   *                  may be adjusted by the subdev driver to device capabilities.
> >> + *
> >> + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> >> + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
> > 
> > Please define the purpose of those operations instead of just pointing
> > to the userspace API.
> > 
> >>   */
> >>  struct v4l2_subdev_pad_ops {
> >>  	int (*init_cfg)(struct v4l2_subdev *sd,
> >> @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> >>  			      struct v4l2_mbus_frame_desc *fd);
> >>  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> >>  			      struct v4l2_mbus_frame_desc *fd);
> >> +	int (*get_routing)(struct v4l2_subdev *sd,
> >> +			   struct v4l2_subdev_routing *route);
> >> +	int (*set_routing)(struct v4l2_subdev *sd,
> >> +			   struct v4l2_subdev_routing *route);
> >>  };
> >>  
> >>  /**
> >> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> >> index 03970ce3074193e6..af069bfb10ca23a5 100644
> >> --- a/include/uapi/linux/v4l2-subdev.h
> >> +++ b/include/uapi/linux/v4l2-subdev.h
> >> @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> >>  	__u32 reserved[8];
> >>  };
> >>  
> >> +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> >> +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> >> +
> >> +/**
> >> + * struct v4l2_subdev_route - A signal route inside a subdev
> >> + * @sink_pad: the sink pad
> >> + * @sink_stream: the sink stream
> >> + * @source_pad: the source pad
> >> + * @source_stream: the source stream
> > 
> > At this point in the series there's no concept of multiplexed streams,
> > so the two fields don't make sense. You may want to reorder patches, or
> > split this in two.
> 
> I think it would make sense to reorder, as adding an IOCTL and then
> changing the argument struct would be something to avoid if possible.
> 
> >> + * @flags: route flags:
> >> + *
> >> + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> >> + *	active stream will start when streaming is enabled on a video
> >> + *	node. Set by the user.
> > 
> > This is very confusing as "stream" isn't defined. The documentation
> > needs a rewrite with more details.
> 
> Yes, we need a little more documentation on this.
> 
> >> + *
> >> + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> >> + *	can it be activated and inactivated? Set by the driver.
> >> + */
> >> +struct v4l2_subdev_route {
> >> +	__u32 sink_pad;
> >> +	__u32 sink_stream;
> >> +	__u32 source_pad;
> >> +	__u32 source_stream;
> >> +	__u32 flags;
> >> +	__u32 reserved[5];
> >> +};
> >> +
> >> +/**
> >> + * struct v4l2_subdev_routing - Routing information
> >> + * @routes: the routes array
> >> + * @num_routes: the total number of routes in the routes array
> >> + */
> >> +struct v4l2_subdev_routing {
> >> +	struct v4l2_subdev_route *routes;
> > 
> > Missing __user ?
> 
> We actually don't have any IOCTLs using __u64 pointer values in V4L2. I
> wonder what Hans thinks, too. I guess it's the way to go. Compat code is so
> awful. :-I
> 
> > 
> >> +	__u32 num_routes;
> >> +	__u32 reserved[5];
> >> +};
> >> +
> >>  /* Backwards compatibility define --- to be removed */
> >>  #define v4l2_subdev_edid v4l2_edid
> >>  
> >> @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
> >>  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
> >>  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
> >>  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> >> +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> >> +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
> >>  
> >>  #endif

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 03/30] media: entity: Walk the graph based on pads
  2018-11-01 23:31 ` [PATCH v2 03/30] media: entity: Walk the graph based on pads Niklas Söderlund
  2019-01-15 22:21   ` Laurent Pinchart
@ 2019-02-14 15:15   ` Jacopo Mondi
  1 sibling, 0 replies; 90+ messages in thread
From: Jacopo Mondi @ 2019-02-14 15:15 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media,
	linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 25673 bytes --]

Hello,
  as I anticipated to Sakari I would like to revive this series,
so I've started from V2 and I'm trying to close comments to re-submit.

In the meantime, I might have some more questions...

On Fri, Nov 02, 2018 at 12:31:17AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
>
> Instead of iterating over graph entities during the walk, iterate the pads
> through which the entity was first reached. This is required in order to
> make the entity pipeline pad-based rather than entity based.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  Documentation/media/kapi/mc-core.rst          |  7 ++-
>  drivers/media/media-entity.c                  | 46 ++++++++++--------
>  drivers/media/platform/exynos4-is/media-dev.c | 20 ++++----
>  drivers/media/platform/omap3isp/ispvideo.c    | 17 +++----
>  drivers/media/platform/vsp1/vsp1_video.c      | 12 ++---
>  drivers/media/platform/xilinx/xilinx-dma.c    | 12 ++---
>  drivers/media/v4l2-core/v4l2-mc.c             | 25 +++++-----
>  .../staging/media/davinci_vpfe/vpfe_video.c   | 47 ++++++++++---------
>  drivers/staging/media/omap4iss/iss_video.c    | 34 +++++++-------
>  include/media/media-entity.h                  |  7 +--
>  10 files changed, 122 insertions(+), 105 deletions(-)
>
> diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst
> index 27aefb9a778b2ad6..849b87439b7a9772 100644
> --- a/Documentation/media/kapi/mc-core.rst
> +++ b/Documentation/media/kapi/mc-core.rst
> @@ -167,8 +167,11 @@ Drivers initiate a graph traversal by calling
>  The graph structure, provided by the caller, is initialized to start graph
>  traversal at the given pad in an entity.
>
> -Drivers can then retrieve the next entity by calling
> -:c:func:`media_graph_walk_next()`
> +Drivers can then retrieve the next pad by calling
> +:c:func:`media_graph_walk_next()`. Only the pad through which the entity
> +is first reached is returned. If the caller is interested in knowing which
> +further pads would be connected, the :c:func:`media_entity_has_route()`
> +function can be used for that.

I found this change confusing. Users of 'media_graph_walk_next()' should be
just notified they will iterate over pads, as one of pads of the next
reachable entity will be put on the stack (this function will always gives
you a pad in the "other entity", as it works on the entity's links)

I don't get what "Only the pad through which the entity is first reached is
returned" stands for here... care to clarify?

Also, the media_entity_has_route() function has not been introduced yet,
and its purpose is to verify if two pads in the same entity has internal
routing, and will be used to make sure the pad put on top of the
stack, is internally connected to the "local pad" link side, not to
get routes to pads in the "other entity".

Am I confused?
Thanks
  j

>
>  When the graph traversal is complete the function will return ``NULL``.
>
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index 892e64a0a9d8ec42..70db03fa33a21db1 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -349,9 +349,9 @@ static void media_graph_walk_iter(struct media_graph *graph)
>  		next->entity->name, next->index);
>  }
>
> -struct media_entity *media_graph_walk_next(struct media_graph *graph)
> +struct media_pad *media_graph_walk_next(struct media_graph *graph)
>  {
> -	struct media_entity *entity;
> +	struct media_pad *pad;
>
>  	if (stack_top(graph) == NULL)
>  		return NULL;
> @@ -364,11 +364,11 @@ struct media_entity *media_graph_walk_next(struct media_graph *graph)
>  	while (link_top(graph) != &stack_top(graph)->entity->links)
>  		media_graph_walk_iter(graph);
>
> -	entity = stack_pop(graph)->entity;
> -	dev_dbg(entity->graph_obj.mdev->dev,
> -		"walk: returning entity '%s'\n", entity->name);
> +	pad = stack_pop(graph);
> +	dev_dbg(pad->graph_obj.mdev->dev,
> +		"walk: returning pad '%s':%u\n", pad->entity->name, pad->index);
>
> -	return entity;
> +	return pad;
>  }
>  EXPORT_SYMBOL_GPL(media_graph_walk_next);
>
> @@ -416,7 +416,8 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  {
>  	struct media_device *mdev = entity->graph_obj.mdev;
>  	struct media_graph *graph = &pipe->graph;
> -	struct media_entity *entity_err = entity;
> +	struct media_pad *pad = entity->pads;
> +	struct media_pad *pad_err = pad;
>  	struct media_link *link;
>  	int ret;
>
> @@ -426,9 +427,11 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  			goto error_graph_walk_start;
>  	}
>
> -	media_graph_walk_start(&pipe->graph, entity->pads);
> +	media_graph_walk_start(&pipe->graph, pad);
> +
> +	while ((pad = media_graph_walk_next(graph))) {
> +		struct media_entity *entity = pad->entity;
>
> -	while ((entity = media_graph_walk_next(graph))) {
>  		DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
>  		DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
>
> @@ -452,11 +455,11 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  		bitmap_fill(has_no_links, entity->num_pads);
>
>  		list_for_each_entry(link, &entity->links, list) {
> -			struct media_pad *pad = link->sink->entity == entity
> -						? link->sink : link->source;
> +			struct media_pad *other_pad = link->sink->entity == entity
> +				? link->sink : link->source;
>
>  			/* Mark that a pad is connected by a link. */
> -			bitmap_clear(has_no_links, pad->index, 1);
> +			bitmap_clear(has_no_links, other_pad->index, 1);
>
>  			/*
>  			 * Pads that either do not need to connect or
> @@ -465,13 +468,13 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  			 */
>  			if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) ||
>  			    link->flags & MEDIA_LNK_FL_ENABLED)
> -				bitmap_set(active, pad->index, 1);
> +				bitmap_set(active, other_pad->index, 1);
>
>  			/*
>  			 * Link validation will only take place for
>  			 * sink ends of the link that are enabled.
>  			 */
> -			if (link->sink != pad ||
> +			if (link->sink != other_pad ||
>  			    !(link->flags & MEDIA_LNK_FL_ENABLED))
>  				continue;
>
> @@ -507,9 +510,11 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  	 * Link validation on graph failed. We revert what we did and
>  	 * return the error.
>  	 */
> -	media_graph_walk_start(graph, entity_err->pads);
> +	media_graph_walk_start(graph, pad_err);
> +
> +	while ((pad_err = media_graph_walk_next(graph))) {
> +		struct media_entity *entity_err = pad_err->entity;
>
> -	while ((entity_err = media_graph_walk_next(graph))) {
>  		/* Sanity check for negative stream_count */
>  		if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) {
>  			entity_err->stream_count--;
> @@ -521,7 +526,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  		 * We haven't increased stream_count further than this
>  		 * so we quit here.
>  		 */
> -		if (entity_err == entity)
> +		if (pad_err == pad)
>  			break;
>  	}
>
> @@ -548,8 +553,9 @@ EXPORT_SYMBOL_GPL(media_pipeline_start);
>
>  void __media_pipeline_stop(struct media_entity *entity)
>  {
> -	struct media_graph *graph = &entity->pipe->graph;
>  	struct media_pipeline *pipe = entity->pipe;
> +	struct media_graph *graph = &pipe->graph;
> +	struct media_pad *pad;
>
>  	/*
>  	 * If the following check fails, the driver has performed an
> @@ -560,7 +566,9 @@ void __media_pipeline_stop(struct media_entity *entity)
>
>  	media_graph_walk_start(graph, entity->pads);
>
> -	while ((entity = media_graph_walk_next(graph))) {
> +	while ((pad = media_graph_walk_next(graph))) {
> +		struct media_entity *entity = pad->entity;
> +
>  		/* Sanity check for negative stream_count */
>  		if (!WARN_ON_ONCE(entity->stream_count <= 0)) {
>  			entity->stream_count--;
> diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
> index 51d2a571c06db6a3..5813639c63b56a2c 100644
> --- a/drivers/media/platform/exynos4-is/media-dev.c
> +++ b/drivers/media/platform/exynos4-is/media-dev.c
> @@ -1135,7 +1135,7 @@ static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable)
>  static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
>  				      struct media_graph *graph)
>  {
> -	struct media_entity *entity_err = entity;
> +	struct media_pad *pad, *pad_err = entity->pads;
>  	int ret;
>
>  	/*
> @@ -1144,13 +1144,13 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
>  	 * through active links. This is needed as we cannot power on/off the
>  	 * subdevs in random order.
>  	 */
> -	media_graph_walk_start(graph, entity->pads);
> +	media_graph_walk_start(graph, pad_err);
>
> -	while ((entity = media_graph_walk_next(graph))) {
> -		if (!is_media_entity_v4l2_video_device(entity))
> +	while ((pad = media_graph_walk_next(graph))) {
> +		if (!is_media_entity_v4l2_video_device(pad->entity))
>  			continue;
>
> -		ret  = __fimc_md_modify_pipeline(entity, enable);
> +		ret  = __fimc_md_modify_pipeline(pad->entity, enable);
>
>  		if (ret < 0)
>  			goto err;
> @@ -1159,15 +1159,15 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
>  	return 0;
>
>  err:
> -	media_graph_walk_start(graph, entity_err->pads);
> +	media_graph_walk_start(graph, pad_err);
>
> -	while ((entity_err = media_graph_walk_next(graph))) {
> -		if (!is_media_entity_v4l2_video_device(entity_err))
> +	while ((pad_err = media_graph_walk_next(graph))) {
> +		if (!is_media_entity_v4l2_video_device(pad_err->entity))
>  			continue;
>
> -		__fimc_md_modify_pipeline(entity_err, !enable);
> +		__fimc_md_modify_pipeline(pad_err->entity, !enable);
>
> -		if (entity_err == entity)
> +		if (pad_err == pad)
>  			break;
>  	}
>
> diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
> index 50ad35bc644eae29..dc11b732dc05b00b 100644
> --- a/drivers/media/platform/omap3isp/ispvideo.c
> +++ b/drivers/media/platform/omap3isp/ispvideo.c
> @@ -226,8 +226,8 @@ static int isp_video_get_graph_data(struct isp_video *video,
>  				    struct isp_pipeline *pipe)
>  {
>  	struct media_graph graph;
> -	struct media_entity *entity = &video->video.entity;
> -	struct media_device *mdev = entity->graph_obj.mdev;
> +	struct media_pad *pad = video->video.entity.pads;
> +	struct media_device *mdev = pad->entity->graph_obj.mdev;
>  	struct isp_video *far_end = NULL;
>  	int ret;
>
> @@ -238,23 +238,24 @@ static int isp_video_get_graph_data(struct isp_video *video,
>  		return ret;
>  	}
>
> -	media_graph_walk_start(&graph, entity->pads);
> +	media_graph_walk_start(&graph, pad);
>
> -	while ((entity = media_graph_walk_next(&graph))) {
> +	while ((pad = media_graph_walk_next(&graph))) {
>  		struct isp_video *__video;
>
> -		media_entity_enum_set(&pipe->ent_enum, entity);
> +		media_entity_enum_set(&pipe->ent_enum, pad->entity);
>
>  		if (far_end != NULL)
>  			continue;
>
> -		if (entity == &video->video.entity)
> +		if (pad == video->video.entity.pads)
>  			continue;
>
> -		if (!is_media_entity_v4l2_video_device(entity))
> +		if (!is_media_entity_v4l2_video_device(pad->entity))
>  			continue;
>
> -		__video = to_isp_video(media_entity_to_video_device(entity));
> +		__video = to_isp_video(media_entity_to_video_device(
> +					       pad->entity));
>  		if (__video->type != video->type)
>  			far_end = __video;
>  	}
> diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
> index e35b2e2340b82f00..806825bd3484167a 100644
> --- a/drivers/media/platform/vsp1/vsp1_video.c
> +++ b/drivers/media/platform/vsp1/vsp1_video.c
> @@ -570,8 +570,8 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
>  				     struct vsp1_video *video)
>  {
>  	struct media_graph graph;
> -	struct media_entity *entity = &video->video.entity;
> -	struct media_device *mdev = entity->graph_obj.mdev;
> +	struct media_pad *pad = video->video.entity.pads;
> +	struct media_device *mdev = pad->entity->graph_obj.mdev;
>  	unsigned int i;
>  	int ret;
>
> @@ -580,17 +580,17 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
>  	if (ret)
>  		return ret;
>
> -	media_graph_walk_start(&graph, entity->pads);
> +	media_graph_walk_start(&graph, pad);
>
> -	while ((entity = media_graph_walk_next(&graph))) {
> +	while ((pad = media_graph_walk_next(&graph))) {
>  		struct v4l2_subdev *subdev;
>  		struct vsp1_rwpf *rwpf;
>  		struct vsp1_entity *e;
>
> -		if (!is_media_entity_v4l2_subdev(entity))
> +		if (!is_media_entity_v4l2_subdev(pad->entity))
>  			continue;
>
> -		subdev = media_entity_to_v4l2_subdev(entity);
> +		subdev = media_entity_to_v4l2_subdev(pad->entity);
>  		e = to_vsp1_entity(subdev);
>  		list_add_tail(&e->list_pipe, &pipe->entities);
>  		e->pipe = pipe;
> diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
> index 566c2d0fb97dc162..a2a329336243bdc7 100644
> --- a/drivers/media/platform/xilinx/xilinx-dma.c
> +++ b/drivers/media/platform/xilinx/xilinx-dma.c
> @@ -178,8 +178,8 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
>  				  struct xvip_dma *start)
>  {
>  	struct media_graph graph;
> -	struct media_entity *entity = &start->video.entity;
> -	struct media_device *mdev = entity->graph_obj.mdev;
> +	struct media_pad *pad = start->video.entity.pads;
> +	struct media_device *mdev = pad->entity->graph_obj.mdev;
>  	unsigned int num_inputs = 0;
>  	unsigned int num_outputs = 0;
>  	int ret;
> @@ -193,15 +193,15 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
>  		return ret;
>  	}
>
> -	media_graph_walk_start(&graph, entity->pads);
> +	media_graph_walk_start(&graph, pad);
>
> -	while ((entity = media_graph_walk_next(&graph))) {
> +	while ((pad = media_graph_walk_next(&graph))) {
>  		struct xvip_dma *dma;
>
> -		if (entity->function != MEDIA_ENT_F_IO_V4L)
> +		if (pad->entity->function != MEDIA_ENT_F_IO_V4L)
>  			continue;
>
> -		dma = to_xvip_dma(media_entity_to_video_device(entity));
> +		dma = to_xvip_dma(media_entity_to_video_device(pad->entity));
>
>  		if (dma->pad.flags & MEDIA_PAD_FL_SINK) {
>  			pipe->output = dma;
> diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
> index 9ed480fe5b6e4762..98edd47b2f0ae747 100644
> --- a/drivers/media/v4l2-core/v4l2-mc.c
> +++ b/drivers/media/v4l2-core/v4l2-mc.c
> @@ -339,13 +339,14 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
>  static int pipeline_pm_use_count(struct media_entity *entity,
>  	struct media_graph *graph)
>  {
> +	struct media_pad *pad;
>  	int use = 0;
>
>  	media_graph_walk_start(graph, entity->pads);
>
> -	while ((entity = media_graph_walk_next(graph))) {
> -		if (is_media_entity_v4l2_video_device(entity))
> -			use += entity->use_count;
> +	while ((pad = media_graph_walk_next(graph))) {
> +		if (is_media_entity_v4l2_video_device(pad->entity))
> +			use += pad->entity->use_count;
>  	}
>
>  	return use;
> @@ -398,7 +399,7 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
>  static int pipeline_pm_power(struct media_entity *entity, int change,
>  	struct media_graph *graph)
>  {
> -	struct media_entity *first = entity;
> +	struct media_pad *tmp_pad, *pad;
>  	int ret = 0;
>
>  	if (!change)
> @@ -406,19 +407,19 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
>
>  	media_graph_walk_start(graph, entity->pads);
>
> -	while (!ret && (entity = media_graph_walk_next(graph)))
> -		if (is_media_entity_v4l2_subdev(entity))
> -			ret = pipeline_pm_power_one(entity, change);
> +	while (!ret && (pad = media_graph_walk_next(graph)))
> +		if (is_media_entity_v4l2_subdev(pad->entity))
> +			ret = pipeline_pm_power_one(pad->entity, change);
>
>  	if (!ret)
>  		return ret;
>
> -	media_graph_walk_start(graph, first->pads);
> +	media_graph_walk_start(graph, entity->pads);
>
> -	while ((first = media_graph_walk_next(graph))
> -	       && first != entity)
> -		if (is_media_entity_v4l2_subdev(first))
> -			pipeline_pm_power_one(first, -change);
> +	while ((tmp_pad = media_graph_walk_next(graph))
> +	       && tmp_pad != pad)
> +		if (is_media_entity_v4l2_subdev(tmp_pad->entity))
> +			pipeline_pm_power_one(tmp_pad->entity, -change);
>
>  	return ret;
>  }
> diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
> index 912d93fc7a483cd4..5219a0372d140f4a 100644
> --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
> +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
> @@ -130,8 +130,8 @@ __vpfe_video_get_format(struct vpfe_video_device *video,
>  static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
>  {
>  	struct media_graph graph;
> -	struct media_entity *entity = &video->video_dev.entity;
> -	struct media_device *mdev = entity->graph_obj.mdev;
> +	struct media_pad *pad = video->video_dev.entity.pads;
> +	struct media_device *mdev = pad->entity->graph_obj.mdev;
>  	struct vpfe_pipeline *pipe = &video->pipe;
>  	struct vpfe_video_device *far_end = NULL;
>  	int ret;
> @@ -150,13 +150,14 @@ static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
>  		mutex_unlock(&mdev->graph_mutex);
>  		return -ENOMEM;
>  	}
> -	media_graph_walk_start(&graph, entity->pads);
> -	while ((entity = media_graph_walk_next(&graph))) {
> -		if (entity == &video->video_dev.entity)
> +	media_graph_walk_start(&graph, pad);
> +	while ((pad = media_graph_walk_next(&graph))) {
> +		if (pad->entity == &video->video_dev.entity)
>  			continue;
> -		if (!is_media_entity_v4l2_video_device(entity))
> +		if (!is_media_entity_v4l2_video_device(pad->entity))
>  			continue;
> -		far_end = to_vpfe_video(media_entity_to_video_device(entity));
> +		far_end = to_vpfe_video(media_entity_to_video_device(
> +						pad->entity));
>  		if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
>  			pipe->inputs[pipe->input_num++] = far_end;
>  		else
> @@ -288,27 +289,27 @@ static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe)
>   */
>  static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
>  {
> -	struct media_entity *entity;
> +	struct media_pad *pad;
>  	struct v4l2_subdev *subdev;
>  	struct media_device *mdev;
>  	int ret;
>
>  	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
> -		entity = vpfe_get_input_entity(pipe->outputs[0]);
> +		pad = vpfe_get_input_entity(pipe->outputs[0])->pads;
>  	else
> -		entity = &pipe->inputs[0]->video_dev.entity;
> +		pad = pipe->inputs[0]->video_dev.entity.pads;
>
> -	mdev = entity->graph_obj.mdev;
> +	mdev = pad->graph_obj.mdev;
>  	mutex_lock(&mdev->graph_mutex);
>  	ret = media_graph_walk_init(&pipe->graph, mdev);
>  	if (ret)
>  		goto out;
> -	media_graph_walk_start(&pipe->graph, entity->pads);
> -	while ((entity = media_graph_walk_next(&pipe->graph))) {
> +	media_graph_walk_start(&pipe->graph, pad);
> +	while ((pad = media_graph_walk_next(&pipe->graph))) {
>
> -		if (!is_media_entity_v4l2_subdev(entity))
> +		if (!is_media_entity_v4l2_subdev(pad->entity))
>  			continue;
> -		subdev = media_entity_to_v4l2_subdev(entity);
> +		subdev = media_entity_to_v4l2_subdev(pad->entity);
>  		ret = v4l2_subdev_call(subdev, video, s_stream, 1);
>  		if (ret < 0 && ret != -ENOIOCTLCMD)
>  			break;
> @@ -333,25 +334,25 @@ static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
>   */
>  static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
>  {
> -	struct media_entity *entity;
> +	struct media_pad *pad;
>  	struct v4l2_subdev *subdev;
>  	struct media_device *mdev;
>  	int ret = 0;
>
>  	if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
> -		entity = vpfe_get_input_entity(pipe->outputs[0]);
> +		pad = vpfe_get_input_entity(pipe->outputs[0])->pads;
>  	else
> -		entity = &pipe->inputs[0]->video_dev.entity;
> +		pad = pipe->inputs[0]->video_dev.entity.pads;
>
> -	mdev = entity->graph_obj.mdev;
> +	mdev = pad->graph_obj.mdev;
>  	mutex_lock(&mdev->graph_mutex);
> -	media_graph_walk_start(&pipe->graph, entity->pads);
> +	media_graph_walk_start(&pipe->graph, pad);
>
> -	while ((entity = media_graph_walk_next(&pipe->graph))) {
> +	while ((pad = media_graph_walk_next(&pipe->graph))) {
>
> -		if (!is_media_entity_v4l2_subdev(entity))
> +		if (!is_media_entity_v4l2_subdev(pad->entity))
>  			continue;
> -		subdev = media_entity_to_v4l2_subdev(entity);
> +		subdev = media_entity_to_v4l2_subdev(pad->entity);
>  		ret = v4l2_subdev_call(subdev, video, s_stream, 0);
>  		if (ret < 0 && ret != -ENOIOCTLCMD)
>  			break;
> diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
> index 6f72c02c8054f496..1271bbacf9e7bdeb 100644
> --- a/drivers/staging/media/omap4iss/iss_video.c
> +++ b/drivers/staging/media/omap4iss/iss_video.c
> @@ -206,8 +206,8 @@ static struct iss_video *
>  iss_video_far_end(struct iss_video *video)
>  {
>  	struct media_graph graph;
> -	struct media_entity *entity = &video->video.entity;
> -	struct media_device *mdev = entity->graph_obj.mdev;
> +	struct media_pad *pad = video->video.entity.pads;
> +	struct media_device *mdev = pad->entity->graph_obj.mdev;
>  	struct iss_video *far_end = NULL;
>
>  	mutex_lock(&mdev->graph_mutex);
> @@ -217,16 +217,17 @@ iss_video_far_end(struct iss_video *video)
>  		return NULL;
>  	}
>
> -	media_graph_walk_start(&graph, entity->pads);
> +	media_graph_walk_start(&graph, pad);
>
> -	while ((entity = media_graph_walk_next(&graph))) {
> -		if (entity == &video->video.entity)
> +	while ((pad = media_graph_walk_next(&graph))) {
> +		if (pad->entity == &video->video.entity)
>  			continue;
>
> -		if (!is_media_entity_v4l2_video_device(entity))
> +		if (!is_media_entity_v4l2_video_device(pad->entity))
>  			continue;
>
> -		far_end = to_iss_video(media_entity_to_video_device(entity));
> +		far_end = to_iss_video(media_entity_to_video_device(
> +						pad->entity));
>  		if (far_end->type != video->type)
>  			break;
>
> @@ -860,7 +861,7 @@ 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_graph graph;
> -	struct media_entity *entity = &video->video.entity;
> +	struct media_pad *pad = video->video.entity.pads;
>  	enum iss_pipeline_state state;
>  	struct iss_pipeline *pipe;
>  	struct iss_video *far_end;
> @@ -876,30 +877,31 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
>  	 * Start streaming on the pipeline. No link touching an entity in the
>  	 * pipeline can be activated or deactivated once streaming is started.
>  	 */
> -	pipe = entity->pipe
> -	     ? to_iss_pipeline(entity) : &video->pipe;
> +	pipe = pad->entity->pipe
> +	     ? to_iss_pipeline(pad->entity) : &video->pipe;
>  	pipe->external = NULL;
>  	pipe->external_rate = 0;
>  	pipe->external_bpp = 0;
>
> -	ret = media_entity_enum_init(&pipe->ent_enum, entity->graph_obj.mdev);
> +	ret = media_entity_enum_init(&pipe->ent_enum,
> +				     pad->entity->graph_obj.mdev);
>  	if (ret)
>  		goto err_graph_walk_init;
>
> -	ret = media_graph_walk_init(&graph, entity->graph_obj.mdev);
> +	ret = media_graph_walk_init(&graph, pad->entity->graph_obj.mdev);
>  	if (ret)
>  		goto err_graph_walk_init;
>
>  	if (video->iss->pdata->set_constraints)
>  		video->iss->pdata->set_constraints(video->iss, true);
>
> -	ret = media_pipeline_start(entity, &pipe->pipe);
> +	ret = media_pipeline_start(pad->entity, &pipe->pipe);
>  	if (ret < 0)
>  		goto err_media_pipeline_start;
>
> -	media_graph_walk_start(&graph, entity->pads);
> -	while ((entity = media_graph_walk_next(&graph)))
> -		media_entity_enum_set(&pipe->ent_enum, entity);
> +	media_graph_walk_start(&graph, pad);
> +	while ((pad = media_graph_walk_next(&graph)))
> +		media_entity_enum_set(&pipe->ent_enum, pad->entity);
>
>  	/*
>  	 * Verify that the currently configured format matches the output of
> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index 99c7606f01317741..cde6350d752bb0ae 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -952,10 +952,11 @@ void media_graph_walk_start(struct media_graph *graph, struct media_pad *pad);
>   * The graph structure must have been previously initialized with a call to
>   * media_graph_walk_start().
>   *
> - * Return: returns the next entity in the graph or %NULL if the whole graph
> - * have been traversed.
> + * Return: returns the next pad in the graph or %NULL if the whole
> + * graph have been traversed. The pad which is returned is the pad
> + * through which a new entity is reached when parsing the graph.
>   */
> -struct media_entity *media_graph_walk_next(struct media_graph *graph);
> +struct media_pad *media_graph_walk_next(struct media_graph *graph);
>
>  /**
>   * media_pipeline_start - Mark a pipeline as streaming
> --
> 2.19.1
>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 05/30] media: entity: Move the pipeline from entity to pads
  2018-11-01 23:31 ` [PATCH v2 05/30] media: entity: Move the pipeline from entity to pads Niklas Söderlund
  2019-01-15 22:38   ` Laurent Pinchart
@ 2019-02-14 15:53   ` Jacopo Mondi
  1 sibling, 0 replies; 90+ messages in thread
From: Jacopo Mondi @ 2019-02-14 15:53 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media,
	linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 15655 bytes --]

Hi Sakari,
    thanks for the patches

On Fri, Nov 02, 2018 at 12:31:19AM +0100, Niklas Söderlund wrote:
> From: Sakari Ailus <sakari.ailus@linux.intel.com>
>
> This moves the pipe and stream_count fields from struct media_entity to
> struct media_pad. Effectively streams become pad-specific rather than
> being stream specific, allowing several independent streams to traverse a
> single entity.
>

There will be quite some rebase here :)

> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/media-entity.c                  | 61 ++++++++++++-------
>  drivers/media/platform/exynos4-is/fimc-isp.c  |  2 +-
>  drivers/media/platform/exynos4-is/fimc-lite.c |  2 +-
>  drivers/media/platform/omap3isp/isp.c         |  2 +-
>  drivers/media/platform/omap3isp/ispvideo.c    |  2 +-
>  drivers/media/platform/omap3isp/ispvideo.h    |  2 +-
>  drivers/media/platform/rcar-vin/rcar-dma.c    |  2 +-
>  drivers/media/platform/xilinx/xilinx-dma.c    |  2 +-
>  drivers/media/platform/xilinx/xilinx-dma.h    |  2 +-
>  drivers/staging/media/imx/imx-media-utils.c   |  2 +-
>  drivers/staging/media/omap4iss/iss.c          |  2 +-
>  drivers/staging/media/omap4iss/iss_video.c    |  2 +-
>  drivers/staging/media/omap4iss/iss_video.h    |  2 +-
>  include/media/media-entity.h                  | 17 ++++--
>  14 files changed, 61 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> index 70db03fa33a21db1..13260149c4dfc90c 100644
> --- a/drivers/media/media-entity.c
> +++ b/drivers/media/media-entity.c
> @@ -419,7 +419,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>  	struct media_pad *pad = entity->pads;
>  	struct media_pad *pad_err = pad;
>  	struct media_link *link;
> -	int ret;
> +	int ret = 0;
>
>  	if (!pipe->streaming_count++) {
>  		ret = media_graph_walk_init(&pipe->graph, mdev);
> @@ -431,21 +431,27 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>
>  	while ((pad = media_graph_walk_next(graph))) {
>  		struct media_entity *entity = pad->entity;
> +		unsigned int i;
> +		bool skip_validation = pad->pipe;
>
>  		DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
>  		DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
>
> -		entity->stream_count++;
> +		for (i = 0; i < entity->num_pads; i++) {
> +			struct media_pad *iter = &entity->pads[i];
>
> -		if (WARN_ON(entity->pipe && entity->pipe != pipe)) {
> -			ret = -EBUSY;
> -			goto error;
> +			if (iter->pipe && WARN_ON(iter->pipe != pipe))
> +				ret = -EBUSY;
> +			else
> +				iter->pipe = pipe;
> +			iter->stream_count++;
>  		}
>
> -		entity->pipe = pipe;
> +		if (ret)
> +			goto error;
>
>  		/* Already streaming --- no need to check. */
> -		if (entity->stream_count > 1)
> +		if (skip_validation)
>  			continue;
>
>  		if (!entity->ops || !entity->ops->link_validate)
> @@ -514,19 +520,24 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
>
>  	while ((pad_err = media_graph_walk_next(graph))) {
>  		struct media_entity *entity_err = pad_err->entity;
> +		unsigned int i;
> +
> +		for (i = 0; i < entity_err->num_pads; i++) {
> +			struct media_pad *iter = &entity_err->pads[i];
>
> -		/* Sanity check for negative stream_count */
> -		if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) {
> -			entity_err->stream_count--;
> -			if (entity_err->stream_count == 0)
> -				entity_err->pipe = NULL;
> +			/* Sanity check for negative stream_count */
> +			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
> +				--iter->stream_count;
> +				if (iter->stream_count == 0)
> +					iter->pipe = NULL;
> +			}
>  		}
>
>  		/*
>  		 * We haven't increased stream_count further than this
>  		 * so we quit here.
>  		 */
> -		if (pad_err == pad)
> +		if (pad_err->entity == pad->entity)
>  			break;
>  	}
>
> @@ -553,7 +564,7 @@ EXPORT_SYMBOL_GPL(media_pipeline_start);
>
>  void __media_pipeline_stop(struct media_entity *entity)
>  {
> -	struct media_pipeline *pipe = entity->pipe;
> +	struct media_pipeline *pipe = entity->pads->pipe;
>  	struct media_graph *graph = &pipe->graph;
>  	struct media_pad *pad;
>
> @@ -567,13 +578,17 @@ void __media_pipeline_stop(struct media_entity *entity)
>  	media_graph_walk_start(graph, entity->pads);
>
>  	while ((pad = media_graph_walk_next(graph))) {
> -		struct media_entity *entity = pad->entity;
> +		unsigned int i;
>
> -		/* Sanity check for negative stream_count */
> -		if (!WARN_ON_ONCE(entity->stream_count <= 0)) {
> -			entity->stream_count--;
> -			if (entity->stream_count == 0)
> -				entity->pipe = NULL;
> +		for (i = 0; i < entity->num_pads; i++) {
> +			struct media_pad *iter = &entity->pads[i];
> +
> +			/* Sanity check for negative stream_count */
> +			if (!WARN_ON_ONCE(iter->stream_count <= 0)) {
> +				iter->stream_count--;
> +				if (iter->stream_count == 0)
> +					iter->pipe = NULL;
> +			}
>  		}
>  	}
>
> @@ -865,7 +880,7 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
>  {
>  	const u32 mask = MEDIA_LNK_FL_ENABLED;
>  	struct media_device *mdev;
> -	struct media_entity *source, *sink;
> +	struct media_pad *source, *sink;
>  	int ret = -EBUSY;
>
>  	if (link == NULL)
> @@ -881,8 +896,8 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
>  	if (link->flags == flags)
>  		return 0;
>
> -	source = link->source->entity;
> -	sink = link->sink->entity;
> +	source = link->source;
> +	sink = link->sink;
>
>  	if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
>  	    (source->stream_count || sink->stream_count))
> diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
> index 9a48c0f69320ba35..79d128a57e87fd58 100644
> --- a/drivers/media/platform/exynos4-is/fimc-isp.c
> +++ b/drivers/media/platform/exynos4-is/fimc-isp.c
> @@ -229,7 +229,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
>  			}
>  		}
>  	} else {
> -		if (sd->entity.stream_count == 0) {
> +		if (sd->entity.pads->stream_count == 0) {
>  			if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
>  				struct v4l2_subdev_format format = *fmt;
>
> diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
> index 96f0a8a0dcae591f..dbadcba6739a286b 100644
> --- a/drivers/media/platform/exynos4-is/fimc-lite.c
> +++ b/drivers/media/platform/exynos4-is/fimc-lite.c
> @@ -1096,7 +1096,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
>  	mutex_lock(&fimc->lock);
>
>  	if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP &&
> -	    sd->entity.stream_count > 0) ||
> +	    sd->entity.pads->stream_count > 0) ||

I'm not sure this is correct. Shouldn't we check the stream count of
the entity.pads[fmt->pad] entry instead of accessing the first one?

Here and in the fimc-isp one as well..

Thanks
   j

>  	    (atomic_read(&fimc->out_path) == FIMC_IO_DMA &&
>  	    vb2_is_busy(&fimc->vb_queue))) {
>  		mutex_unlock(&fimc->lock);
> diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
> index 77fb7987b42f33cd..3663dfd00cadc2f0 100644
> --- a/drivers/media/platform/omap3isp/isp.c
> +++ b/drivers/media/platform/omap3isp/isp.c
> @@ -927,7 +927,7 @@ static int isp_pipeline_is_last(struct media_entity *me)
>  	struct isp_pipeline *pipe;
>  	struct media_pad *pad;
>
> -	if (!me->pipe)
> +	if (!me->pads->pipe)
>  		return 0;
>  	pipe = to_isp_pipeline(me);
>  	if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
> diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
> index dc11b732dc05b00b..f354cd7ceb8ffce5 100644
> --- a/drivers/media/platform/omap3isp/ispvideo.c
> +++ b/drivers/media/platform/omap3isp/ispvideo.c
> @@ -1102,7 +1102,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
>  	/* Start streaming on the pipeline. No link touching an entity in the
>  	 * pipeline can be activated or deactivated once streaming is started.
>  	 */
> -	pipe = video->video.entity.pipe
> +	pipe = video->video.entity.pads->pipe
>  	     ? to_isp_pipeline(&video->video.entity) : &video->pipe;
>
>  	ret = media_entity_enum_init(&pipe->ent_enum, &video->isp->media_dev);
> diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
> index f6a2082b4a0a7708..8f4146c25a1b1293 100644
> --- a/drivers/media/platform/omap3isp/ispvideo.h
> +++ b/drivers/media/platform/omap3isp/ispvideo.h
> @@ -103,7 +103,7 @@ struct isp_pipeline {
>  };
>
>  #define to_isp_pipeline(__e) \
> -	container_of((__e)->pipe, struct isp_pipeline, pipe)
> +	container_of((__e)->pads->pipe, struct isp_pipeline, pipe)
>
>  static inline int isp_pipeline_ready(struct isp_pipeline *pipe)
>  {
> diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
> index 92323310f7352147..e749096926f34d4a 100644
> --- a/drivers/media/platform/rcar-vin/rcar-dma.c
> +++ b/drivers/media/platform/rcar-vin/rcar-dma.c
> @@ -1128,7 +1128,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on)
>  	 */
>  	mdev = vin->vdev.entity.graph_obj.mdev;
>  	mutex_lock(&mdev->graph_mutex);
> -	pipe = sd->entity.pipe ? sd->entity.pipe : &vin->vdev.pipe;
> +	pipe = sd->entity.pads->pipe ? sd->entity.pads->pipe : &vin->vdev.pipe;
>  	ret = __media_pipeline_start(&vin->vdev.entity, pipe);
>  	mutex_unlock(&mdev->graph_mutex);
>  	if (ret)
> diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
> index a2a329336243bdc7..f27a7be5f5d0f0b5 100644
> --- a/drivers/media/platform/xilinx/xilinx-dma.c
> +++ b/drivers/media/platform/xilinx/xilinx-dma.c
> @@ -406,7 +406,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
>  	 * Use the pipeline object embedded in the first DMA object that starts
>  	 * streaming.
>  	 */
> -	pipe = dma->video.entity.pipe
> +	pipe = dma->video.entity.pads->pipe
>  	     ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe;
>
>  	ret = media_pipeline_start(&dma->video.entity, &pipe->pipe);
> diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
> index e95d136c153a8f5f..c12e053ff41eed1c 100644
> --- a/drivers/media/platform/xilinx/xilinx-dma.h
> +++ b/drivers/media/platform/xilinx/xilinx-dma.h
> @@ -50,7 +50,7 @@ struct xvip_pipeline {
>
>  static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
>  {
> -	return container_of(e->pipe, struct xvip_pipeline, pipe);
> +	return container_of(e->pads->pipe, struct xvip_pipeline, pipe);
>  }
>
>  /**
> diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
> index 0eaa353d5cb39768..ba9d9a8337cb159e 100644
> --- a/drivers/staging/media/imx/imx-media-utils.c
> +++ b/drivers/staging/media/imx/imx-media-utils.c
> @@ -917,7 +917,7 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
>  			__media_pipeline_stop(entity);
>  	} else {
>  		v4l2_subdev_call(sd, video, s_stream, 0);
> -		if (entity->pipe)
> +		if (entity->pads->pipe)
>  			__media_pipeline_stop(entity);
>  	}
>
> diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
> index c8be1db532ab2555..030808b222cf3ae5 100644
> --- a/drivers/staging/media/omap4iss/iss.c
> +++ b/drivers/staging/media/omap4iss/iss.c
> @@ -543,7 +543,7 @@ static int iss_pipeline_is_last(struct media_entity *me)
>  	struct iss_pipeline *pipe;
>  	struct media_pad *pad;
>
> -	if (!me->pipe)
> +	if (!me->pads->pipe)
>  		return 0;
>  	pipe = to_iss_pipeline(me);
>  	if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED)
> diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
> index 1271bbacf9e7bdeb..65f1e358271b3743 100644
> --- a/drivers/staging/media/omap4iss/iss_video.c
> +++ b/drivers/staging/media/omap4iss/iss_video.c
> @@ -877,7 +877,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
>  	 * Start streaming on the pipeline. No link touching an entity in the
>  	 * pipeline can be activated or deactivated once streaming is started.
>  	 */
> -	pipe = pad->entity->pipe
> +	pipe = pad->pipe
>  	     ? to_iss_pipeline(pad->entity) : &video->pipe;
>  	pipe->external = NULL;
>  	pipe->external_rate = 0;
> diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
> index f22489edb5624af2..cdea8543b3f93ecf 100644
> --- a/drivers/staging/media/omap4iss/iss_video.h
> +++ b/drivers/staging/media/omap4iss/iss_video.h
> @@ -94,7 +94,7 @@ struct iss_pipeline {
>  };
>
>  #define to_iss_pipeline(__e) \
> -	container_of((__e)->pipe, struct iss_pipeline, pipe)
> +	container_of((__e)->pads->pipe, struct iss_pipeline, pipe)
>
>  static inline int iss_pipeline_ready(struct iss_pipeline *pipe)
>  {
> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index cde6350d752bb0ae..ca0b79288ea7fd11 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -188,15 +188,25 @@ enum media_pad_signal_type {
>   *
>   * @graph_obj:	Embedded structure containing the media object common data
>   * @entity:	Entity this pad belongs to
> + * @pipe:	Pipeline this entity belongs to.
> + * @stream_count: Stream count for the entity.
>   * @index:	Pad index in the entity pads array, numbered from 0 to n
>   * @sig_type:	Type of the signal inside a media pad
>   * @flags:	Pad flags, as defined in
>   *		:ref:`include/uapi/linux/media.h <media_header>`
>   *		(seek for ``MEDIA_PAD_FL_*``)
> + * .. note::
> + *
> + *    @stream_count reference counts must never be negative, but are
> + *    signed integers on purpose: a simple ``WARN_ON(<0)`` check can
> + *    be used to detect reference count bugs that would make them
> + *    negative.
>   */
>  struct media_pad {
>  	struct media_gobj graph_obj;	/* must be first field in struct */
>  	struct media_entity *entity;
> +	struct media_pipeline *pipe;
> +	int stream_count;
>  	u16 index;
>  	enum media_pad_signal_type sig_type;
>  	unsigned long flags;
> @@ -274,9 +284,7 @@ enum media_entity_type {
>   * @pads:	Pads array with the size defined by @num_pads.
>   * @links:	List of data links.
>   * @ops:	Entity operations.
> - * @stream_count: Stream count for the entity.
>   * @use_count:	Use count for the entity.
> - * @pipe:	Pipeline this entity belongs to.
>   * @info:	Union with devnode information.  Kept just for backward
>   *		compatibility.
>   * @info.dev:	Contains device major and minor info.
> @@ -289,7 +297,7 @@ enum media_entity_type {
>   *
>   * .. note::
>   *
> - *    @stream_count and @use_count reference counts must never be
> + *    @use_count reference counts must never be
>   *    negative, but are signed integers on purpose: a simple ``WARN_ON(<0)``
>   *    check can be used to detect reference count bugs that would make them
>   *    negative.
> @@ -311,11 +319,8 @@ struct media_entity {
>
>  	const struct media_entity_operations *ops;
>
> -	int stream_count;
>  	int use_count;
>
> -	struct media_pipeline *pipe;
> -
>  	union {
>  		struct {
>  			u32 major;
> --
> 2.19.1
>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink
  2019-01-22 15:20       ` Laurent Pinchart
@ 2019-02-18  9:21         ` Jacopo Mondi
  2019-02-22 12:18           ` Laurent Pinchart
  0 siblings, 1 reply; 90+ messages in thread
From: Jacopo Mondi @ 2019-02-18  9:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Sakari Ailus, Niklas Söderlund, Benoit Parrot, linux-media,
	linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 3267 bytes --]

Hi Laurent, Sakari,

On Tue, Jan 22, 2019 at 05:20:30PM +0200, Laurent Pinchart wrote:
> Hi Sakari,
>
> On Tue, Jan 22, 2019 at 05:15:06PM +0200, Sakari Ailus wrote:
> > On Wed, Jan 16, 2019 at 12:57:43AM +0200, Laurent Pinchart wrote:
> > >>
> > >> This way the pads are always passed to the has_route() op sink pad first.
> > >> Makes sense.
> > >
> > > Is there anything in the API that mandates one pad to be a sink and the
> > > other pad to the a source ? I had designed the operation to allow
> > > sink-sink and source-source connections to be checked too.
> >
> > Do you have a use case in mind for sink--sink or source--source routes? The
> > routes are about flows of data, so I'd presume only source--sink or
> > sink--source routes are meaningful.
> >
> > If you did, then the driver would have to handle that by itself. This still
> > simplifies the implementation for drivers that do not.
>
> I don't have use cases for such routes, but we use the has_route
> operation when traversing pipelines, and at that point we need to get
> all the internally connected pads. In another patch in this series you
> implement a helper function that handles this, but its implementation
> isn't complete. I explained in my review of that patch that I fear a
> correct generic implementation would become quite complex, while the
> complexity should be easy to handle on the driver side as the code can
> then be specialized for the case at hand.
>

As a compromise, in v3 I'm thinking of maintaining support for the
most common case of two sources connected to the same sink, as
Sakari's patch does, but let more complex cases be handled by the
driver implementation of has_route().

Ack?

> > > If your goal is to simplify the implementation of the .has_route()
> > > operation in drivers, I would instead sort pad0 and pad1 by value.
> >
> > That'd be another option to make the order deterministic for the driver.
> > I'm fine with that as well.
> >

In v3 I have taken both suggestions in: try the "sink then source" order
first, then order by index in case the pads are of the same time. This
needs to be documented in has_route() operation definition though.

Would that be fine with you?

Thanks
   j

> > >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > >> ---
> > >>  drivers/media/media-entity.c | 4 ++++
> > >>  1 file changed, 4 insertions(+)
> > >>
> > >> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> > >> index 3c0e7425c8983b45..33f00e35ccd92c6f 100644
> > >> --- a/drivers/media/media-entity.c
> > >> +++ b/drivers/media/media-entity.c
> > >> @@ -249,6 +249,10 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> > >>  	if (!entity->ops || !entity->ops->has_route)
> > >>  		return true;
> > >>
> > >> +	if (entity->pads[pad0].flags & MEDIA_PAD_FL_SOURCE
> > >> +	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
> > >> +		swap(pad0, pad1);
> > >> +
> > >>  	return entity->ops->has_route(entity, pad0, pad1);
> > >>  }
> > >>  EXPORT_SYMBOL_GPL(media_entity_has_route);
>
> --
> Regards,
>
> Laurent Pinchart

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING
  2019-01-15 23:53   ` Laurent Pinchart
  2019-01-22 15:57     ` Sakari Ailus
@ 2019-02-18 11:21     ` Jacopo Mondi
  2019-02-21 23:50       ` Sakari Ailus
  1 sibling, 1 reply; 90+ messages in thread
From: Jacopo Mondi @ 2019-02-18 11:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Sakari Ailus, Benoit Parrot, linux-media,
	linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 5426 bytes --]

Hi Laurent, Sakari,

On Wed, Jan 16, 2019 at 01:53:03AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
>
> Thank you for the patch.
>
> On Fri, Nov 02, 2018 at 12:31:31AM +0100, Niklas Söderlund wrote:
> > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> >
> > Implement compat IOCTL handling for VIDIOC_SUBDEV_G_ROUTING and
> > VIDIOC_SUBDEV_S_ROUTING IOCTLs.
>
> Let's instead design the ioctl in a way that doesn't require compat
> handling.
>

Care to explain what makes this ioctl require a compat version? I
don't see assumptions on the word length on the implementation. What
am I missing?

Thanks
  j

> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 77 +++++++++++++++++++
> >  1 file changed, 77 insertions(+)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> > index 6481212fda772c73..83af332763f41a6b 100644
> > --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> > +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> > @@ -1045,6 +1045,66 @@ static int put_v4l2_event32(struct v4l2_event __user *p64,
> >  	return 0;
> >  }
> >
> > +struct v4l2_subdev_routing32 {
> > +	compat_caddr_t routes;
> > +	__u32 num_routes;
> > +	__u32 reserved[5];
> > +};
> > +
> > +static int get_v4l2_subdev_routing(struct v4l2_subdev_routing __user *p64,
> > +				   struct v4l2_subdev_routing32 __user *p32)
> > +{
> > +	struct v4l2_subdev_route __user *routes;
> > +	compat_caddr_t p;
> > +	u32 num_routes;
> > +
> > +	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
> > +	    get_user(p, &p32->routes) ||
> > +	    get_user(num_routes, &p32->num_routes) ||
> > +	    put_user(num_routes, &p64->num_routes) ||
> > +	    copy_in_user(&p64->reserved, &p32->reserved,
> > +			 sizeof(p64->reserved)) ||
> > +	    num_routes > U32_MAX / sizeof(*p64->routes))
> > +		return -EFAULT;
> > +
> > +	routes = compat_ptr(p);
> > +
> > +	if (!access_ok(VERIFY_READ, routes,
> > +		       num_routes * sizeof(*p64->routes)))
> > +		return -EFAULT;
> > +
> > +	if (put_user((__force struct v4l2_subdev_route *)routes,
> > +		     &p64->routes))
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> > +static int put_v4l2_subdev_routing(struct v4l2_subdev_routing __user *p64,
> > +				   struct v4l2_subdev_routing32 __user *p32)
> > +{
> > +	struct v4l2_subdev_route __user *routes;
> > +	compat_caddr_t p;
> > +	u32 num_routes;
> > +
> > +	if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
> > +	    get_user(p, &p32->routes) ||
> > +	    get_user(num_routes, &p64->num_routes) ||
> > +	    put_user(num_routes, &p32->num_routes) ||
> > +	    copy_in_user(&p32->reserved, &p64->reserved,
> > +			 sizeof(p64->reserved)) ||
> > +	    num_routes > U32_MAX / sizeof(*p64->routes))
> > +		return -EFAULT;
> > +
> > +	routes = compat_ptr(p);
> > +
> > +	if (!access_ok(VERIFY_WRITE, routes,
> > +		       num_routes * sizeof(*p64->routes)))
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> >  struct v4l2_edid32 {
> >  	__u32 pad;
> >  	__u32 start_block;
> > @@ -1117,6 +1177,8 @@ static int put_v4l2_edid32(struct v4l2_edid __user *p64,
> >  #define VIDIOC_STREAMOFF32	_IOW ('V', 19, s32)
> >  #define VIDIOC_G_INPUT32	_IOR ('V', 38, s32)
> >  #define VIDIOC_S_INPUT32	_IOWR('V', 39, s32)
> > +#define VIDIOC_SUBDEV_G_ROUTING32 _IOWR('V', 38, struct v4l2_subdev_routing32)
> > +#define VIDIOC_SUBDEV_S_ROUTING32 _IOWR('V', 39, struct v4l2_subdev_routing32)
> >  #define VIDIOC_G_OUTPUT32	_IOR ('V', 46, s32)
> >  #define VIDIOC_S_OUTPUT32	_IOWR('V', 47, s32)
> >
> > @@ -1195,6 +1257,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
> >  	case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
> >  	case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
> >  	case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
> > +	case VIDIOC_SUBDEV_G_ROUTING32: cmd = VIDIOC_SUBDEV_G_ROUTING; break;
> > +	case VIDIOC_SUBDEV_S_ROUTING32: cmd = VIDIOC_SUBDEV_S_ROUTING; break;
> >  	case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
> >  	case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
> >  	case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
> > @@ -1227,6 +1291,15 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
> >  		compatible_arg = 0;
> >  		break;
> >
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +	case VIDIOC_SUBDEV_S_ROUTING:
> > +		err = alloc_userspace(sizeof(struct v4l2_subdev_routing),
> > +				      0, &new_p64);
> > +		if (!err)
> > +			err = get_v4l2_subdev_routing(new_p64, p32);
> > +		compatible_arg = 0;
> > +		break;
> > +
> >  	case VIDIOC_G_EDID:
> >  	case VIDIOC_S_EDID:
> >  		err = alloc_userspace(sizeof(struct v4l2_edid), 0, &new_p64);
> > @@ -1368,6 +1441,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
> >  		if (put_v4l2_edid32(new_p64, p32))
> >  			err = -EFAULT;
> >  		break;
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +	case VIDIOC_SUBDEV_S_ROUTING:
> > +		err = put_v4l2_subdev_routing(new_p64, p32);
> > +		break;
> >  	}
> >  	if (err)
> >  		return err;
>
> --
> Regards,
>
> Laurent Pinchart

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 25/30] adv748x: csi2: only allow formats on sink pads
  2018-11-01 23:31 ` [PATCH v2 25/30] adv748x: csi2: only allow formats on sink pads Niklas Söderlund
@ 2019-02-21 14:18   ` Jacopo Mondi
  0 siblings, 0 replies; 90+ messages in thread
From: Jacopo Mondi @ 2019-02-21 14:18 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media,
	linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 2123 bytes --]

Hi Niklas,

On Fri, Nov 02, 2018 at 12:31:39AM +0100, Niklas Söderlund wrote:
> Once the CSI-2 subdevice of the ADV748X becomes aware of multiplexed
> streams the format of the source pad is of no value as it carries
> multiple streams. Prepare for this by explicitly denying setting a
> format on anything but the sink pad.
>
> Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/i2c/adv748x/adv748x-csi2.c | 6 ++++++
>  1 file changed, 6 insertions(+)
>
> diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
> index 8a7cc713c7adfcc1..9f2c49221a8ddebc 100644
> --- a/drivers/media/i2c/adv748x/adv748x-csi2.c
> +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
> @@ -163,6 +163,9 @@ static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
>  	struct adv748x_state *state = tx->state;
>  	struct v4l2_mbus_framefmt *mbusformat;
>
> +	if (sdformat->pad != ADV748X_CSI2_SINK)
> +		return -EINVAL;
> +
>  	mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
>  						 sdformat->which);
>  	if (!mbusformat)
> @@ -186,6 +189,9 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
>  	struct v4l2_mbus_framefmt *mbusformat;
>  	int ret = 0;
>
> +	if (sdformat->pad != ADV748X_CSI2_SINK)
> +		return -EINVAL;
> +

The adv748x set_format on the source pad already ignores the provided
format argument and just replicates the format applied on the sink on
itself. I agree this change makes sense, but then you should remove
the big if switch a few lines here below.

	if (sdformat->pad == ADV748X_CSI2_SOURCE) {

With your ack, I can make this change in the forthcoming v3.

Thanks
   j

PS: I'm thinking of sending the v4l2-mux core patches (01->23 of v2)
separate from adv748x and rcar-csi2 ones, to ease review, and maybe
speed up inclusion of the core changes. What would your (and Sakari's
and Laurent's) opinion on that?

>  	mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
>  						 sdformat->which);
>  	if (!mbusformat)
> --
> 2.19.1
>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2018-11-01 23:31 ` [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations Niklas Söderlund
  2019-01-15 23:51   ` Laurent Pinchart
@ 2019-02-21 14:39   ` Jacopo Mondi
  2019-02-21 22:31     ` Sakari Ailus
  1 sibling, 1 reply; 90+ messages in thread
From: Jacopo Mondi @ 2019-02-21 14:39 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Laurent Pinchart, Sakari Ailus, Benoit Parrot, linux-media,
	linux-renesas-soc, Michal Simek

[-- Attachment #1: Type: text/plain, Size: 7354 bytes --]

Hi Sakari,
   one quick question

On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
>
> - Add sink and source streams for multiplexed links
> - Copy the argument back in case of an error. This is needed to let the
>   caller know the number of routes.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
>  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
>  include/media/v4l2-subdev.h           |  7 +++++
>  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
>  4 files changed, 94 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index 7de041bae84fb2f2..40406acb51ec0906 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -19,6 +19,7 @@
>  #include <linux/kernel.h>
>  #include <linux/version.h>
>
> +#include <linux/v4l2-subdev.h>
>  #include <linux/videodev2.h>
>
>  #include <media/v4l2-common.h>
> @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
>  		}
>  		break;
>  	}
> +
> +	case VIDIOC_SUBDEV_G_ROUTING:
> +	case VIDIOC_SUBDEV_S_ROUTING: {
> +		struct v4l2_subdev_routing *route = parg;
> +
> +		if (route->num_routes > 0) {
> +			if (route->num_routes > 256)
> +				return -EINVAL;
> +
> +			*user_ptr = (void __user *)route->routes;
> +			*kernel_ptr = (void *)&route->routes;
> +			*array_size = sizeof(struct v4l2_subdev_route)
> +				    * route->num_routes;
> +			ret = 1;
> +		}
> +		break;
> +	}
>  	}
>
>  	return ret;
> @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
>  	 * Some ioctls can return an error, but still have valid
>  	 * results that must be returned.
>  	 */
> -	if (err < 0 && !always_copy)
> +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
>  		goto out;
>
>  out_array_args:
> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> index 792f41dffe2329b9..1d3b37cf548fa533 100644
> --- a/drivers/media/v4l2-core/v4l2-subdev.c
> +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
>
>  	case VIDIOC_SUBDEV_QUERYSTD:
>  		return v4l2_subdev_call(sd, video, querystd, arg);
> +
> +	case VIDIOC_SUBDEV_G_ROUTING:
> +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> +
> +	case VIDIOC_SUBDEV_S_ROUTING: {
> +		struct v4l2_subdev_routing *route = arg;
> +		unsigned int i;
> +
> +		if (route->num_routes > sd->entity.num_pads)
> +			return -EINVAL;

Can't the number of routes exceeds the total number of pad?

To make an example, a subdevice with 2 sink pads, and 1 multiplexed
source pad, with 2 streams would expose the following routing table,
right?

pad #0 = sink, 1 stream
pad #1 = sink, 1 stream
pad #2 = source, 2 streams

Routing table:
0/0 -> 2/0
0/0 -> 2/1
1/0 -> 2/0
1/0 -> 2/1

In general, the number of accepted routes should depend on the number
of streams, not pads, and that's better handled by drivers, am I
wrong?

Thanks
  j

> +
> +		for (i = 0; i < route->num_routes; ++i) {
> +			unsigned int sink = route->routes[i].sink_pad;
> +			unsigned int source = route->routes[i].source_pad;
> +			struct media_pad *pads = sd->entity.pads;
> +
> +			if (sink >= sd->entity.num_pads ||
> +			    source >= sd->entity.num_pads)
> +				return -EINVAL;
> +
> +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> +				return -EINVAL;
> +		}
> +
> +		return v4l2_subdev_call(sd, pad, set_routing, route);
> +	}
>  #endif
> +
>  	default:
>  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
>  	}
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
>   *
>   * @set_frame_desc: set the low level media bus frame parameters, @fd array
>   *                  may be adjusted by the subdev driver to device capabilities.
> + *
> + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
>   */
>  struct v4l2_subdev_pad_ops {
>  	int (*init_cfg)(struct v4l2_subdev *sd,
> @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
>  			      struct v4l2_mbus_frame_desc *fd);
>  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
>  			      struct v4l2_mbus_frame_desc *fd);
> +	int (*get_routing)(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_routing *route);
> +	int (*set_routing)(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_routing *route);
>  };
>
>  /**
> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> index 03970ce3074193e6..af069bfb10ca23a5 100644
> --- a/include/uapi/linux/v4l2-subdev.h
> +++ b/include/uapi/linux/v4l2-subdev.h
> @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
>  	__u32 reserved[8];
>  };
>
> +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> +
> +/**
> + * struct v4l2_subdev_route - A signal route inside a subdev
> + * @sink_pad: the sink pad
> + * @sink_stream: the sink stream
> + * @source_pad: the source pad
> + * @source_stream: the source stream
> + * @flags: route flags:
> + *
> + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> + *	active stream will start when streaming is enabled on a video
> + *	node. Set by the user.
> + *
> + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> + *	can it be activated and inactivated? Set by the driver.
> + */
> +struct v4l2_subdev_route {
> +	__u32 sink_pad;
> +	__u32 sink_stream;
> +	__u32 source_pad;
> +	__u32 source_stream;
> +	__u32 flags;
> +	__u32 reserved[5];
> +};
> +
> +/**
> + * struct v4l2_subdev_routing - Routing information
> + * @routes: the routes array
> + * @num_routes: the total number of routes in the routes array
> + */
> +struct v4l2_subdev_routing {
> +	struct v4l2_subdev_route *routes;
> +	__u32 num_routes;
> +	__u32 reserved[5];
> +};
> +
>  /* Backwards compatibility define --- to be removed */
>  #define v4l2_subdev_edid v4l2_edid
>
> @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
>  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
>  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
>  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
>
>  #endif
> --
> 2.19.1
>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-01-15 23:51   ` Laurent Pinchart
  2019-01-22 16:14     ` Sakari Ailus
@ 2019-02-21 14:59     ` Jacopo Mondi
  2019-02-21 23:49       ` Sakari Ailus
  1 sibling, 1 reply; 90+ messages in thread
From: Jacopo Mondi @ 2019-02-21 14:59 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Sakari Ailus, Benoit Parrot, linux-media,
	linux-renesas-soc, Michal Simek

[-- Attachment #1: Type: text/plain, Size: 9020 bytes --]

Hi Sakari, Laurent, Niklas,
   (another) quick question, but a different one :)

On Wed, Jan 16, 2019 at 01:51:45AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
>
> Thank you for the patch.
>
> On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> >
> > - Add sink and source streams for multiplexed links
> > - Copy the argument back in case of an error. This is needed to let the
> >   caller know the number of routes.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> >  include/media/v4l2-subdev.h           |  7 +++++
> >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
>
> Missing documentation :-(
>
> >  4 files changed, 94 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/kernel.h>
> >  #include <linux/version.h>
> >
> > +#include <linux/v4l2-subdev.h>
> >  #include <linux/videodev2.h>
> >
> >  #include <media/v4l2-common.h>
> > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> >  		}
> >  		break;
> >  	}
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = parg;
> > +
> > +		if (route->num_routes > 0) {
> > +			if (route->num_routes > 256)
> > +				return -EINVAL;
> > +
> > +			*user_ptr = (void __user *)route->routes;
> > +			*kernel_ptr = (void *)&route->routes;
> > +			*array_size = sizeof(struct v4l2_subdev_route)
> > +				    * route->num_routes;
> > +			ret = 1;
> > +		}
> > +		break;
> > +	}
> >  	}
> >
> >  	return ret;
> > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> >  	 * Some ioctls can return an error, but still have valid
> >  	 * results that must be returned.
> >  	 */
> > -	if (err < 0 && !always_copy)
> > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
>
> This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
> always_copy instead ?
>
> >  		goto out;
> >
> >  out_array_args:
> > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> >
> >  	case VIDIOC_SUBDEV_QUERYSTD:
> >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > +
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = arg;
> > +		unsigned int i;
> > +
> > +		if (route->num_routes > sd->entity.num_pads)
> > +			return -EINVAL;
> > +
> > +		for (i = 0; i < route->num_routes; ++i) {

How have you envisioned the number of routes to be negotiated with
applications? I'm writing the documentation for this ioctl, and I
would like to insert this part as well.

Would a model like the one implemented in G_TOPOLOGY work in your
opinion? In my understanding, at the moment applications do not have a
way to reserve a known number of routes entries, but would likely
reserve 'enough(tm)' (ie 256) and pass them to the G_ROUTING ioctl that the
first time will likely adjust the number of num_routes and return -ENOSPC.

Wouldn't it work to make the IOCTL behave in a way that it
expects the first call to be performed with (num_routes == 0) and no routes
entries reserved, and just adjust 'num_routes' in that case?
So that applications should call G_ROUTING a first time with
num_routes = 0, get back the number of routes entries, reserve memory
for them, and then call G_ROUTING again to have the entries populated
by the driver. Do you have different ideas or was this the intended
behavior already?

Thanks
   j

> > +			unsigned int sink = route->routes[i].sink_pad;
> > +			unsigned int source = route->routes[i].source_pad;
> > +			struct media_pad *pads = sd->entity.pads;
> > +
> > +			if (sink >= sd->entity.num_pads ||
> > +			    source >= sd->entity.num_pads)
> > +				return -EINVAL;
> > +
> > +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> > +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> > +				return -EINVAL;
> > +		}
> > +
> > +		return v4l2_subdev_call(sd, pad, set_routing, route);
> > +	}
> >  #endif
> > +
> >  	default:
> >  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> >  	}
> > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> > --- a/include/media/v4l2-subdev.h
> > +++ b/include/media/v4l2-subdev.h
> > @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> >   *
> >   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> >   *                  may be adjusted by the subdev driver to device capabilities.
> > + *
> > + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> > + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
>
> Please define the purpose of those operations instead of just pointing
> to the userspace API.
>
> >   */
> >  struct v4l2_subdev_pad_ops {
> >  	int (*init_cfg)(struct v4l2_subdev *sd,
> > @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> >  			      struct v4l2_mbus_frame_desc *fd);
> >  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> >  			      struct v4l2_mbus_frame_desc *fd);
> > +	int (*get_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> > +	int (*set_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> >  };
> >
> >  /**
> > diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> > index 03970ce3074193e6..af069bfb10ca23a5 100644
> > --- a/include/uapi/linux/v4l2-subdev.h
> > +++ b/include/uapi/linux/v4l2-subdev.h
> > @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> >  	__u32 reserved[8];
> >  };
> >
> > +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> > +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> > +
> > +/**
> > + * struct v4l2_subdev_route - A signal route inside a subdev
> > + * @sink_pad: the sink pad
> > + * @sink_stream: the sink stream
> > + * @source_pad: the source pad
> > + * @source_stream: the source stream
>
> At this point in the series there's no concept of multiplexed streams,
> so the two fields don't make sense. You may want to reorder patches, or
> split this in two.
>
> > + * @flags: route flags:
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> > + *	active stream will start when streaming is enabled on a video
> > + *	node. Set by the user.
>
> This is very confusing as "stream" isn't defined. The documentation
> needs a rewrite with more details.
>
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> > + *	can it be activated and inactivated? Set by the driver.
> > + */
> > +struct v4l2_subdev_route {
> > +	__u32 sink_pad;
> > +	__u32 sink_stream;
> > +	__u32 source_pad;
> > +	__u32 source_stream;
> > +	__u32 flags;
> > +	__u32 reserved[5];
> > +};
> > +
> > +/**
> > + * struct v4l2_subdev_routing - Routing information
> > + * @routes: the routes array
> > + * @num_routes: the total number of routes in the routes array
> > + */
> > +struct v4l2_subdev_routing {
> > +	struct v4l2_subdev_route *routes;
>
> Missing __user ?
>
> > +	__u32 num_routes;
> > +	__u32 reserved[5];
> > +};
> > +
> >  /* Backwards compatibility define --- to be removed */
> >  #define v4l2_subdev_edid v4l2_edid
> >
> > @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
> >  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
> >  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
> >  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> > +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> > +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
> >
> >  #endif
> > --
> > 2.19.1
> >
>
> --
> Regards,
>
> Laurent Pinchart

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-02-21 14:39   ` Jacopo Mondi
@ 2019-02-21 22:31     ` Sakari Ailus
  2019-02-22  8:40       ` Jacopo Mondi
  0 siblings, 1 reply; 90+ messages in thread
From: Sakari Ailus @ 2019-02-21 22:31 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Niklas Söderlund, Laurent Pinchart, Benoit Parrot,
	linux-media, linux-renesas-soc, Michal Simek

Hi Jacopo,

On Thu, Feb 21, 2019 at 03:39:40PM +0100, Jacopo Mondi wrote:
> Hi Sakari,
>    one quick question
> 
> On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> >
> > - Add sink and source streams for multiplexed links
> > - Copy the argument back in case of an error. This is needed to let the
> >   caller know the number of routes.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> >  include/media/v4l2-subdev.h           |  7 +++++
> >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> >  4 files changed, 94 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/kernel.h>
> >  #include <linux/version.h>
> >
> > +#include <linux/v4l2-subdev.h>
> >  #include <linux/videodev2.h>
> >
> >  #include <media/v4l2-common.h>
> > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> >  		}
> >  		break;
> >  	}
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = parg;
> > +
> > +		if (route->num_routes > 0) {
> > +			if (route->num_routes > 256)
> > +				return -EINVAL;
> > +
> > +			*user_ptr = (void __user *)route->routes;
> > +			*kernel_ptr = (void *)&route->routes;
> > +			*array_size = sizeof(struct v4l2_subdev_route)
> > +				    * route->num_routes;
> > +			ret = 1;
> > +		}
> > +		break;
> > +	}
> >  	}
> >
> >  	return ret;
> > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> >  	 * Some ioctls can return an error, but still have valid
> >  	 * results that must be returned.
> >  	 */
> > -	if (err < 0 && !always_copy)
> > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> >  		goto out;
> >
> >  out_array_args:
> > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> >
> >  	case VIDIOC_SUBDEV_QUERYSTD:
> >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > +
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = arg;
> > +		unsigned int i;
> > +
> > +		if (route->num_routes > sd->entity.num_pads)
> > +			return -EINVAL;
> 
> Can't the number of routes exceeds the total number of pad?
> 
> To make an example, a subdevice with 2 sink pads, and 1 multiplexed
> source pad, with 2 streams would expose the following routing table,
> right?
> 
> pad #0 = sink, 1 stream
> pad #1 = sink, 1 stream
> pad #2 = source, 2 streams
> 
> Routing table:
> 0/0 -> 2/0
> 0/0 -> 2/1
> 1/0 -> 2/0
> 1/0 -> 2/1
> 
> In general, the number of accepted routes should depend on the number
> of streams, not pads, and that's better handled by drivers, am I
> wrong?

Good point. Is the above configuration meaningful? I.e. you have a mux
device that does some processing as well by combining the streams?

It's far-fetched but at the moment the API does not really bend for that.
It still might in the future.

I guess we could just remove the check, and let drivers handle it.

> 
> Thanks
>   j
> 
> > +
> > +		for (i = 0; i < route->num_routes; ++i) {
> > +			unsigned int sink = route->routes[i].sink_pad;
> > +			unsigned int source = route->routes[i].source_pad;
> > +			struct media_pad *pads = sd->entity.pads;
> > +
> > +			if (sink >= sd->entity.num_pads ||
> > +			    source >= sd->entity.num_pads)
> > +				return -EINVAL;
> > +
> > +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> > +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> > +				return -EINVAL;
> > +		}
> > +
> > +		return v4l2_subdev_call(sd, pad, set_routing, route);
> > +	}
> >  #endif
> > +
> >  	default:
> >  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> >  	}
> > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> > --- a/include/media/v4l2-subdev.h
> > +++ b/include/media/v4l2-subdev.h
> > @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> >   *
> >   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> >   *                  may be adjusted by the subdev driver to device capabilities.
> > + *
> > + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> > + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
> >   */
> >  struct v4l2_subdev_pad_ops {
> >  	int (*init_cfg)(struct v4l2_subdev *sd,
> > @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> >  			      struct v4l2_mbus_frame_desc *fd);
> >  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> >  			      struct v4l2_mbus_frame_desc *fd);
> > +	int (*get_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> > +	int (*set_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> >  };
> >
> >  /**
> > diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> > index 03970ce3074193e6..af069bfb10ca23a5 100644
> > --- a/include/uapi/linux/v4l2-subdev.h
> > +++ b/include/uapi/linux/v4l2-subdev.h
> > @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> >  	__u32 reserved[8];
> >  };
> >
> > +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> > +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> > +
> > +/**
> > + * struct v4l2_subdev_route - A signal route inside a subdev
> > + * @sink_pad: the sink pad
> > + * @sink_stream: the sink stream
> > + * @source_pad: the source pad
> > + * @source_stream: the source stream
> > + * @flags: route flags:
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> > + *	active stream will start when streaming is enabled on a video
> > + *	node. Set by the user.
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> > + *	can it be activated and inactivated? Set by the driver.
> > + */
> > +struct v4l2_subdev_route {
> > +	__u32 sink_pad;
> > +	__u32 sink_stream;
> > +	__u32 source_pad;
> > +	__u32 source_stream;
> > +	__u32 flags;
> > +	__u32 reserved[5];
> > +};
> > +
> > +/**
> > + * struct v4l2_subdev_routing - Routing information
> > + * @routes: the routes array
> > + * @num_routes: the total number of routes in the routes array
> > + */
> > +struct v4l2_subdev_routing {
> > +	struct v4l2_subdev_route *routes;

This should be just __u64, to avoid writing compat code. The patch was
written before we started doing that. :-) Please see e.g. the media device
topology IOCTL.

> > +	__u32 num_routes;
> > +	__u32 reserved[5];
> > +};
> > +
> >  /* Backwards compatibility define --- to be removed */
> >  #define v4l2_subdev_edid v4l2_edid
> >
> > @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
> >  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
> >  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
> >  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> > +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> > +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
> >
> >  #endif

-- 
Regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-02-21 14:59     ` Jacopo Mondi
@ 2019-02-21 23:49       ` Sakari Ailus
  2019-02-22  8:46         ` Jacopo Mondi
  0 siblings, 1 reply; 90+ messages in thread
From: Sakari Ailus @ 2019-02-21 23:49 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Laurent Pinchart, Niklas Söderlund, Benoit Parrot,
	linux-media, linux-renesas-soc, Michal Simek

Hi Jacopo,

On Thu, Feb 21, 2019 at 03:59:20PM +0100, Jacopo Mondi wrote:
> Hi Sakari, Laurent, Niklas,
>    (another) quick question, but a different one :)
> 
> On Wed, Jan 16, 2019 at 01:51:45AM +0200, Laurent Pinchart wrote:
> > Hi Niklas,
> >
> > Thank you for the patch.
> >
> > On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > >
> > > - Add sink and source streams for multiplexed links
> > > - Copy the argument back in case of an error. This is needed to let the
> > >   caller know the number of routes.
> > >
> > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > > ---
> > >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> > >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> > >  include/media/v4l2-subdev.h           |  7 +++++
> > >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> >
> > Missing documentation :-(
> >
> > >  4 files changed, 94 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > @@ -19,6 +19,7 @@
> > >  #include <linux/kernel.h>
> > >  #include <linux/version.h>
> > >
> > > +#include <linux/v4l2-subdev.h>
> > >  #include <linux/videodev2.h>
> > >
> > >  #include <media/v4l2-common.h>
> > > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> > >  		}
> > >  		break;
> > >  	}
> > > +
> > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > +		struct v4l2_subdev_routing *route = parg;
> > > +
> > > +		if (route->num_routes > 0) {
> > > +			if (route->num_routes > 256)
> > > +				return -EINVAL;
> > > +
> > > +			*user_ptr = (void __user *)route->routes;
> > > +			*kernel_ptr = (void *)&route->routes;
> > > +			*array_size = sizeof(struct v4l2_subdev_route)
> > > +				    * route->num_routes;
> > > +			ret = 1;
> > > +		}
> > > +		break;
> > > +	}
> > >  	}
> > >
> > >  	return ret;
> > > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> > >  	 * Some ioctls can return an error, but still have valid
> > >  	 * results that must be returned.
> > >  	 */
> > > -	if (err < 0 && !always_copy)
> > > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> >
> > This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
> > always_copy instead ?
> >
> > >  		goto out;
> > >
> > >  out_array_args:
> > > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> > >
> > >  	case VIDIOC_SUBDEV_QUERYSTD:
> > >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > > +
> > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > > +
> > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > +		struct v4l2_subdev_routing *route = arg;
> > > +		unsigned int i;
> > > +
> > > +		if (route->num_routes > sd->entity.num_pads)
> > > +			return -EINVAL;
> > > +
> > > +		for (i = 0; i < route->num_routes; ++i) {
> 
> How have you envisioned the number of routes to be negotiated with
> applications? I'm writing the documentation for this ioctl, and I
> would like to insert this part as well.
> 
> Would a model like the one implemented in G_TOPOLOGY work in your
> opinion? In my understanding, at the moment applications do not have a
> way to reserve a known number of routes entries, but would likely
> reserve 'enough(tm)' (ie 256) and pass them to the G_ROUTING ioctl that the
> first time will likely adjust the number of num_routes and return -ENOSPC.
> 
> Wouldn't it work to make the IOCTL behave in a way that it
> expects the first call to be performed with (num_routes == 0) and no routes
> entries reserved, and just adjust 'num_routes' in that case?
> So that applications should call G_ROUTING a first time with
> num_routes = 0, get back the number of routes entries, reserve memory
> for them, and then call G_ROUTING again to have the entries populated
> by the driver. Do you have different ideas or was this the intended
> behavior already?

I think whenever the number of routes isn't enough to return them all, the
IOCTL should return -ENOSPC, and set the actual number of routes there. Not
just zero. The user could e.g. try with a static allocation of some, and
allocate memory if the static allocation turns not to be enough.

Btw. the idea behind S_ROUTING behaviour was to allow multiple users to
work on a single sub-device without having to know about each other. That's
why there are flags to tell which routes are enabled and which are not.

I'll be better available tomorrow, let's discuss e.g. on #v4l then.

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING
  2019-02-18 11:21     ` Jacopo Mondi
@ 2019-02-21 23:50       ` Sakari Ailus
  0 siblings, 0 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-02-21 23:50 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Laurent Pinchart, Niklas Söderlund, Benoit Parrot,
	linux-media, linux-renesas-soc

On Mon, Feb 18, 2019 at 12:21:09PM +0100, Jacopo Mondi wrote:
> Hi Laurent, Sakari,
> 
> On Wed, Jan 16, 2019 at 01:53:03AM +0200, Laurent Pinchart wrote:
> > Hi Niklas,
> >
> > Thank you for the patch.
> >
> > On Fri, Nov 02, 2018 at 12:31:31AM +0100, Niklas Söderlund wrote:
> > > From: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >
> > > Implement compat IOCTL handling for VIDIOC_SUBDEV_G_ROUTING and
> > > VIDIOC_SUBDEV_S_ROUTING IOCTLs.
> >
> > Let's instead design the ioctl in a way that doesn't require compat
> > handling.
> >
> 
> Care to explain what makes this ioctl require a compat version? I
> don't see assumptions on the word length on the implementation. What
> am I missing?

The size of the "routes" pointer isn't constant, therefore affecting the
memory layout of the struct (and thus requiring compat code). It should be
__u64. (Please see my other reply to the same patch.)

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-02-21 22:31     ` Sakari Ailus
@ 2019-02-22  8:40       ` Jacopo Mondi
  2019-02-22 11:04         ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Jacopo Mondi @ 2019-02-22  8:40 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Niklas Söderlund, Laurent Pinchart, Benoit Parrot,
	linux-media, linux-renesas-soc, Michal Simek

[-- Attachment #1: Type: text/plain, Size: 10279 bytes --]

Hi Sakari,

On Fri, Feb 22, 2019 at 12:31:32AM +0200, Sakari Ailus wrote:
> Hi Jacopo,
>
> On Thu, Feb 21, 2019 at 03:39:40PM +0100, Jacopo Mondi wrote:
> > Hi Sakari,
> >    one quick question
> >
> > On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > >
> > > - Add sink and source streams for multiplexed links
> > > - Copy the argument back in case of an error. This is needed to let the
> > >   caller know the number of routes.
> > >
> > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > > ---
> > >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> > >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> > >  include/media/v4l2-subdev.h           |  7 +++++
> > >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> > >  4 files changed, 94 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > @@ -19,6 +19,7 @@
> > >  #include <linux/kernel.h>
> > >  #include <linux/version.h>
> > >
> > > +#include <linux/v4l2-subdev.h>
> > >  #include <linux/videodev2.h>
> > >
> > >  #include <media/v4l2-common.h>
> > > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> > >  		}
> > >  		break;
> > >  	}
> > > +
> > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > +		struct v4l2_subdev_routing *route = parg;
> > > +
> > > +		if (route->num_routes > 0) {
> > > +			if (route->num_routes > 256)
> > > +				return -EINVAL;
> > > +
> > > +			*user_ptr = (void __user *)route->routes;
> > > +			*kernel_ptr = (void *)&route->routes;
> > > +			*array_size = sizeof(struct v4l2_subdev_route)
> > > +				    * route->num_routes;
> > > +			ret = 1;
> > > +		}
> > > +		break;
> > > +	}
> > >  	}
> > >
> > >  	return ret;
> > > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> > >  	 * Some ioctls can return an error, but still have valid
> > >  	 * results that must be returned.
> > >  	 */
> > > -	if (err < 0 && !always_copy)
> > > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> > >  		goto out;
> > >
> > >  out_array_args:
> > > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> > >
> > >  	case VIDIOC_SUBDEV_QUERYSTD:
> > >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > > +
> > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > > +
> > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > +		struct v4l2_subdev_routing *route = arg;
> > > +		unsigned int i;
> > > +
> > > +		if (route->num_routes > sd->entity.num_pads)
> > > +			return -EINVAL;
> >
> > Can't the number of routes exceeds the total number of pad?
> >
> > To make an example, a subdevice with 2 sink pads, and 1 multiplexed
> > source pad, with 2 streams would expose the following routing table,
> > right?
> >
> > pad #0 = sink, 1 stream
> > pad #1 = sink, 1 stream
> > pad #2 = source, 2 streams
> >
> > Routing table:
> > 0/0 -> 2/0
> > 0/0 -> 2/1
> > 1/0 -> 2/0
> > 1/0 -> 2/1
> >
> > In general, the number of accepted routes should depend on the number
> > of streams, not pads, and that's better handled by drivers, am I
> > wrong?
>
> Good point. Is the above configuration meaningful? I.e. you have a mux
> device that does some processing as well by combining the streams?
>
> It's far-fetched but at the moment the API does not really bend for that.
> It still might in the future.

Well, how would you expect a routing table for a device that
supports multiplexing using Virtual Channels to look like?

As far as I got it, even with a single sink and a single source, it
would be:

[SINK/SINK_STREAM -> SOURCE/SOURCE_STREAM]
0/0 -> 1/0
0/0 -> 1/1
0/0 -> 1/2
0/0 -> 1/3

On the previous example, I thought about GMSL-like devices, that can
output the video streams received from different remotes in a
separate virtual channel, at the same time.

A possible routing table in that case would be like:

Pads 0, 1, 2, 3 = SINKS
Pad 4 = SOURCE with 4 streams (1 for each VC)

0/0 -> 4/0
0/0 -> 4/1
0/0 -> 4/2
0/0 -> 4/3
1/0 -> 4/0
1/0 -> 4/1
1/0 -> 4/2
1/0 -> 4/3
2/0 -> 4/0
2/0 -> 4/1
2/0 -> 4/2
2/0 -> 4/3
3/0 -> 4/0
3/0 -> 4/1
3/0 -> 4/2
3/0 -> 4/3

With only one route per virtual channel active at a time.

Does this match your idea?

>
> I guess we could just remove the check, and let drivers handle it.
>

Yup, I agree!

> >
> > Thanks
> >   j
> >
> > > +
> > > +		for (i = 0; i < route->num_routes; ++i) {
> > > +			unsigned int sink = route->routes[i].sink_pad;
> > > +			unsigned int source = route->routes[i].source_pad;
> > > +			struct media_pad *pads = sd->entity.pads;
> > > +
> > > +			if (sink >= sd->entity.num_pads ||
> > > +			    source >= sd->entity.num_pads)
> > > +				return -EINVAL;
> > > +
> > > +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> > > +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> > > +				return -EINVAL;
> > > +		}
> > > +
> > > +		return v4l2_subdev_call(sd, pad, set_routing, route);
> > > +	}
> > >  #endif
> > > +
> > >  	default:
> > >  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> > >  	}
> > > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > > index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> > > --- a/include/media/v4l2-subdev.h
> > > +++ b/include/media/v4l2-subdev.h
> > > @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> > >   *
> > >   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> > >   *                  may be adjusted by the subdev driver to device capabilities.
> > > + *
> > > + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> > > + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
> > >   */
> > >  struct v4l2_subdev_pad_ops {
> > >  	int (*init_cfg)(struct v4l2_subdev *sd,
> > > @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> > >  			      struct v4l2_mbus_frame_desc *fd);
> > >  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> > >  			      struct v4l2_mbus_frame_desc *fd);
> > > +	int (*get_routing)(struct v4l2_subdev *sd,
> > > +			   struct v4l2_subdev_routing *route);
> > > +	int (*set_routing)(struct v4l2_subdev *sd,
> > > +			   struct v4l2_subdev_routing *route);
> > >  };
> > >
> > >  /**
> > > diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> > > index 03970ce3074193e6..af069bfb10ca23a5 100644
> > > --- a/include/uapi/linux/v4l2-subdev.h
> > > +++ b/include/uapi/linux/v4l2-subdev.h
> > > @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> > >  	__u32 reserved[8];
> > >  };
> > >
> > > +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> > > +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> > > +
> > > +/**
> > > + * struct v4l2_subdev_route - A signal route inside a subdev
> > > + * @sink_pad: the sink pad
> > > + * @sink_stream: the sink stream
> > > + * @source_pad: the source pad
> > > + * @source_stream: the source stream
> > > + * @flags: route flags:
> > > + *
> > > + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> > > + *	active stream will start when streaming is enabled on a video
> > > + *	node. Set by the user.
> > > + *
> > > + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> > > + *	can it be activated and inactivated? Set by the driver.
> > > + */
> > > +struct v4l2_subdev_route {
> > > +	__u32 sink_pad;
> > > +	__u32 sink_stream;
> > > +	__u32 source_pad;
> > > +	__u32 source_stream;
> > > +	__u32 flags;
> > > +	__u32 reserved[5];
> > > +};
> > > +
> > > +/**
> > > + * struct v4l2_subdev_routing - Routing information
> > > + * @routes: the routes array
> > > + * @num_routes: the total number of routes in the routes array
> > > + */
> > > +struct v4l2_subdev_routing {
> > > +	struct v4l2_subdev_route *routes;
>
> This should be just __u64, to avoid writing compat code. The patch was
> written before we started doing that. :-) Please see e.g. the media device
> topology IOCTL.
>

Thanks, I had a look at the MEDIA_ ioctls yesterday, G_TOPOLOGY in
particular, which uses several pointers to arrays.

Unfortunately, I didn't come up with anything better than using a
translation structure, from the IOCTL layer to the subdevice
operations layer:
https://paste.debian.net/hidden/b192969d/
(sharing a link for early comments, I can send v3 and you can comment
there directly if you prefer to :)

Thanks
   j

> > > +	__u32 num_routes;
> > > +	__u32 reserved[5];
> > > +};
> > > +
> > >  /* Backwards compatibility define --- to be removed */
> > >  #define v4l2_subdev_edid v4l2_edid
> > >
> > > @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
> > >  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
> > >  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
> > >  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> > > +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> > > +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
> > >
> > >  #endif
>
> --
> Regards,
>
> Sakari Ailus
> sakari.ailus@linux.intel.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-02-21 23:49       ` Sakari Ailus
@ 2019-02-22  8:46         ` Jacopo Mondi
  0 siblings, 0 replies; 90+ messages in thread
From: Jacopo Mondi @ 2019-02-22  8:46 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Laurent Pinchart, Niklas Söderlund, Benoit Parrot,
	linux-media, linux-renesas-soc, Michal Simek

[-- Attachment #1: Type: text/plain, Size: 6363 bytes --]

Hi Sakari,

On Fri, Feb 22, 2019 at 01:49:36AM +0200, Sakari Ailus wrote:
> Hi Jacopo,
>
> On Thu, Feb 21, 2019 at 03:59:20PM +0100, Jacopo Mondi wrote:
> > Hi Sakari, Laurent, Niklas,
> >    (another) quick question, but a different one :)
> >
> > On Wed, Jan 16, 2019 at 01:51:45AM +0200, Laurent Pinchart wrote:
> > > Hi Niklas,
> > >
> > > Thank you for the patch.
> > >
> > > On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > > > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > >
> > > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > > >
> > > > - Add sink and source streams for multiplexed links
> > > > - Copy the argument back in case of an error. This is needed to let the
> > > >   caller know the number of routes.
> > > >
> > > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > > > ---
> > > >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> > > >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> > > >  include/media/v4l2-subdev.h           |  7 +++++
> > > >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> > >
> > > Missing documentation :-(
> > >
> > > >  4 files changed, 94 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > @@ -19,6 +19,7 @@
> > > >  #include <linux/kernel.h>
> > > >  #include <linux/version.h>
> > > >
> > > > +#include <linux/v4l2-subdev.h>
> > > >  #include <linux/videodev2.h>
> > > >
> > > >  #include <media/v4l2-common.h>
> > > > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> > > >  		}
> > > >  		break;
> > > >  	}
> > > > +
> > > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > > +		struct v4l2_subdev_routing *route = parg;
> > > > +
> > > > +		if (route->num_routes > 0) {
> > > > +			if (route->num_routes > 256)
> > > > +				return -EINVAL;
> > > > +
> > > > +			*user_ptr = (void __user *)route->routes;
> > > > +			*kernel_ptr = (void *)&route->routes;
> > > > +			*array_size = sizeof(struct v4l2_subdev_route)
> > > > +				    * route->num_routes;
> > > > +			ret = 1;
> > > > +		}
> > > > +		break;
> > > > +	}
> > > >  	}
> > > >
> > > >  	return ret;
> > > > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> > > >  	 * Some ioctls can return an error, but still have valid
> > > >  	 * results that must be returned.
> > > >  	 */
> > > > -	if (err < 0 && !always_copy)
> > > > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> > >
> > > This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
> > > always_copy instead ?
> > >
> > > >  		goto out;
> > > >
> > > >  out_array_args:
> > > > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > > > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > > > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> > > >
> > > >  	case VIDIOC_SUBDEV_QUERYSTD:
> > > >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > > > +
> > > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > > > +
> > > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > > +		struct v4l2_subdev_routing *route = arg;
> > > > +		unsigned int i;
> > > > +
> > > > +		if (route->num_routes > sd->entity.num_pads)
> > > > +			return -EINVAL;
> > > > +
> > > > +		for (i = 0; i < route->num_routes; ++i) {
> >
> > How have you envisioned the number of routes to be negotiated with
> > applications? I'm writing the documentation for this ioctl, and I
> > would like to insert this part as well.
> >
> > Would a model like the one implemented in G_TOPOLOGY work in your
> > opinion? In my understanding, at the moment applications do not have a
> > way to reserve a known number of routes entries, but would likely
> > reserve 'enough(tm)' (ie 256) and pass them to the G_ROUTING ioctl that the
> > first time will likely adjust the number of num_routes and return -ENOSPC.
> >
> > Wouldn't it work to make the IOCTL behave in a way that it
> > expects the first call to be performed with (num_routes == 0) and no routes
> > entries reserved, and just adjust 'num_routes' in that case?
> > So that applications should call G_ROUTING a first time with
> > num_routes = 0, get back the number of routes entries, reserve memory
> > for them, and then call G_ROUTING again to have the entries populated
> > by the driver. Do you have different ideas or was this the intended
> > behavior already?
>
> I think whenever the number of routes isn't enough to return them all, the
> IOCTL should return -ENOSPC, and set the actual number of routes there. Not
> just zero. The user could e.g. try with a static allocation of some, and
> allocate memory if the static allocation turns not to be enough.

I see. That's fine, I just wanted to make sure I was not missing
something... Fine with me if num_routes is not adequate, it should be
corrected by the driver and -ENOSPC returned. How applications deal
with allocation is up to them (even if documentation might suggest to
perform and "call with 0, allocate, call again" sequence as a way to
ease this)

>
> Btw. the idea behind S_ROUTING behaviour was to allow multiple users to
> work on a single sub-device without having to know about each other. That's
> why there are flags to tell which routes are enabled and which are not.
>
> I'll be better available tomorrow, let's discuss e.g. on #v4l then.
>

Unfortunately I won't too much today :) I'll keep pinging in the next
days then, sorry about this :p

Thanks
   j

> --
> Sakari Ailus
> sakari.ailus@linux.intel.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-02-22  8:40       ` Jacopo Mondi
@ 2019-02-22 11:04         ` Sakari Ailus
  2019-02-22 11:17           ` Jacopo Mondi
  0 siblings, 1 reply; 90+ messages in thread
From: Sakari Ailus @ 2019-02-22 11:04 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Niklas Söderlund, Laurent Pinchart, Benoit Parrot,
	linux-media, linux-renesas-soc, Michal Simek

Hi Jacopo,

On Fri, Feb 22, 2019 at 09:40:19AM +0100, Jacopo Mondi wrote:
> Hi Sakari,
> 
> On Fri, Feb 22, 2019 at 12:31:32AM +0200, Sakari Ailus wrote:
> > Hi Jacopo,
> >
> > On Thu, Feb 21, 2019 at 03:39:40PM +0100, Jacopo Mondi wrote:
> > > Hi Sakari,
> > >    one quick question
> > >
> > > On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > > > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > >
> > > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > > >
> > > > - Add sink and source streams for multiplexed links
> > > > - Copy the argument back in case of an error. This is needed to let the
> > > >   caller know the number of routes.
> > > >
> > > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > > > ---
> > > >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> > > >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> > > >  include/media/v4l2-subdev.h           |  7 +++++
> > > >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> > > >  4 files changed, 94 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > @@ -19,6 +19,7 @@
> > > >  #include <linux/kernel.h>
> > > >  #include <linux/version.h>
> > > >
> > > > +#include <linux/v4l2-subdev.h>
> > > >  #include <linux/videodev2.h>
> > > >
> > > >  #include <media/v4l2-common.h>
> > > > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> > > >  		}
> > > >  		break;
> > > >  	}
> > > > +
> > > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > > +		struct v4l2_subdev_routing *route = parg;
> > > > +
> > > > +		if (route->num_routes > 0) {
> > > > +			if (route->num_routes > 256)
> > > > +				return -EINVAL;
> > > > +
> > > > +			*user_ptr = (void __user *)route->routes;
> > > > +			*kernel_ptr = (void *)&route->routes;
> > > > +			*array_size = sizeof(struct v4l2_subdev_route)
> > > > +				    * route->num_routes;
> > > > +			ret = 1;
> > > > +		}
> > > > +		break;
> > > > +	}
> > > >  	}
> > > >
> > > >  	return ret;
> > > > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> > > >  	 * Some ioctls can return an error, but still have valid
> > > >  	 * results that must be returned.
> > > >  	 */
> > > > -	if (err < 0 && !always_copy)
> > > > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> > > >  		goto out;
> > > >
> > > >  out_array_args:
> > > > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > > > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > > > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> > > >
> > > >  	case VIDIOC_SUBDEV_QUERYSTD:
> > > >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > > > +
> > > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > > > +
> > > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > > +		struct v4l2_subdev_routing *route = arg;
> > > > +		unsigned int i;
> > > > +
> > > > +		if (route->num_routes > sd->entity.num_pads)
> > > > +			return -EINVAL;
> > >
> > > Can't the number of routes exceeds the total number of pad?
> > >
> > > To make an example, a subdevice with 2 sink pads, and 1 multiplexed
> > > source pad, with 2 streams would expose the following routing table,
> > > right?
> > >
> > > pad #0 = sink, 1 stream
> > > pad #1 = sink, 1 stream
> > > pad #2 = source, 2 streams
> > >
> > > Routing table:
> > > 0/0 -> 2/0
> > > 0/0 -> 2/1
> > > 1/0 -> 2/0
> > > 1/0 -> 2/1
> > >
> > > In general, the number of accepted routes should depend on the number
> > > of streams, not pads, and that's better handled by drivers, am I
> > > wrong?
> >
> > Good point. Is the above configuration meaningful? I.e. you have a mux
> > device that does some processing as well by combining the streams?
> >
> > It's far-fetched but at the moment the API does not really bend for that.
> > It still might in the future.
> 
> Well, how would you expect a routing table for a device that
> supports multiplexing using Virtual Channels to look like?
> 
> As far as I got it, even with a single sink and a single source, it
> would be:
> 
> [SINK/SINK_STREAM -> SOURCE/SOURCE_STREAM]
> 0/0 -> 1/0
> 0/0 -> 1/1
> 0/0 -> 1/2
> 0/0 -> 1/3
> 
> On the previous example, I thought about GMSL-like devices, that can
> output the video streams received from different remotes in a
> separate virtual channel, at the same time.
> 
> A possible routing table in that case would be like:
> 
> Pads 0, 1, 2, 3 = SINKS
> Pad 4 = SOURCE with 4 streams (1 for each VC)
> 
> 0/0 -> 4/0
> 0/0 -> 4/1
> 0/0 -> 4/2
> 0/0 -> 4/3
> 1/0 -> 4/0
> 1/0 -> 4/1
> 1/0 -> 4/2
> 1/0 -> 4/3
> 2/0 -> 4/0
> 2/0 -> 4/1
> 2/0 -> 4/2
> 2/0 -> 4/3
> 3/0 -> 4/0
> 3/0 -> 4/1
> 3/0 -> 4/2
> 3/0 -> 4/3

If more than one pad can handle multiplexed streams, then you may end up in
a situation like that. Indeed.

> 
> With only one route per virtual channel active at a time.
> 
> Does this match your idea?
> 
> >
> > I guess we could just remove the check, and let drivers handle it.
> >
> 
> Yup, I agree!
> 
> > >
> > > Thanks
> > >   j
> > >
> > > > +
> > > > +		for (i = 0; i < route->num_routes; ++i) {
> > > > +			unsigned int sink = route->routes[i].sink_pad;
> > > > +			unsigned int source = route->routes[i].source_pad;
> > > > +			struct media_pad *pads = sd->entity.pads;
> > > > +
> > > > +			if (sink >= sd->entity.num_pads ||
> > > > +			    source >= sd->entity.num_pads)
> > > > +				return -EINVAL;
> > > > +
> > > > +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> > > > +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> > > > +				return -EINVAL;
> > > > +		}
> > > > +
> > > > +		return v4l2_subdev_call(sd, pad, set_routing, route);
> > > > +	}
> > > >  #endif
> > > > +
> > > >  	default:
> > > >  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> > > >  	}
> > > > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > > > index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> > > > --- a/include/media/v4l2-subdev.h
> > > > +++ b/include/media/v4l2-subdev.h
> > > > @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> > > >   *
> > > >   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> > > >   *                  may be adjusted by the subdev driver to device capabilities.
> > > > + *
> > > > + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> > > > + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
> > > >   */
> > > >  struct v4l2_subdev_pad_ops {
> > > >  	int (*init_cfg)(struct v4l2_subdev *sd,
> > > > @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> > > >  			      struct v4l2_mbus_frame_desc *fd);
> > > >  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> > > >  			      struct v4l2_mbus_frame_desc *fd);
> > > > +	int (*get_routing)(struct v4l2_subdev *sd,
> > > > +			   struct v4l2_subdev_routing *route);
> > > > +	int (*set_routing)(struct v4l2_subdev *sd,
> > > > +			   struct v4l2_subdev_routing *route);
> > > >  };
> > > >
> > > >  /**
> > > > diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> > > > index 03970ce3074193e6..af069bfb10ca23a5 100644
> > > > --- a/include/uapi/linux/v4l2-subdev.h
> > > > +++ b/include/uapi/linux/v4l2-subdev.h
> > > > @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> > > >  	__u32 reserved[8];
> > > >  };
> > > >
> > > > +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> > > > +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> > > > +
> > > > +/**
> > > > + * struct v4l2_subdev_route - A signal route inside a subdev
> > > > + * @sink_pad: the sink pad
> > > > + * @sink_stream: the sink stream
> > > > + * @source_pad: the source pad
> > > > + * @source_stream: the source stream
> > > > + * @flags: route flags:
> > > > + *
> > > > + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> > > > + *	active stream will start when streaming is enabled on a video
> > > > + *	node. Set by the user.
> > > > + *
> > > > + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> > > > + *	can it be activated and inactivated? Set by the driver.
> > > > + */
> > > > +struct v4l2_subdev_route {
> > > > +	__u32 sink_pad;
> > > > +	__u32 sink_stream;
> > > > +	__u32 source_pad;
> > > > +	__u32 source_stream;
> > > > +	__u32 flags;
> > > > +	__u32 reserved[5];
> > > > +};
> > > > +
> > > > +/**
> > > > + * struct v4l2_subdev_routing - Routing information
> > > > + * @routes: the routes array
> > > > + * @num_routes: the total number of routes in the routes array
> > > > + */
> > > > +struct v4l2_subdev_routing {
> > > > +	struct v4l2_subdev_route *routes;
> >
> > This should be just __u64, to avoid writing compat code. The patch was
> > written before we started doing that. :-) Please see e.g. the media device
> > topology IOCTL.
> >
> 
> Thanks, I had a look at the MEDIA_ ioctls yesterday, G_TOPOLOGY in
> particular, which uses several pointers to arrays.
> 
> Unfortunately, I didn't come up with anything better than using a
> translation structure, from the IOCTL layer to the subdevice
> operations layer:
> https://paste.debian.net/hidden/b192969d/
> (sharing a link for early comments, I can send v3 and you can comment
> there directly if you prefer to :)

Hmm. That is a downside indeed. It's still a lesser problem than the compat
code in general --- which has been a source for bugs as well as nasty
security problems over time.

I think we need a naming scheme for such structs. How about just
calling that struct e.g. v4l2_subdev_krouting instead? It's simple, easy to
understand and it includes a suggestion which one is the kernel-only
variant.

You can btw. zero the struct memory by assigning { 0 } to it in
declaration. memset() in general is much more trouble. In this case you
could even do the assignments in delaration as well.

There is a check that requires that one pad is a source and another is a
sink; I think we could remove that check as well.

-- 
Regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-02-22 11:04         ` Sakari Ailus
@ 2019-02-22 11:17           ` Jacopo Mondi
  2019-02-22 11:29             ` Sakari Ailus
  0 siblings, 1 reply; 90+ messages in thread
From: Jacopo Mondi @ 2019-02-22 11:17 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Niklas Söderlund, Laurent Pinchart, Benoit Parrot,
	linux-media, linux-renesas-soc, Michal Simek

[-- Attachment #1: Type: text/plain, Size: 2771 bytes --]

Hi Sakari,
    thanks for your suggestions.

On Fri, Feb 22, 2019 at 01:04:29PM +0200, Sakari Ailus wrote:
> Hi Jacopo,

[snip]

> > On the previous example, I thought about GMSL-like devices, that can
> > output the video streams received from different remotes in a
> > separate virtual channel, at the same time.
> >
> > A possible routing table in that case would be like:
> >
> > Pads 0, 1, 2, 3 = SINKS
> > Pad 4 = SOURCE with 4 streams (1 for each VC)
> >
> > 0/0 -> 4/0
> > 0/0 -> 4/1
> > 0/0 -> 4/2
> > 0/0 -> 4/3
> > 1/0 -> 4/0
> > 1/0 -> 4/1
> > 1/0 -> 4/2
> > 1/0 -> 4/3
> > 2/0 -> 4/0
> > 2/0 -> 4/1
> > 2/0 -> 4/2
> > 2/0 -> 4/3
> > 3/0 -> 4/0
> > 3/0 -> 4/1
> > 3/0 -> 4/2
> > 3/0 -> 4/3
>
> If more than one pad can handle multiplexed streams, then you may end up in
> a situation like that. Indeed.
>

Please note that in this case there is only one pad that can handle
multiplexed stream. The size of the routing table is the
multiplication of the total number of pads by the product of all
streams per pad. In this case (4 * (1 * 1 * 1 * 4))

> >
> > With only one route per virtual channel active at a time.

[snip]

> >
> > Thanks, I had a look at the MEDIA_ ioctls yesterday, G_TOPOLOGY in
> > particular, which uses several pointers to arrays.
> >
> > Unfortunately, I didn't come up with anything better than using a
> > translation structure, from the IOCTL layer to the subdevice
> > operations layer:
> > https://paste.debian.net/hidden/b192969d/
> > (sharing a link for early comments, I can send v3 and you can comment
> > there directly if you prefer to :)
>
> Hmm. That is a downside indeed. It's still a lesser problem than the compat
> code in general --- which has been a source for bugs as well as nasty
> security problems over time.
>

Good!

> I think we need a naming scheme for such structs. How about just
> calling that struct e.g. v4l2_subdev_krouting instead? It's simple, easy to
> understand and it includes a suggestion which one is the kernel-only
> variant.
>

I kind of like that! thanks!

> You can btw. zero the struct memory by assigning { 0 } to it in
> declaration. memset() in general is much more trouble. In this case you
> could even do the assignments in delaration as well.
>

Thanks, noted. I have been lazy and copied memset from other places in
the ioctl handling code. I should check on your suggestions because I
remember one of the many 0-initialization statement was a GCC specific one,
don't remember which...

Initializing in-place would solve both issues :)

> There is a check that requires that one pad is a source and another is a
> sink; I think we could remove that check as well.

Correct, I'll handle that!

Thanks again
   j

>
> --
> Regards,
>
> Sakari Ailus
> sakari.ailus@linux.intel.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-02-22 11:17           ` Jacopo Mondi
@ 2019-02-22 11:29             ` Sakari Ailus
  2019-02-22 13:37               ` Ian Arkver
  2019-02-22 13:50               ` Geert Uytterhoeven
  0 siblings, 2 replies; 90+ messages in thread
From: Sakari Ailus @ 2019-02-22 11:29 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Niklas Söderlund, Laurent Pinchart, Benoit Parrot,
	linux-media, linux-renesas-soc, Michal Simek

Hi Jacopo,

On Fri, Feb 22, 2019 at 12:17:47PM +0100, Jacopo Mondi wrote:
> Hi Sakari,
>     thanks for your suggestions.
> 
> On Fri, Feb 22, 2019 at 01:04:29PM +0200, Sakari Ailus wrote:
> > Hi Jacopo,
> 
> [snip]
> 
> > > On the previous example, I thought about GMSL-like devices, that can
> > > output the video streams received from different remotes in a
> > > separate virtual channel, at the same time.
> > >
> > > A possible routing table in that case would be like:
> > >
> > > Pads 0, 1, 2, 3 = SINKS
> > > Pad 4 = SOURCE with 4 streams (1 for each VC)
> > >
> > > 0/0 -> 4/0
> > > 0/0 -> 4/1
> > > 0/0 -> 4/2
> > > 0/0 -> 4/3
> > > 1/0 -> 4/0
> > > 1/0 -> 4/1
> > > 1/0 -> 4/2
> > > 1/0 -> 4/3
> > > 2/0 -> 4/0
> > > 2/0 -> 4/1
> > > 2/0 -> 4/2
> > > 2/0 -> 4/3
> > > 3/0 -> 4/0
> > > 3/0 -> 4/1
> > > 3/0 -> 4/2
> > > 3/0 -> 4/3
> >
> > If more than one pad can handle multiplexed streams, then you may end up in
> > a situation like that. Indeed.
> >
> 
> Please note that in this case there is only one pad that can handle
> multiplexed stream. The size of the routing table is the
> multiplication of the total number of pads by the product of all
> streams per pad. In this case (4 * (1 * 1 * 1 * 4))

Oh, good point, that's the case for G_ROUTING. I thought of S_ROUTING only.
:-)

> 
> > >
> > > With only one route per virtual channel active at a time.
> 
> [snip]
> 
> > >
> > > Thanks, I had a look at the MEDIA_ ioctls yesterday, G_TOPOLOGY in
> > > particular, which uses several pointers to arrays.
> > >
> > > Unfortunately, I didn't come up with anything better than using a
> > > translation structure, from the IOCTL layer to the subdevice
> > > operations layer:
> > > https://paste.debian.net/hidden/b192969d/
> > > (sharing a link for early comments, I can send v3 and you can comment
> > > there directly if you prefer to :)
> >
> > Hmm. That is a downside indeed. It's still a lesser problem than the compat
> > code in general --- which has been a source for bugs as well as nasty
> > security problems over time.
> >
> 
> Good!
> 
> > I think we need a naming scheme for such structs. How about just
> > calling that struct e.g. v4l2_subdev_krouting instead? It's simple, easy to
> > understand and it includes a suggestion which one is the kernel-only
> > variant.
> >
> 
> I kind of like that! thanks!
> 
> > You can btw. zero the struct memory by assigning { 0 } to it in
> > declaration. memset() in general is much more trouble. In this case you
> > could even do the assignments in delaration as well.
> >
> 
> Thanks, noted. I have been lazy and copied memset from other places in
> the ioctl handling code. I should check on your suggestions because I
> remember one of the many 0-initialization statement was a GCC specific one,
> don't remember which...

{} is GCC specific whereas { 0 } is not. But there have been long-standing
GCC bugs related to the use of { 0 } which is quite unfortunate --- they've
produced warnings or errors from code that is valid C...

-- 
Regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink
  2019-02-18  9:21         ` Jacopo Mondi
@ 2019-02-22 12:18           ` Laurent Pinchart
  2019-03-04 12:35             ` Jacopo Mondi
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-02-22 12:18 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, Niklas Söderlund, Benoit Parrot, linux-media,
	linux-renesas-soc

Hi Jacopo,

On Mon, Feb 18, 2019 at 10:21:07AM +0100, Jacopo Mondi wrote:
> On Tue, Jan 22, 2019 at 05:20:30PM +0200, Laurent Pinchart wrote:
> > On Tue, Jan 22, 2019 at 05:15:06PM +0200, Sakari Ailus wrote:
> >> On Wed, Jan 16, 2019 at 12:57:43AM +0200, Laurent Pinchart wrote:
> >>>>
> >>>> This way the pads are always passed to the has_route() op sink pad first.
> >>>> Makes sense.
> >>>
> >>> Is there anything in the API that mandates one pad to be a sink and the
> >>> other pad to the a source ? I had designed the operation to allow
> >>> sink-sink and source-source connections to be checked too.
> >>
> >> Do you have a use case in mind for sink--sink or source--source routes? The
> >> routes are about flows of data, so I'd presume only source--sink or
> >> sink--source routes are meaningful.
> >>
> >> If you did, then the driver would have to handle that by itself. This still
> >> simplifies the implementation for drivers that do not.
> >
> > I don't have use cases for such routes, but we use the has_route
> > operation when traversing pipelines, and at that point we need to get
> > all the internally connected pads. In another patch in this series you
> > implement a helper function that handles this, but its implementation
> > isn't complete. I explained in my review of that patch that I fear a
> > correct generic implementation would become quite complex, while the
> > complexity should be easy to handle on the driver side as the code can
> > then be specialized for the case at hand.
> >
> 
> As a compromise, in v3 I'm thinking of maintaining support for the
> most common case of two sources connected to the same sink, as
> Sakari's patch does, but let more complex cases be handled by the
> driver implementation of has_route().
> 
> Ack?

I fear this will be confusing for subdevs, as they would have to
implement part of the operation.

Could it be that the subdev has_route operation isn't the best API for
the job, if it gets that complex ? I wonder if it would be easier to
create another operation that takes a pad index as argument, and returns
the list of pads (possibly as a bitmask ?) or connected pads.
media_entity_has_route() could easily be implemented on top of that, and
these new semantics may be easier for subdevs to implement.

> >>> If your goal is to simplify the implementation of the .has_route()
> >>> operation in drivers, I would instead sort pad0 and pad1 by value.
> >>
> >> That'd be another option to make the order deterministic for the driver.
> >> I'm fine with that as well.
> 
> In v3 I have taken both suggestions in: try the "sink then source" order
> first, then order by index in case the pads are of the same time. This
> needs to be documented in has_route() operation definition though.
> 
> Would that be fine with you?

I think that's the worst of both worlds from a subdev point of view :-)

> >>>> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >>>> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >>>> ---
> >>>>  drivers/media/media-entity.c | 4 ++++
> >>>>  1 file changed, 4 insertions(+)
> >>>>
> >>>> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> >>>> index 3c0e7425c8983b45..33f00e35ccd92c6f 100644
> >>>> --- a/drivers/media/media-entity.c
> >>>> +++ b/drivers/media/media-entity.c
> >>>> @@ -249,6 +249,10 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> >>>>  	if (!entity->ops || !entity->ops->has_route)
> >>>>  		return true;
> >>>>
> >>>> +	if (entity->pads[pad0].flags & MEDIA_PAD_FL_SOURCE
> >>>> +	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
> >>>> +		swap(pad0, pad1);
> >>>> +
> >>>>  	return entity->ops->has_route(entity, pad0, pad1);
> >>>>  }
> >>>>  EXPORT_SYMBOL_GPL(media_entity_has_route);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-02-22 11:29             ` Sakari Ailus
@ 2019-02-22 13:37               ` Ian Arkver
  2019-02-22 13:50               ` Geert Uytterhoeven
  1 sibling, 0 replies; 90+ messages in thread
From: Ian Arkver @ 2019-02-22 13:37 UTC (permalink / raw)
  To: Sakari Ailus, Jacopo Mondi
  Cc: Niklas Söderlund, Laurent Pinchart, Benoit Parrot,
	linux-media, linux-renesas-soc, Michal Simek

Hi,

On 22/02/2019 11:29, Sakari Ailus wrote:
> Hi Jacopo,
> 
> On Fri, Feb 22, 2019 at 12:17:47PM +0100, Jacopo Mondi wrote:
>> Hi Sakari,
>>      thanks for your suggestions.
>>
>> On Fri, Feb 22, 2019 at 01:04:29PM +0200, Sakari Ailus wrote:
>>> Hi Jacopo,
>>
>> [snip]
>>
>>>> On the previous example, I thought about GMSL-like devices, that can
>>>> output the video streams received from different remotes in a
>>>> separate virtual channel, at the same time.
>>>>
>>>> A possible routing table in that case would be like:
>>>>
>>>> Pads 0, 1, 2, 3 = SINKS
>>>> Pad 4 = SOURCE with 4 streams (1 for each VC)
>>>>
>>>> 0/0 -> 4/0
>>>> 0/0 -> 4/1
>>>> 0/0 -> 4/2
>>>> 0/0 -> 4/3
>>>> 1/0 -> 4/0
>>>> 1/0 -> 4/1
>>>> 1/0 -> 4/2
>>>> 1/0 -> 4/3
>>>> 2/0 -> 4/0
>>>> 2/0 -> 4/1
>>>> 2/0 -> 4/2
>>>> 2/0 -> 4/3
>>>> 3/0 -> 4/0
>>>> 3/0 -> 4/1
>>>> 3/0 -> 4/2
>>>> 3/0 -> 4/3
>>>
>>> If more than one pad can handle multiplexed streams, then you may end up in
>>> a situation like that. Indeed.
>>>
>>
>> Please note that in this case there is only one pad that can handle
>> multiplexed stream. The size of the routing table is the
>> multiplication of the total number of pads by the product of all
>> streams per pad. In this case (4 * (1 * 1 * 1 * 4))
> 
> Oh, good point, that's the case for G_ROUTING. I thought of S_ROUTING only.
> :-)
> 
>>
>>>>
>>>> With only one route per virtual channel active at a time.
>>
>> [snip]
>>
>>>>
>>>> Thanks, I had a look at the MEDIA_ ioctls yesterday, G_TOPOLOGY in
>>>> particular, which uses several pointers to arrays.
>>>>
>>>> Unfortunately, I didn't come up with anything better than using a
>>>> translation structure, from the IOCTL layer to the subdevice
>>>> operations layer:
>>>> https://paste.debian.net/hidden/b192969d/
>>>> (sharing a link for early comments, I can send v3 and you can comment
>>>> there directly if you prefer to :)
>>>
>>> Hmm. That is a downside indeed. It's still a lesser problem than the compat
>>> code in general --- which has been a source for bugs as well as nasty
>>> security problems over time.
>>>
>>
>> Good!
>>
>>> I think we need a naming scheme for such structs. How about just
>>> calling that struct e.g. v4l2_subdev_krouting instead? It's simple, easy to
>>> understand and it includes a suggestion which one is the kernel-only
>>> variant.
>>>
>>
>> I kind of like that! thanks!
>>
>>> You can btw. zero the struct memory by assigning { 0 } to it in
>>> declaration. memset() in general is much more trouble. In this case you
>>> could even do the assignments in delaration as well.
>>>
>>
>> Thanks, noted. I have been lazy and copied memset from other places in
>> the ioctl handling code. I should check on your suggestions because I
>> remember one of the many 0-initialization statement was a GCC specific one,
>> don't remember which...
> 
> {} is GCC specific whereas { 0 } is not. But there have been long-standing
> GCC bugs related to the use of { 0 } which is quite unfortunate --- they've
> produced warnings or errors from code that is valid C...
> 

Using = {} to intialise structs is all over the kernel and quite 
accepted. Eg. recent discussion with Mauro at [1].

[1] https://lore.kernel.org/linux-media/20181207105816.4c53aeaa@coco.lan/

Regards,
Ian

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations
  2019-02-22 11:29             ` Sakari Ailus
  2019-02-22 13:37               ` Ian Arkver
@ 2019-02-22 13:50               ` Geert Uytterhoeven
  1 sibling, 0 replies; 90+ messages in thread
From: Geert Uytterhoeven @ 2019-02-22 13:50 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Jacopo Mondi, Niklas Söderlund, Laurent Pinchart,
	Benoit Parrot, Linux Media Mailing List, Linux-Renesas,
	Michal Simek

Hi Sakari,

On Fri, Feb 22, 2019 at 12:30 PM Sakari Ailus
<sakari.ailus@linux.intel.com> wrote:
> On Fri, Feb 22, 2019 at 12:17:47PM +0100, Jacopo Mondi wrote:
> > On Fri, Feb 22, 2019 at 01:04:29PM +0200, Sakari Ailus wrote:
> > > You can btw. zero the struct memory by assigning { 0 } to it in
> > > declaration. memset() in general is much more trouble. In this case you
> > > could even do the assignments in delaration as well.
> > >
> >
> > Thanks, noted. I have been lazy and copied memset from other places in
> > the ioctl handling code. I should check on your suggestions because I
> > remember one of the many 0-initialization statement was a GCC specific one,
> > don't remember which...
>
> {} is GCC specific whereas { 0 } is not. But there have been long-standing
> GCC bugs related to the use of { 0 } which is quite unfortunate --- they've
> produced warnings or errors from code that is valid C...

Most of these are gone since commit cafa0010cd51fb71 ("Raise the minimum
required gcc version to 4.6").

Gr{oetje,eeting}s,

                        Geert


--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink
  2019-02-22 12:18           ` Laurent Pinchart
@ 2019-03-04 12:35             ` Jacopo Mondi
  2019-03-05 20:04               ` Laurent Pinchart
  0 siblings, 1 reply; 90+ messages in thread
From: Jacopo Mondi @ 2019-03-04 12:35 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Sakari Ailus, Niklas Söderlund, Benoit Parrot, linux-media,
	linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 4546 bytes --]

Hi Laurent,

On Fri, Feb 22, 2019 at 02:18:11PM +0200, Laurent Pinchart wrote:
> Hi Jacopo,
>
> On Mon, Feb 18, 2019 at 10:21:07AM +0100, Jacopo Mondi wrote:
> > On Tue, Jan 22, 2019 at 05:20:30PM +0200, Laurent Pinchart wrote:
> > > On Tue, Jan 22, 2019 at 05:15:06PM +0200, Sakari Ailus wrote:
> > >> On Wed, Jan 16, 2019 at 12:57:43AM +0200, Laurent Pinchart wrote:
> > >>>>
> > >>>> This way the pads are always passed to the has_route() op sink pad first.
> > >>>> Makes sense.
> > >>>
> > >>> Is there anything in the API that mandates one pad to be a sink and the
> > >>> other pad to the a source ? I had designed the operation to allow
> > >>> sink-sink and source-source connections to be checked too.
> > >>
> > >> Do you have a use case in mind for sink--sink or source--source routes? The
> > >> routes are about flows of data, so I'd presume only source--sink or
> > >> sink--source routes are meaningful.
> > >>
> > >> If you did, then the driver would have to handle that by itself. This still
> > >> simplifies the implementation for drivers that do not.
> > >
> > > I don't have use cases for such routes, but we use the has_route
> > > operation when traversing pipelines, and at that point we need to get
> > > all the internally connected pads. In another patch in this series you
> > > implement a helper function that handles this, but its implementation
> > > isn't complete. I explained in my review of that patch that I fear a
> > > correct generic implementation would become quite complex, while the
> > > complexity should be easy to handle on the driver side as the code can
> > > then be specialized for the case at hand.
> > >
> >
> > As a compromise, in v3 I'm thinking of maintaining support for the
> > most common case of two sources connected to the same sink, as
> > Sakari's patch does, but let more complex cases be handled by the
> > driver implementation of has_route().
> >
> > Ack?
>
> I fear this will be confusing for subdevs, as they would have to
> implement part of the operation.
>
> Could it be that the subdev has_route operation isn't the best API for
> the job, if it gets that complex ? I wonder if it would be easier to
> create another operation that takes a pad index as argument, and returns
> the list of pads (possibly as a bitmask ?) or connected pads.
> media_entity_has_route() could easily be implemented on top of that, and
> these new semantics may be easier for subdevs to implement.
>

I see, but if subdevs can easily elaborate that list, they could as
well easily check if the pad provided as argument is on that list.

> > >>> If your goal is to simplify the implementation of the .has_route()
> > >>> operation in drivers, I would instead sort pad0 and pad1 by value.
> > >>
> > >> That'd be another option to make the order deterministic for the driver.
> > >> I'm fine with that as well.
> >
> > In v3 I have taken both suggestions in: try the "sink then source" order
> > first, then order by index in case the pads are of the same time. This
> > needs to be documented in has_route() operation definition though.
> >
> > Would that be fine with you?
>
> I think that's the worst of both worlds from a subdev point of view :-)
>

Possibly :)

Should we drop completely the sink-source ordering in favour of
ordering by value, and drop [15/30] that adds support for trivial
indirect routes?

Let's reach consensus so I could send v3.

Thanks
   j

> > >>>> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >>>> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > >>>> ---
> > >>>>  drivers/media/media-entity.c | 4 ++++
> > >>>>  1 file changed, 4 insertions(+)
> > >>>>
> > >>>> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> > >>>> index 3c0e7425c8983b45..33f00e35ccd92c6f 100644
> > >>>> --- a/drivers/media/media-entity.c
> > >>>> +++ b/drivers/media/media-entity.c
> > >>>> @@ -249,6 +249,10 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> > >>>>  	if (!entity->ops || !entity->ops->has_route)
> > >>>>  		return true;
> > >>>>
> > >>>> +	if (entity->pads[pad0].flags & MEDIA_PAD_FL_SOURCE
> > >>>> +	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
> > >>>> +		swap(pad0, pad1);
> > >>>> +
> > >>>>  	return entity->ops->has_route(entity, pad0, pad1);
> > >>>>  }
> > >>>>  EXPORT_SYMBOL_GPL(media_entity_has_route);
>
> --
> Regards,
>
> Laurent Pinchart

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink
  2019-03-04 12:35             ` Jacopo Mondi
@ 2019-03-05 20:04               ` Laurent Pinchart
  2019-03-06  8:29                 ` Jacopo Mondi
  0 siblings, 1 reply; 90+ messages in thread
From: Laurent Pinchart @ 2019-03-05 20:04 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, Niklas Söderlund, Benoit Parrot, linux-media,
	linux-renesas-soc

Hi Jacopo,

On Mon, Mar 04, 2019 at 01:35:36PM +0100, Jacopo Mondi wrote:
> On Fri, Feb 22, 2019 at 02:18:11PM +0200, Laurent Pinchart wrote:
> > On Mon, Feb 18, 2019 at 10:21:07AM +0100, Jacopo Mondi wrote:
> >> On Tue, Jan 22, 2019 at 05:20:30PM +0200, Laurent Pinchart wrote:
> >>> On Tue, Jan 22, 2019 at 05:15:06PM +0200, Sakari Ailus wrote:
> >>>> On Wed, Jan 16, 2019 at 12:57:43AM +0200, Laurent Pinchart wrote:
> >>>>>>
> >>>>>> This way the pads are always passed to the has_route() op sink pad first.
> >>>>>> Makes sense.
> >>>>>
> >>>>> Is there anything in the API that mandates one pad to be a sink and the
> >>>>> other pad to the a source ? I had designed the operation to allow
> >>>>> sink-sink and source-source connections to be checked too.
> >>>>
> >>>> Do you have a use case in mind for sink--sink or source--source routes? The
> >>>> routes are about flows of data, so I'd presume only source--sink or
> >>>> sink--source routes are meaningful.
> >>>>
> >>>> If you did, then the driver would have to handle that by itself. This still
> >>>> simplifies the implementation for drivers that do not.
> >>>
> >>> I don't have use cases for such routes, but we use the has_route
> >>> operation when traversing pipelines, and at that point we need to get
> >>> all the internally connected pads. In another patch in this series you
> >>> implement a helper function that handles this, but its implementation
> >>> isn't complete. I explained in my review of that patch that I fear a
> >>> correct generic implementation would become quite complex, while the
> >>> complexity should be easy to handle on the driver side as the code can
> >>> then be specialized for the case at hand.
> >>>
> >>
> >> As a compromise, in v3 I'm thinking of maintaining support for the
> >> most common case of two sources connected to the same sink, as
> >> Sakari's patch does, but let more complex cases be handled by the
> >> driver implementation of has_route().
> >>
> >> Ack?
> >
> > I fear this will be confusing for subdevs, as they would have to
> > implement part of the operation.
> >
> > Could it be that the subdev has_route operation isn't the best API for
> > the job, if it gets that complex ? I wonder if it would be easier to
> > create another operation that takes a pad index as argument, and returns
> > the list of pads (possibly as a bitmask ?) or connected pads.
> > media_entity_has_route() could easily be implemented on top of that, and
> > these new semantics may be easier for subdevs to implement.
> >
> 
> I see, but if subdevs can easily elaborate that list, they could as
> well easily check if the pad provided as argument is on that list.

Possibly. In any case, if we keep this operation as-is, I wouldn't try
to split the logic between the subdev drivers and the core, that would
be asking for trouble. If it gets too complex to implement for subdev
drivers, then we need a different operation with a different logic in
the subdev API, and a helper that wraps around it.

> >>>>> If your goal is to simplify the implementation of the .has_route()
> >>>>> operation in drivers, I would instead sort pad0 and pad1 by value.
> >>>>
> >>>> That'd be another option to make the order deterministic for the driver.
> >>>> I'm fine with that as well.
> >>
> >> In v3 I have taken both suggestions in: try the "sink then source" order
> >> first, then order by index in case the pads are of the same time. This
> >> needs to be documented in has_route() operation definition though.
> >>
> >> Would that be fine with you?
> >
> > I think that's the worst of both worlds from a subdev point of view :-)
> 
> Possibly :)
> 
> Should we drop completely the sink-source ordering in favour of
> ordering by value, and drop [15/30] that adds support for trivial
> indirect routes?
> 
> Let's reach consensus so I could send v3.

I would certainly drop 15/30, and I don't think ordering by value would
help subdev drivers much.

> >>>>>> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >>>>>> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >>>>>> ---
> >>>>>>  drivers/media/media-entity.c | 4 ++++
> >>>>>>  1 file changed, 4 insertions(+)
> >>>>>>
> >>>>>> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> >>>>>> index 3c0e7425c8983b45..33f00e35ccd92c6f 100644
> >>>>>> --- a/drivers/media/media-entity.c
> >>>>>> +++ b/drivers/media/media-entity.c
> >>>>>> @@ -249,6 +249,10 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> >>>>>>  	if (!entity->ops || !entity->ops->has_route)
> >>>>>>  		return true;
> >>>>>>
> >>>>>> +	if (entity->pads[pad0].flags & MEDIA_PAD_FL_SOURCE
> >>>>>> +	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
> >>>>>> +		swap(pad0, pad1);
> >>>>>> +
> >>>>>>  	return entity->ops->has_route(entity, pad0, pad1);
> >>>>>>  }
> >>>>>>  EXPORT_SYMBOL_GPL(media_entity_has_route);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink
  2019-03-05 20:04               ` Laurent Pinchart
@ 2019-03-06  8:29                 ` Jacopo Mondi
  0 siblings, 0 replies; 90+ messages in thread
From: Jacopo Mondi @ 2019-03-06  8:29 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Sakari Ailus, Niklas Söderlund, Benoit Parrot, linux-media,
	linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 5718 bytes --]

HI Laurent,

On Tue, Mar 05, 2019 at 10:04:58PM +0200, Laurent Pinchart wrote:
> Hi Jacopo,
>
> On Mon, Mar 04, 2019 at 01:35:36PM +0100, Jacopo Mondi wrote:
> > On Fri, Feb 22, 2019 at 02:18:11PM +0200, Laurent Pinchart wrote:
> > > On Mon, Feb 18, 2019 at 10:21:07AM +0100, Jacopo Mondi wrote:
> > >> On Tue, Jan 22, 2019 at 05:20:30PM +0200, Laurent Pinchart wrote:
> > >>> On Tue, Jan 22, 2019 at 05:15:06PM +0200, Sakari Ailus wrote:
> > >>>> On Wed, Jan 16, 2019 at 12:57:43AM +0200, Laurent Pinchart wrote:
> > >>>>>>
> > >>>>>> This way the pads are always passed to the has_route() op sink pad first.
> > >>>>>> Makes sense.
> > >>>>>
> > >>>>> Is there anything in the API that mandates one pad to be a sink and the
> > >>>>> other pad to the a source ? I had designed the operation to allow
> > >>>>> sink-sink and source-source connections to be checked too.
> > >>>>
> > >>>> Do you have a use case in mind for sink--sink or source--source routes? The
> > >>>> routes are about flows of data, so I'd presume only source--sink or
> > >>>> sink--source routes are meaningful.
> > >>>>
> > >>>> If you did, then the driver would have to handle that by itself. This still
> > >>>> simplifies the implementation for drivers that do not.
> > >>>
> > >>> I don't have use cases for such routes, but we use the has_route
> > >>> operation when traversing pipelines, and at that point we need to get
> > >>> all the internally connected pads. In another patch in this series you
> > >>> implement a helper function that handles this, but its implementation
> > >>> isn't complete. I explained in my review of that patch that I fear a
> > >>> correct generic implementation would become quite complex, while the
> > >>> complexity should be easy to handle on the driver side as the code can
> > >>> then be specialized for the case at hand.
> > >>>
> > >>
> > >> As a compromise, in v3 I'm thinking of maintaining support for the
> > >> most common case of two sources connected to the same sink, as
> > >> Sakari's patch does, but let more complex cases be handled by the
> > >> driver implementation of has_route().
> > >>
> > >> Ack?
> > >
> > > I fear this will be confusing for subdevs, as they would have to
> > > implement part of the operation.
> > >
> > > Could it be that the subdev has_route operation isn't the best API for
> > > the job, if it gets that complex ? I wonder if it would be easier to
> > > create another operation that takes a pad index as argument, and returns
> > > the list of pads (possibly as a bitmask ?) or connected pads.
> > > media_entity_has_route() could easily be implemented on top of that, and
> > > these new semantics may be easier for subdevs to implement.
> > >
> >
> > I see, but if subdevs can easily elaborate that list, they could as
> > well easily check if the pad provided as argument is on that list.
>
> Possibly. In any case, if we keep this operation as-is, I wouldn't try
> to split the logic between the subdev drivers and the core, that would
> be asking for trouble. If it gets too complex to implement for subdev
> drivers, then we need a different operation with a different logic in
> the subdev API, and a helper that wraps around it.

In v3 I have removed support for indirect routes from the framework
part. It's all on the subdevice driver for now.
>
> > >>>>> If your goal is to simplify the implementation of the .has_route()
> > >>>>> operation in drivers, I would instead sort pad0 and pad1 by value.
> > >>>>
> > >>>> That'd be another option to make the order deterministic for the driver.
> > >>>> I'm fine with that as well.
> > >>
> > >> In v3 I have taken both suggestions in: try the "sink then source" order
> > >> first, then order by index in case the pads are of the same time. This
> > >> needs to be documented in has_route() operation definition though.
> > >>
> > >> Would that be fine with you?
> > >
> > > I think that's the worst of both worlds from a subdev point of view :-)
> >
> > Possibly :)
> >
> > Should we drop completely the sink-source ordering in favour of
> > ordering by value, and drop [15/30] that adds support for trivial
> > indirect routes?
> >
> > Let's reach consensus so I could send v3.
>
> I would certainly drop 15/30, and I don't think ordering by value would
> help subdev drivers much.

Yes, but sorting by index makes it easier to deal with the sink-sink
and source-source use cases, if the subdevice supports indirect
routes.

I have dropped 15/30 and specified pads are passed by index in v3.

Thanks
  j

>
> > >>>>>> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > >>>>>> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > >>>>>> ---
> > >>>>>>  drivers/media/media-entity.c | 4 ++++
> > >>>>>>  1 file changed, 4 insertions(+)
> > >>>>>>
> > >>>>>> diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
> > >>>>>> index 3c0e7425c8983b45..33f00e35ccd92c6f 100644
> > >>>>>> --- a/drivers/media/media-entity.c
> > >>>>>> +++ b/drivers/media/media-entity.c
> > >>>>>> @@ -249,6 +249,10 @@ bool media_entity_has_route(struct media_entity *entity, unsigned int pad0,
> > >>>>>>  	if (!entity->ops || !entity->ops->has_route)
> > >>>>>>  		return true;
> > >>>>>>
> > >>>>>> +	if (entity->pads[pad0].flags & MEDIA_PAD_FL_SOURCE
> > >>>>>> +	    && entity->pads[pad1].flags & MEDIA_PAD_FL_SINK)
> > >>>>>> +		swap(pad0, pad1);
> > >>>>>> +
> > >>>>>>  	return entity->ops->has_route(entity, pad0, pad1);
> > >>>>>>  }
> > >>>>>>  EXPORT_SYMBOL_GPL(media_entity_has_route);
>
> --
> Regards,
>
> Laurent Pinchart

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 90+ messages in thread

end of thread, other threads:[~2019-03-06  8:29 UTC | newest]

Thread overview: 90+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-01 23:31 [PATCH v2 00/30] v4l: add support for multiplexed streams Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 01/30] media: entity: Use pad as a starting point for graph walk Niklas Söderlund
2019-01-15 21:43   ` Laurent Pinchart
2018-11-01 23:31 ` [PATCH v2 02/30] media: entity: Use pads instead of entities in the media graph walk stack Niklas Söderlund
2019-01-15 22:03   ` Laurent Pinchart
2019-01-15 22:13     ` Sakari Ailus
2019-01-15 22:07   ` Laurent Pinchart
2018-11-01 23:31 ` [PATCH v2 03/30] media: entity: Walk the graph based on pads Niklas Söderlund
2019-01-15 22:21   ` Laurent Pinchart
     [not found]     ` <20190115223406.mxgzl36cp54gb7nv@kekkonen.localdomain>
2019-01-15 23:28       ` Laurent Pinchart
2019-01-22 14:50         ` Sakari Ailus
2019-02-14 15:15   ` Jacopo Mondi
2018-11-01 23:31 ` [PATCH v2 04/30] v4l: mc: Start walk from a specific pad in use count calculation Niklas Söderlund
2019-01-15 22:24   ` Laurent Pinchart
2019-01-15 22:36     ` Sakari Ailus
2018-11-01 23:31 ` [PATCH v2 05/30] media: entity: Move the pipeline from entity to pads Niklas Söderlund
2019-01-15 22:38   ` Laurent Pinchart
2019-01-15 22:48     ` Sakari Ailus
2019-02-14 15:53   ` Jacopo Mondi
2018-11-01 23:31 ` [PATCH v2 06/30] media: entity: Use pad as the starting point for a pipeline Niklas Söderlund
2019-01-15 22:54   ` Laurent Pinchart
2019-01-22 15:31     ` Sakari Ailus
2019-01-22 15:37       ` Laurent Pinchart
2019-01-22 16:16         ` Sakari Ailus
2018-11-01 23:31 ` [PATCH v2 07/30] media: entity: Add has_route entity operation Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 08/30] media: entity: Add media_has_route() function Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 09/30] media: entity: Swap pads if route is checked from source to sink Niklas Söderlund
2019-01-15 22:57   ` Laurent Pinchart
2019-01-22 15:15     ` Sakari Ailus
2019-01-22 15:20       ` Laurent Pinchart
2019-02-18  9:21         ` Jacopo Mondi
2019-02-22 12:18           ` Laurent Pinchart
2019-03-04 12:35             ` Jacopo Mondi
2019-03-05 20:04               ` Laurent Pinchart
2019-03-06  8:29                 ` Jacopo Mondi
2018-11-01 23:31 ` [PATCH v2 10/30] media: entity: Use routing information during graph traversal Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 11/30] media: entity: Skip link validation for pads to which there is no route to Niklas Söderlund
2019-01-15 23:13   ` Laurent Pinchart
2018-11-01 23:31 ` [PATCH v2 12/30] media: entity: Add an iterator helper for connected pads Niklas Söderlund
2019-01-15 23:24   ` Laurent Pinchart
2019-01-22 15:36     ` Sakari Ailus
2019-01-22 15:38       ` Laurent Pinchart
2019-01-22 16:21         ` Sakari Ailus
2018-11-01 23:31 ` [PATCH v2 13/30] media: entity: Add only connected pads to the pipeline Niklas Söderlund
2019-01-15 23:33   ` Laurent Pinchart
2018-11-01 23:31 ` [PATCH v2 14/30] media: entity: Add debug information in graph walk route check Niklas Söderlund
2019-01-15 23:35   ` Laurent Pinchart
2019-01-22 15:38     ` Sakari Ailus
2018-11-01 23:31 ` [PATCH v2 15/30] media: entity: Look for indirect routes Niklas Söderlund
2019-01-15 23:41   ` Laurent Pinchart
2019-01-22 15:56     ` Sakari Ailus
2018-11-01 23:31 ` [PATCH v2 16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations Niklas Söderlund
2019-01-15 23:51   ` Laurent Pinchart
2019-01-22 16:14     ` Sakari Ailus
2019-01-22 17:00       ` Laurent Pinchart
2019-02-21 14:59     ` Jacopo Mondi
2019-02-21 23:49       ` Sakari Ailus
2019-02-22  8:46         ` Jacopo Mondi
2019-02-21 14:39   ` Jacopo Mondi
2019-02-21 22:31     ` Sakari Ailus
2019-02-22  8:40       ` Jacopo Mondi
2019-02-22 11:04         ` Sakari Ailus
2019-02-22 11:17           ` Jacopo Mondi
2019-02-22 11:29             ` Sakari Ailus
2019-02-22 13:37               ` Ian Arkver
2019-02-22 13:50               ` Geert Uytterhoeven
2018-11-01 23:31 ` [PATCH v2 17/30] v4l: subdev: compat: Implement handling for VIDIOC_SUBDEV_[GS]_ROUTING Niklas Söderlund
2019-01-08 10:04   ` Geert Uytterhoeven
2019-01-15 23:53   ` Laurent Pinchart
2019-01-22 15:57     ` Sakari Ailus
2019-02-18 11:21     ` Jacopo Mondi
2019-02-21 23:50       ` Sakari Ailus
2018-11-01 23:31 ` [PATCH v2 18/30] v4l: subdev: Take routing information into account in link validation Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 19/30] v4l: subdev: Improve link format validation debug messages Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 20/30] v4l: mc: Add an S_ROUTING helper function for power state changes Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 21/30] v4l: Add bus type to frame descriptors Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 22/30] v4l: Add CSI-2 bus configuration " Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 23/30] v4l: Add stream to frame descriptor Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 24/30] adv748x: csi2: add translation from pixelcode to CSI-2 datatype Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 25/30] adv748x: csi2: only allow formats on sink pads Niklas Söderlund
2019-02-21 14:18   ` Jacopo Mondi
2018-11-01 23:31 ` [PATCH v2 26/30] adv748x: csi2: describe the multiplexed stream Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 27/30] adv748x: csi2: add internal routing configuration Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 28/30] adv748x: afe: add routing support Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 29/30] rcar-csi2: use frame description information to configure CSI-2 bus Niklas Söderlund
2018-11-01 23:31 ` [PATCH v2 30/30] rcar-csi2: expose the subdevice internal routing Niklas Söderlund
2018-11-14 13:10   ` Nikita Yushchenko
2018-11-14 19:45     ` Niklas Söderlund
2018-12-03 22:16 ` [PATCH v2 00/30] v4l: add support for multiplexed streams Sakari Ailus
2018-12-05 22:09   ` Niklas Söderlund

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).