All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hans Verkuil <hverkuil@xs4all.nl>
To: Sakari Ailus <sakari.ailus@linux.intel.com>, linux-media@vger.kernel.org
Cc: niklas.soderlund@ragnatech.se, robh@kernel.org,
	laurent.pinchart@ideasonboard.com, linux-acpi@vger.kernel.org,
	mika.westerberg@intel.com, devicetree@vger.kernel.org,
	pavel@ucw.cz, sre@kernel.org
Subject: Re: [PATCH v10 14/24] v4l: async: Allow binding notifiers to sub-devices
Date: Mon, 11 Sep 2017 10:57:16 +0200	[thread overview]
Message-ID: <19a5c075-92ca-050e-fc50-c78f02579df3@xs4all.nl> (raw)
In-Reply-To: <20170911080008.21208-15-sakari.ailus@linux.intel.com>

On 09/11/2017 09:59 AM, Sakari Ailus wrote:
> Registering a notifier has required the knowledge of struct v4l2_device
> for the reason that sub-devices generally are registered to the
> v4l2_device (as well as the media device, also available through
> v4l2_device).
> 
> This information is not available for sub-device drivers at probe time.
> 
> What this patch does is that it allows registering notifiers without
> having v4l2_device around. Instead the sub-device pointer is stored in the
> notifier. Once the sub-device of the driver that registered the notifier
> is registered, the notifier will gain the knowledge of the v4l2_device,
> and the binding of async sub-devices from the sub-device driver's notifier
> may proceed.
> 
> The root notifier's complete callback is only called when all sub-device
> notifiers are completed.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c | 217 ++++++++++++++++++++++++++++++-----
>  include/media/v4l2-async.h           |  16 ++-
>  2 files changed, 202 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 9ebc2e079d03..6f788b2e922a 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -53,6 +53,10 @@ static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
>  	return n->ops->complete(n);
>  }
>  
> +static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> +				   struct v4l2_subdev *sd,
> +				   struct v4l2_async_subdev *asd);
> +
>  static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
>  {
>  #if IS_ENABLED(CONFIG_I2C)
> @@ -124,14 +128,128 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
>  	return NULL;
>  }
>  
> +/* Get the sub-device notifier registered by a sub-device driver. */
> +static struct v4l2_async_notifier *v4l2_async_get_subdev_notifier(

I prefer to call this v4l2_async_find_subdev_notifier(). 'get' suggests
a getter function, but this actually has to find it. I think this may have
confused me during an earlier review of this code. The comment also needs
updating: "Find the sub-device...".

> +	struct v4l2_subdev *sd)
> +{
> +	struct v4l2_async_notifier *n;
> +
> +	list_for_each_entry(n, &notifier_list, list)
> +		if (n->sd == sd)
> +			return n;
> +
> +	return NULL;
> +}
> +
> +/* Return true if all sub-device notifiers are complete, false otherwise. */
> +static bool v4l2_async_subdev_notifiers_complete(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_subdev *sd;
> +
> +	if (!list_empty(&notifier->waiting))
> +		return false;
> +
> +	list_for_each_entry(sd, &notifier->done, async_list) {
> +		struct v4l2_async_notifier *subdev_notifier =
> +			v4l2_async_get_subdev_notifier(sd);

Would it make sense to add a 'struct v4l2_async_notifier *subdev_notifier'
field to struct v4l2_subdev? It's set when a subdev registers a notifier.

That way you can just use sd->subdev_notifier here.

I wonder if v4l2_async_get_subdev_notifier() is needed at all if you do
this.

> +
> +		if (!subdev_notifier)
> +			continue;
> +
> +		if (!v4l2_async_subdev_notifiers_complete(subdev_notifier))
> +			return false;
> +	}
> +
> +	return true;
> +}
> +
> +/* Get v4l2_device related to the notifier if one can be found. */
> +static struct v4l2_device *v4l2_async_notifier_get_v4l2_dev(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	while (notifier->parent)
> +		notifier = notifier->parent;
> +
> +	return notifier->v4l2_dev;
> +}
> +
> +/* Test all async sub-devices in a notifier for a match. */
> +static int v4l2_async_notifier_try_all_subdevs(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_subdev *sd;
> +
> +	if (!v4l2_async_notifier_get_v4l2_dev(notifier))
> +		return 0;
> +
> +again:
> +	list_for_each_entry(sd, &subdev_list, async_list) {
> +		struct v4l2_async_subdev *asd;
> +		int ret;
> +
> +		asd = v4l2_async_find_match(notifier, sd);
> +		if (!asd)
> +			continue;
> +
> +		ret = v4l2_async_match_notify(notifier, sd, asd);
> +		if (ret < 0)
> +			return ret;
> +
> +		/*
> +		 * v4l2_async_match_notify() may lead to registering a
> +		 * new notifier and thus changing the async subdevs
> +		 * list. In order to proceed safely from here, restart
> +		 * parsing the list from the beginning.
> +		 */
> +		goto again;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Try completing a notifier. */
> +static int v4l2_async_notifier_try_complete(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	do {
> +		int ret;
> +
> +		/* Any local async sub-devices left? */
> +		if (!list_empty(&notifier->waiting))
> +			return 0;
> +
> +		/*
> +		 * Any sub-device notifiers waiting for async subdevs
> +		 * to be bound?
> +		 */
> +		if (!v4l2_async_subdev_notifiers_complete(notifier))
> +			return 0;
> +
> +		/* Proceed completing the notifier */
> +		ret = v4l2_async_notifier_call_complete(notifier);
> +		if (ret < 0)
> +			return ret;
> +
> +		/*
> +		 * Obtain notifier's parent. If there is one, repeat
> +		 * the process, otherwise we're done here.
> +		 */
> +	} while ((notifier = notifier->parent));
> +
> +	return 0;
> +}
> +
>  static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  				   struct v4l2_subdev *sd,
>  				   struct v4l2_async_subdev *asd)
>  {
> +	struct v4l2_async_notifier *subdev_notifier;
>  	int ret;
>  
> -	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> -	if (ret < 0)
> +	ret = v4l2_device_register_subdev(
> +		v4l2_async_notifier_get_v4l2_dev(notifier), sd);
> +	if (ret)
>  		return ret;
>  
>  	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
> @@ -148,10 +266,20 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  	/* Move from the global subdevice list to notifier's done */
>  	list_move(&sd->async_list, &notifier->done);
>  
> -	if (list_empty(&notifier->waiting))
> -		return v4l2_async_notifier_call_complete(notifier);
> +	/*
> +	 * See if the sub-device has a notifier. If it does, proceed
> +	 * with checking for its async sub-devices.
> +	 */
> +	subdev_notifier = v4l2_async_get_subdev_notifier(sd);
> +	if (subdev_notifier && !subdev_notifier->parent) {
> +		subdev_notifier->parent = notifier;
> +		ret = v4l2_async_notifier_try_all_subdevs(subdev_notifier);
> +		if (ret)
> +			return ret;
> +	}
>  
> -	return 0;
> +	/* Try completing the notifier and its parent(s). */
> +	return v4l2_async_notifier_try_complete(notifier);
>  }
>  
>  static void v4l2_async_cleanup(struct v4l2_subdev *sd)
> @@ -163,20 +291,18 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  	sd->dev = NULL;
>  }
>  
> -int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> -				 struct v4l2_async_notifier *notifier)
> +static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  {
> -	struct v4l2_subdev *sd, *tmp;
>  	struct v4l2_async_subdev *asd;
> +	int ret;
>  	int i;
>  
> -	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
> +	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
>  		return -EINVAL;
>  
>  	if (!notifier->num_subdevs)
>  		return v4l2_async_notifier_call_complete(notifier);
>  
> -	notifier->v4l2_dev = v4l2_dev;
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> @@ -200,18 +326,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  
>  	mutex_lock(&list_lock);
>  
> -	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> -		int ret;
> -
> -		asd = v4l2_async_find_match(notifier, sd);
> -		if (!asd)
> -			continue;
> -
> -		ret = v4l2_async_match_notify(notifier, sd, asd);
> -		if (ret < 0) {
> -			mutex_unlock(&list_lock);
> -			return ret;
> -		}
> +	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> +	if (ret) {
> +		mutex_unlock(&list_lock);
> +		return ret;
>  	}
>  
>  	/* Keep also completed notifiers on the list */
> @@ -221,28 +339,67 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  
>  	return 0;
>  }
> +
> +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> +				 struct v4l2_async_notifier *notifier)
> +{
> +	if (!v4l2_dev || notifier->sd)

Should this be a WARN_ON?

> +		return -EINVAL;
> +
> +	notifier->v4l2_dev = v4l2_dev;
> +
> +	return __v4l2_async_notifier_register(notifier);
> +}
>  EXPORT_SYMBOL(v4l2_async_notifier_register);
>  
> -void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> +int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
> +					struct v4l2_async_notifier *notifier)
>  {
> -	struct v4l2_subdev *sd, *tmp;
> +	if (!sd || notifier->v4l2_dev)

Ditto.

> +		return -EINVAL;
>  
> -	if (!notifier->v4l2_dev)
> -		return;
> +	notifier->sd = sd;
>  
> -	mutex_lock(&list_lock);
> +	return __v4l2_async_notifier_register(notifier);
> +}
> +EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
>  
> -	list_del(&notifier->list);
> +/* Unbind all sub-devices in the notifier tree. */
> +static void v4l2_async_notifier_unbind_all_subdevs(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_subdev *sd, *tmp;
>  
>  	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> +		struct v4l2_async_notifier *subdev_notifier =
> +			v4l2_async_get_subdev_notifier(sd);
> +
> +		if (subdev_notifier)
> +			v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
> +
>  		v4l2_async_cleanup(sd);
>  
>  		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
> +
> +		list_del(&sd->async_list);
> +		list_add(&sd->async_list, &subdev_list);
>  	}
>  
> -	mutex_unlock(&list_lock);
> +	notifier->parent = NULL;

Shouldn't notifier->v4l2_dev and notifier->sd be set to NULL as well?
I can't really tell.

> +}
> +
> +void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> +{
> +	if (!notifier->v4l2_dev && !notifier->sd)
> +		return;
>  
> -	notifier->v4l2_dev = NULL;
> +	mutex_lock(&list_lock);
> +
> +	v4l2_async_notifier_unbind_all_subdevs(notifier);
> +
> +	list_del(&notifier->list);
> +
> +	mutex_unlock(&list_lock);
>  }
>  EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>  
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 3bc8a7c0d83f..cf409d45208c 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -102,7 +102,9 @@ struct v4l2_async_notifier_operations {
>   * @num_subdevs: number of subdevices used in the subdevs array
>   * @max_subdevs: number of subdevices allocated in the subdevs array
>   * @subdevs:	array of pointers to subdevice descriptors
> - * @v4l2_dev:	pointer to struct v4l2_device
> + * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
> + * @sd:		sub-device that registered the notifier, NULL otherwise
> + * @parent:	parent notifier carrying @v4l2_dev

That's not correct, it only carries v4l2_dev if it is the root notifier.
I think just 'parent notifier' is sufficient here.

>   * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
>   * @done:	list of struct v4l2_subdev, already probed
>   * @list:	member in a global list of notifiers
> @@ -113,6 +115,8 @@ struct v4l2_async_notifier {
>  	unsigned int max_subdevs;
>  	struct v4l2_async_subdev **subdevs;
>  	struct v4l2_device *v4l2_dev;
> +	struct v4l2_subdev *sd;
> +	struct v4l2_async_notifier *parent;
>  	struct list_head waiting;
>  	struct list_head done;
>  	struct list_head list;
> @@ -128,6 +132,16 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  				 struct v4l2_async_notifier *notifier);
>  
>  /**
> + * v4l2_async_subdev_notifier_register - registers a subdevice asynchronous
> + *					 notifier for a sub-device
> + *
> + * @sd: pointer to &struct v4l2_subdev
> + * @notifier: pointer to &struct v4l2_async_notifier
> + */
> +int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
> +					struct v4l2_async_notifier *notifier);
> +
> +/**
>   * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier
>   *
>   * @notifier: pointer to &struct v4l2_async_notifier
> 

Regards,

	Hans

  reply	other threads:[~2017-09-11  8:57 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-11  7:59 [PATCH v10 00/24] Unified fwnode endpoint parser, async sub-device notifier support, N9 flash DTS Sakari Ailus
2017-09-11  7:59 ` Sakari Ailus
2017-09-11  7:59 ` [PATCH v10 01/24] v4l: fwnode: Move KernelDoc documentation to the header Sakari Ailus
2017-09-11  7:59 ` [PATCH v10 02/24] v4l: async: Remove re-probing support Sakari Ailus
2017-09-11  7:59 ` [PATCH v10 03/24] v4l: async: Use more intuitive names for internal functions Sakari Ailus
2017-09-11  7:59 ` [PATCH v10 05/24] v4l: fwnode: Support generic parsing of graph endpoints in a device Sakari Ailus
2017-09-11  7:59 ` [PATCH v10 08/24] omap3isp: Fix check for our own sub-devices Sakari Ailus
2017-09-11  7:59 ` [PATCH v10 09/24] omap3isp: Print the name of the entity where no source pads could be found Sakari Ailus
     [not found] ` <20170911080008.21208-1-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-09-11  7:59   ` [PATCH v10 04/24] v4l: async: Add V4L2 async documentation to the documentation build Sakari Ailus
2017-09-11  7:59     ` Sakari Ailus
2017-09-11  7:59   ` [PATCH v10 06/24] omap3isp: Use generic parser for parsing fwnode endpoints Sakari Ailus
2017-09-11  7:59     ` Sakari Ailus
2017-09-11  7:59   ` [PATCH v10 07/24] rcar-vin: " Sakari Ailus
2017-09-11  7:59     ` Sakari Ailus
2017-09-11  7:59   ` [PATCH v10 10/24] v4l: async: Move async subdev notifier operations to a separate structure Sakari Ailus
2017-09-11  7:59     ` Sakari Ailus
2017-09-11  7:59   ` [PATCH v10 13/24] v4l: async: Allow async notifier register call succeed with no subdevs Sakari Ailus
2017-09-11  7:59     ` Sakari Ailus
2017-09-11  7:59   ` [PATCH v10 14/24] v4l: async: Allow binding notifiers to sub-devices Sakari Ailus
2017-09-11  7:59     ` Sakari Ailus
2017-09-11  8:57     ` Hans Verkuil [this message]
2017-09-11  9:30       ` Sakari Ailus
2017-09-11  8:00   ` [PATCH v10 17/24] v4l: fwnode: Add a helper function for parsing generic references Sakari Ailus
2017-09-11  8:00     ` Sakari Ailus
2017-09-11  9:14     ` Hans Verkuil
2017-09-11  9:59       ` Sakari Ailus
2017-09-11  8:00   ` [PATCH v10 18/24] v4l: fwnode: Add a helper function to obtain device / interger references Sakari Ailus
2017-09-11  8:00     ` Sakari Ailus
2017-09-11  9:38     ` Hans Verkuil
2017-09-11 12:28       ` Sakari Ailus
2017-09-11 12:38         ` Hans Verkuil
2017-09-11 13:27           ` Sakari Ailus
2017-09-11 13:34             ` Hans Verkuil
2017-09-11 14:12               ` Sakari Ailus
2017-09-11  8:00   ` [PATCH v10 21/24] smiapp: Add support for flash and lens devices Sakari Ailus
2017-09-11  8:00     ` Sakari Ailus
2017-09-11  9:48     ` Hans Verkuil
2017-09-11  7:59 ` [PATCH v10 11/24] v4l: async: Introduce helpers for calling async ops callbacks Sakari Ailus
2017-09-11  7:59 ` [PATCH v10 12/24] v4l: async: Register sub-devices before calling bound callback Sakari Ailus
2017-09-11  7:59 ` [PATCH v10 15/24] dt: bindings: Add a binding for flash LED devices associated to a sensor Sakari Ailus
2017-09-11  8:00 ` [PATCH v10 16/24] dt: bindings: Add lens-focus binding for image sensors Sakari Ailus
2017-09-11  8:00 ` [PATCH v10 19/24] v4l: fwnode: Add convenience function for parsing common external refs Sakari Ailus
2017-09-11  9:47   ` Hans Verkuil
2017-09-11 11:06     ` Sakari Ailus
2017-09-11 11:17   ` Pavel Machek
2017-09-11 14:15     ` Sakari Ailus
2017-09-11  8:00 ` [PATCH v10 20/24] dt: bindings: smiapp: Document lens-focus and flash properties Sakari Ailus
     [not found]   ` <20170911080008.21208-21-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-09-11  9:40     ` Hans Verkuil
2017-09-11  9:40       ` Hans Verkuil
2017-09-11 11:11     ` Pavel Machek
2017-09-11 11:11       ` Pavel Machek
2017-09-18 21:00   ` Rob Herring
2017-09-18 21:56     ` Sakari Ailus
     [not found]       ` <ef8edab3-5b55-c298-2a40-72b5e22586ea-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-09-19 20:00         ` Rob Herring
2017-09-19 20:00           ` Rob Herring
     [not found]           ` <CAL_Jsq+YKSDn7Hoq-2wRsGyGRbQvNPEVXrj13bSNCqQpKE2CvQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-09-28 21:02             ` Sakari Ailus
2017-09-28 21:02               ` Sakari Ailus
2017-09-11  8:00 ` [PATCH v10 22/24] ov5670: Add support for flash and lens devices Sakari Ailus
     [not found]   ` <20170911080008.21208-23-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-09-11  9:49     ` Hans Verkuil
2017-09-11  9:49       ` Hans Verkuil
2017-09-11  8:00 ` [PATCH v10 23/24] ov13858: " Sakari Ailus
2017-09-11  9:49   ` Hans Verkuil
2017-09-11  8:00 ` [PATCH v10 24/24] arm: dts: omap3: N9/N950: Add flash references to the camera Sakari Ailus
     [not found]   ` <20170911080008.21208-25-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-09-11  9:50     ` Hans Verkuil
2017-09-11  9:50       ` Hans Verkuil
2017-09-11 11:12   ` Pavel Machek
2017-10-03  0:04 ` [PATCH v10 00/24] Unified fwnode endpoint parser, async sub-device notifier support, N9 flash DTS Rafael J. Wysocki
2017-10-04 12:45   ` Sakari Ailus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=19a5c075-92ca-050e-fc50-c78f02579df3@xs4all.nl \
    --to=hverkuil@xs4all.nl \
    --cc=devicetree@vger.kernel.org \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mika.westerberg@intel.com \
    --cc=niklas.soderlund@ragnatech.se \
    --cc=pavel@ucw.cz \
    --cc=robh@kernel.org \
    --cc=sakari.ailus@linux.intel.com \
    --cc=sre@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.