Re: [PATCH v4 5/6] media: rcar-vin: Merge all notifiers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Laurent,

Thanks for your feedback!

On 2025-05-27 13:45:13 +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thank you for the patch.
> 
> On Wed, May 21, 2025 at 03:20:36PM +0200, Niklas Söderlund wrote:
> > The VIN usage of v4l-async is complex and stems from organic growth of
> > the driver of supporting both private local subdevices (Gen2, Gen3) and
> > subdevices shared between all VIN instances (Gen3 and Gen4).
> > 
> > The driver used a separate notifier for each VIN for the private local
> > ones, and a shared group notifier for the shared ones. This was complex
> > and lead to subtle bugs when unbinding and later rebinding subdevices in
> > on of the notifiers having to handle different edge cases depending on
> 
> s/on of/one of/ (I think)
> 
> > if it also had subdevices in the other notifiers etc.
> > 
> > To simplify this have the Gen2 devices allocate and form a VIN group
> > too. This way all subdevices on all models can be collect in a
> > single group notifier. Then there is only a single complete callback for
> > all where the video devices and subdevice nodes can be registered etc.
> > 
> > Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@xxxxxxxxxxxx>
> > ---
> >  .../platform/renesas/rcar-vin/rcar-core.c     | 263 ++++++++----------
> >  .../platform/renesas/rcar-vin/rcar-vin.h      |   2 -
> >  2 files changed, 114 insertions(+), 151 deletions(-)
> > 
> > diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
> > index 60ec57d73a12..b0727e98dac6 100644
> > --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c
> > +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
> > @@ -43,6 +43,9 @@
> >  
> >  #define v4l2_dev_to_vin(d)	container_of(d, struct rvin_dev, v4l2_dev)
> >  
> > +static int rvin_parallel_subdevice_attach(struct rvin_dev *vin,
> > +					  struct v4l2_subdev *subdev);
> 
> Any chance you could move the function instead of forward-declaring it ?

I could move it in a separate commit prior to this patch. But the last 
patch in the series removes the function all together so I thought that 
to be more churn then needed.

> 
> > +
> >  /* -----------------------------------------------------------------------------
> >   * Gen3 Group Allocator
> >   */
> > @@ -232,7 +235,10 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier)
> >  		}
> >  	}
> >  
> > -	return vin->group->link_setup(vin->group);
> > +	if (vin->group->link_setup)
> > +		return vin->group->link_setup(vin->group);
> > +
> > +	return  0;
> >  }
> >  
> >  static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
> > @@ -240,22 +246,31 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
> >  				     struct v4l2_async_connection *asc)
> >  {
> >  	struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
> > -	unsigned int i;
> > +	struct rvin_group *group = vin->group;
> >  
> > -	for (i = 0; i < RCAR_VIN_NUM; i++)
> > -		if (vin->group->vin[i])
> > -			rvin_v4l2_unregister(vin->group->vin[i]);
> > +	for (unsigned int i = 0; i < RCAR_VIN_NUM; i++)
> 
> While at it, you can use ARRAY_SIZE().

The use of RCAR_VIN_NUM is everywhere in the driver. I do however agree 
using ARRAY_SIZE() is better. I will convert the whole driver to 
ARRAY_SIZE() in a follow up patch outside this series.

I think it's important that all loops look the same and I'm worried this 
series is growing too large with all nice, but unrelated, cleanups 
unearth by it. I hope this is OK.

I will however keep the conversion to ARRAY_SIZE() for the 
RVIN_REMOTES_MAX define as this was already something this series needed 
to address in patch 1 and it's only used in one location that was not 
already touched by this series.

> 
> > +		if (group->vin[i])
> > +			rvin_v4l2_unregister(group->vin[i]);
> 
> And please use curly braces for the for statement.
> 
> >  
> >  	mutex_lock(&vin->group->lock);
> 
> Add a blank line.
> 
> > +	for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) {
> 
> ARRAY_SIZE() here too. Same below where applicable.
> 
> > +		if (!group->vin[i] || group->vin[i]->parallel.asc != asc)
> > +			continue;
> > +
> > +		group->vin[i]->parallel.subdev = NULL;
> > +
> > +		vin_dbg(group->vin[i], "Unbind parallel subdev %s\n",
> > +			subdev->name);
> > +	}
> >  
> > -	for (i = 0; i < RVIN_REMOTES_MAX; i++) {
> > -		if (vin->group->remotes[i].asc != asc)
> > +	for (unsigned int i = 0; i < RVIN_REMOTES_MAX; i++) {
> > +		if (group->remotes[i].asc != asc)
> >  			continue;
> > -		vin->group->remotes[i].subdev = NULL;
> > +
> > +		group->remotes[i].subdev = NULL;
> > +
> >  		vin_dbg(vin, "Unbind %s from slot %u\n", subdev->name, i);
> > -		break;
> >  	}
> > -
> 
> You can keep this blank line :-)
> 
> >  	mutex_unlock(&vin->group->lock);
> >  
> >  	media_device_unregister(&vin->group->mdev);
> > @@ -266,21 +281,38 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier,
> >  				   struct v4l2_async_connection *asc)
> >  {
> >  	struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
> > -	unsigned int i;
> > +	struct rvin_group *group = vin->group;
> >  
> > -	mutex_lock(&vin->group->lock);
> > +	guard(mutex)(&group->lock);
> >  
> > -	for (i = 0; i < RVIN_REMOTES_MAX; i++) {
> > +	for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) {
> > +		int ret;
> > +
> > +		if (!group->vin[i] || group->vin[i]->parallel.asc != asc)
> > +			continue;
> > +
> > +		ret = rvin_parallel_subdevice_attach(group->vin[i], subdev);
> > +		if (ret)
> > +			return ret;
> > +
> > +		v4l2_set_subdev_hostdata(subdev, group->vin[i]);
> > +
> > +		vin_dbg(group->vin[i], "Bound subdev %s\n", subdev->name);
> > +
> > +		return 0;
> > +	}
> > +
> > +	for (unsigned int i = 0; i < RVIN_REMOTES_MAX; i++) {
> >  		if (vin->group->remotes[i].asc != asc)
> >  			continue;
> > +
> >  		vin->group->remotes[i].subdev = subdev;
> >  		vin_dbg(vin, "Bound %s to slot %u\n", subdev->name, i);
> > -		break;
> > +
> > +		return 0;
> >  	}
> >  
> > -	mutex_unlock(&vin->group->lock);
> > -
> > -	return 0;
> > +	return -ENODEV;
> >  }
> >  
> >  static const struct v4l2_async_notifier_operations rvin_group_notify_ops = {
> > @@ -374,7 +406,7 @@ static int rvin_parallel_parse_of(struct rvin_dev *vin)
> >  		goto out;
> >  	}
> >  
> > -	asc = v4l2_async_nf_add_fwnode(&vin->notifier, fwnode,
> > +	asc = v4l2_async_nf_add_fwnode(&vin->group->notifier, fwnode,
> >  				       struct v4l2_async_connection);
> >  	if (IS_ERR(asc)) {
> >  		ret = PTR_ERR(asc);
> > @@ -424,6 +456,12 @@ static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port,
> >  		if (!(vin_mask & BIT(i)))
> >  			continue;
> >  
> > +		/* Parse local subdevice. */
> > +		ret = rvin_parallel_parse_of(vin->group->vin[i]);
> > +		if (ret)
> > +			return ret;
> > +
> > +		/* Prase shared subdevices. */
> >  		for (id = 0; id < max_id; id++) {
> >  			if (vin->group->remotes[id].asc)
> >  				continue;
> > @@ -603,124 +641,6 @@ static int rvin_parallel_subdevice_attach(struct rvin_dev *vin,
> >  	return 0;
> >  }
> >  
> > -static void rvin_parallel_subdevice_detach(struct rvin_dev *vin)
> > -{
> > -	rvin_v4l2_unregister(vin);
> > -	vin->parallel.subdev = NULL;
> > -
> > -	if (!vin->info->use_mc)
> > -		rvin_free_controls(vin);
> > -}
> > -
> > -static int rvin_parallel_notify_complete(struct v4l2_async_notifier *notifier)
> > -{
> > -	struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
> > -	struct media_entity *source;
> > -	struct media_entity *sink;
> > -	int ret;
> > -
> > -	ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
> > -	if (ret < 0) {
> > -		vin_err(vin, "Failed to register subdev nodes\n");
> > -		return ret;
> > -	}
> > -
> > -	if (!video_is_registered(&vin->vdev)) {
> > -		ret = rvin_v4l2_register(vin);
> > -		if (ret < 0)
> > -			return ret;
> > -	}
> > -
> > -	if (!vin->info->use_mc)
> > -		return 0;
> > -
> > -	/* If we're running with media-controller, link the subdevs. */
> > -	source = &vin->parallel.subdev->entity;
> > -	sink = &vin->vdev.entity;
> > -
> > -	ret = media_create_pad_link(source, vin->parallel.source_pad,
> > -				    sink, vin->parallel.sink_pad, 0);
> > -	if (ret)
> > -		vin_err(vin, "Error adding link from %s to %s: %d\n",
> > -			source->name, sink->name, ret);
> > -
> > -	return ret;
> > -}
> > -
> > -static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier,
> > -					struct v4l2_subdev *subdev,
> > -					struct v4l2_async_connection *asc)
> > -{
> > -	struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
> > -
> > -	vin_dbg(vin, "unbind parallel subdev %s\n", subdev->name);
> > -
> > -	mutex_lock(&vin->lock);
> > -	rvin_parallel_subdevice_detach(vin);
> > -	mutex_unlock(&vin->lock);
> > -}
> > -
> > -static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier,
> > -				      struct v4l2_subdev *subdev,
> > -				      struct v4l2_async_connection *asc)
> > -{
> > -	struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
> > -	int ret;
> > -
> > -	mutex_lock(&vin->lock);
> > -	ret = rvin_parallel_subdevice_attach(vin, subdev);
> > -	mutex_unlock(&vin->lock);
> > -	if (ret)
> > -		return ret;
> > -
> > -	v4l2_set_subdev_hostdata(subdev, vin);
> > -
> > -	vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n",
> > -		subdev->name, vin->parallel.source_pad,
> > -		vin->parallel.sink_pad);
> > -
> > -	return 0;
> > -}
> > -
> > -static const struct v4l2_async_notifier_operations rvin_parallel_notify_ops = {
> > -	.bound = rvin_parallel_notify_bound,
> > -	.unbind = rvin_parallel_notify_unbind,
> > -	.complete = rvin_parallel_notify_complete,
> > -};
> > -
> > -static void rvin_parallel_cleanup(struct rvin_dev *vin)
> > -{
> > -	v4l2_async_nf_unregister(&vin->notifier);
> > -	v4l2_async_nf_cleanup(&vin->notifier);
> > -}
> > -
> > -static int rvin_parallel_init(struct rvin_dev *vin)
> > -{
> > -	int ret;
> > -
> > -	v4l2_async_nf_init(&vin->notifier, &vin->v4l2_dev);
> > -
> > -	ret = rvin_parallel_parse_of(vin);
> > -	if (ret)
> > -		return ret;
> > -
> > -	if (!vin->parallel.asc)
> > -		return -ENODEV;
> > -
> > -	vin_dbg(vin, "Found parallel subdevice %pOF\n",
> > -		to_of_node(vin->parallel.asc->match.fwnode));
> > -
> > -	vin->notifier.ops = &rvin_parallel_notify_ops;
> > -	ret = v4l2_async_nf_register(&vin->notifier);
> > -	if (ret < 0) {
> > -		vin_err(vin, "Notifier registration failed\n");
> > -		v4l2_async_nf_cleanup(&vin->notifier);
> > -		return ret;
> > -	}
> > -
> > -	return 0;
> > -}
> > -
> >  /* -----------------------------------------------------------------------------
> >   * CSI-2
> >   */
> > @@ -895,11 +815,63 @@ static int rvin_csi2_create_link(struct rvin_group *group, unsigned int id,
> >  	return 0;
> >  }
> >  
> > +static int rvin_parallel_setup_links(struct rvin_group *group)
> > +{
> > +	u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
> > +	int ret = 0;
> > +
> > +	mutex_lock(&group->lock);
> 
> Use a guard.
> 
> > +	/* If the group also have links don't enable the link. */
> 
> s/have/has/
> 
> > +	for (unsigned int i = 0; i < RVIN_REMOTES_MAX; i++) {
> > +		if (group->remotes[i].subdev) {
> > +			flags = 0;
> > +			break;
> > +		}
> > +	}
> > +
> > +	/* Create links */
> 
> s/links/links./
> 
> > +	for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) {
> > +		struct rvin_dev *vin = group->vin[i];
> > +		struct media_entity *source;
> > +		struct media_entity *sink;
> > +
> > +		/* Noting to do if their is no VIN or parallel subdev. */
> 
> s/Noting/Nothing/
> s/their/there/
> 
> > +		if (!vin || !vin->parallel.subdev)
> > +			continue;
> > +
> > +		source = &vin->parallel.subdev->entity;
> > +		sink = &vin->vdev.entity;
> > +
> > +		ret = media_create_pad_link(source, vin->parallel.source_pad,
> > +					    sink, 0, flags);
> > +		if (ret)
> > +			break;
> 
> 			return ret;
> 
> (thanks to the guard above)
> 
> > +	}
> > +	mutex_unlock(&group->lock);
> > +
> > +	return ret;
> 
> 	return 0;
> 
> > +}
> > +
> >  static int rvin_csi2_setup_links(struct rvin_group *group)
> >  {
> >  	const struct rvin_group_route *routes, *route;
> >  	unsigned int id;
> > -	int ret = -EINVAL;
> > +	int ret;
> > +
> > +	/* Find any VIN in group to get route info. */
> > +	routes = NULL;
> > +	for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) {
> > +		if (group->vin[i]) {
> > +			routes = group->vin[i]->info->routes;
> > +			break;
> > +		}
> > +	}
> > +	if (!routes)
> > +		return -ENODEV;
> 
> Storing the info pointer in the group as proposed in the review of a
> previous patch from the same series would help here too.

I agree. I have added a patch that introduce this change separatly and 
all new code uses the info from the group structure. I have added to my 
ever growing todo file to remove the info struct all together from the 
private VIN data structure in a follow up patch. This change would 
depend on this series as Gen2 currently do not participate in the group 
concept.

> 
> > +
> > +	ret = rvin_parallel_setup_links(group);
> > +	if (ret)
> > +		return ret;
> >  
> >  	/* Find any VIN in group to get route info. */
> >  	routes = NULL;
> > @@ -914,6 +886,7 @@ static int rvin_csi2_setup_links(struct rvin_group *group)
> >  
> >  	/* Create all media device links between VINs and CSI-2's. */
> >  	mutex_lock(&group->lock);
> > +	ret = -EINVAL;
> >  	for (route = routes; route->chsel; route++) {
> >  		/* Check that VIN' master is part of the group. */
> >  		if (!group->vin[route->master])
> > @@ -941,7 +914,6 @@ static int rvin_csi2_setup_links(struct rvin_group *group)
> >  
> >  static void rvin_csi2_cleanup(struct rvin_dev *vin)
> >  {
> > -	rvin_parallel_cleanup(vin);
> >  	rvin_group_notifier_cleanup(vin);
> >  	rvin_group_put(vin);
> >  	rvin_free_controls(vin);
> > @@ -964,18 +936,11 @@ static int rvin_csi2_init(struct rvin_dev *vin)
> >  	if (ret)
> >  		goto err_controls;
> >  
> > -	/* It's OK to not have a parallel subdevice. */
> > -	ret = rvin_parallel_init(vin);
> > -	if (ret && ret != -ENODEV)
> > -		goto err_group;
> > -
> >  	ret = rvin_group_notifier_init(vin, 1, RVIN_CSI_MAX);
> >  	if (ret)
> > -		goto err_parallel;
> > +		goto err_group;
> >  
> >  	return 0;
> > -err_parallel:
> > -	rvin_parallel_cleanup(vin);
> >  err_group:
> >  	rvin_group_put(vin);
> >  err_controls:
> > @@ -1448,7 +1413,9 @@ static int rcar_vin_probe(struct platform_device *pdev)
> >  		    rvin_group_id_to_master(vin->id) == vin->id)
> >  			vin->scaler = vin->info->scaler;
> >  	} else {
> > -		ret = rvin_parallel_init(vin);
> > +		ret = rvin_group_get(vin, NULL, NULL);
> > +		if (!ret)
> > +			ret = rvin_group_notifier_init(vin, 0, 0);
> >  
> >  		if (vin->info->scaler)
> >  			vin->scaler = vin->info->scaler;
> > @@ -1478,8 +1445,6 @@ static void rcar_vin_remove(struct platform_device *pdev)
> >  		rvin_isp_cleanup(vin);
> >  	else if (vin->info->use_mc)
> >  		rvin_csi2_cleanup(vin);
> > -	else
> > -		rvin_parallel_cleanup(vin);
> >  
> >  	rvin_id_put(vin);
> >  
> > diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
> > index 7d4fce248976..a577f4fe4a6c 100644
> > --- a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
> > +++ b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
> > @@ -149,7 +149,6 @@ struct rvin_info {
> >   * @vdev:		V4L2 video device associated with VIN
> >   * @v4l2_dev:		V4L2 device
> >   * @ctrl_handler:	V4L2 control handler
> > - * @notifier:		V4L2 asynchronous subdevs notifier
> >   *
> >   * @parallel:		parallel input subdevice descriptor
> >   *
> > @@ -189,7 +188,6 @@ struct rvin_dev {
> >  	struct video_device vdev;
> >  	struct v4l2_device v4l2_dev;
> >  	struct v4l2_ctrl_handler ctrl_handler;
> > -	struct v4l2_async_notifier notifier;
> >  
> >  	struct rvin_parallel_entity parallel;
> >  
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Kind Regards,
Niklas Söderlund




[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux