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

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

 



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 ?

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

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

> +
> +	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