Re: [PATCH v10 14/24] v4l: async: Allow binding notifiers to sub-devices
Hi Hans, Thanks for the review! On Mon, Sep 11, 2017 at 10:57:16AM +0200, Hans Verkuil wrote: > 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 > > --- > > 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...". Yes, makes sense. Get also suggests that there would be reference counting which is not the case here. I made the corresponding change to v4l2_async_notifier_find_v4l2_dev() as well. > > > + struct v4l2_subdev *sd) > > +{ > > + struct v4l2_async_notifier *n; > > + > > + list_for_each_entry(n, ¬ifier_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(¬ifier->waiting)) > > + return false; > > + > > + list_for_each_entry(sd, ¬ifier->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. I thought of that, but ended up keeping the information in the notifier. As the information is already available elsewhere, I didn't end up adding a new field for the purpose. This is certainly not performance critical either. > > > + > > + 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(no
Re: [PATCH v10 14/24] v4l: async: Allow binding notifiers to sub-devices
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 > --- > 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, ¬ifier_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(¬ifier->waiting)) > + return false; > + > + list_for_each_entry(sd, ¬ifier->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_noti
[PATCH v10 14/24] v4l: async: Allow binding notifiers to sub-devices
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 --- 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( + struct v4l2_subdev *sd) +{ + struct v4l2_async_notifier *n; + + list_for_each_entry(n, ¬ifier_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(¬ifier->waiting)) + return false; + + list_for_each_entry(sd, ¬ifier->done, async_list) { + struct v4l2_async_notifier *subdev_notifier = + v4l2_async_get_subdev_notifier(sd); + + 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(¬ifier->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 +* t