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

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

 



On Fri, Jun 06, 2025 at 04:09:33PM +0200, Niklas Söderlund wrote:
> 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.

OK it's fine then.

> > > +
> > >  /* -----------------------------------------------------------------------------
> > >   * 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.

OK.

> 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




[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