diff mbox series

[37/55] media: mc-entity: Add a new helper function to get a remote pad

Message ID 20220614191127.3420492-38-paul.elder@ideasonboard.com (mailing list archive)
State Superseded
Headers show
Series media: rkisp1: Cleanups and add support for i.MX8MP | expand

Commit Message

Paul Elder June 14, 2022, 7:11 p.m. UTC
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

The media_entity_remote_pad() helper function returns the first remote
pad it find connected to a given pad. Beside being possibly ill-named
(as it operates on a pad, not an entity) and non-deterministic (as it
stops at the first enabled link), the fact that it returns the first
match makes it unsuitable for drivers that need to guarantee that a
single link is enabled, for instance when an entity can process data
from one of multiple sources at a time.

For those use cases, add a new helper function,
media_entity_remote_pad_unique(), that operates on an entity and returns
a remote pad, with a guarantee that only one link is enabled. To ease
its use in drivers, also add an inline wrapper that locates source pads
specifically. A wrapper that locates sink pads can easily be added when
needed.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 Documentation/driver-api/media/mc-core.rst |  4 +-
 drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
 include/media/media-entity.h               | 45 ++++++++++++++++++++++
 3 files changed, 85 insertions(+), 2 deletions(-)

Comments

Laurent Pinchart June 15, 2022, 10:38 p.m. UTC | #1
+ Sakari and Hans

On Wed, Jun 15, 2022 at 04:11:09AM +0900, Paul Elder wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> The media_entity_remote_pad() helper function returns the first remote
> pad it find connected to a given pad. Beside being possibly ill-named
> (as it operates on a pad, not an entity) and non-deterministic (as it
> stops at the first enabled link), the fact that it returns the first
> match makes it unsuitable for drivers that need to guarantee that a
> single link is enabled, for instance when an entity can process data
> from one of multiple sources at a time.
> 
> For those use cases, add a new helper function,
> media_entity_remote_pad_unique(), that operates on an entity and returns
> a remote pad, with a guarantee that only one link is enabled. To ease
> its use in drivers, also add an inline wrapper that locates source pads
> specifically. A wrapper that locates sink pads can easily be added when
> needed.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  Documentation/driver-api/media/mc-core.rst |  4 +-
>  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
>  include/media/media-entity.h               | 45 ++++++++++++++++++++++
>  3 files changed, 85 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
> index 02481a2513b9..a2d1e32e3abb 100644
> --- a/Documentation/driver-api/media/mc-core.rst
> +++ b/Documentation/driver-api/media/mc-core.rst
> @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
>  
>  Helper functions can be used to find a link between two given pads, or a pad
>  connected to another pad through an enabled link
> -:c:func:`media_entity_find_link()` and
> -:c:func:`media_entity_remote_pad()`.
> +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
> +:c:func:`media_entity_remote_source_pad()`).
>  
>  Use count and power handling
>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
> index 11f5207f73aa..1febf5a86be6 100644
> --- a/drivers/media/mc/mc-entity.c
> +++ b/drivers/media/mc/mc-entity.c
> @@ -9,6 +9,7 @@
>   */
>  
>  #include <linux/bitmap.h>
> +#include <linux/list.h>
>  #include <linux/property.h>
>  #include <linux/slab.h>
>  #include <media/media-entity.h>
> @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
>  }
>  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
>  
> +struct media_pad *
> +media_entity_remote_pad_unique(const struct media_entity *entity,
> +			       unsigned int type)
> +{
> +	struct media_pad *pad = NULL;
> +	struct media_link *link;
> +
> +	list_for_each_entry(link, &entity->links, list) {
> +		struct media_pad *local_pad;
> +		struct media_pad *remote_pad;
> +
> +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
> +			continue;
> +
> +		if (type == MEDIA_PAD_FL_SOURCE) {
> +			local_pad = link->sink;
> +			remote_pad = link->source;
> +		} else {
> +			local_pad = link->source;
> +			remote_pad = link->sink;
> +		}
> +
> +		if (local_pad->entity == entity) {
> +			if (pad)
> +				return ERR_PTR(-ENOTUNIQ);
> +
> +			pad = remote_pad;
> +		}
> +	}
> +
> +	if (!pad)
> +		return ERR_PTR(-ENOLINK);
> +
> +	return pad;
> +}
> +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
> +
>  static void media_interface_init(struct media_device *mdev,
>  				 struct media_interface *intf,
>  				 u32 gobj_type,
> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index a9a1c0ec5d1c..33d5f52719a0 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
>   */
>  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
>  
> +/**
> + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
> + * @entity: The entity
> + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
> + *
> + * Search for and return a remote pad of @type connected to @entity through an
> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> + * is returned.
> + *
> + * The uniqueness constraint makes this helper function suitable for entities
> + * that support a single active source or sink at a time.
> + *
> + * Return: A pointer to the remote pad, or one of the following error pointers
> + * if an error occurs:
> + *
> + * * -ENOTUNIQ - Multiple links are enabled
> + * * -ENOLINK - No connected pad found
> + */
> +struct media_pad *
> +media_entity_remote_pad_unique(const struct media_entity *entity,
> +			       unsigned int type);
> +
> +/**
> + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
> + * @entity: The entity
> + *
> + * Search for and return a remote source pad connected to @entity through an
> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> + * is returned.
> + *
> + * The uniqueness constraint makes this helper function suitable for entities
> + * that support a single active source at a time.
> + *
> + * Return: A pointer to the remote pad, or one of the following error pointers
> + * if an error occurs:
> + *
> + * * -ENOTUNIQ - Multiple links are enabled
> + * * -ENOLINK - No connected pad found
> + */
> +static inline struct media_pad *
> +media_entity_remote_source_pad(const struct media_entity *entity)
> +{
> +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
> +}
> +
>  /**
>   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
>   * @entity: The entity
> -- 
> 2.30.2
>
Hans Verkuil June 17, 2022, 11:38 a.m. UTC | #2
On 6/14/22 21:11, Paul Elder wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> The media_entity_remote_pad() helper function returns the first remote
> pad it find connected to a given pad. Beside being possibly ill-named

find -> finds

> (as it operates on a pad, not an entity) and non-deterministic (as it
> stops at the first enabled link), the fact that it returns the first
> match makes it unsuitable for drivers that need to guarantee that a
> single link is enabled, for instance when an entity can process data
> from one of multiple sources at a time.
> 
> For those use cases, add a new helper function,
> media_entity_remote_pad_unique(), that operates on an entity and returns
> a remote pad, with a guarantee that only one link is enabled. To ease
> its use in drivers, also add an inline wrapper that locates source pads
> specifically. A wrapper that locates sink pads can easily be added when
> needed.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  Documentation/driver-api/media/mc-core.rst |  4 +-
>  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
>  include/media/media-entity.h               | 45 ++++++++++++++++++++++
>  3 files changed, 85 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
> index 02481a2513b9..a2d1e32e3abb 100644
> --- a/Documentation/driver-api/media/mc-core.rst
> +++ b/Documentation/driver-api/media/mc-core.rst
> @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
>  
>  Helper functions can be used to find a link between two given pads, or a pad
>  connected to another pad through an enabled link
> -:c:func:`media_entity_find_link()` and
> -:c:func:`media_entity_remote_pad()`.
> +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
> +:c:func:`media_entity_remote_source_pad()`).
>  
>  Use count and power handling
>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
> index 11f5207f73aa..1febf5a86be6 100644
> --- a/drivers/media/mc/mc-entity.c
> +++ b/drivers/media/mc/mc-entity.c
> @@ -9,6 +9,7 @@
>   */
>  
>  #include <linux/bitmap.h>
> +#include <linux/list.h>
>  #include <linux/property.h>
>  #include <linux/slab.h>
>  #include <media/media-entity.h>
> @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
>  }
>  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
>  
> +struct media_pad *
> +media_entity_remote_pad_unique(const struct media_entity *entity,
> +			       unsigned int type)
> +{
> +	struct media_pad *pad = NULL;
> +	struct media_link *link;
> +
> +	list_for_each_entry(link, &entity->links, list) {
> +		struct media_pad *local_pad;
> +		struct media_pad *remote_pad;
> +
> +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
> +			continue;
> +
> +		if (type == MEDIA_PAD_FL_SOURCE) {
> +			local_pad = link->sink;
> +			remote_pad = link->source;
> +		} else {
> +			local_pad = link->source;
> +			remote_pad = link->sink;
> +		}
> +
> +		if (local_pad->entity == entity) {
> +			if (pad)
> +				return ERR_PTR(-ENOTUNIQ);
> +
> +			pad = remote_pad;
> +		}
> +	}
> +
> +	if (!pad)
> +		return ERR_PTR(-ENOLINK);
> +
> +	return pad;
> +}
> +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
> +
>  static void media_interface_init(struct media_device *mdev,
>  				 struct media_interface *intf,
>  				 u32 gobj_type,
> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index a9a1c0ec5d1c..33d5f52719a0 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
>   */
>  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
>  
> +/**
> + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
> + * @entity: The entity
> + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
> + *
> + * Search for and return a remote pad of @type connected to @entity through an
> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> + * is returned.
> + *
> + * The uniqueness constraint makes this helper function suitable for entities
> + * that support a single active source or sink at a time.
> + *
> + * Return: A pointer to the remote pad, or one of the following error pointers
> + * if an error occurs:
> + *
> + * * -ENOTUNIQ - Multiple links are enabled
> + * * -ENOLINK - No connected pad found
> + */
> +struct media_pad *
> +media_entity_remote_pad_unique(const struct media_entity *entity,
> +			       unsigned int type);
> +
> +/**
> + * media_entity_remote_source_pad - Find a remote source pad connected to an entity

Shouldn't this be called media_entity_remote_source_pad_unique?

After all, it has the uniqueness constraint, but that's not reflected in the name.

With that change you can add my:

Acked-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>

Regards,

	Hans

> + * @entity: The entity
> + *
> + * Search for and return a remote source pad connected to @entity through an
> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> + * is returned.
> + *
> + * The uniqueness constraint makes this helper function suitable for entities
> + * that support a single active source at a time.
> + *
> + * Return: A pointer to the remote pad, or one of the following error pointers
> + * if an error occurs:
> + *
> + * * -ENOTUNIQ - Multiple links are enabled
> + * * -ENOLINK - No connected pad found
> + */
> +static inline struct media_pad *
> +media_entity_remote_source_pad(const struct media_entity *entity)
> +{
> +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
> +}
> +
>  /**
>   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
>   * @entity: The entity
Hans Verkuil June 17, 2022, 11:48 a.m. UTC | #3
On 6/14/22 21:11, Paul Elder wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> The media_entity_remote_pad() helper function returns the first remote
> pad it find connected to a given pad. Beside being possibly ill-named
> (as it operates on a pad, not an entity) and non-deterministic (as it
> stops at the first enabled link), the fact that it returns the first
> match makes it unsuitable for drivers that need to guarantee that a
> single link is enabled, for instance when an entity can process data
> from one of multiple sources at a time.

Question: of all the callers of this function, are there any that really
need media_entity_remote_pad() instead of media_pad_remote_pad_unique()?

Would it be possible to replace all callers of the old function with the
new function? If that's the case, then the _unique suffix can be dropped,
since that would effectively be the default. And if a function is needed
to handle the case where there are multiple enabled links, then a new
function should be created.

Also, media_entity_remote_pad() should really be renamed to
media_pad_remote_pad_first() or something like that, right? I'm not saying
you should, but that's really what it does, as I understand it.

Regards,

	Hans

> 
> For those use cases, add a new helper function,
> media_entity_remote_pad_unique(), that operates on an entity and returns
> a remote pad, with a guarantee that only one link is enabled. To ease
> its use in drivers, also add an inline wrapper that locates source pads
> specifically. A wrapper that locates sink pads can easily be added when
> needed.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  Documentation/driver-api/media/mc-core.rst |  4 +-
>  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
>  include/media/media-entity.h               | 45 ++++++++++++++++++++++
>  3 files changed, 85 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
> index 02481a2513b9..a2d1e32e3abb 100644
> --- a/Documentation/driver-api/media/mc-core.rst
> +++ b/Documentation/driver-api/media/mc-core.rst
> @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
>  
>  Helper functions can be used to find a link between two given pads, or a pad
>  connected to another pad through an enabled link
> -:c:func:`media_entity_find_link()` and
> -:c:func:`media_entity_remote_pad()`.
> +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
> +:c:func:`media_entity_remote_source_pad()`).
>  
>  Use count and power handling
>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
> index 11f5207f73aa..1febf5a86be6 100644
> --- a/drivers/media/mc/mc-entity.c
> +++ b/drivers/media/mc/mc-entity.c
> @@ -9,6 +9,7 @@
>   */
>  
>  #include <linux/bitmap.h>
> +#include <linux/list.h>
>  #include <linux/property.h>
>  #include <linux/slab.h>
>  #include <media/media-entity.h>
> @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
>  }
>  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
>  
> +struct media_pad *
> +media_entity_remote_pad_unique(const struct media_entity *entity,
> +			       unsigned int type)
> +{
> +	struct media_pad *pad = NULL;
> +	struct media_link *link;
> +
> +	list_for_each_entry(link, &entity->links, list) {
> +		struct media_pad *local_pad;
> +		struct media_pad *remote_pad;
> +
> +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
> +			continue;
> +
> +		if (type == MEDIA_PAD_FL_SOURCE) {
> +			local_pad = link->sink;
> +			remote_pad = link->source;
> +		} else {
> +			local_pad = link->source;
> +			remote_pad = link->sink;
> +		}
> +
> +		if (local_pad->entity == entity) {
> +			if (pad)
> +				return ERR_PTR(-ENOTUNIQ);
> +
> +			pad = remote_pad;
> +		}
> +	}
> +
> +	if (!pad)
> +		return ERR_PTR(-ENOLINK);
> +
> +	return pad;
> +}
> +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
> +
>  static void media_interface_init(struct media_device *mdev,
>  				 struct media_interface *intf,
>  				 u32 gobj_type,
> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index a9a1c0ec5d1c..33d5f52719a0 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
>   */
>  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
>  
> +/**
> + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
> + * @entity: The entity
> + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
> + *
> + * Search for and return a remote pad of @type connected to @entity through an
> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> + * is returned.
> + *
> + * The uniqueness constraint makes this helper function suitable for entities
> + * that support a single active source or sink at a time.
> + *
> + * Return: A pointer to the remote pad, or one of the following error pointers
> + * if an error occurs:
> + *
> + * * -ENOTUNIQ - Multiple links are enabled
> + * * -ENOLINK - No connected pad found
> + */
> +struct media_pad *
> +media_entity_remote_pad_unique(const struct media_entity *entity,
> +			       unsigned int type);
> +
> +/**
> + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
> + * @entity: The entity
> + *
> + * Search for and return a remote source pad connected to @entity through an
> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> + * is returned.
> + *
> + * The uniqueness constraint makes this helper function suitable for entities
> + * that support a single active source at a time.
> + *
> + * Return: A pointer to the remote pad, or one of the following error pointers
> + * if an error occurs:
> + *
> + * * -ENOTUNIQ - Multiple links are enabled
> + * * -ENOLINK - No connected pad found
> + */
> +static inline struct media_pad *
> +media_entity_remote_source_pad(const struct media_entity *entity)
> +{
> +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
> +}
> +
>  /**
>   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
>   * @entity: The entity
Daniel Scally June 17, 2022, 9:34 p.m. UTC | #4
Hello all

On 14/06/2022 20:11, Paul Elder wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
> The media_entity_remote_pad() helper function returns the first remote
> pad it find connected to a given pad. Beside being possibly ill-named
> (as it operates on a pad, not an entity) and non-deterministic (as it
> stops at the first enabled link), the fact that it returns the first
> match makes it unsuitable for drivers that need to guarantee that a
> single link is enabled, for instance when an entity can process data
> from one of multiple sources at a time.
>
> For those use cases, add a new helper function,
> media_entity_remote_pad_unique(), that operates on an entity and returns
> a remote pad, with a guarantee that only one link is enabled. To ease
> its use in drivers, also add an inline wrapper that locates source pads
> specifically. A wrapper that locates sink pads can easily be added when
> needed.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  Documentation/driver-api/media/mc-core.rst |  4 +-
>  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
>  include/media/media-entity.h               | 45 ++++++++++++++++++++++
>  3 files changed, 85 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
> index 02481a2513b9..a2d1e32e3abb 100644
> --- a/Documentation/driver-api/media/mc-core.rst
> +++ b/Documentation/driver-api/media/mc-core.rst
> @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
>  
>  Helper functions can be used to find a link between two given pads, or a pad
>  connected to another pad through an enabled link
> -:c:func:`media_entity_find_link()` and
> -:c:func:`media_entity_remote_pad()`.
> +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
> +:c:func:`media_entity_remote_source_pad()`).
>  
>  Use count and power handling
>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
> index 11f5207f73aa..1febf5a86be6 100644
> --- a/drivers/media/mc/mc-entity.c
> +++ b/drivers/media/mc/mc-entity.c
> @@ -9,6 +9,7 @@
>   */
>  
>  #include <linux/bitmap.h>
> +#include <linux/list.h>
>  #include <linux/property.h>
>  #include <linux/slab.h>
>  #include <media/media-entity.h>
> @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
>  }
>  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
>  
> +struct media_pad *
> +media_entity_remote_pad_unique(const struct media_entity *entity,
> +			       unsigned int type)
> +{
> +	struct media_pad *pad = NULL;
> +	struct media_link *link;
> +
> +	list_for_each_entry(link, &entity->links, list) {
> +		struct media_pad *local_pad;
> +		struct media_pad *remote_pad;
> +
> +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
> +			continue;
Does this need another guard here to make sure the link isn't an
ancillary link? Only likely to happen at least in the immediate future
where the entity represents a camera sensor, so possibly not applicable
here - I couldn't find where the new function is used in the series to
check. I _think_ it would actually work ok regardless...media_gobj
type-punning makes my brain ache, but I think the local_pad->entity ==
entity comparison would actually compare the entity->name member of the
entity at the end of an ancillary link to the entity parameter, not find
a match and so continue the loop without failing, but that feels a bit
sub-optimal.



> +
> +		if (type == MEDIA_PAD_FL_SOURCE) {
> +			local_pad = link->sink;
> +			remote_pad = link->source;
> +		} else {
> +			local_pad = link->source;
> +			remote_pad = link->sink;
> +		}
> +
> +		if (local_pad->entity == entity) {
> +			if (pad)
> +				return ERR_PTR(-ENOTUNIQ);
> +
> +			pad = remote_pad;
> +		}
> +	}
> +
> +	if (!pad)
> +		return ERR_PTR(-ENOLINK);
> +
> +	return pad;
> +}
> +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
> +
>  static void media_interface_init(struct media_device *mdev,
>  				 struct media_interface *intf,
>  				 u32 gobj_type,
> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> index a9a1c0ec5d1c..33d5f52719a0 100644
> --- a/include/media/media-entity.h
> +++ b/include/media/media-entity.h
> @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
>   */
>  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
>  
> +/**
> + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
> + * @entity: The entity
> + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
> + *
> + * Search for and return a remote pad of @type connected to @entity through an
> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> + * is returned.
> + *
> + * The uniqueness constraint makes this helper function suitable for entities
> + * that support a single active source or sink at a time.
> + *
> + * Return: A pointer to the remote pad, or one of the following error pointers
> + * if an error occurs:
> + *
> + * * -ENOTUNIQ - Multiple links are enabled
> + * * -ENOLINK - No connected pad found
> + */
> +struct media_pad *
> +media_entity_remote_pad_unique(const struct media_entity *entity,
> +			       unsigned int type);
> +
> +/**
> + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
> + * @entity: The entity
> + *
> + * Search for and return a remote source pad connected to @entity through an
> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> + * is returned.
> + *
> + * The uniqueness constraint makes this helper function suitable for entities
> + * that support a single active source at a time.
> + *
> + * Return: A pointer to the remote pad, or one of the following error pointers
> + * if an error occurs:
> + *
> + * * -ENOTUNIQ - Multiple links are enabled
> + * * -ENOLINK - No connected pad found
> + */
> +static inline struct media_pad *
> +media_entity_remote_source_pad(const struct media_entity *entity)
> +{
> +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
> +}
> +
>  /**
>   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
>   * @entity: The entity
Daniel Scally June 17, 2022, 10:33 p.m. UTC | #5
On 17/06/2022 22:34, Daniel Scally wrote:
> Hello all
>
> On 14/06/2022 20:11, Paul Elder wrote:
>> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>
>> The media_entity_remote_pad() helper function returns the first remote
>> pad it find connected to a given pad. Beside being possibly ill-named
>> (as it operates on a pad, not an entity) and non-deterministic (as it
>> stops at the first enabled link), the fact that it returns the first
>> match makes it unsuitable for drivers that need to guarantee that a
>> single link is enabled, for instance when an entity can process data
>> from one of multiple sources at a time.
>>
>> For those use cases, add a new helper function,
>> media_entity_remote_pad_unique(), that operates on an entity and returns
>> a remote pad, with a guarantee that only one link is enabled. To ease
>> its use in drivers, also add an inline wrapper that locates source pads
>> specifically. A wrapper that locates sink pads can easily be added when
>> needed.
>>
>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> ---
>>  Documentation/driver-api/media/mc-core.rst |  4 +-
>>  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
>>  include/media/media-entity.h               | 45 ++++++++++++++++++++++
>>  3 files changed, 85 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
>> index 02481a2513b9..a2d1e32e3abb 100644
>> --- a/Documentation/driver-api/media/mc-core.rst
>> +++ b/Documentation/driver-api/media/mc-core.rst
>> @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
>>  
>>  Helper functions can be used to find a link between two given pads, or a pad
>>  connected to another pad through an enabled link
>> -:c:func:`media_entity_find_link()` and
>> -:c:func:`media_entity_remote_pad()`.
>> +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
>> +:c:func:`media_entity_remote_source_pad()`).
>>  
>>  Use count and power handling
>>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
>> index 11f5207f73aa..1febf5a86be6 100644
>> --- a/drivers/media/mc/mc-entity.c
>> +++ b/drivers/media/mc/mc-entity.c
>> @@ -9,6 +9,7 @@
>>   */
>>  
>>  #include <linux/bitmap.h>
>> +#include <linux/list.h>
>>  #include <linux/property.h>
>>  #include <linux/slab.h>
>>  #include <media/media-entity.h>
>> @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
>>  }
>>  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
>>  
>> +struct media_pad *
>> +media_entity_remote_pad_unique(const struct media_entity *entity,
>> +			       unsigned int type)
>> +{
>> +	struct media_pad *pad = NULL;
>> +	struct media_link *link;
>> +
>> +	list_for_each_entry(link, &entity->links, list) {
>> +		struct media_pad *local_pad;
>> +		struct media_pad *remote_pad;
>> +
>> +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
>> +			continue;
> Does this need another guard here to make sure the link isn't an
> ancillary link? Only likely to happen at least in the immediate future
> where the entity represents a camera sensor, so possibly not applicable
> here - I couldn't find where the new function is used in the series to
> check. I _think_ it would actually work ok regardless...media_gobj
> type-punning makes my brain ache, but I think the local_pad->entity ==
> entity comparison would actually compare the entity->name member of the
> entity at the end of an ancillary link to the entity parameter, not find
> a match and so continue the loop without failing, but that feels a bit
> sub-optimal.
>

Or perhaps a better approach would be to provide something like a
"list_for_each_data_link()" iterator - the potential problem here (as
with Quentin's recent issue with the rkisp1 driver) is the assumption
that all links are data links, so maybe it's best to just guarantee that
if we can.

>
>> +
>> +		if (type == MEDIA_PAD_FL_SOURCE) {
>> +			local_pad = link->sink;
>> +			remote_pad = link->source;
>> +		} else {
>> +			local_pad = link->source;
>> +			remote_pad = link->sink;
>> +		}
>> +
>> +		if (local_pad->entity == entity) {
>> +			if (pad)
>> +				return ERR_PTR(-ENOTUNIQ);
>> +
>> +			pad = remote_pad;
>> +		}
>> +	}
>> +
>> +	if (!pad)
>> +		return ERR_PTR(-ENOLINK);
>> +
>> +	return pad;
>> +}
>> +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
>> +
>>  static void media_interface_init(struct media_device *mdev,
>>  				 struct media_interface *intf,
>>  				 u32 gobj_type,
>> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
>> index a9a1c0ec5d1c..33d5f52719a0 100644
>> --- a/include/media/media-entity.h
>> +++ b/include/media/media-entity.h
>> @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
>>   */
>>  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
>>  
>> +/**
>> + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
>> + * @entity: The entity
>> + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
>> + *
>> + * Search for and return a remote pad of @type connected to @entity through an
>> + * enabled link. If multiple (or no) remote pads match these criteria, an error
>> + * is returned.
>> + *
>> + * The uniqueness constraint makes this helper function suitable for entities
>> + * that support a single active source or sink at a time.
>> + *
>> + * Return: A pointer to the remote pad, or one of the following error pointers
>> + * if an error occurs:
>> + *
>> + * * -ENOTUNIQ - Multiple links are enabled
>> + * * -ENOLINK - No connected pad found
>> + */
>> +struct media_pad *
>> +media_entity_remote_pad_unique(const struct media_entity *entity,
>> +			       unsigned int type);
>> +
>> +/**
>> + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
>> + * @entity: The entity
>> + *
>> + * Search for and return a remote source pad connected to @entity through an
>> + * enabled link. If multiple (or no) remote pads match these criteria, an error
>> + * is returned.
>> + *
>> + * The uniqueness constraint makes this helper function suitable for entities
>> + * that support a single active source at a time.
>> + *
>> + * Return: A pointer to the remote pad, or one of the following error pointers
>> + * if an error occurs:
>> + *
>> + * * -ENOTUNIQ - Multiple links are enabled
>> + * * -ENOLINK - No connected pad found
>> + */
>> +static inline struct media_pad *
>> +media_entity_remote_source_pad(const struct media_entity *entity)
>> +{
>> +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
>> +}
>> +
>>  /**
>>   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
>>   * @entity: The entity
Laurent Pinchart June 17, 2022, 10:40 p.m. UTC | #6
Hi Daniel,

On Fri, Jun 17, 2022 at 11:33:03PM +0100, Daniel Scally wrote:
> On 17/06/2022 22:34, Daniel Scally wrote:
> > On 14/06/2022 20:11, Paul Elder wrote:
> >> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >>
> >> The media_entity_remote_pad() helper function returns the first remote
> >> pad it find connected to a given pad. Beside being possibly ill-named
> >> (as it operates on a pad, not an entity) and non-deterministic (as it
> >> stops at the first enabled link), the fact that it returns the first
> >> match makes it unsuitable for drivers that need to guarantee that a
> >> single link is enabled, for instance when an entity can process data
> >> from one of multiple sources at a time.
> >>
> >> For those use cases, add a new helper function,
> >> media_entity_remote_pad_unique(), that operates on an entity and returns
> >> a remote pad, with a guarantee that only one link is enabled. To ease
> >> its use in drivers, also add an inline wrapper that locates source pads
> >> specifically. A wrapper that locates sink pads can easily be added when
> >> needed.
> >>
> >> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >> ---
> >>  Documentation/driver-api/media/mc-core.rst |  4 +-
> >>  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
> >>  include/media/media-entity.h               | 45 ++++++++++++++++++++++
> >>  3 files changed, 85 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
> >> index 02481a2513b9..a2d1e32e3abb 100644
> >> --- a/Documentation/driver-api/media/mc-core.rst
> >> +++ b/Documentation/driver-api/media/mc-core.rst
> >> @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
> >>  
> >>  Helper functions can be used to find a link between two given pads, or a pad
> >>  connected to another pad through an enabled link
> >> -:c:func:`media_entity_find_link()` and
> >> -:c:func:`media_entity_remote_pad()`.
> >> +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
> >> +:c:func:`media_entity_remote_source_pad()`).
> >>  
> >>  Use count and power handling
> >>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >> diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
> >> index 11f5207f73aa..1febf5a86be6 100644
> >> --- a/drivers/media/mc/mc-entity.c
> >> +++ b/drivers/media/mc/mc-entity.c
> >> @@ -9,6 +9,7 @@
> >>   */
> >>  
> >>  #include <linux/bitmap.h>
> >> +#include <linux/list.h>
> >>  #include <linux/property.h>
> >>  #include <linux/slab.h>
> >>  #include <media/media-entity.h>
> >> @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
> >>  }
> >>  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
> >>  
> >> +struct media_pad *
> >> +media_entity_remote_pad_unique(const struct media_entity *entity,
> >> +			       unsigned int type)
> >> +{
> >> +	struct media_pad *pad = NULL;
> >> +	struct media_link *link;
> >> +
> >> +	list_for_each_entry(link, &entity->links, list) {
> >> +		struct media_pad *local_pad;
> >> +		struct media_pad *remote_pad;
> >> +
> >> +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
> >> +			continue;
> > 
> > Does this need another guard here to make sure the link isn't an
> > ancillary link? Only likely to happen at least in the immediate future
> > where the entity represents a camera sensor, so possibly not applicable
> > here - I couldn't find where the new function is used in the series to
> > check. I _think_ it would actually work ok regardless...media_gobj
> > type-punning makes my brain ache, but I think the local_pad->entity ==
> > entity comparison would actually compare the entity->name member of the
> > entity at the end of an ancillary link to the entity parameter, not find
> > a match and so continue the loop without failing, but that feels a bit
> > sub-optimal.
> 
> Or perhaps a better approach would be to provide something like a
> "list_for_each_data_link()" iterator - the potential problem here (as
> with Quentin's recent issue with the rkisp1 driver) is the assumption
> that all links are data links, so maybe it's best to just guarantee that
> if we can.

I agree with you, without a dedicated iterator, we're bound to repeat
the mistake over and over.

Would you like to submit a patch to add that iterator, or should I ? I'd
name it for_each_media_entity_data_link() or something similar.

> >> +
> >> +		if (type == MEDIA_PAD_FL_SOURCE) {
> >> +			local_pad = link->sink;
> >> +			remote_pad = link->source;
> >> +		} else {
> >> +			local_pad = link->source;
> >> +			remote_pad = link->sink;
> >> +		}
> >> +
> >> +		if (local_pad->entity == entity) {
> >> +			if (pad)
> >> +				return ERR_PTR(-ENOTUNIQ);
> >> +
> >> +			pad = remote_pad;
> >> +		}
> >> +	}
> >> +
> >> +	if (!pad)
> >> +		return ERR_PTR(-ENOLINK);
> >> +
> >> +	return pad;
> >> +}
> >> +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
> >> +
> >>  static void media_interface_init(struct media_device *mdev,
> >>  				 struct media_interface *intf,
> >>  				 u32 gobj_type,
> >> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> >> index a9a1c0ec5d1c..33d5f52719a0 100644
> >> --- a/include/media/media-entity.h
> >> +++ b/include/media/media-entity.h
> >> @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
> >>   */
> >>  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
> >>  
> >> +/**
> >> + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
> >> + * @entity: The entity
> >> + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
> >> + *
> >> + * Search for and return a remote pad of @type connected to @entity through an
> >> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> >> + * is returned.
> >> + *
> >> + * The uniqueness constraint makes this helper function suitable for entities
> >> + * that support a single active source or sink at a time.
> >> + *
> >> + * Return: A pointer to the remote pad, or one of the following error pointers
> >> + * if an error occurs:
> >> + *
> >> + * * -ENOTUNIQ - Multiple links are enabled
> >> + * * -ENOLINK - No connected pad found
> >> + */
> >> +struct media_pad *
> >> +media_entity_remote_pad_unique(const struct media_entity *entity,
> >> +			       unsigned int type);
> >> +
> >> +/**
> >> + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
> >> + * @entity: The entity
> >> + *
> >> + * Search for and return a remote source pad connected to @entity through an
> >> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> >> + * is returned.
> >> + *
> >> + * The uniqueness constraint makes this helper function suitable for entities
> >> + * that support a single active source at a time.
> >> + *
> >> + * Return: A pointer to the remote pad, or one of the following error pointers
> >> + * if an error occurs:
> >> + *
> >> + * * -ENOTUNIQ - Multiple links are enabled
> >> + * * -ENOLINK - No connected pad found
> >> + */
> >> +static inline struct media_pad *
> >> +media_entity_remote_source_pad(const struct media_entity *entity)
> >> +{
> >> +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
> >> +}
> >> +
> >>  /**
> >>   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
> >>   * @entity: The entity
Daniel Scally June 18, 2022, 9:35 a.m. UTC | #7
Morning Laurent

On 17/06/2022 23:40, Laurent Pinchart wrote:
> Hi Daniel,
>
> On Fri, Jun 17, 2022 at 11:33:03PM +0100, Daniel Scally wrote:
>> On 17/06/2022 22:34, Daniel Scally wrote:
>>> On 14/06/2022 20:11, Paul Elder wrote:
>>>> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>>>
>>>> The media_entity_remote_pad() helper function returns the first remote
>>>> pad it find connected to a given pad. Beside being possibly ill-named
>>>> (as it operates on a pad, not an entity) and non-deterministic (as it
>>>> stops at the first enabled link), the fact that it returns the first
>>>> match makes it unsuitable for drivers that need to guarantee that a
>>>> single link is enabled, for instance when an entity can process data
>>>> from one of multiple sources at a time.
>>>>
>>>> For those use cases, add a new helper function,
>>>> media_entity_remote_pad_unique(), that operates on an entity and returns
>>>> a remote pad, with a guarantee that only one link is enabled. To ease
>>>> its use in drivers, also add an inline wrapper that locates source pads
>>>> specifically. A wrapper that locates sink pads can easily be added when
>>>> needed.
>>>>
>>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>>> ---
>>>>  Documentation/driver-api/media/mc-core.rst |  4 +-
>>>>  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
>>>>  include/media/media-entity.h               | 45 ++++++++++++++++++++++
>>>>  3 files changed, 85 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
>>>> index 02481a2513b9..a2d1e32e3abb 100644
>>>> --- a/Documentation/driver-api/media/mc-core.rst
>>>> +++ b/Documentation/driver-api/media/mc-core.rst
>>>> @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
>>>>  
>>>>  Helper functions can be used to find a link between two given pads, or a pad
>>>>  connected to another pad through an enabled link
>>>> -:c:func:`media_entity_find_link()` and
>>>> -:c:func:`media_entity_remote_pad()`.
>>>> +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
>>>> +:c:func:`media_entity_remote_source_pad()`).
>>>>  
>>>>  Use count and power handling
>>>>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>>> diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
>>>> index 11f5207f73aa..1febf5a86be6 100644
>>>> --- a/drivers/media/mc/mc-entity.c
>>>> +++ b/drivers/media/mc/mc-entity.c
>>>> @@ -9,6 +9,7 @@
>>>>   */
>>>>  
>>>>  #include <linux/bitmap.h>
>>>> +#include <linux/list.h>
>>>>  #include <linux/property.h>
>>>>  #include <linux/slab.h>
>>>>  #include <media/media-entity.h>
>>>> @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
>>>>  }
>>>>  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
>>>>  
>>>> +struct media_pad *
>>>> +media_entity_remote_pad_unique(const struct media_entity *entity,
>>>> +			       unsigned int type)
>>>> +{
>>>> +	struct media_pad *pad = NULL;
>>>> +	struct media_link *link;
>>>> +
>>>> +	list_for_each_entry(link, &entity->links, list) {
>>>> +		struct media_pad *local_pad;
>>>> +		struct media_pad *remote_pad;
>>>> +
>>>> +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
>>>> +			continue;
>>> Does this need another guard here to make sure the link isn't an
>>> ancillary link? Only likely to happen at least in the immediate future
>>> where the entity represents a camera sensor, so possibly not applicable
>>> here - I couldn't find where the new function is used in the series to
>>> check. I _think_ it would actually work ok regardless...media_gobj
>>> type-punning makes my brain ache, but I think the local_pad->entity ==
>>> entity comparison would actually compare the entity->name member of the
>>> entity at the end of an ancillary link to the entity parameter, not find
>>> a match and so continue the loop without failing, but that feels a bit
>>> sub-optimal.
>> Or perhaps a better approach would be to provide something like a
>> "list_for_each_data_link()" iterator - the potential problem here (as
>> with Quentin's recent issue with the rkisp1 driver) is the assumption
>> that all links are data links, so maybe it's best to just guarantee that
>> if we can.
> I agree with you, without a dedicated iterator, we're bound to repeat
> the mistake over and over.
>
> Would you like to submit a patch to add that iterator, or should I ? I'd
> name it for_each_media_entity_data_link() or something similar.


I've started one - I'll send it later (using your function name though,
naming things was never my strong suit!)

>
>>>> +
>>>> +		if (type == MEDIA_PAD_FL_SOURCE) {
>>>> +			local_pad = link->sink;
>>>> +			remote_pad = link->source;
>>>> +		} else {
>>>> +			local_pad = link->source;
>>>> +			remote_pad = link->sink;
>>>> +		}
>>>> +
>>>> +		if (local_pad->entity == entity) {
>>>> +			if (pad)
>>>> +				return ERR_PTR(-ENOTUNIQ);
>>>> +
>>>> +			pad = remote_pad;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	if (!pad)
>>>> +		return ERR_PTR(-ENOLINK);
>>>> +
>>>> +	return pad;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
>>>> +
>>>>  static void media_interface_init(struct media_device *mdev,
>>>>  				 struct media_interface *intf,
>>>>  				 u32 gobj_type,
>>>> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
>>>> index a9a1c0ec5d1c..33d5f52719a0 100644
>>>> --- a/include/media/media-entity.h
>>>> +++ b/include/media/media-entity.h
>>>> @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
>>>>   */
>>>>  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
>>>>  
>>>> +/**
>>>> + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
>>>> + * @entity: The entity
>>>> + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
>>>> + *
>>>> + * Search for and return a remote pad of @type connected to @entity through an
>>>> + * enabled link. If multiple (or no) remote pads match these criteria, an error
>>>> + * is returned.
>>>> + *
>>>> + * The uniqueness constraint makes this helper function suitable for entities
>>>> + * that support a single active source or sink at a time.
>>>> + *
>>>> + * Return: A pointer to the remote pad, or one of the following error pointers
>>>> + * if an error occurs:
>>>> + *
>>>> + * * -ENOTUNIQ - Multiple links are enabled
>>>> + * * -ENOLINK - No connected pad found
>>>> + */
>>>> +struct media_pad *
>>>> +media_entity_remote_pad_unique(const struct media_entity *entity,
>>>> +			       unsigned int type);
>>>> +
>>>> +/**
>>>> + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
>>>> + * @entity: The entity
>>>> + *
>>>> + * Search for and return a remote source pad connected to @entity through an
>>>> + * enabled link. If multiple (or no) remote pads match these criteria, an error
>>>> + * is returned.
>>>> + *
>>>> + * The uniqueness constraint makes this helper function suitable for entities
>>>> + * that support a single active source at a time.
>>>> + *
>>>> + * Return: A pointer to the remote pad, or one of the following error pointers
>>>> + * if an error occurs:
>>>> + *
>>>> + * * -ENOTUNIQ - Multiple links are enabled
>>>> + * * -ENOLINK - No connected pad found
>>>> + */
>>>> +static inline struct media_pad *
>>>> +media_entity_remote_source_pad(const struct media_entity *entity)
>>>> +{
>>>> +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
>>>> +}
>>>> +
>>>>  /**
>>>>   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
>>>>   * @entity: The entity
Laurent Pinchart June 25, 2022, 5 p.m. UTC | #8
Hi Hans,

On Fri, Jun 17, 2022 at 01:48:05PM +0200, Hans Verkuil wrote:
> On 6/14/22 21:11, Paul Elder wrote:
> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > 
> > The media_entity_remote_pad() helper function returns the first remote
> > pad it find connected to a given pad. Beside being possibly ill-named
> > (as it operates on a pad, not an entity) and non-deterministic (as it
> > stops at the first enabled link), the fact that it returns the first
> > match makes it unsuitable for drivers that need to guarantee that a
> > single link is enabled, for instance when an entity can process data
> > from one of multiple sources at a time.
> 
> Question: of all the callers of this function, are there any that really
> need media_entity_remote_pad() instead of media_pad_remote_pad_unique()?
> 
> Would it be possible to replace all callers of the old function with the
> new function? If that's the case, then the _unique suffix can be dropped,
> since that would effectively be the default. And if a function is needed
> to handle the case where there are multiple enabled links, then a new
> function should be created.

I don't think so. media_entity_remote_pad() operates on a pad, switching
to media_pad_remote_pad_unique() wouldn't work on subdevs that have
multiple sink or source pads with one active link each.

> Also, media_entity_remote_pad() should really be renamed to
> media_pad_remote_pad_first() or something like that, right? I'm not saying
> you should, but that's really what it does, as I understand it.

Yes, I think that would make sense, and it would freethe
media_entity_remote_pad() name, so the new function wouldn't need the
_unique suffix. I'll give it a try.

> > For those use cases, add a new helper function,
> > media_entity_remote_pad_unique(), that operates on an entity and returns
> > a remote pad, with a guarantee that only one link is enabled. To ease
> > its use in drivers, also add an inline wrapper that locates source pads
> > specifically. A wrapper that locates sink pads can easily be added when
> > needed.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  Documentation/driver-api/media/mc-core.rst |  4 +-
> >  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
> >  include/media/media-entity.h               | 45 ++++++++++++++++++++++
> >  3 files changed, 85 insertions(+), 2 deletions(-)
> > 
> > diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
> > index 02481a2513b9..a2d1e32e3abb 100644
> > --- a/Documentation/driver-api/media/mc-core.rst
> > +++ b/Documentation/driver-api/media/mc-core.rst
> > @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
> >  
> >  Helper functions can be used to find a link between two given pads, or a pad
> >  connected to another pad through an enabled link
> > -:c:func:`media_entity_find_link()` and
> > -:c:func:`media_entity_remote_pad()`.
> > +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
> > +:c:func:`media_entity_remote_source_pad()`).
> >  
> >  Use count and power handling
> >  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
> > index 11f5207f73aa..1febf5a86be6 100644
> > --- a/drivers/media/mc/mc-entity.c
> > +++ b/drivers/media/mc/mc-entity.c
> > @@ -9,6 +9,7 @@
> >   */
> >  
> >  #include <linux/bitmap.h>
> > +#include <linux/list.h>
> >  #include <linux/property.h>
> >  #include <linux/slab.h>
> >  #include <media/media-entity.h>
> > @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
> >  }
> >  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
> >  
> > +struct media_pad *
> > +media_entity_remote_pad_unique(const struct media_entity *entity,
> > +			       unsigned int type)
> > +{
> > +	struct media_pad *pad = NULL;
> > +	struct media_link *link;
> > +
> > +	list_for_each_entry(link, &entity->links, list) {
> > +		struct media_pad *local_pad;
> > +		struct media_pad *remote_pad;
> > +
> > +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
> > +			continue;
> > +
> > +		if (type == MEDIA_PAD_FL_SOURCE) {
> > +			local_pad = link->sink;
> > +			remote_pad = link->source;
> > +		} else {
> > +			local_pad = link->source;
> > +			remote_pad = link->sink;
> > +		}
> > +
> > +		if (local_pad->entity == entity) {
> > +			if (pad)
> > +				return ERR_PTR(-ENOTUNIQ);
> > +
> > +			pad = remote_pad;
> > +		}
> > +	}
> > +
> > +	if (!pad)
> > +		return ERR_PTR(-ENOLINK);
> > +
> > +	return pad;
> > +}
> > +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
> > +
> >  static void media_interface_init(struct media_device *mdev,
> >  				 struct media_interface *intf,
> >  				 u32 gobj_type,
> > diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> > index a9a1c0ec5d1c..33d5f52719a0 100644
> > --- a/include/media/media-entity.h
> > +++ b/include/media/media-entity.h
> > @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
> >   */
> >  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
> >  
> > +/**
> > + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
> > + * @entity: The entity
> > + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
> > + *
> > + * Search for and return a remote pad of @type connected to @entity through an
> > + * enabled link. If multiple (or no) remote pads match these criteria, an error
> > + * is returned.
> > + *
> > + * The uniqueness constraint makes this helper function suitable for entities
> > + * that support a single active source or sink at a time.
> > + *
> > + * Return: A pointer to the remote pad, or one of the following error pointers
> > + * if an error occurs:
> > + *
> > + * * -ENOTUNIQ - Multiple links are enabled
> > + * * -ENOLINK - No connected pad found
> > + */
> > +struct media_pad *
> > +media_entity_remote_pad_unique(const struct media_entity *entity,
> > +			       unsigned int type);
> > +
> > +/**
> > + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
> > + * @entity: The entity
> > + *
> > + * Search for and return a remote source pad connected to @entity through an
> > + * enabled link. If multiple (or no) remote pads match these criteria, an error
> > + * is returned.
> > + *
> > + * The uniqueness constraint makes this helper function suitable for entities
> > + * that support a single active source at a time.
> > + *
> > + * Return: A pointer to the remote pad, or one of the following error pointers
> > + * if an error occurs:
> > + *
> > + * * -ENOTUNIQ - Multiple links are enabled
> > + * * -ENOLINK - No connected pad found
> > + */
> > +static inline struct media_pad *
> > +media_entity_remote_source_pad(const struct media_entity *entity)
> > +{
> > +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
> > +}
> > +
> >  /**
> >   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
> >   * @entity: The entity
Laurent Pinchart June 25, 2022, 5:28 p.m. UTC | #9
Hi Hans,

On Sat, Jun 25, 2022 at 08:00:51PM +0300, Laurent Pinchart wrote:
> On Fri, Jun 17, 2022 at 01:48:05PM +0200, Hans Verkuil wrote:
> > On 6/14/22 21:11, Paul Elder wrote:
> > > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > 
> > > The media_entity_remote_pad() helper function returns the first remote
> > > pad it find connected to a given pad. Beside being possibly ill-named
> > > (as it operates on a pad, not an entity) and non-deterministic (as it
> > > stops at the first enabled link), the fact that it returns the first
> > > match makes it unsuitable for drivers that need to guarantee that a
> > > single link is enabled, for instance when an entity can process data
> > > from one of multiple sources at a time.
> > 
> > Question: of all the callers of this function, are there any that really
> > need media_entity_remote_pad() instead of media_pad_remote_pad_unique()?
> > 
> > Would it be possible to replace all callers of the old function with the
> > new function? If that's the case, then the _unique suffix can be dropped,
> > since that would effectively be the default. And if a function is needed
> > to handle the case where there are multiple enabled links, then a new
> > function should be created.
> 
> I don't think so. media_entity_remote_pad() operates on a pad, switching
> to media_pad_remote_pad_unique() wouldn't work on subdevs that have
> multiple sink or source pads with one active link each.
> 
> > Also, media_entity_remote_pad() should really be renamed to
> > media_pad_remote_pad_first() or something like that, right? I'm not saying
> > you should, but that's really what it does, as I understand it.
> 
> Yes, I think that would make sense, and it would freethe
> media_entity_remote_pad() name, so the new function wouldn't need the
> _unique suffix. I'll give it a try.

The rename was easy enough, but I've decided to keep the
media_entity_remote_pad_unique() name and renamed
media_entity_remote_source_pad() to
media_entity_remote_source_pad_unique() to make the API clearer. If
those names end up being too long, we can rename them later.

> > > For those use cases, add a new helper function,
> > > media_entity_remote_pad_unique(), that operates on an entity and returns
> > > a remote pad, with a guarantee that only one link is enabled. To ease
> > > its use in drivers, also add an inline wrapper that locates source pads
> > > specifically. A wrapper that locates sink pads can easily be added when
> > > needed.
> > > 
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > ---
> > >  Documentation/driver-api/media/mc-core.rst |  4 +-
> > >  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
> > >  include/media/media-entity.h               | 45 ++++++++++++++++++++++
> > >  3 files changed, 85 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
> > > index 02481a2513b9..a2d1e32e3abb 100644
> > > --- a/Documentation/driver-api/media/mc-core.rst
> > > +++ b/Documentation/driver-api/media/mc-core.rst
> > > @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
> > >  
> > >  Helper functions can be used to find a link between two given pads, or a pad
> > >  connected to another pad through an enabled link
> > > -:c:func:`media_entity_find_link()` and
> > > -:c:func:`media_entity_remote_pad()`.
> > > +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
> > > +:c:func:`media_entity_remote_source_pad()`).
> > >  
> > >  Use count and power handling
> > >  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > > diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
> > > index 11f5207f73aa..1febf5a86be6 100644
> > > --- a/drivers/media/mc/mc-entity.c
> > > +++ b/drivers/media/mc/mc-entity.c
> > > @@ -9,6 +9,7 @@
> > >   */
> > >  
> > >  #include <linux/bitmap.h>
> > > +#include <linux/list.h>
> > >  #include <linux/property.h>
> > >  #include <linux/slab.h>
> > >  #include <media/media-entity.h>
> > > @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
> > >  }
> > >  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
> > >  
> > > +struct media_pad *
> > > +media_entity_remote_pad_unique(const struct media_entity *entity,
> > > +			       unsigned int type)
> > > +{
> > > +	struct media_pad *pad = NULL;
> > > +	struct media_link *link;
> > > +
> > > +	list_for_each_entry(link, &entity->links, list) {
> > > +		struct media_pad *local_pad;
> > > +		struct media_pad *remote_pad;
> > > +
> > > +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
> > > +			continue;
> > > +
> > > +		if (type == MEDIA_PAD_FL_SOURCE) {
> > > +			local_pad = link->sink;
> > > +			remote_pad = link->source;
> > > +		} else {
> > > +			local_pad = link->source;
> > > +			remote_pad = link->sink;
> > > +		}
> > > +
> > > +		if (local_pad->entity == entity) {
> > > +			if (pad)
> > > +				return ERR_PTR(-ENOTUNIQ);
> > > +
> > > +			pad = remote_pad;
> > > +		}
> > > +	}
> > > +
> > > +	if (!pad)
> > > +		return ERR_PTR(-ENOLINK);
> > > +
> > > +	return pad;
> > > +}
> > > +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
> > > +
> > >  static void media_interface_init(struct media_device *mdev,
> > >  				 struct media_interface *intf,
> > >  				 u32 gobj_type,
> > > diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> > > index a9a1c0ec5d1c..33d5f52719a0 100644
> > > --- a/include/media/media-entity.h
> > > +++ b/include/media/media-entity.h
> > > @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
> > >   */
> > >  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
> > >  
> > > +/**
> > > + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
> > > + * @entity: The entity
> > > + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
> > > + *
> > > + * Search for and return a remote pad of @type connected to @entity through an
> > > + * enabled link. If multiple (or no) remote pads match these criteria, an error
> > > + * is returned.
> > > + *
> > > + * The uniqueness constraint makes this helper function suitable for entities
> > > + * that support a single active source or sink at a time.
> > > + *
> > > + * Return: A pointer to the remote pad, or one of the following error pointers
> > > + * if an error occurs:
> > > + *
> > > + * * -ENOTUNIQ - Multiple links are enabled
> > > + * * -ENOLINK - No connected pad found
> > > + */
> > > +struct media_pad *
> > > +media_entity_remote_pad_unique(const struct media_entity *entity,
> > > +			       unsigned int type);
> > > +
> > > +/**
> > > + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
> > > + * @entity: The entity
> > > + *
> > > + * Search for and return a remote source pad connected to @entity through an
> > > + * enabled link. If multiple (or no) remote pads match these criteria, an error
> > > + * is returned.
> > > + *
> > > + * The uniqueness constraint makes this helper function suitable for entities
> > > + * that support a single active source at a time.
> > > + *
> > > + * Return: A pointer to the remote pad, or one of the following error pointers
> > > + * if an error occurs:
> > > + *
> > > + * * -ENOTUNIQ - Multiple links are enabled
> > > + * * -ENOLINK - No connected pad found
> > > + */
> > > +static inline struct media_pad *
> > > +media_entity_remote_source_pad(const struct media_entity *entity)
> > > +{
> > > +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
> > > +}
> > > +
> > >  /**
> > >   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
> > >   * @entity: The entity
Laurent Pinchart June 25, 2022, 5:34 p.m. UTC | #10
Hi Dan,

On Sat, Jun 18, 2022 at 10:35:12AM +0100, Daniel Scally wrote:
> On 17/06/2022 23:40, Laurent Pinchart wrote:
> > On Fri, Jun 17, 2022 at 11:33:03PM +0100, Daniel Scally wrote:
> >> On 17/06/2022 22:34, Daniel Scally wrote:
> >>> On 14/06/2022 20:11, Paul Elder wrote:
> >>>> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >>>>
> >>>> The media_entity_remote_pad() helper function returns the first remote
> >>>> pad it find connected to a given pad. Beside being possibly ill-named
> >>>> (as it operates on a pad, not an entity) and non-deterministic (as it
> >>>> stops at the first enabled link), the fact that it returns the first
> >>>> match makes it unsuitable for drivers that need to guarantee that a
> >>>> single link is enabled, for instance when an entity can process data
> >>>> from one of multiple sources at a time.
> >>>>
> >>>> For those use cases, add a new helper function,
> >>>> media_entity_remote_pad_unique(), that operates on an entity and returns
> >>>> a remote pad, with a guarantee that only one link is enabled. To ease
> >>>> its use in drivers, also add an inline wrapper that locates source pads
> >>>> specifically. A wrapper that locates sink pads can easily be added when
> >>>> needed.
> >>>>
> >>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >>>> ---
> >>>>  Documentation/driver-api/media/mc-core.rst |  4 +-
> >>>>  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
> >>>>  include/media/media-entity.h               | 45 ++++++++++++++++++++++
> >>>>  3 files changed, 85 insertions(+), 2 deletions(-)
> >>>>
> >>>> diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
> >>>> index 02481a2513b9..a2d1e32e3abb 100644
> >>>> --- a/Documentation/driver-api/media/mc-core.rst
> >>>> +++ b/Documentation/driver-api/media/mc-core.rst
> >>>> @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
> >>>>  
> >>>>  Helper functions can be used to find a link between two given pads, or a pad
> >>>>  connected to another pad through an enabled link
> >>>> -:c:func:`media_entity_find_link()` and
> >>>> -:c:func:`media_entity_remote_pad()`.
> >>>> +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
> >>>> +:c:func:`media_entity_remote_source_pad()`).
> >>>>  
> >>>>  Use count and power handling
> >>>>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >>>> diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
> >>>> index 11f5207f73aa..1febf5a86be6 100644
> >>>> --- a/drivers/media/mc/mc-entity.c
> >>>> +++ b/drivers/media/mc/mc-entity.c
> >>>> @@ -9,6 +9,7 @@
> >>>>   */
> >>>>  
> >>>>  #include <linux/bitmap.h>
> >>>> +#include <linux/list.h>
> >>>>  #include <linux/property.h>
> >>>>  #include <linux/slab.h>
> >>>>  #include <media/media-entity.h>
> >>>> @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
> >>>>  }
> >>>>  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
> >>>>  
> >>>> +struct media_pad *
> >>>> +media_entity_remote_pad_unique(const struct media_entity *entity,
> >>>> +			       unsigned int type)
> >>>> +{
> >>>> +	struct media_pad *pad = NULL;
> >>>> +	struct media_link *link;
> >>>> +
> >>>> +	list_for_each_entry(link, &entity->links, list) {
> >>>> +		struct media_pad *local_pad;
> >>>> +		struct media_pad *remote_pad;
> >>>> +
> >>>> +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
> >>>> +			continue;
> >>> 
> >>> Does this need another guard here to make sure the link isn't an
> >>> ancillary link? Only likely to happen at least in the immediate future
> >>> where the entity represents a camera sensor, so possibly not applicable
> >>> here - I couldn't find where the new function is used in the series to
> >>> check. I _think_ it would actually work ok regardless...media_gobj
> >>> type-punning makes my brain ache, but I think the local_pad->entity ==
> >>> entity comparison would actually compare the entity->name member of the
> >>> entity at the end of an ancillary link to the entity parameter, not find
> >>> a match and so continue the loop without failing, but that feels a bit
> >>> sub-optimal.
> >> 
> >> Or perhaps a better approach would be to provide something like a
> >> "list_for_each_data_link()" iterator - the potential problem here (as
> >> with Quentin's recent issue with the rkisp1 driver) is the assumption
> >> that all links are data links, so maybe it's best to just guarantee that
> >> if we can.
> >> 
> > I agree with you, without a dedicated iterator, we're bound to repeat
> > the mistake over and over.
> >
> > Would you like to submit a patch to add that iterator, or should I ? I'd
> > name it for_each_media_entity_data_link() or something similar.
> 
> I've started one - I'll send it later (using your function name though,
> naming things was never my strong suit!)

I've modified this patch to skip non-data links manually, to avoid
depending on your series. If the iterator gets merged first, I'll update
the media_entity_remote_pad_unique() helper to use it.

> >>>> +
> >>>> +		if (type == MEDIA_PAD_FL_SOURCE) {
> >>>> +			local_pad = link->sink;
> >>>> +			remote_pad = link->source;
> >>>> +		} else {
> >>>> +			local_pad = link->source;
> >>>> +			remote_pad = link->sink;
> >>>> +		}
> >>>> +
> >>>> +		if (local_pad->entity == entity) {
> >>>> +			if (pad)
> >>>> +				return ERR_PTR(-ENOTUNIQ);
> >>>> +
> >>>> +			pad = remote_pad;
> >>>> +		}
> >>>> +	}
> >>>> +
> >>>> +	if (!pad)
> >>>> +		return ERR_PTR(-ENOLINK);
> >>>> +
> >>>> +	return pad;
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
> >>>> +
> >>>>  static void media_interface_init(struct media_device *mdev,
> >>>>  				 struct media_interface *intf,
> >>>>  				 u32 gobj_type,
> >>>> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> >>>> index a9a1c0ec5d1c..33d5f52719a0 100644
> >>>> --- a/include/media/media-entity.h
> >>>> +++ b/include/media/media-entity.h
> >>>> @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
> >>>>   */
> >>>>  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
> >>>>  
> >>>> +/**
> >>>> + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
> >>>> + * @entity: The entity
> >>>> + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
> >>>> + *
> >>>> + * Search for and return a remote pad of @type connected to @entity through an
> >>>> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> >>>> + * is returned.
> >>>> + *
> >>>> + * The uniqueness constraint makes this helper function suitable for entities
> >>>> + * that support a single active source or sink at a time.
> >>>> + *
> >>>> + * Return: A pointer to the remote pad, or one of the following error pointers
> >>>> + * if an error occurs:
> >>>> + *
> >>>> + * * -ENOTUNIQ - Multiple links are enabled
> >>>> + * * -ENOLINK - No connected pad found
> >>>> + */
> >>>> +struct media_pad *
> >>>> +media_entity_remote_pad_unique(const struct media_entity *entity,
> >>>> +			       unsigned int type);
> >>>> +
> >>>> +/**
> >>>> + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
> >>>> + * @entity: The entity
> >>>> + *
> >>>> + * Search for and return a remote source pad connected to @entity through an
> >>>> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> >>>> + * is returned.
> >>>> + *
> >>>> + * The uniqueness constraint makes this helper function suitable for entities
> >>>> + * that support a single active source at a time.
> >>>> + *
> >>>> + * Return: A pointer to the remote pad, or one of the following error pointers
> >>>> + * if an error occurs:
> >>>> + *
> >>>> + * * -ENOTUNIQ - Multiple links are enabled
> >>>> + * * -ENOLINK - No connected pad found
> >>>> + */
> >>>> +static inline struct media_pad *
> >>>> +media_entity_remote_source_pad(const struct media_entity *entity)
> >>>> +{
> >>>> +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
> >>>> +}
> >>>> +
> >>>>  /**
> >>>>   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
> >>>>   * @entity: The entity
Hans Verkuil July 7, 2022, 6:52 a.m. UTC | #11
On 6/25/22 19:00, Laurent Pinchart wrote:
> Hi Hans,
> 
> On Fri, Jun 17, 2022 at 01:48:05PM +0200, Hans Verkuil wrote:
>> On 6/14/22 21:11, Paul Elder wrote:
>>> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>>
>>> The media_entity_remote_pad() helper function returns the first remote
>>> pad it find connected to a given pad. Beside being possibly ill-named
>>> (as it operates on a pad, not an entity) and non-deterministic (as it
>>> stops at the first enabled link), the fact that it returns the first
>>> match makes it unsuitable for drivers that need to guarantee that a
>>> single link is enabled, for instance when an entity can process data
>>> from one of multiple sources at a time.
>>
>> Question: of all the callers of this function, are there any that really
>> need media_entity_remote_pad() instead of media_pad_remote_pad_unique()?
>>
>> Would it be possible to replace all callers of the old function with the
>> new function? If that's the case, then the _unique suffix can be dropped,
>> since that would effectively be the default. And if a function is needed
>> to handle the case where there are multiple enabled links, then a new
>> function should be created.
> 
> I don't think so. media_entity_remote_pad() operates on a pad, switching
> to media_pad_remote_pad_unique() wouldn't work on subdevs that have
> multiple sink or source pads with one active link each.

Do we have those today in the mainline kernel? Just checking...

Regards,

	Hans

> 
>> Also, media_entity_remote_pad() should really be renamed to
>> media_pad_remote_pad_first() or something like that, right? I'm not saying
>> you should, but that's really what it does, as I understand it.
> 
> Yes, I think that would make sense, and it would freethe
> media_entity_remote_pad() name, so the new function wouldn't need the
> _unique suffix. I'll give it a try.
> 
>>> For those use cases, add a new helper function,
>>> media_entity_remote_pad_unique(), that operates on an entity and returns
>>> a remote pad, with a guarantee that only one link is enabled. To ease
>>> its use in drivers, also add an inline wrapper that locates source pads
>>> specifically. A wrapper that locates sink pads can easily be added when
>>> needed.
>>>
>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>> ---
>>>  Documentation/driver-api/media/mc-core.rst |  4 +-
>>>  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
>>>  include/media/media-entity.h               | 45 ++++++++++++++++++++++
>>>  3 files changed, 85 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
>>> index 02481a2513b9..a2d1e32e3abb 100644
>>> --- a/Documentation/driver-api/media/mc-core.rst
>>> +++ b/Documentation/driver-api/media/mc-core.rst
>>> @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
>>>  
>>>  Helper functions can be used to find a link between two given pads, or a pad
>>>  connected to another pad through an enabled link
>>> -:c:func:`media_entity_find_link()` and
>>> -:c:func:`media_entity_remote_pad()`.
>>> +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
>>> +:c:func:`media_entity_remote_source_pad()`).
>>>  
>>>  Use count and power handling
>>>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
>>> index 11f5207f73aa..1febf5a86be6 100644
>>> --- a/drivers/media/mc/mc-entity.c
>>> +++ b/drivers/media/mc/mc-entity.c
>>> @@ -9,6 +9,7 @@
>>>   */
>>>  
>>>  #include <linux/bitmap.h>
>>> +#include <linux/list.h>
>>>  #include <linux/property.h>
>>>  #include <linux/slab.h>
>>>  #include <media/media-entity.h>
>>> @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
>>>  }
>>>  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
>>>  
>>> +struct media_pad *
>>> +media_entity_remote_pad_unique(const struct media_entity *entity,
>>> +			       unsigned int type)
>>> +{
>>> +	struct media_pad *pad = NULL;
>>> +	struct media_link *link;
>>> +
>>> +	list_for_each_entry(link, &entity->links, list) {
>>> +		struct media_pad *local_pad;
>>> +		struct media_pad *remote_pad;
>>> +
>>> +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
>>> +			continue;
>>> +
>>> +		if (type == MEDIA_PAD_FL_SOURCE) {
>>> +			local_pad = link->sink;
>>> +			remote_pad = link->source;
>>> +		} else {
>>> +			local_pad = link->source;
>>> +			remote_pad = link->sink;
>>> +		}
>>> +
>>> +		if (local_pad->entity == entity) {
>>> +			if (pad)
>>> +				return ERR_PTR(-ENOTUNIQ);
>>> +
>>> +			pad = remote_pad;
>>> +		}
>>> +	}
>>> +
>>> +	if (!pad)
>>> +		return ERR_PTR(-ENOLINK);
>>> +
>>> +	return pad;
>>> +}
>>> +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
>>> +
>>>  static void media_interface_init(struct media_device *mdev,
>>>  				 struct media_interface *intf,
>>>  				 u32 gobj_type,
>>> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
>>> index a9a1c0ec5d1c..33d5f52719a0 100644
>>> --- a/include/media/media-entity.h
>>> +++ b/include/media/media-entity.h
>>> @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
>>>   */
>>>  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
>>>  
>>> +/**
>>> + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
>>> + * @entity: The entity
>>> + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
>>> + *
>>> + * Search for and return a remote pad of @type connected to @entity through an
>>> + * enabled link. If multiple (or no) remote pads match these criteria, an error
>>> + * is returned.
>>> + *
>>> + * The uniqueness constraint makes this helper function suitable for entities
>>> + * that support a single active source or sink at a time.
>>> + *
>>> + * Return: A pointer to the remote pad, or one of the following error pointers
>>> + * if an error occurs:
>>> + *
>>> + * * -ENOTUNIQ - Multiple links are enabled
>>> + * * -ENOLINK - No connected pad found
>>> + */
>>> +struct media_pad *
>>> +media_entity_remote_pad_unique(const struct media_entity *entity,
>>> +			       unsigned int type);
>>> +
>>> +/**
>>> + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
>>> + * @entity: The entity
>>> + *
>>> + * Search for and return a remote source pad connected to @entity through an
>>> + * enabled link. If multiple (or no) remote pads match these criteria, an error
>>> + * is returned.
>>> + *
>>> + * The uniqueness constraint makes this helper function suitable for entities
>>> + * that support a single active source at a time.
>>> + *
>>> + * Return: A pointer to the remote pad, or one of the following error pointers
>>> + * if an error occurs:
>>> + *
>>> + * * -ENOTUNIQ - Multiple links are enabled
>>> + * * -ENOLINK - No connected pad found
>>> + */
>>> +static inline struct media_pad *
>>> +media_entity_remote_source_pad(const struct media_entity *entity)
>>> +{
>>> +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
>>> +}
>>> +
>>>  /**
>>>   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
>>>   * @entity: The entity
>
Laurent Pinchart July 7, 2022, 11:50 a.m. UTC | #12
Hi Hans,

On Thu, Jul 07, 2022 at 08:52:16AM +0200, Hans Verkuil wrote:
> On 6/25/22 19:00, Laurent Pinchart wrote:
> > On Fri, Jun 17, 2022 at 01:48:05PM +0200, Hans Verkuil wrote:
> >> On 6/14/22 21:11, Paul Elder wrote:
> >>> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >>>
> >>> The media_entity_remote_pad() helper function returns the first remote
> >>> pad it find connected to a given pad. Beside being possibly ill-named
> >>> (as it operates on a pad, not an entity) and non-deterministic (as it
> >>> stops at the first enabled link), the fact that it returns the first
> >>> match makes it unsuitable for drivers that need to guarantee that a
> >>> single link is enabled, for instance when an entity can process data
> >>> from one of multiple sources at a time.
> >>
> >> Question: of all the callers of this function, are there any that really
> >> need media_entity_remote_pad() instead of media_pad_remote_pad_unique()?
> >>
> >> Would it be possible to replace all callers of the old function with the
> >> new function? If that's the case, then the _unique suffix can be dropped,
> >> since that would effectively be the default. And if a function is needed
> >> to handle the case where there are multiple enabled links, then a new
> >> function should be created.
> > 
> > I don't think so. media_entity_remote_pad() operates on a pad, switching
> > to media_pad_remote_pad_unique() wouldn't work on subdevs that have
> > multiple sink or source pads with one active link each.
> 
> Do we have those today in the mainline kernel? Just checking...

Re-reading my reply, it seems I may have been mistaken. We may be able
to ditch media_pad_remote_pad_first() and replace it with
media_pad_remote_pad_unique() (at least in the majority of cases), but
we'll need to carefully review each user.

> >> Also, media_entity_remote_pad() should really be renamed to
> >> media_pad_remote_pad_first() or something like that, right? I'm not saying
> >> you should, but that's really what it does, as I understand it.
> > 
> > Yes, I think that would make sense, and it would freethe
> > media_entity_remote_pad() name, so the new function wouldn't need the
> > _unique suffix. I'll give it a try.
> > 
> >>> For those use cases, add a new helper function,
> >>> media_entity_remote_pad_unique(), that operates on an entity and returns
> >>> a remote pad, with a guarantee that only one link is enabled. To ease
> >>> its use in drivers, also add an inline wrapper that locates source pads
> >>> specifically. A wrapper that locates sink pads can easily be added when
> >>> needed.
> >>>
> >>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >>> ---
> >>>  Documentation/driver-api/media/mc-core.rst |  4 +-
> >>>  drivers/media/mc/mc-entity.c               | 38 ++++++++++++++++++
> >>>  include/media/media-entity.h               | 45 ++++++++++++++++++++++
> >>>  3 files changed, 85 insertions(+), 2 deletions(-)
> >>>
> >>> diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
> >>> index 02481a2513b9..a2d1e32e3abb 100644
> >>> --- a/Documentation/driver-api/media/mc-core.rst
> >>> +++ b/Documentation/driver-api/media/mc-core.rst
> >>> @@ -186,8 +186,8 @@ is required and the graph structure can be freed normally.
> >>>  
> >>>  Helper functions can be used to find a link between two given pads, or a pad
> >>>  connected to another pad through an enabled link
> >>> -:c:func:`media_entity_find_link()` and
> >>> -:c:func:`media_entity_remote_pad()`.
> >>> +(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
> >>> +:c:func:`media_entity_remote_source_pad()`).
> >>>  
> >>>  Use count and power handling
> >>>  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >>> diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
> >>> index 11f5207f73aa..1febf5a86be6 100644
> >>> --- a/drivers/media/mc/mc-entity.c
> >>> +++ b/drivers/media/mc/mc-entity.c
> >>> @@ -9,6 +9,7 @@
> >>>   */
> >>>  
> >>>  #include <linux/bitmap.h>
> >>> +#include <linux/list.h>
> >>>  #include <linux/property.h>
> >>>  #include <linux/slab.h>
> >>>  #include <media/media-entity.h>
> >>> @@ -920,6 +921,43 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
> >>>  }
> >>>  EXPORT_SYMBOL_GPL(media_entity_remote_pad);
> >>>  
> >>> +struct media_pad *
> >>> +media_entity_remote_pad_unique(const struct media_entity *entity,
> >>> +			       unsigned int type)
> >>> +{
> >>> +	struct media_pad *pad = NULL;
> >>> +	struct media_link *link;
> >>> +
> >>> +	list_for_each_entry(link, &entity->links, list) {
> >>> +		struct media_pad *local_pad;
> >>> +		struct media_pad *remote_pad;
> >>> +
> >>> +		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
> >>> +			continue;
> >>> +
> >>> +		if (type == MEDIA_PAD_FL_SOURCE) {
> >>> +			local_pad = link->sink;
> >>> +			remote_pad = link->source;
> >>> +		} else {
> >>> +			local_pad = link->source;
> >>> +			remote_pad = link->sink;
> >>> +		}
> >>> +
> >>> +		if (local_pad->entity == entity) {
> >>> +			if (pad)
> >>> +				return ERR_PTR(-ENOTUNIQ);
> >>> +
> >>> +			pad = remote_pad;
> >>> +		}
> >>> +	}
> >>> +
> >>> +	if (!pad)
> >>> +		return ERR_PTR(-ENOLINK);
> >>> +
> >>> +	return pad;
> >>> +}
> >>> +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
> >>> +
> >>>  static void media_interface_init(struct media_device *mdev,
> >>>  				 struct media_interface *intf,
> >>>  				 u32 gobj_type,
> >>> diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> >>> index a9a1c0ec5d1c..33d5f52719a0 100644
> >>> --- a/include/media/media-entity.h
> >>> +++ b/include/media/media-entity.h
> >>> @@ -859,6 +859,51 @@ struct media_link *media_entity_find_link(struct media_pad *source,
> >>>   */
> >>>  struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
> >>>  
> >>> +/**
> >>> + * media_entity_remote_pad_unique - Find a remote pad connected to an entity
> >>> + * @entity: The entity
> >>> + * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
> >>> + *
> >>> + * Search for and return a remote pad of @type connected to @entity through an
> >>> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> >>> + * is returned.
> >>> + *
> >>> + * The uniqueness constraint makes this helper function suitable for entities
> >>> + * that support a single active source or sink at a time.
> >>> + *
> >>> + * Return: A pointer to the remote pad, or one of the following error pointers
> >>> + * if an error occurs:
> >>> + *
> >>> + * * -ENOTUNIQ - Multiple links are enabled
> >>> + * * -ENOLINK - No connected pad found
> >>> + */
> >>> +struct media_pad *
> >>> +media_entity_remote_pad_unique(const struct media_entity *entity,
> >>> +			       unsigned int type);
> >>> +
> >>> +/**
> >>> + * media_entity_remote_source_pad - Find a remote source pad connected to an entity
> >>> + * @entity: The entity
> >>> + *
> >>> + * Search for and return a remote source pad connected to @entity through an
> >>> + * enabled link. If multiple (or no) remote pads match these criteria, an error
> >>> + * is returned.
> >>> + *
> >>> + * The uniqueness constraint makes this helper function suitable for entities
> >>> + * that support a single active source at a time.
> >>> + *
> >>> + * Return: A pointer to the remote pad, or one of the following error pointers
> >>> + * if an error occurs:
> >>> + *
> >>> + * * -ENOTUNIQ - Multiple links are enabled
> >>> + * * -ENOLINK - No connected pad found
> >>> + */
> >>> +static inline struct media_pad *
> >>> +media_entity_remote_source_pad(const struct media_entity *entity)
> >>> +{
> >>> +	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
> >>> +}
> >>> +
> >>>  /**
> >>>   * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
> >>>   * @entity: The entity
diff mbox series

Patch

diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst
index 02481a2513b9..a2d1e32e3abb 100644
--- a/Documentation/driver-api/media/mc-core.rst
+++ b/Documentation/driver-api/media/mc-core.rst
@@ -186,8 +186,8 @@  is required and the graph structure can be freed normally.
 
 Helper functions can be used to find a link between two given pads, or a pad
 connected to another pad through an enabled link
-:c:func:`media_entity_find_link()` and
-:c:func:`media_entity_remote_pad()`.
+(:c:func:`media_entity_find_link()`, :c:func:`media_entity_remote_pad()` and
+:c:func:`media_entity_remote_source_pad()`).
 
 Use count and power handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
index 11f5207f73aa..1febf5a86be6 100644
--- a/drivers/media/mc/mc-entity.c
+++ b/drivers/media/mc/mc-entity.c
@@ -9,6 +9,7 @@ 
  */
 
 #include <linux/bitmap.h>
+#include <linux/list.h>
 #include <linux/property.h>
 #include <linux/slab.h>
 #include <media/media-entity.h>
@@ -920,6 +921,43 @@  struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
 }
 EXPORT_SYMBOL_GPL(media_entity_remote_pad);
 
+struct media_pad *
+media_entity_remote_pad_unique(const struct media_entity *entity,
+			       unsigned int type)
+{
+	struct media_pad *pad = NULL;
+	struct media_link *link;
+
+	list_for_each_entry(link, &entity->links, list) {
+		struct media_pad *local_pad;
+		struct media_pad *remote_pad;
+
+		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
+			continue;
+
+		if (type == MEDIA_PAD_FL_SOURCE) {
+			local_pad = link->sink;
+			remote_pad = link->source;
+		} else {
+			local_pad = link->source;
+			remote_pad = link->sink;
+		}
+
+		if (local_pad->entity == entity) {
+			if (pad)
+				return ERR_PTR(-ENOTUNIQ);
+
+			pad = remote_pad;
+		}
+	}
+
+	if (!pad)
+		return ERR_PTR(-ENOLINK);
+
+	return pad;
+}
+EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
+
 static void media_interface_init(struct media_device *mdev,
 				 struct media_interface *intf,
 				 u32 gobj_type,
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index a9a1c0ec5d1c..33d5f52719a0 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -859,6 +859,51 @@  struct media_link *media_entity_find_link(struct media_pad *source,
  */
 struct media_pad *media_entity_remote_pad(const struct media_pad *pad);
 
+/**
+ * media_entity_remote_pad_unique - Find a remote pad connected to an entity
+ * @entity: The entity
+ * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
+ *
+ * Search for and return a remote pad of @type connected to @entity through an
+ * enabled link. If multiple (or no) remote pads match these criteria, an error
+ * is returned.
+ *
+ * The uniqueness constraint makes this helper function suitable for entities
+ * that support a single active source or sink at a time.
+ *
+ * Return: A pointer to the remote pad, or one of the following error pointers
+ * if an error occurs:
+ *
+ * * -ENOTUNIQ - Multiple links are enabled
+ * * -ENOLINK - No connected pad found
+ */
+struct media_pad *
+media_entity_remote_pad_unique(const struct media_entity *entity,
+			       unsigned int type);
+
+/**
+ * media_entity_remote_source_pad - Find a remote source pad connected to an entity
+ * @entity: The entity
+ *
+ * Search for and return a remote source pad connected to @entity through an
+ * enabled link. If multiple (or no) remote pads match these criteria, an error
+ * is returned.
+ *
+ * The uniqueness constraint makes this helper function suitable for entities
+ * that support a single active source at a time.
+ *
+ * Return: A pointer to the remote pad, or one of the following error pointers
+ * if an error occurs:
+ *
+ * * -ENOTUNIQ - Multiple links are enabled
+ * * -ENOLINK - No connected pad found
+ */
+static inline struct media_pad *
+media_entity_remote_source_pad(const struct media_entity *entity)
+{
+	return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
+}
+
 /**
  * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
  * @entity: The entity