Re: [RESEND PATCH v3 13/32] media: v4l: async: Simplify async sub-device fwnode matching

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

 



Hi Sakari,

Thank you for the patch.

On Thu, May 25, 2023 at 12:15:56PM +0300, Sakari Ailus wrote:
> V4L2 async sub-device matching originally used the device nodes only.
> Endpoint nodes were taken into use instead as using the device nodes was
> problematic for it was in some cases ambiguous which link might have been
> in question.
> 
> There is however no need to use endpoint nodes on both sides, as the async
> sub-device's fwnode can always be trivially obtained using
> fwnode_graph_get_remote_endpoint() when needed while what counts is
> whether or not the link is between two device nodes, i.e. the device nodes
> match.
> 
> This will briefly break the adv748x driver but it will be fixed later in
> the set, by patch "media: adv748x: Return to endpoint matching".

I'm afraid I don't like this. This series is complex and has a high risk
of causing tricky issues. I would like to be able to bisect the changes.

> Signed-off-by: Sakari Ailus <sakari.ailus@xxxxxxxxxxxxxxx>
> ---
>  drivers/media/i2c/adv748x/adv748x-csi2.c   |  5 +-
>  drivers/media/i2c/max9286.c                | 14 +---
>  drivers/media/i2c/rdacm20.c                | 16 +---
>  drivers/media/i2c/rdacm21.c                | 15 +---
>  drivers/media/i2c/tc358746.c               |  5 --
>  drivers/media/platform/nxp/imx-mipi-csis.c |  7 --
>  drivers/media/v4l2-core/v4l2-async.c       | 88 ++++++----------------
>  7 files changed, 26 insertions(+), 124 deletions(-)
> 
> diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
> index bd4f3fe0e3096..b6f93c1db3d2a 100644
> --- a/drivers/media/i2c/adv748x/adv748x-csi2.c
> +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
> @@ -296,13 +296,12 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
>  	if (!is_tx_enabled(tx))
>  		return 0;
>  
> +	/* FIXME: Do endpoint matching again! */
> +
>  	adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
>  			    MEDIA_ENT_F_VID_IF_BRIDGE,
>  			    is_txa(tx) ? "txa" : "txb");
>  
> -	/* Ensure that matching is based upon the endpoint fwnodes */
> -	tx->sd.fwnode = of_fwnode_handle(state->endpoints[tx->port]);
> -
>  	/* Register internal ops for incremental subdev registration */
>  	tx->sd.internal_ops = &adv748x_csi2_internal_ops;
>  
> diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
> index 13a986b885889..64f5c49cae776 100644
> --- a/drivers/media/i2c/max9286.c
> +++ b/drivers/media/i2c/max9286.c
> @@ -1051,7 +1051,6 @@ static const struct v4l2_ctrl_ops max9286_ctrl_ops = {
>  static int max9286_v4l2_register(struct max9286_priv *priv)
>  {
>  	struct device *dev = &priv->client->dev;
> -	struct fwnode_handle *ep;
>  	int ret;
>  	int i;
>  
> @@ -1093,25 +1092,14 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
>  	if (ret)
>  		goto err_async;
>  
> -	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), MAX9286_SRC_PAD,
> -					     0, 0);
> -	if (!ep) {
> -		dev_err(dev, "Unable to retrieve endpoint on \"port@4\"\n");
> -		ret = -ENOENT;
> -		goto err_async;
> -	}
> -	priv->sd.fwnode = ep;
> -
>  	ret = v4l2_async_register_subdev(&priv->sd);
>  	if (ret < 0) {
>  		dev_err(dev, "Unable to register subdevice\n");
> -		goto err_put_node;
> +		goto err_async;
>  	}
>  
>  	return 0;
>  
> -err_put_node:
> -	fwnode_handle_put(ep);
>  err_async:
>  	v4l2_ctrl_handler_free(&priv->ctrls);
>  	max9286_v4l2_notifier_unregister(priv);
> diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
> index a2263fa825b59..9d8a8f9efd835 100644
> --- a/drivers/media/i2c/rdacm20.c
> +++ b/drivers/media/i2c/rdacm20.c
> @@ -567,7 +567,6 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
>  static int rdacm20_probe(struct i2c_client *client)
>  {
>  	struct rdacm20_device *dev;
> -	struct fwnode_handle *ep;
>  	int ret;
>  
>  	dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
> @@ -616,24 +615,12 @@ static int rdacm20_probe(struct i2c_client *client)
>  	if (ret < 0)
>  		goto error_free_ctrls;
>  
> -	ep = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
> -	if (!ep) {
> -		dev_err(&client->dev,
> -			"Unable to get endpoint in node %pOF\n",
> -			client->dev.of_node);
> -		ret = -ENOENT;
> -		goto error_free_ctrls;
> -	}
> -	dev->sd.fwnode = ep;
> -
>  	ret = v4l2_async_register_subdev(&dev->sd);
>  	if (ret)
> -		goto error_put_node;
> +		goto error_free_ctrls;
>  
>  	return 0;
>  
> -error_put_node:
> -	fwnode_handle_put(ep);
>  error_free_ctrls:
>  	v4l2_ctrl_handler_free(&dev->ctrls);
>  error:
> @@ -650,7 +637,6 @@ static void rdacm20_remove(struct i2c_client *client)
>  {
>  	struct rdacm20_device *dev = i2c_to_rdacm20(client);
>  
> -	fwnode_handle_put(dev->sd.fwnode);
>  	v4l2_async_unregister_subdev(&dev->sd);
>  	v4l2_ctrl_handler_free(&dev->ctrls);
>  	media_entity_cleanup(&dev->sd.entity);
> diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> index 9ccc56c30d3b0..d67cfcb2e05a4 100644
> --- a/drivers/media/i2c/rdacm21.c
> +++ b/drivers/media/i2c/rdacm21.c
> @@ -543,7 +543,6 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
>  static int rdacm21_probe(struct i2c_client *client)
>  {
>  	struct rdacm21_device *dev;
> -	struct fwnode_handle *ep;
>  	int ret;
>  
>  	dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
> @@ -588,24 +587,12 @@ static int rdacm21_probe(struct i2c_client *client)
>  	if (ret < 0)
>  		goto error_free_ctrls;
>  
> -	ep = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
> -	if (!ep) {
> -		dev_err(&client->dev,
> -			"Unable to get endpoint in node %pOF\n",
> -			client->dev.of_node);
> -		ret = -ENOENT;
> -		goto error_free_ctrls;
> -	}
> -	dev->sd.fwnode = ep;
> -
>  	ret = v4l2_async_register_subdev(&dev->sd);
>  	if (ret)
> -		goto error_put_node;
> +		goto error_free_ctrls;
>  
>  	return 0;
>  
> -error_put_node:
> -	fwnode_handle_put(dev->sd.fwnode);
>  error_free_ctrls:
>  	v4l2_ctrl_handler_free(&dev->ctrls);
>  error:
> diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
> index ec1a193ba161a..b37a9ff73f6ad 100644
> --- a/drivers/media/i2c/tc358746.c
> +++ b/drivers/media/i2c/tc358746.c
> @@ -1476,9 +1476,6 @@ static int tc358746_async_register(struct tc358746 *tc358746)
>  	if (err)
>  		goto err_cleanup;
>  
> -	tc358746->sd.fwnode = fwnode_graph_get_endpoint_by_id(
> -		dev_fwnode(tc358746->sd.dev), TC358746_SOURCE, 0, 0);
> -
>  	err = v4l2_async_register_subdev(&tc358746->sd);
>  	if (err)
>  		goto err_unregister;
> @@ -1486,7 +1483,6 @@ static int tc358746_async_register(struct tc358746 *tc358746)
>  	return 0;
>  
>  err_unregister:
> -	fwnode_handle_put(tc358746->sd.fwnode);
>  	v4l2_async_nf_unregister(&tc358746->notifier);
>  err_cleanup:
>  	v4l2_async_nf_cleanup(&tc358746->notifier);
> @@ -1605,7 +1601,6 @@ static void tc358746_remove(struct i2c_client *client)
>  	v4l2_fwnode_endpoint_free(&tc358746->csi_vep);
>  	v4l2_async_nf_unregister(&tc358746->notifier);
>  	v4l2_async_nf_cleanup(&tc358746->notifier);
> -	fwnode_handle_put(sd->fwnode);
>  	v4l2_async_unregister_subdev(sd);
>  	media_entity_cleanup(&sd->entity);
>  
> diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
> index 05d52762e7926..d0dc30187775d 100644
> --- a/drivers/media/platform/nxp/imx-mipi-csis.c
> +++ b/drivers/media/platform/nxp/imx-mipi-csis.c
> @@ -1365,13 +1365,6 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
>  
>  	sd->dev = csis->dev;
>  
> -	sd->fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev),
> -						     1, 0, 0);
> -	if (!sd->fwnode) {
> -		dev_err(csis->dev, "Unable to retrieve endpoint for port@1\n");
> -		return -ENOENT;
> -	}
> -
>  	csis->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
>  					 | MEDIA_PAD_FL_MUST_CONNECT;
>  	csis->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 06b1e1a1a5f87..335597889f365 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -94,89 +94,36 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
>  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
>  		 struct v4l2_async_match_desc *match)
>  {
> -	struct fwnode_handle *other_fwnode;
> -	struct fwnode_handle *dev_fwnode;
> -	bool asd_fwnode_is_ep;
> -	bool sd_fwnode_is_ep;
> -	struct device *dev;
> +	struct fwnode_handle *asd_dev_fwnode;
> +	bool ret;
>  
>  	dev_dbg(notifier_dev(notifier),
>  		"v4l2-async: fwnode match: need %pfw, trying %pfw\n",
>  		sd_fwnode, match->fwnode);
>  
> -	/*
> -	 * Both the subdev and the async subdev can provide either an endpoint
> -	 * fwnode or a device fwnode. Start with the simple case of direct
> -	 * fwnode matching.
> -	 */
>  	if (sd_fwnode == match->fwnode) {
>  		dev_dbg(notifier_dev(notifier),
>  			"v4l2-async: direct match found\n");
>  		return true;
>  	}
>  
> -	/*
> -	 * Otherwise, check if the sd fwnode and the asd fwnode refer to an
> -	 * endpoint or a device. If they're of the same type, there's no match.
> -	 * Technically speaking this checks if the nodes refer to a connected
> -	 * endpoint, which is the simplest check that works for both OF and
> -	 * ACPI. This won't make a difference, as drivers should not try to
> -	 * match unconnected endpoints.
> -	 */
> -	sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd_fwnode);
> -	asd_fwnode_is_ep = fwnode_graph_is_endpoint(match->fwnode);
> -
> -	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
> +	if (!fwnode_graph_is_endpoint(match->fwnode)) {
>  		dev_dbg(notifier_dev(notifier),
>  			"v4l2-async: direct match not found\n");
>  		return false;
>  	}
>  
> -	/*
> -	 * The sd and asd fwnodes are of different types. Get the device fwnode
> -	 * parent of the endpoint fwnode, and compare it with the other fwnode.
> -	 */
> -	if (sd_fwnode_is_ep) {
> -		dev_fwnode = fwnode_graph_get_port_parent(sd_fwnode);
> -		other_fwnode = match->fwnode;
> -	} else {
> -		dev_fwnode = fwnode_graph_get_port_parent(match->fwnode);
> -		other_fwnode = sd_fwnode;
> -	}
> +	asd_dev_fwnode = fwnode_graph_get_port_parent(match->fwnode);
>  
> -	dev_dbg(notifier_dev(notifier),
> -		"v4l2-async: fwnode compat match: need %pfw, trying %pfw\n",
> -		dev_fwnode, other_fwnode);
> +	ret = sd_fwnode == asd_dev_fwnode;
>  
> -	fwnode_handle_put(dev_fwnode);
> +	fwnode_handle_put(asd_dev_fwnode);
>  
> -	if (dev_fwnode != other_fwnode) {
> -		dev_dbg(notifier_dev(notifier),
> -			"v4l2-async: compat match not found\n");
> -		return false;
> -	}
> -
> -	/*
> -	 * We have a heterogeneous match. Retrieve the struct device of the side
> -	 * that matched on a device fwnode to print its driver name.
> -	 */
> -	if (sd_fwnode_is_ep)
> -		dev = notifier->v4l2_dev ? notifier->v4l2_dev->dev
> -		    : notifier->sd->dev;
> -	else
> -		dev = sd->dev;
> -
> -	if (dev && dev->driver) {
> -		if (sd_fwnode_is_ep)
> -			dev_warn(dev, "Driver %s uses device fwnode, incorrect match may occur\n",
> -				 dev->driver->name);
> -		dev_notice(dev, "Consider updating driver %s to match on endpoints\n",
> -			   dev->driver->name);
> -	}
> -
> -	dev_dbg(notifier_dev(notifier), "v4l2-async: compat match found\n");
> +	dev_dbg(notifier_dev(notifier),
> +		"v4l2-async: device--endpoint match %sfound\n",
> +		ret ? "" : "not ");
>  
> -	return true;
> +	return ret;
>  }
>  
>  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> @@ -814,12 +761,19 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	int ret;
>  
>  	/*
> -	 * No reference taken. The reference is held by the device
> -	 * (struct v4l2_subdev.dev), and async sub-device does not
> -	 * exist independently of the device at any point of time.
> +	 * No reference taken. The reference is held by the device (struct
> +	 * v4l2_subdev.dev), and async sub-device does not exist independently
> +	 * of the device at any point of time.
> +	 *
> +	 * The async sub-device shall always be registered for its device node,
> +	 * not the endpoint node.
>  	 */
> -	if (!sd->fwnode && sd->dev)
> +	if (!sd->fwnode && sd->dev) {
>  		sd->fwnode = dev_fwnode(sd->dev);
> +	} else if (fwnode_graph_is_endpoint(sd->fwnode)) {
> +		dev_warn(sd->dev, "sub-device fwnode is an endpoint!\n");
> +		return -EINVAL;
> +	}
>  
>  	mutex_lock(&list_lock);
>  

-- 
Regards,

Laurent Pinchart



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux