linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/18] Separate links and async sub-devices
@ 2023-03-30 11:58 Sakari Ailus
  2023-03-30 11:58 ` [PATCH 01/18] media: v4l: async: Return async sub-devices to subnotifier list Sakari Ailus
                   ` (18 more replies)
  0 siblings, 19 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi all,

This set adds support for multiple downstream links in an async
sub-device, by separating the sub-device registration from the link
creation.

A new concept, V4L2 async connection is added. Generally async notifiers
have a number of connections but at that level there is no knowledge of
how many sub-devices they will connect to. The bound and unbound callbacks
now work on connections. For the existing drivers there's only one
connection so I do not expect regressions because of that.

Async sub-device fwnode matching will now take place between the device
(the dev field of struct v4l2_subdev) and a struct v4l2_async_connection
(an endpoint for devices that have endpoints or the device for those that
do not). This is because the graph data structure only describes
point-to-point connections so therefore defining one end of the connection
defines the entire connection.

This set is unlikely to address all needs people have related to the async
framework but I think that beyond what it does, it paves some way for
addressing more of those additional needs.

To be frank, I'd like to get rid of the entire V4L2 async framework, but
it would require allowing much more dynamic driver initialisation,
including sub-devices and device nodes popping up in the system in the
order and extent there is successfully probed hardware. Until that, and
this may well be the entire foreseeable future, we have at least some of
this complexity.

There's a bugfix, too, in the first patch. That should be merged
separately. The rest depends on it so I'm sending it as part of the set.

since RFC v1:

- Address missing API usage changes in a lot of drivers.

- Fix compilation problems in intermediate patches.

- Move V4L2 device registration earlier or move notifier initialisation
  and fwnode endpoint parsing past the current V4L2 device registration
  (patches 11--16).

Sakari Ailus (18):
  media: v4l: async: Return async sub-devices to subnotifier list
  media: v4l: async: Add some debug prints
  media: v4l: async: Simplify async sub-device fwnode matching
  media: v4l: async: Make V4L2 async match information a struct
  media: v4l: async: Clean testing for duplicated async subdevs
  media: v4l: async: Only pass match information for async subdev
    validation
  media: v4l: async: Clean up list heads and entries
  media: v4l: async: Rename v4l2_async_subdev as v4l2_async_connection
  media: v4l: async: Differentiate connecting and creating sub-devices
  media: pxa_camera: Register V4L2 device early, fix probe error
    handling
  media: marvell: cafe: Register V4L2 device earlier
  media: am437x-vpfe: Register V4L2 device early
  media: omap3isp: Initialise V4L2 async notifier later
  media: xilinx-vipp: Init async notifier after registering V4L2 device
  media: davinci: Init async notifier after registering V4L2 device
  media: qcom: Initialise V4L2 async notifier later
  media: v4l: async: Set v4l2_device in async notifier init
  Documentation: media: Document sub-device notifiers

 .../driver-api/media/v4l2-subdev.rst          |  16 +-
 drivers/media/i2c/adv748x/adv748x-csi2.c      |   3 -
 drivers/media/i2c/max9286.c                   |  27 +-
 drivers/media/i2c/rdacm20.c                   |  15 +-
 drivers/media/i2c/rdacm21.c                   |  15 +-
 drivers/media/i2c/st-mipid02.c                |  12 +-
 drivers/media/i2c/tc358746.c                  |  13 +-
 drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  14 +-
 drivers/media/platform/atmel/atmel-isi.c      |  12 +-
 drivers/media/platform/atmel/atmel-isi.h      |   2 +-
 drivers/media/platform/cadence/cdns-csi2rx.c  |  10 +-
 drivers/media/platform/intel/pxa_camera.c     |  46 +-
 drivers/media/platform/marvell/cafe-driver.c  |  19 +-
 drivers/media/platform/marvell/mcam-core.c    |  12 +-
 drivers/media/platform/marvell/mmp-driver.c   |   6 +-
 .../platform/microchip/microchip-csi2dc.c     |  11 +-
 .../platform/microchip/microchip-isc-base.c   |   4 +-
 .../media/platform/microchip/microchip-isc.h  |   2 +-
 .../microchip/microchip-sama5d2-isc.c         |   9 +-
 .../microchip/microchip-sama7g5-isc.c         |   9 +-
 drivers/media/platform/nxp/imx-mipi-csis.c    |  10 +-
 drivers/media/platform/nxp/imx7-media-csi.c   |  10 +-
 drivers/media/platform/qcom/camss/camss.c     |  26 +-
 drivers/media/platform/qcom/camss/camss.h     |   2 +-
 drivers/media/platform/renesas/rcar-isp.c     |  12 +-
 .../platform/renesas/rcar-vin/rcar-core.c     |  26 +-
 .../platform/renesas/rcar-vin/rcar-csi2.c     |  12 +-
 .../platform/renesas/rcar-vin/rcar-vin.h      |   4 +-
 drivers/media/platform/renesas/rcar_drif.c    |  12 +-
 drivers/media/platform/renesas/renesas-ceu.c  |  10 +-
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  14 +-
 .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |   2 +-
 .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   |  12 +-
 .../platform/rockchip/rkisp1/rkisp1-dev.c     |  12 +-
 .../platform/samsung/exynos4-is/media-dev.c   |  11 +-
 .../platform/samsung/exynos4-is/media-dev.h   |   2 +-
 drivers/media/platform/st/stm32/stm32-dcmi.c  |  12 +-
 .../platform/sunxi/sun4i-csi/sun4i_csi.c      |  10 +-
 .../sunxi/sun6i-csi/sun6i_csi_bridge.c        |   8 +-
 .../sunxi/sun6i-csi/sun6i_csi_bridge.h        |   2 +-
 .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c   |  10 +-
 .../sun8i_a83t_mipi_csi2.c                    |  10 +-
 .../media/platform/ti/am437x/am437x-vpfe.c    |  37 +-
 .../media/platform/ti/am437x/am437x-vpfe.h    |   2 +-
 drivers/media/platform/ti/cal/cal.c           |  10 +-
 .../media/platform/ti/davinci/vpif_capture.c  |  33 +-
 drivers/media/platform/ti/omap3isp/isp.c      |  17 +-
 drivers/media/platform/video-mux.c            |  10 +-
 drivers/media/platform/xilinx/xilinx-vipp.c   |  29 +-
 drivers/media/v4l2-core/v4l2-async.c          | 601 +++++++++++-------
 drivers/media/v4l2-core/v4l2-fwnode.c         |  20 +-
 .../media/deprecated/atmel/atmel-isc-base.c   |   4 +-
 .../media/deprecated/atmel/atmel-isc.h        |   2 +-
 .../deprecated/atmel/atmel-sama5d2-isc.c      |   9 +-
 .../deprecated/atmel/atmel-sama7g5-isc.c      |   4 +-
 drivers/staging/media/imx/imx-media-csi.c     |  10 +-
 .../staging/media/imx/imx-media-dev-common.c  |   8 +-
 drivers/staging/media/imx/imx-media-dev.c     |   2 +-
 drivers/staging/media/imx/imx-media-of.c      |   4 +-
 drivers/staging/media/imx/imx6-mipi-csi2.c    |  12 +-
 drivers/staging/media/imx/imx8mq-mipi-csi2.c  |  10 +-
 .../media/sunxi/sun6i-isp/sun6i_isp_proc.c    |   6 +-
 .../media/sunxi/sun6i-isp/sun6i_isp_proc.h    |   2 +-
 drivers/staging/media/tegra-video/vi.c        |  18 +-
 drivers/staging/media/tegra-video/vi.h        |   2 +-
 include/media/davinci/vpif_types.h            |   2 +-
 include/media/v4l2-async.h                    | 181 +++---
 include/media/v4l2-fwnode.h                   |  10 +-
 include/media/v4l2-subdev.h                   |   2 +-
 69 files changed, 825 insertions(+), 708 deletions(-)

-- 
2.30.2

^ permalink raw reply	[flat|nested] 73+ messages in thread

* [PATCH 01/18] media: v4l: async: Return async sub-devices to subnotifier list
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-13 16:49   ` Jacopo Mondi
  2023-04-25  1:28   ` Laurent Pinchart
  2023-03-30 11:58 ` [PATCH 02/18] media: v4l: async: Add some debug prints Sakari Ailus
                   ` (17 subsequent siblings)
  18 siblings, 2 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

When an async notifier is unregistered, the async sub-devices in the
notifier's done list will disappear with the notifier. However this is
currently also done to the sub-notifiers that remain registered. Their
sub-devices only need to be unbound while the async sub-devices themselves
need to be returned to the sub-notifier's waiting list. Do this now.

Fixes: 2cab00bb076b ("media: v4l: async: Allow binding notifiers to sub-devices")
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 2f1b718a9189..008a2a3e312e 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -414,7 +414,8 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 
 /* Unbind all sub-devices in the notifier tree. */
 static void
-v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
+v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
+				 bool readd)
 {
 	struct v4l2_subdev *sd, *tmp;
 
@@ -423,9 +424,11 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
 			v4l2_async_find_subdev_notifier(sd);
 
 		if (subdev_notifier)
-			v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
+			v4l2_async_nf_unbind_all_subdevs(subdev_notifier, true);
 
 		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
+		if (readd)
+			list_add_tail(&sd->asd->list, &notifier->waiting);
 		v4l2_async_cleanup(sd);
 
 		list_move(&sd->async_list, &subdev_list);
@@ -557,7 +560,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 	/*
 	 * On failure, unbind all sub-devices registered through this notifier.
 	 */
-	v4l2_async_nf_unbind_all_subdevs(notifier);
+	v4l2_async_nf_unbind_all_subdevs(notifier, false);
 
 err_unlock:
 	mutex_unlock(&list_lock);
@@ -607,7 +610,7 @@ __v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
 	if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
 		return;
 
-	v4l2_async_nf_unbind_all_subdevs(notifier);
+	v4l2_async_nf_unbind_all_subdevs(notifier, false);
 
 	notifier->sd = NULL;
 	notifier->v4l2_dev = NULL;
@@ -805,7 +808,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 	 */
 	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
 	if (subdev_notifier)
-		v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
+		v4l2_async_nf_unbind_all_subdevs(subdev_notifier, false);
 
 	if (sd->asd)
 		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 02/18] media: v4l: async: Add some debug prints
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
  2023-03-30 11:58 ` [PATCH 01/18] media: v4l: async: Return async sub-devices to subnotifier list Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-13 16:49   ` Jacopo Mondi
  2023-03-30 11:58 ` [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching Sakari Ailus
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Just add some debug prints for V4L2 async sub-device matching process.
These might come useful in figuring out why things don't work as expected.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 59 ++++++++++++++++++++++++----
 1 file changed, 52 insertions(+), 7 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 008a2a3e312e..6dd426c2ca68 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -75,6 +75,12 @@ static bool match_i2c(struct v4l2_async_notifier *notifier,
 #endif
 }
 
+static struct device *notifier_dev(struct v4l2_async_notifier *notifier)
+{
+	return notifier->sd ? notifier->sd->dev : notifier->v4l2_dev ?
+		notifier->v4l2_dev->dev : NULL;
+}
+
 static bool
 match_fwnode_one(struct v4l2_async_notifier *notifier,
 		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
@@ -86,13 +92,18 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
 	bool sd_fwnode_is_ep;
 	struct device *dev;
 
+	dev_dbg(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
+		sd_fwnode, asd->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 == asd->match.fwnode)
+	if (sd_fwnode == asd->match.fwnode) {
+		dev_dbg(sd->dev, "async: direct match found\n");
 		return true;
+	}
 
 	/*
 	 * Otherwise, check if the sd fwnode and the asd fwnode refer to an
@@ -105,8 +116,10 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
 	sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd_fwnode);
 	asd_fwnode_is_ep = fwnode_graph_is_endpoint(asd->match.fwnode);
 
-	if (sd_fwnode_is_ep == asd_fwnode_is_ep)
+	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
+		dev_dbg(sd->dev, "async: matching node types\n");
 		return false;
+	}
 
 	/*
 	 * The sd and asd fwnodes are of different types. Get the device fwnode
@@ -120,10 +133,15 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
 		other_fwnode = sd_fwnode;
 	}
 
+	dev_dbg(sd->dev, "async: fwnode compat match, need %pfw, trying %pfw\n",
+		dev_fwnode, other_fwnode);
+
 	fwnode_handle_put(dev_fwnode);
 
-	if (dev_fwnode != other_fwnode)
+	if (dev_fwnode != other_fwnode) {
+		dev_dbg(sd->dev, "async: compat match not found\n");
 		return false;
+	}
 
 	/*
 	 * We have a heterogeneous match. Retrieve the struct device of the side
@@ -143,12 +161,17 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
 			   dev->driver->name);
 	}
 
+	dev_dbg(sd->dev, "async: compat match found\n");
+
 	return true;
 }
 
 static bool match_fwnode(struct v4l2_async_notifier *notifier,
 			 struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
 {
+	dev_dbg(sd->dev, "async: matching for notifier %pfw, sd %pfw\n",
+		dev_fwnode(notifier_dev(notifier)), sd->fwnode);
+
 	if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
 		return true;
 
@@ -156,6 +179,8 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
 	if (IS_ERR_OR_NULL(sd->fwnode->secondary))
 		return false;
 
+	dev_dbg(sd->dev, "async: trying secondary fwnode match\n");
+
 	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
 }
 
@@ -247,16 +272,21 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_subdev *sd;
 
-	if (!list_empty(&notifier->waiting))
+	if (!list_empty(&notifier->waiting)) {
+		dev_dbg(notifier_dev(notifier), "async: waiting for subdevs\n");
 		return false;
+	}
 
 	list_for_each_entry(sd, &notifier->done, async_list) {
 		struct v4l2_async_notifier *subdev_notifier =
 			v4l2_async_find_subdev_notifier(sd);
 
 		if (subdev_notifier &&
-		    !v4l2_async_nf_can_complete(subdev_notifier))
+		    !v4l2_async_nf_can_complete(subdev_notifier)) {
+			dev_dbg(notifier_dev(notifier),
+				"async: cannot complete\n");
 			return false;
+		}
 	}
 
 	return true;
@@ -269,22 +299,32 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
 static int
 v4l2_async_nf_try_complete(struct v4l2_async_notifier *notifier)
 {
+	struct v4l2_async_notifier *__notifier = notifier;
+
 	/* Quick check whether there are still more sub-devices here. */
 	if (!list_empty(&notifier->waiting))
 		return 0;
 
+	if (notifier->sd)
+		dev_dbg(notifier_dev(notifier), "async: trying to complete\n");
+
 	/* Check the entire notifier tree; find the root notifier first. */
 	while (notifier->parent)
 		notifier = notifier->parent;
 
 	/* This is root if it has v4l2_dev. */
-	if (!notifier->v4l2_dev)
+	if (!notifier->v4l2_dev) {
+		dev_dbg(notifier_dev(__notifier),
+			"async: V4L2 device not available\n");
 		return 0;
+	}
 
 	/* Is everything ready? */
 	if (!v4l2_async_nf_can_complete(notifier))
 		return 0;
 
+	dev_dbg(notifier_dev(__notifier), "async: complete\n");
+
 	return v4l2_async_nf_call_complete(notifier);
 }
 
@@ -362,7 +402,12 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 	 */
 	subdev_notifier->parent = notifier;
 
-	return v4l2_async_nf_try_all_subdevs(subdev_notifier);
+	ret = v4l2_async_nf_try_all_subdevs(subdev_notifier);
+
+	dev_dbg(sd->dev, "async: bound to %s's notifier (ret %d)\n",
+		dev_name(notifier_dev(notifier)), ret);
+
+	return ret;
 }
 
 /* Test all async sub-devices in a notifier for a match. */
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
  2023-03-30 11:58 ` [PATCH 01/18] media: v4l: async: Return async sub-devices to subnotifier list Sakari Ailus
  2023-03-30 11:58 ` [PATCH 02/18] media: v4l: async: Add some debug prints Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-13 16:50   ` Jacopo Mondi
  2023-03-30 11:58 ` [PATCH 04/18] media: v4l: async: Make V4L2 async match information a struct Sakari Ailus
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

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.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/i2c/adv748x/adv748x-csi2.c |  3 -
 drivers/media/i2c/max9286.c              | 14 +---
 drivers/media/i2c/rdacm20.c              | 15 +----
 drivers/media/i2c/rdacm21.c              | 15 +----
 drivers/media/i2c/tc358746.c             |  3 -
 drivers/media/v4l2-core/v4l2-async.c     | 86 ++++++------------------
 6 files changed, 24 insertions(+), 112 deletions(-)

diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index bd4f3fe0e309..3d830816243f 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -300,9 +300,6 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
 			    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 701038d6d19b..2d0f43e3fb9f 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 a2263fa825b5..ea1111152285 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:
diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
index 9ccc56c30d3b..d67cfcb2e05a 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 4063754a6732..56f2b43d4edf 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;
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 6dd426c2ca68..13fe0bdc70b6 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -86,84 +86,33 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
 		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
 		 struct v4l2_async_subdev *asd)
 {
-	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(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
 		sd_fwnode, asd->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 == asd->match.fwnode) {
 		dev_dbg(sd->dev, "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(asd->match.fwnode);
-
-	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
-		dev_dbg(sd->dev, "async: matching node types\n");
+	if (!fwnode_graph_is_endpoint(asd->match.fwnode)) {
+		dev_dbg(sd->dev,
+			"async: async subdev fwnode not endpoint, no match\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 = asd->match.fwnode;
-	} else {
-		dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
-		other_fwnode = sd_fwnode;
-	}
-
-	dev_dbg(sd->dev, "async: fwnode compat match, need %pfw, trying %pfw\n",
-		dev_fwnode, other_fwnode);
+	asd_dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
 
-	fwnode_handle_put(dev_fwnode);
+	ret = sd_fwnode == asd_dev_fwnode;
 
-	if (dev_fwnode != other_fwnode) {
-		dev_dbg(sd->dev, "async: compat match not found\n");
-		return false;
-	}
+	fwnode_handle_put(asd_dev_fwnode);
 
-	/*
-	 * 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(sd->dev, "async: compat match found\n");
+	dev_dbg(sd->dev, "async: device--endpoint match %sfound\n",
+		ret ? "" : "not ");
 
-	return true;
+	return ret;
 }
 
 static bool match_fwnode(struct v4l2_async_notifier *notifier,
@@ -804,12 +753,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. Issue a warning in that case. Once there is
+	 * certainty no driver no longer does this, remove the warning (and
+	 * compatibility code) below.
 	 */
 	if (!sd->fwnode && sd->dev)
 		sd->fwnode = dev_fwnode(sd->dev);
+	else if (WARN_ON(fwnode_graph_is_endpoint(sd->fwnode)))
+		sd->fwnode = fwnode_graph_get_port_parent(sd->fwnode);
 
 	mutex_lock(&list_lock);
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 04/18] media: v4l: async: Make V4L2 async match information a struct
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (2 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-13 16:51   ` Jacopo Mondi
  2023-04-25  1:10   ` Laurent Pinchart
  2023-03-30 11:58 ` [PATCH 05/18] media: v4l: async: Clean testing for duplicated async subdevs Sakari Ailus
                   ` (14 subsequent siblings)
  18 siblings, 2 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Make V4L2 async match information a struct, making it easier to use it
elsewhere outside the scope of struct v4l2_async_subdev.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-async.c  | 18 ++++++-------
 drivers/media/v4l2-core/v4l2-fwnode.c |  2 +-
 include/media/v4l2-async.h            | 39 ++++++++++++++++-----------
 3 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 13fe0bdc70b6..bb78e3618ab5 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -147,7 +147,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
 
 	list_for_each_entry(asd, &notifier->waiting, list) {
 		/* bus_type has been verified valid before */
-		switch (asd->match_type) {
+		switch (asd->match.type) {
 		case V4L2_ASYNC_MATCH_I2C:
 			match = match_i2c;
 			break;
@@ -172,10 +172,10 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
 static bool asd_equal(struct v4l2_async_subdev *asd_x,
 		      struct v4l2_async_subdev *asd_y)
 {
-	if (asd_x->match_type != asd_y->match_type)
+	if (asd_x->match.type != asd_y->match.type)
 		return false;
 
-	switch (asd_x->match_type) {
+	switch (asd_x->match.type) {
 	case V4L2_ASYNC_MATCH_I2C:
 		return asd_x->match.i2c.adapter_id ==
 			asd_y->match.i2c.adapter_id &&
@@ -494,7 +494,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
 	if (!asd)
 		return -EINVAL;
 
-	switch (asd->match_type) {
+	switch (asd->match.type) {
 	case V4L2_ASYNC_MATCH_I2C:
 	case V4L2_ASYNC_MATCH_FWNODE:
 		if (v4l2_async_nf_has_async_subdev(notifier, asd, this_index)) {
@@ -504,7 +504,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
 		break;
 	default:
 		dev_err(dev, "Invalid match type %u on %p\n",
-			asd->match_type, asd);
+			asd->match.type, asd);
 		return -EINVAL;
 	}
 
@@ -630,7 +630,7 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
 		return;
 
 	list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
-		switch (asd->match_type) {
+		switch (asd->match.type) {
 		case V4L2_ASYNC_MATCH_FWNODE:
 			fwnode_handle_put(asd->match.fwnode);
 			break;
@@ -685,7 +685,7 @@ __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
 	if (!asd)
 		return ERR_PTR(-ENOMEM);
 
-	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
 	asd->match.fwnode = fwnode_handle_get(fwnode);
 
 	ret = __v4l2_async_nf_add_subdev(notifier, asd);
@@ -732,7 +732,7 @@ __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier, int adapter_id,
 	if (!asd)
 		return ERR_PTR(-ENOMEM);
 
-	asd->match_type = V4L2_ASYNC_MATCH_I2C;
+	asd->match.type = V4L2_ASYNC_MATCH_I2C;
 	asd->match.i2c.adapter_id = adapter_id;
 	asd->match.i2c.address = address;
 
@@ -850,7 +850,7 @@ EXPORT_SYMBOL(v4l2_async_unregister_subdev);
 static void print_waiting_subdev(struct seq_file *s,
 				 struct v4l2_async_subdev *asd)
 {
-	switch (asd->match_type) {
+	switch (asd->match.type) {
 	case V4L2_ASYNC_MATCH_I2C:
 		seq_printf(s, " [i2c] dev=%d-%04x\n", asd->match.i2c.adapter_id,
 			   asd->match.i2c.address);
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 3d9533c1b202..e6bd63364bed 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -811,7 +811,7 @@ v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
 	if (!asd)
 		return -ENOMEM;
 
-	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
 	asd->match.fwnode =
 		fwnode_graph_get_remote_port_parent(endpoint);
 	if (!asd->match.fwnode) {
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 25eb1d138c06..0c4cffd081c9 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -34,23 +34,38 @@ enum v4l2_async_match_type {
 };
 
 /**
- * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
+ * struct v4l2_async_match - async sub-device match information
  *
- * @match_type:	type of match that will be used
- * @match:	union of per-bus type matching data sets
- * @match.fwnode:
+ * @type:	type of match that will be used
+ * @fwnode:
  *		pointer to &struct fwnode_handle to be matched.
  *		Used if @match_type is %V4L2_ASYNC_MATCH_FWNODE.
- * @match.i2c:	embedded struct with I2C parameters to be matched.
+ * @i2c:	embedded struct with I2C parameters to be matched.
  *		Both @match.i2c.adapter_id and @match.i2c.address
  *		should be matched.
  *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
- * @match.i2c.adapter_id:
+ * @i2c.adapter_id:
  *		I2C adapter ID to be matched.
  *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
- * @match.i2c.address:
+ * @i2c.address:
  *		I2C address to be matched.
  *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
+ */
+struct v4l2_async_match {
+	enum v4l2_async_match_type type;
+	union {
+		struct fwnode_handle *fwnode;
+		struct {
+			int adapter_id;
+			unsigned short address;
+		} i2c;
+	};
+};
+
+/**
+ * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
+ *
+ * @match:	struct of match type and per-bus type matching data sets
  * @asd_list:	used to add struct v4l2_async_subdev objects to the
  *		master notifier @asd_list
  * @list:	used to link struct v4l2_async_subdev objects, waiting to be
@@ -61,15 +76,7 @@ enum v4l2_async_match_type {
  * v4l2_async_subdev as its first member.
  */
 struct v4l2_async_subdev {
-	enum v4l2_async_match_type match_type;
-	union {
-		struct fwnode_handle *fwnode;
-		struct {
-			int adapter_id;
-			unsigned short address;
-		} i2c;
-	} match;
-
+	struct v4l2_async_match match;
 	/* v4l2-async core private: not to be used by drivers */
 	struct list_head list;
 	struct list_head asd_list;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 05/18] media: v4l: async: Clean testing for duplicated async subdevs
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (3 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 04/18] media: v4l: async: Make V4L2 async match information a struct Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-13 16:58   ` Jacopo Mondi
  2023-04-25  1:15   ` Laurent Pinchart
  2023-03-30 11:58 ` [PATCH 06/18] media: v4l: async: Only pass match information for async subdev validation Sakari Ailus
                   ` (13 subsequent siblings)
  18 siblings, 2 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

There's a need to verify that a single async sub-device isn't being added
multiple times, this would be an error. This takes place at the time of
adding the async sub-device to the notifier's list as well as when the
notifier is added to the global notifier's list.

Use the pointer to the sub-device for testing this instead of an index to
an array that is long gone.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index bb78e3618ab5..fc9ae22e2b47 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -456,21 +456,19 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
 
 /*
  * Find out whether an async sub-device was set up already or
- * whether it exists in a given notifier before @this_index.
- * If @this_index < 0, search the notifier's entire @asd_list.
+ * whether it exists in a given notifier.
  */
 static bool
 v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
-			       struct v4l2_async_subdev *asd, int this_index)
+			       struct v4l2_async_subdev *asd, bool skip_self)
 {
 	struct v4l2_async_subdev *asd_y;
-	int j = 0;
 
 	lockdep_assert_held(&list_lock);
 
 	/* Check that an asd is not being added more than once. */
 	list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
-		if (this_index >= 0 && j++ >= this_index)
+		if (asd == asd_y)
 			break;
 		if (asd_equal(asd, asd_y))
 			return true;
@@ -486,7 +484,7 @@ v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
 
 static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
 				   struct v4l2_async_subdev *asd,
-				   int this_index)
+				   bool skip_self)
 {
 	struct device *dev =
 		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
@@ -497,7 +495,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
 	switch (asd->match.type) {
 	case V4L2_ASYNC_MATCH_I2C:
 	case V4L2_ASYNC_MATCH_FWNODE:
-		if (v4l2_async_nf_has_async_subdev(notifier, asd, this_index)) {
+		if (v4l2_async_nf_has_async_subdev(notifier, asd, skip_self)) {
 			dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
 			return -EEXIST;
 		}
@@ -520,7 +518,7 @@ EXPORT_SYMBOL(v4l2_async_nf_init);
 static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_async_subdev *asd;
-	int ret, i = 0;
+	int ret;
 
 	INIT_LIST_HEAD(&notifier->waiting);
 	INIT_LIST_HEAD(&notifier->done);
@@ -528,7 +526,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 	mutex_lock(&list_lock);
 
 	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
-		ret = v4l2_async_nf_asd_valid(notifier, asd, i++);
+		ret = v4l2_async_nf_asd_valid(notifier, asd, true);
 		if (ret)
 			goto err_unlock;
 
@@ -661,7 +659,7 @@ int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
 
 	mutex_lock(&list_lock);
 
-	ret = v4l2_async_nf_asd_valid(notifier, asd, -1);
+	ret = v4l2_async_nf_asd_valid(notifier, asd, false);
 	if (ret)
 		goto unlock;
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 06/18] media: v4l: async: Only pass match information for async subdev validation
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (4 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 05/18] media: v4l: async: Clean testing for duplicated async subdevs Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-14  7:15   ` Jacopo Mondi
  2023-04-25  1:24   ` Laurent Pinchart
  2023-03-30 11:58 ` [PATCH 07/18] media: v4l: async: Clean up list heads and entries Sakari Ailus
                   ` (12 subsequent siblings)
  18 siblings, 2 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Pass only information required for sub-device matching to functions
checking whether the async sub-device already exists. Do the same for
debug message printing. This makes further changes to other aspects of
async sub-devices easier.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 93 ++++++++++++++--------------
 1 file changed, 46 insertions(+), 47 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index fc9ae22e2b47..224ebf50f2d0 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -62,14 +62,14 @@ static void v4l2_async_nf_call_destroy(struct v4l2_async_notifier *n,
 }
 
 static bool match_i2c(struct v4l2_async_notifier *notifier,
-		      struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
+		      struct v4l2_subdev *sd, struct v4l2_async_match *match)
 {
 #if IS_ENABLED(CONFIG_I2C)
 	struct i2c_client *client = i2c_verify_client(sd->dev);
 
 	return client &&
-		asd->match.i2c.adapter_id == client->adapter->nr &&
-		asd->match.i2c.address == client->addr;
+		match->i2c.adapter_id == client->adapter->nr &&
+		match->i2c.address == client->addr;
 #else
 	return false;
 #endif
@@ -84,26 +84,26 @@ static struct device *notifier_dev(struct v4l2_async_notifier *notifier)
 static bool
 match_fwnode_one(struct v4l2_async_notifier *notifier,
 		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
-		 struct v4l2_async_subdev *asd)
+		 struct v4l2_async_match *match)
 {
 	struct fwnode_handle *asd_dev_fwnode;
 	bool ret;
 
 	dev_dbg(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
-		sd_fwnode, asd->match.fwnode);
+		sd_fwnode, match->fwnode);
 
-	if (sd_fwnode == asd->match.fwnode) {
+	if (sd_fwnode == match->fwnode) {
 		dev_dbg(sd->dev, "async: direct match found\n");
 		return true;
 	}
 
-	if (!fwnode_graph_is_endpoint(asd->match.fwnode)) {
+	if (!fwnode_graph_is_endpoint(match->fwnode)) {
 		dev_dbg(sd->dev,
 			"async: async subdev fwnode not endpoint, no match\n");
 		return false;
 	}
 
-	asd_dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
+	asd_dev_fwnode = fwnode_graph_get_port_parent(match->fwnode);
 
 	ret = sd_fwnode == asd_dev_fwnode;
 
@@ -116,12 +116,12 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
 }
 
 static bool match_fwnode(struct v4l2_async_notifier *notifier,
-			 struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
+			 struct v4l2_subdev *sd, struct v4l2_async_match *match)
 {
 	dev_dbg(sd->dev, "async: matching for notifier %pfw, sd %pfw\n",
 		dev_fwnode(notifier_dev(notifier)), sd->fwnode);
 
-	if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
+	if (match_fwnode_one(notifier, sd, sd->fwnode, match))
 		return true;
 
 	/* Also check the secondary fwnode. */
@@ -130,7 +130,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
 
 	dev_dbg(sd->dev, "async: trying secondary fwnode match\n");
 
-	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
+	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, match);
 }
 
 static LIST_HEAD(subdev_list);
@@ -142,7 +142,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
 		      struct v4l2_subdev *sd)
 {
 	bool (*match)(struct v4l2_async_notifier *notifier,
-		      struct v4l2_subdev *sd, struct v4l2_async_subdev *asd);
+		      struct v4l2_subdev *sd, struct v4l2_async_match *match);
 	struct v4l2_async_subdev *asd;
 
 	list_for_each_entry(asd, &notifier->waiting, list) {
@@ -161,7 +161,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
 		}
 
 		/* match cannot be NULL here */
-		if (match(notifier, sd, asd))
+		if (match(notifier, sd, &asd->match))
 			return asd;
 	}
 
@@ -169,20 +169,18 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
 }
 
 /* Compare two async sub-device descriptors for equivalence */
-static bool asd_equal(struct v4l2_async_subdev *asd_x,
-		      struct v4l2_async_subdev *asd_y)
+static bool asd_equal(struct v4l2_async_match *match1,
+		      struct v4l2_async_match *match2)
 {
-	if (asd_x->match.type != asd_y->match.type)
+	if (match1->type != match2->type)
 		return false;
 
-	switch (asd_x->match.type) {
+	switch (match1->type) {
 	case V4L2_ASYNC_MATCH_I2C:
-		return asd_x->match.i2c.adapter_id ==
-			asd_y->match.i2c.adapter_id &&
-			asd_x->match.i2c.address ==
-			asd_y->match.i2c.address;
+		return match1->i2c.adapter_id == match2->i2c.adapter_id &&
+			match1->i2c.address == match2->i2c.address;
 	case V4L2_ASYNC_MATCH_FWNODE:
-		return asd_x->match.fwnode == asd_y->match.fwnode;
+		return match1->fwnode == match2->fwnode;
 	default:
 		break;
 	}
@@ -434,20 +432,20 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
 /* See if an async sub-device can be found in a notifier's lists. */
 static bool
 __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
-				 struct v4l2_async_subdev *asd)
+				 struct v4l2_async_match *match)
 {
-	struct v4l2_async_subdev *asd_y;
+	struct v4l2_async_subdev *asd;
 	struct v4l2_subdev *sd;
 
-	list_for_each_entry(asd_y, &notifier->waiting, list)
-		if (asd_equal(asd, asd_y))
+	list_for_each_entry(asd, &notifier->waiting, list)
+		if (asd_equal(&asd->match, match))
 			return true;
 
 	list_for_each_entry(sd, &notifier->done, async_list) {
 		if (WARN_ON(!sd->asd))
 			continue;
 
-		if (asd_equal(asd, sd->asd))
+		if (asd_equal(&sd->asd->match, match))
 			return true;
 	}
 
@@ -460,49 +458,50 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
  */
 static bool
 v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
-			       struct v4l2_async_subdev *asd, bool skip_self)
+			       struct v4l2_async_match *match, bool skip_self)
 {
-	struct v4l2_async_subdev *asd_y;
+	struct v4l2_async_subdev *asd;
 
 	lockdep_assert_held(&list_lock);
 
 	/* Check that an asd is not being added more than once. */
-	list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
-		if (asd == asd_y)
+	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
+		if (&asd->match == match)
 			break;
-		if (asd_equal(asd, asd_y))
+		if (asd_equal(&asd->match, match))
 			return true;
 	}
 
 	/* Check that an asd does not exist in other notifiers. */
 	list_for_each_entry(notifier, &notifier_list, list)
-		if (__v4l2_async_nf_has_async_subdev(notifier, asd))
+		if (__v4l2_async_nf_has_async_subdev(notifier, match))
 			return true;
 
 	return false;
 }
 
 static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
-				   struct v4l2_async_subdev *asd,
+				   struct v4l2_async_match *match,
 				   bool skip_self)
 {
 	struct device *dev =
 		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
 
-	if (!asd)
+	if (!match)
 		return -EINVAL;
 
-	switch (asd->match.type) {
+	switch (match->type) {
 	case V4L2_ASYNC_MATCH_I2C:
 	case V4L2_ASYNC_MATCH_FWNODE:
-		if (v4l2_async_nf_has_async_subdev(notifier, asd, skip_self)) {
+		if (v4l2_async_nf_has_async_subdev(notifier, match,
+						   skip_self)) {
 			dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
 			return -EEXIST;
 		}
 		break;
 	default:
-		dev_err(dev, "Invalid match type %u on %p\n",
-			asd->match.type, asd);
+		dev_err(dev, "Invalid match type %u on %p\n", match->type,
+			match);
 		return -EINVAL;
 	}
 
@@ -526,7 +525,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 	mutex_lock(&list_lock);
 
 	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
-		ret = v4l2_async_nf_asd_valid(notifier, asd, true);
+		ret = v4l2_async_nf_asd_valid(notifier, &asd->match, true);
 		if (ret)
 			goto err_unlock;
 
@@ -659,7 +658,7 @@ int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
 
 	mutex_lock(&list_lock);
 
-	ret = v4l2_async_nf_asd_valid(notifier, asd, false);
+	ret = v4l2_async_nf_asd_valid(notifier, &asd->match, false);
 	if (ret)
 		goto unlock;
 
@@ -846,15 +845,15 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 EXPORT_SYMBOL(v4l2_async_unregister_subdev);
 
 static void print_waiting_subdev(struct seq_file *s,
-				 struct v4l2_async_subdev *asd)
+				 struct v4l2_async_match *match)
 {
-	switch (asd->match.type) {
+	switch (match->type) {
 	case V4L2_ASYNC_MATCH_I2C:
-		seq_printf(s, " [i2c] dev=%d-%04x\n", asd->match.i2c.adapter_id,
-			   asd->match.i2c.address);
+		seq_printf(s, " [i2c] dev=%d-%04x\n", match->i2c.adapter_id,
+			   match->i2c.address);
 		break;
 	case V4L2_ASYNC_MATCH_FWNODE: {
-		struct fwnode_handle *devnode, *fwnode = asd->match.fwnode;
+		struct fwnode_handle *devnode, *fwnode = match->fwnode;
 
 		devnode = fwnode_graph_is_endpoint(fwnode) ?
 			  fwnode_graph_get_port_parent(fwnode) :
@@ -891,7 +890,7 @@ static int pending_subdevs_show(struct seq_file *s, void *data)
 	list_for_each_entry(notif, &notifier_list, list) {
 		seq_printf(s, "%s:\n", v4l2_async_nf_name(notif));
 		list_for_each_entry(asd, &notif->waiting, list)
-			print_waiting_subdev(s, asd);
+			print_waiting_subdev(s, &asd->match);
 	}
 
 	mutex_unlock(&list_lock);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 07/18] media: v4l: async: Clean up list heads and entries
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (5 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 06/18] media: v4l: async: Only pass match information for async subdev validation Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-14  7:26   ` Jacopo Mondi
  2023-04-25  0:49   ` Laurent Pinchart
  2023-03-30 11:58 ` [PATCH 08/18] media: v4l: async: Rename v4l2_async_subdev as v4l2_async_connection Sakari Ailus
                   ` (11 subsequent siblings)
  18 siblings, 2 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

The naming of list heads and list entries is confusing as they're named
similarly. Use _head for list head and _list for list entries.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  2 +-
 .../platform/renesas/rcar-vin/rcar-core.c     |  2 +-
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  2 +-
 drivers/media/platform/xilinx/xilinx-vipp.c   | 10 +--
 drivers/media/v4l2-core/v4l2-async.c          | 66 +++++++++----------
 .../staging/media/imx/imx-media-dev-common.c  |  2 +-
 drivers/staging/media/tegra-video/vi.c        |  6 +-
 include/media/v4l2-async.h                    | 21 +++---
 8 files changed, 56 insertions(+), 55 deletions(-)

diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
index 3b76a9d0383a..8b37c2ec8643 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
@@ -1419,7 +1419,7 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier)
 	unsigned int pad;
 	int ret;
 
-	list_for_each_entry(asd, &cio2->notifier.asd_list, asd_list) {
+	list_for_each_entry(asd, &cio2->notifier.asd_head, asd_list) {
 		s_asd = to_sensor_asd(asd);
 		q = &cio2->queue[s_asd->csi2.port];
 
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
index 5e53d6b7036c..1b530da1c341 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
@@ -397,7 +397,7 @@ static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port,
 		}
 	}
 
-	if (list_empty(&vin->group->notifier.asd_list))
+	if (list_empty(&vin->group->notifier.asd_head))
 		return 0;
 
 	vin->group->notifier.ops = &rvin_group_notify_ops;
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 5939f5165a5e..bfef297f5ec5 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -191,7 +191,7 @@ static int rzg2l_cru_mc_parse_of_graph(struct rzg2l_cru_dev *cru)
 
 	cru->notifier.ops = &rzg2l_cru_async_ops;
 
-	if (list_empty(&cru->notifier.asd_list))
+	if (list_empty(&cru->notifier.asd_head))
 		return 0;
 
 	ret = v4l2_async_nf_register(&cru->v4l2_dev, &cru->notifier);
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index 0a16c218a50a..80157b7a28ee 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -56,7 +56,7 @@ xvip_graph_find_entity(struct xvip_composite_device *xdev,
 	struct xvip_graph_entity *entity;
 	struct v4l2_async_subdev *asd;
 
-	list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
+	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
 		entity = to_xvip_entity(asd);
 		if (entity->asd.match.fwnode == fwnode)
 			return entity;
@@ -291,7 +291,7 @@ static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier)
 	dev_dbg(xdev->dev, "notify complete, all subdevs registered\n");
 
 	/* Create links for every entity. */
-	list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
+	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
 		entity = to_xvip_entity(asd);
 		ret = xvip_graph_build_one(xdev, entity);
 		if (ret < 0)
@@ -322,7 +322,7 @@ static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
 	/* Locate the entity corresponding to the bound subdev and store the
 	 * subdev pointer.
 	 */
-	list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
+	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
 		entity = to_xvip_entity(asd);
 
 		if (entity->asd.match.fwnode != subdev->fwnode)
@@ -415,7 +415,7 @@ static int xvip_graph_parse(struct xvip_composite_device *xdev)
 	if (ret < 0)
 		return 0;
 
-	list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
+	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
 		entity = to_xvip_entity(asd);
 		ret = xvip_graph_parse_one(xdev, entity->asd.match.fwnode);
 		if (ret < 0) {
@@ -523,7 +523,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
 		goto done;
 	}
 
-	if (list_empty(&xdev->notifier.asd_list)) {
+	if (list_empty(&xdev->notifier.asd_head)) {
 		dev_err(xdev->dev, "no subdev found in graph\n");
 		ret = -ENOENT;
 		goto done;
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 224ebf50f2d0..fdc995dfc15c 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -133,8 +133,8 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
 	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, match);
 }
 
-static LIST_HEAD(subdev_list);
-static LIST_HEAD(notifier_list);
+static LIST_HEAD(subdev_head);
+static LIST_HEAD(notifier_head);
 static DEFINE_MUTEX(list_lock);
 
 static struct v4l2_async_subdev *
@@ -145,7 +145,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
 		      struct v4l2_subdev *sd, struct v4l2_async_match *match);
 	struct v4l2_async_subdev *asd;
 
-	list_for_each_entry(asd, &notifier->waiting, list) {
+	list_for_each_entry(asd, &notifier->waiting_head, waiting_list) {
 		/* bus_type has been verified valid before */
 		switch (asd->match.type) {
 		case V4L2_ASYNC_MATCH_I2C:
@@ -194,7 +194,7 @@ v4l2_async_find_subdev_notifier(struct v4l2_subdev *sd)
 {
 	struct v4l2_async_notifier *n;
 
-	list_for_each_entry(n, &notifier_list, list)
+	list_for_each_entry(n, &notifier_head, notifier_list)
 		if (n->sd == sd)
 			return n;
 
@@ -219,12 +219,12 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_subdev *sd;
 
-	if (!list_empty(&notifier->waiting)) {
+	if (!list_empty(&notifier->waiting_head)) {
 		dev_dbg(notifier_dev(notifier), "async: waiting for subdevs\n");
 		return false;
 	}
 
-	list_for_each_entry(sd, &notifier->done, async_list) {
+	list_for_each_entry(sd, &notifier->done_head, async_list) {
 		struct v4l2_async_notifier *subdev_notifier =
 			v4l2_async_find_subdev_notifier(sd);
 
@@ -249,7 +249,7 @@ v4l2_async_nf_try_complete(struct v4l2_async_notifier *notifier)
 	struct v4l2_async_notifier *__notifier = notifier;
 
 	/* Quick check whether there are still more sub-devices here. */
-	if (!list_empty(&notifier->waiting))
+	if (!list_empty(&notifier->waiting_head))
 		return 0;
 
 	if (notifier->sd)
@@ -327,13 +327,12 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 		return ret;
 	}
 
-	/* Remove from the waiting list */
-	list_del(&asd->list);
+	list_del(&asd->waiting_list);
 	sd->asd = asd;
 	sd->notifier = notifier;
 
 	/* Move from the global subdevice list to notifier's done */
-	list_move(&sd->async_list, &notifier->done);
+	list_move(&sd->async_list, &notifier->done_head);
 
 	/*
 	 * See if the sub-device has a notifier. If not, return here.
@@ -369,7 +368,7 @@ v4l2_async_nf_try_all_subdevs(struct v4l2_async_notifier *notifier)
 		return 0;
 
 again:
-	list_for_each_entry(sd, &subdev_list, async_list) {
+	list_for_each_entry(sd, &subdev_head, async_list) {
 		struct v4l2_async_subdev *asd;
 		int ret;
 
@@ -411,7 +410,7 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
 {
 	struct v4l2_subdev *sd, *tmp;
 
-	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
+	list_for_each_entry_safe(sd, tmp, &notifier->done_head, async_list) {
 		struct v4l2_async_notifier *subdev_notifier =
 			v4l2_async_find_subdev_notifier(sd);
 
@@ -420,10 +419,11 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
 
 		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
 		if (readd)
-			list_add_tail(&sd->asd->list, &notifier->waiting);
+			list_add_tail(&sd->asd->waiting_list,
+				      &notifier->waiting_head);
 		v4l2_async_cleanup(sd);
 
-		list_move(&sd->async_list, &subdev_list);
+		list_move(&sd->async_list, &subdev_head);
 	}
 
 	notifier->parent = NULL;
@@ -437,11 +437,11 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
 	struct v4l2_async_subdev *asd;
 	struct v4l2_subdev *sd;
 
-	list_for_each_entry(asd, &notifier->waiting, list)
+	list_for_each_entry(asd, &notifier->waiting_head, waiting_list)
 		if (asd_equal(&asd->match, match))
 			return true;
 
-	list_for_each_entry(sd, &notifier->done, async_list) {
+	list_for_each_entry(sd, &notifier->done_head, async_list) {
 		if (WARN_ON(!sd->asd))
 			continue;
 
@@ -465,7 +465,7 @@ v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
 	lockdep_assert_held(&list_lock);
 
 	/* Check that an asd is not being added more than once. */
-	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
+	list_for_each_entry(asd, &notifier->asd_head, asd_list) {
 		if (&asd->match == match)
 			break;
 		if (asd_equal(&asd->match, match))
@@ -473,7 +473,7 @@ v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
 	}
 
 	/* Check that an asd does not exist in other notifiers. */
-	list_for_each_entry(notifier, &notifier_list, list)
+	list_for_each_entry(notifier, &notifier_head, notifier_list)
 		if (__v4l2_async_nf_has_async_subdev(notifier, match))
 			return true;
 
@@ -510,7 +510,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
 
 void v4l2_async_nf_init(struct v4l2_async_notifier *notifier)
 {
-	INIT_LIST_HEAD(&notifier->asd_list);
+	INIT_LIST_HEAD(&notifier->asd_head);
 }
 EXPORT_SYMBOL(v4l2_async_nf_init);
 
@@ -519,17 +519,17 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 	struct v4l2_async_subdev *asd;
 	int ret;
 
-	INIT_LIST_HEAD(&notifier->waiting);
-	INIT_LIST_HEAD(&notifier->done);
+	INIT_LIST_HEAD(&notifier->waiting_head);
+	INIT_LIST_HEAD(&notifier->done_head);
 
 	mutex_lock(&list_lock);
 
-	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
+	list_for_each_entry(asd, &notifier->asd_head, asd_list) {
 		ret = v4l2_async_nf_asd_valid(notifier, &asd->match, true);
 		if (ret)
 			goto err_unlock;
 
-		list_add_tail(&asd->list, &notifier->waiting);
+		list_add_tail(&asd->waiting_list, &notifier->waiting_head);
 	}
 
 	ret = v4l2_async_nf_try_all_subdevs(notifier);
@@ -541,7 +541,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 		goto err_unbind;
 
 	/* Keep also completed notifiers on the list */
-	list_add(&notifier->list, &notifier_list);
+	list_add(&notifier->notifier_list, &notifier_head);
 
 	mutex_unlock(&list_lock);
 
@@ -606,7 +606,7 @@ __v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
 	notifier->sd = NULL;
 	notifier->v4l2_dev = NULL;
 
-	list_del(&notifier->list);
+	list_del(&notifier->notifier_list);
 }
 
 void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
@@ -623,10 +623,10 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_async_subdev *asd, *tmp;
 
-	if (!notifier || !notifier->asd_list.next)
+	if (!notifier || !notifier->asd_head.next)
 		return;
 
-	list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
+	list_for_each_entry_safe(asd, tmp, &notifier->asd_head, asd_list) {
 		switch (asd->match.type) {
 		case V4L2_ASYNC_MATCH_FWNODE:
 			fwnode_handle_put(asd->match.fwnode);
@@ -662,7 +662,7 @@ int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
 	if (ret)
 		goto unlock;
 
-	list_add_tail(&asd->asd_list, &notifier->asd_list);
+	list_add_tail(&asd->asd_list, &notifier->asd_head);
 
 unlock:
 	mutex_unlock(&list_lock);
@@ -768,7 +768,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 
 	INIT_LIST_HEAD(&sd->async_list);
 
-	list_for_each_entry(notifier, &notifier_list, list) {
+	list_for_each_entry(notifier, &notifier_head, notifier_list) {
 		struct v4l2_device *v4l2_dev =
 			v4l2_async_nf_find_v4l2_dev(notifier);
 		struct v4l2_async_subdev *asd;
@@ -792,7 +792,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 	}
 
 	/* None matched, wait for hot-plugging */
-	list_add(&sd->async_list, &subdev_list);
+	list_add(&sd->async_list, &subdev_head);
 
 out_unlock:
 	mutex_unlock(&list_lock);
@@ -833,7 +833,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 	if (sd->asd) {
 		struct v4l2_async_notifier *notifier = sd->notifier;
 
-		list_add(&sd->asd->list, &notifier->waiting);
+		list_add(&sd->asd->waiting_list, &notifier->waiting_head);
 
 		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
 	}
@@ -887,9 +887,9 @@ static int pending_subdevs_show(struct seq_file *s, void *data)
 
 	mutex_lock(&list_lock);
 
-	list_for_each_entry(notif, &notifier_list, list) {
+	list_for_each_entry(notif, &notifier_head, notifier_list) {
 		seq_printf(s, "%s:\n", v4l2_async_nf_name(notif));
-		list_for_each_entry(asd, &notif->waiting, list)
+		list_for_each_entry(asd, &notif->waiting_head, waiting_list)
 			print_waiting_subdev(s, &asd->match);
 	}
 
diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c
index e6d6ed3b1161..eaa54848df6a 100644
--- a/drivers/staging/media/imx/imx-media-dev-common.c
+++ b/drivers/staging/media/imx/imx-media-dev-common.c
@@ -398,7 +398,7 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd,
 	int ret;
 
 	/* no subdevs? just bail */
-	if (list_empty(&imxmd->notifier.asd_list)) {
+	if (list_empty(&imxmd->notifier.asd_head)) {
 		v4l2_err(&imxmd->v4l2_dev, "no subdevs\n");
 		return -ENODEV;
 	}
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 11dd142c98c5..4818646fe637 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -1563,7 +1563,7 @@ tegra_vi_graph_find_entity(struct tegra_vi_channel *chan,
 	struct tegra_vi_graph_entity *entity;
 	struct v4l2_async_subdev *asd;
 
-	list_for_each_entry(asd, &chan->notifier.asd_list, asd_list) {
+	list_for_each_entry(asd, &chan->notifier.asd_head, asd_list) {
 		entity = to_tegra_vi_graph_entity(asd);
 		if (entity->asd.match.fwnode == fwnode)
 			return entity;
@@ -1707,7 +1707,7 @@ static int tegra_vi_graph_notify_complete(struct v4l2_async_notifier *notifier)
 	}
 
 	/* create links between the entities */
-	list_for_each_entry(asd, &chan->notifier.asd_list, asd_list) {
+	list_for_each_entry(asd, &chan->notifier.asd_head, asd_list) {
 		entity = to_tegra_vi_graph_entity(asd);
 		ret = tegra_vi_graph_build(chan, entity);
 		if (ret < 0)
@@ -1874,7 +1874,7 @@ static int tegra_vi_graph_init(struct tegra_vi *vi)
 
 		ret = tegra_vi_graph_parse_one(chan, remote);
 		fwnode_handle_put(remote);
-		if (ret < 0 || list_empty(&chan->notifier.asd_list))
+		if (ret < 0 || list_empty(&chan->notifier.asd_head))
 			continue;
 
 		chan->notifier.ops = &tegra_vi_async_ops;
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 0c4cffd081c9..425280b4d387 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -68,7 +68,7 @@ struct v4l2_async_match {
  * @match:	struct of match type and per-bus type matching data sets
  * @asd_list:	used to add struct v4l2_async_subdev objects to the
  *		master notifier @asd_list
- * @list:	used to link struct v4l2_async_subdev objects, waiting to be
+ * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
  *		probed, to a notifier->waiting list
  *
  * When this struct is used as a member in a driver specific struct,
@@ -77,9 +77,10 @@ struct v4l2_async_match {
  */
 struct v4l2_async_subdev {
 	struct v4l2_async_match match;
+
 	/* v4l2-async core private: not to be used by drivers */
-	struct list_head list;
 	struct list_head asd_list;
+	struct list_head waiting_list;
 };
 
 /**
@@ -108,20 +109,20 @@ struct v4l2_async_notifier_operations {
  * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
  * @sd:		sub-device that registered the notifier, NULL otherwise
  * @parent:	parent notifier
- * @asd_list:	master list of struct v4l2_async_subdev
- * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
- * @done:	list of struct v4l2_subdev, already probed
- * @list:	member in a global list of notifiers
+ * @asd_head:	master list of struct v4l2_async_subdev
+ * @waiting_list: list of struct v4l2_async_subdev, waiting for their drivers
+ * @done_head:	list of struct v4l2_subdev, already probed
+ * @notifier_list: member in a global list of notifiers
  */
 struct v4l2_async_notifier {
 	const struct v4l2_async_notifier_operations *ops;
 	struct v4l2_device *v4l2_dev;
 	struct v4l2_subdev *sd;
 	struct v4l2_async_notifier *parent;
-	struct list_head asd_list;
-	struct list_head waiting;
-	struct list_head done;
-	struct list_head list;
+	struct list_head asd_head;
+	struct list_head waiting_head;
+	struct list_head done_head;
+	struct list_head notifier_list;
 };
 
 /**
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 08/18] media: v4l: async: Rename v4l2_async_subdev as v4l2_async_connection
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (6 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 07/18] media: v4l: async: Clean up list heads and entries Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-14  8:22   ` Jacopo Mondi
  2023-03-30 11:58 ` [PATCH 09/18] media: v4l: async: Differentiate connecting and creating sub-devices Sakari Ailus
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

This patch has been generated by:

	git grep -l v4l2_async_subdev | \
		while read i; do \
			spatch --sp-file async.spatch --in-place $i; done \
			perl -i -pe 's/v4l2_async_\Ksubdev/connection/g' $i \
		done

While async.spatch looks like:

@ name @
@@
- struct v4l2_async_subdev
+ struct v4l2_async_connection

Additionally, __v4l2_async_nf_add_subdev() has been renamed as
__v4l2_async_nf_add_connection(). Some manual editing has been performed
as well.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 .../driver-api/media/v4l2-subdev.rst          |  10 +-
 drivers/media/i2c/max9286.c                   |   9 +-
 drivers/media/i2c/st-mipid02.c                |   8 +-
 drivers/media/i2c/tc358746.c                  |   6 +-
 drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  10 +-
 drivers/media/platform/atmel/atmel-isi.c      |   8 +-
 drivers/media/platform/atmel/atmel-isi.h      |   2 +-
 drivers/media/platform/cadence/cdns-csi2rx.c  |   6 +-
 drivers/media/platform/intel/pxa_camera.c     |  12 +-
 drivers/media/platform/marvell/cafe-driver.c  |   5 +-
 drivers/media/platform/marvell/mcam-core.c    |   4 +-
 drivers/media/platform/marvell/mmp-driver.c   |   4 +-
 .../platform/microchip/microchip-csi2dc.c     |   6 +-
 .../platform/microchip/microchip-isc-base.c   |   4 +-
 .../media/platform/microchip/microchip-isc.h  |   2 +-
 .../microchip/microchip-sama5d2-isc.c         |   4 +-
 .../microchip/microchip-sama7g5-isc.c         |   4 +-
 drivers/media/platform/nxp/imx-mipi-csis.c    |   6 +-
 drivers/media/platform/nxp/imx7-media-csi.c   |   6 +-
 drivers/media/platform/qcom/camss/camss.c     |   2 +-
 drivers/media/platform/qcom/camss/camss.h     |   2 +-
 drivers/media/platform/renesas/rcar-isp.c     |   8 +-
 .../platform/renesas/rcar-vin/rcar-core.c     |  18 +-
 .../platform/renesas/rcar-vin/rcar-csi2.c     |   8 +-
 .../platform/renesas/rcar-vin/rcar-vin.h      |   4 +-
 drivers/media/platform/renesas/rcar_drif.c    |   8 +-
 drivers/media/platform/renesas/renesas-ceu.c  |   6 +-
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  10 +-
 .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |   2 +-
 .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   |   8 +-
 .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
 .../platform/rockchip/rkisp1/rkisp1-dev.c     |   4 +-
 .../platform/samsung/exynos4-is/media-dev.c   |   6 +-
 .../platform/samsung/exynos4-is/media-dev.h   |   2 +-
 drivers/media/platform/st/stm32/stm32-dcmi.c  |   8 +-
 .../platform/sunxi/sun4i-csi/sun4i_csi.c      |   6 +-
 .../sunxi/sun6i-csi/sun6i_csi_bridge.c        |   2 +-
 .../sunxi/sun6i-csi/sun6i_csi_bridge.h        |   2 +-
 .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c   |   6 +-
 .../sun8i_a83t_mipi_csi2.c                    |   6 +-
 .../media/platform/ti/am437x/am437x-vpfe.c    |   5 +-
 .../media/platform/ti/am437x/am437x-vpfe.h    |   2 +-
 drivers/media/platform/ti/cal/cal.c           |   6 +-
 .../media/platform/ti/davinci/vpif_capture.c  |   7 +-
 drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
 drivers/media/platform/video-mux.c            |   6 +-
 drivers/media/platform/xilinx/xilinx-vipp.c   |  24 +--
 drivers/media/v4l2-core/v4l2-async.c          | 166 +++++++++---------
 drivers/media/v4l2-core/v4l2-fwnode.c         |  14 +-
 .../media/deprecated/atmel/atmel-isc-base.c   |   4 +-
 .../media/deprecated/atmel/atmel-isc.h        |   2 +-
 .../deprecated/atmel/atmel-sama5d2-isc.c      |   4 +-
 .../deprecated/atmel/atmel-sama7g5-isc.c      |   4 +-
 drivers/staging/media/imx/imx-media-csi.c     |   6 +-
 .../staging/media/imx/imx-media-dev-common.c  |   4 +-
 drivers/staging/media/imx/imx-media-dev.c     |   2 +-
 drivers/staging/media/imx/imx-media-of.c      |   4 +-
 drivers/staging/media/imx/imx6-mipi-csi2.c    |   8 +-
 drivers/staging/media/imx/imx8mq-mipi-csi2.c  |   6 +-
 .../media/sunxi/sun6i-isp/sun6i_isp_proc.c    |   2 +-
 .../media/sunxi/sun6i-isp/sun6i_isp_proc.h    |   2 +-
 drivers/staging/media/tegra-video/vi.c        |  14 +-
 drivers/staging/media/tegra-video/vi.h        |   2 +-
 include/media/davinci/vpif_types.h            |   2 +-
 include/media/v4l2-async.h                    |  78 ++++----
 include/media/v4l2-fwnode.h                   |  10 +-
 include/media/v4l2-subdev.h                   |   4 +-
 67 files changed, 313 insertions(+), 313 deletions(-)

diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst
index 260cfa8c3f3d..1c5cb1a637ab 100644
--- a/Documentation/driver-api/media/v4l2-subdev.rst
+++ b/Documentation/driver-api/media/v4l2-subdev.rst
@@ -215,13 +215,13 @@ found in firmware. The notifier for the sub-device is unregistered with the
 async sub-device.
 
 These functions allocate an async sub-device descriptor which is of type struct
-:c:type:`v4l2_async_subdev` embedded in a driver-specific struct. The &struct
-:c:type:`v4l2_async_subdev` shall be the first member of this struct:
+:c:type:`v4l2_async_connection` embedded in a driver-specific struct. The &struct
+:c:type:`v4l2_async_connection` shall be the first member of this struct:
 
 .. code-block:: c
 
 	struct my_async_subdev {
-		struct v4l2_async_subdev asd;
+		struct v4l2_async_connection asd;
 		...
 	};
 
@@ -244,10 +244,10 @@ notifier callback is called. After all subdevices have been located the
 system the .unbind() method is called. All three callbacks are optional.
 
 Drivers can store any type of custom data in their driver-specific
-:c:type:`v4l2_async_subdev` wrapper. If any of that data requires special
+:c:type:`v4l2_async_connection` wrapper. If any of that data requires special
 handling when the structure is freed, drivers must implement the ``.destroy()``
 notifier callback. The framework will call it right before freeing the
-:c:type:`v4l2_async_subdev`.
+:c:type:`v4l2_async_connection`.
 
 Calling subdev operations
 ~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 2d0f43e3fb9f..13cb2537a06d 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -161,11 +161,12 @@ struct max9286_source {
 };
 
 struct max9286_asd {
-	struct v4l2_async_subdev base;
+	struct v4l2_async_connection base;
 	struct max9286_source *source;
 };
 
-static inline struct max9286_asd *to_max9286_asd(struct v4l2_async_subdev *asd)
+static inline struct max9286_asd *
+to_max9286_asd(struct v4l2_async_connection *asd)
 {
 	return container_of(asd, struct max9286_asd, base);
 }
@@ -659,7 +660,7 @@ static int max9286_set_pixelrate(struct max9286_priv *priv)
 
 static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
 				struct v4l2_subdev *subdev,
-				struct v4l2_async_subdev *asd)
+				struct v4l2_async_connection *asd)
 {
 	struct max9286_priv *priv = sd_to_max9286(notifier->sd);
 	struct max9286_source *source = to_max9286_asd(asd)->source;
@@ -721,7 +722,7 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
 
 static void max9286_notify_unbind(struct v4l2_async_notifier *notifier,
 				  struct v4l2_subdev *subdev,
-				  struct v4l2_async_subdev *asd)
+				  struct v4l2_async_connection *asd)
 {
 	struct max9286_priv *priv = sd_to_max9286(notifier->sd);
 	struct max9286_source *source = to_max9286_asd(asd)->source;
diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c
index 31b89aff0e86..daea4cb29ec8 100644
--- a/drivers/media/i2c/st-mipid02.c
+++ b/drivers/media/i2c/st-mipid02.c
@@ -820,7 +820,7 @@ static const struct media_entity_operations mipid02_subdev_entity_ops = {
 
 static int mipid02_async_bound(struct v4l2_async_notifier *notifier,
 			       struct v4l2_subdev *s_subdev,
-			       struct v4l2_async_subdev *asd)
+			       struct v4l2_async_connection *asd)
 {
 	struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd);
 	struct i2c_client *client = bridge->i2c_client;
@@ -854,7 +854,7 @@ static int mipid02_async_bound(struct v4l2_async_notifier *notifier,
 
 static void mipid02_async_unbind(struct v4l2_async_notifier *notifier,
 				 struct v4l2_subdev *s_subdev,
-				 struct v4l2_async_subdev *asd)
+				 struct v4l2_async_connection *asd)
 {
 	struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd);
 
@@ -870,7 +870,7 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge)
 {
 	struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
 	struct i2c_client *client = bridge->i2c_client;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct device_node *ep_node;
 	int ret;
 
@@ -905,7 +905,7 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge)
 	v4l2_async_nf_init(&bridge->notifier);
 	asd = v4l2_async_nf_add_fwnode_remote(&bridge->notifier,
 					      of_fwnode_handle(ep_node),
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 	of_node_put(ep_node);
 
 	if (IS_ERR(asd)) {
diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
index 56f2b43d4edf..f1f747f12228 100644
--- a/drivers/media/i2c/tc358746.c
+++ b/drivers/media/i2c/tc358746.c
@@ -1426,7 +1426,7 @@ static int tc358746_init_controls(struct tc358746 *tc358746)
 
 static int tc358746_notify_bound(struct v4l2_async_notifier *notifier,
 				 struct v4l2_subdev *sd,
-				 struct v4l2_async_subdev *asd)
+				 struct v4l2_async_connection *asd)
 {
 	struct tc358746 *tc358746 =
 		container_of(notifier, struct tc358746, notifier);
@@ -1445,7 +1445,7 @@ static int tc358746_async_register(struct tc358746 *tc358746)
 	struct v4l2_fwnode_endpoint vep = {
 		.bus_type = V4L2_MBUS_PARALLEL,
 	};
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct fwnode_handle *ep;
 	int err;
 
@@ -1462,7 +1462,7 @@ static int tc358746_async_register(struct tc358746 *tc358746)
 
 	v4l2_async_nf_init(&tc358746->notifier);
 	asd = v4l2_async_nf_add_fwnode_remote(&tc358746->notifier, ep,
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 	fwnode_handle_put(ep);
 
 	if (IS_ERR(asd)) {
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
index 8b37c2ec8643..b70db7e20acb 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
@@ -1370,7 +1370,7 @@ static const struct v4l2_subdev_ops cio2_subdev_ops = {
 /******* V4L2 sub-device asynchronous registration callbacks***********/
 
 struct sensor_async_subdev {
-	struct v4l2_async_subdev asd;
+	struct v4l2_async_connection asd;
 	struct csi2_bus_info csi2;
 };
 
@@ -1379,7 +1379,7 @@ struct sensor_async_subdev {
 /* The .bound() notifier callback when a match is found */
 static int cio2_notifier_bound(struct v4l2_async_notifier *notifier,
 			       struct v4l2_subdev *sd,
-			       struct v4l2_async_subdev *asd)
+			       struct v4l2_async_connection *asd)
 {
 	struct cio2_device *cio2 = to_cio2_device(notifier);
 	struct sensor_async_subdev *s_asd = to_sensor_asd(asd);
@@ -1400,7 +1400,7 @@ static int cio2_notifier_bound(struct v4l2_async_notifier *notifier,
 /* The .unbind callback */
 static void cio2_notifier_unbind(struct v4l2_async_notifier *notifier,
 				 struct v4l2_subdev *sd,
-				 struct v4l2_async_subdev *asd)
+				 struct v4l2_async_connection *asd)
 {
 	struct cio2_device *cio2 = to_cio2_device(notifier);
 	struct sensor_async_subdev *s_asd = to_sensor_asd(asd);
@@ -1414,12 +1414,12 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier)
 	struct cio2_device *cio2 = to_cio2_device(notifier);
 	struct device *dev = &cio2->pci_dev->dev;
 	struct sensor_async_subdev *s_asd;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct cio2_queue *q;
 	unsigned int pad;
 	int ret;
 
-	list_for_each_entry(asd, &cio2->notifier.asd_head, asd_list) {
+	list_for_each_entry(asd, &cio2->notifier.asc_head, asc_list) {
 		s_asd = to_sensor_asd(asd);
 		q = &cio2->queue[s_asd->csi2.port];
 
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index 4d15814e4481..2da5918bbff0 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -1120,7 +1120,7 @@ static int isi_graph_notify_complete(struct v4l2_async_notifier *notifier)
 
 static void isi_graph_notify_unbind(struct v4l2_async_notifier *notifier,
 				     struct v4l2_subdev *sd,
-				     struct v4l2_async_subdev *asd)
+				     struct v4l2_async_connection *asd)
 {
 	struct atmel_isi *isi = notifier_to_isi(notifier);
 
@@ -1132,7 +1132,7 @@ static void isi_graph_notify_unbind(struct v4l2_async_notifier *notifier,
 
 static int isi_graph_notify_bound(struct v4l2_async_notifier *notifier,
 				   struct v4l2_subdev *subdev,
-				   struct v4l2_async_subdev *asd)
+				   struct v4l2_async_connection *asd)
 {
 	struct atmel_isi *isi = notifier_to_isi(notifier);
 
@@ -1151,7 +1151,7 @@ static const struct v4l2_async_notifier_operations isi_graph_notify_ops = {
 
 static int isi_graph_init(struct atmel_isi *isi)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct device_node *ep;
 	int ret;
 
@@ -1163,7 +1163,7 @@ static int isi_graph_init(struct atmel_isi *isi)
 
 	asd = v4l2_async_nf_add_fwnode_remote(&isi->notifier,
 					      of_fwnode_handle(ep),
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 	of_node_put(ep);
 
 	if (IS_ERR(asd))
diff --git a/drivers/media/platform/atmel/atmel-isi.h b/drivers/media/platform/atmel/atmel-isi.h
index 7ad3895a2c87..58ce900ca4c9 100644
--- a/drivers/media/platform/atmel/atmel-isi.h
+++ b/drivers/media/platform/atmel/atmel-isi.h
@@ -121,7 +121,7 @@
 #define ISI_DATAWIDTH_8				0x01
 #define ISI_DATAWIDTH_10			0x02
 
-struct v4l2_async_subdev;
+struct v4l2_async_connection;
 
 struct isi_platform_data {
 	u8 has_emb_sync;
diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
index cc3ebb0d96f6..790a27205f5d 100644
--- a/drivers/media/platform/cadence/cdns-csi2rx.c
+++ b/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -246,7 +246,7 @@ static const struct v4l2_subdev_ops csi2rx_subdev_ops = {
 
 static int csi2rx_async_bound(struct v4l2_async_notifier *notifier,
 			      struct v4l2_subdev *s_subdev,
-			      struct v4l2_async_subdev *asd)
+			      struct v4l2_async_connection *asd)
 {
 	struct v4l2_subdev *subdev = notifier->sd;
 	struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev);
@@ -365,7 +365,7 @@ static int csi2rx_get_resources(struct csi2rx_priv *csi2rx,
 static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
 {
 	struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 };
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct fwnode_handle *fwh;
 	struct device_node *ep;
 	int ret;
@@ -402,7 +402,7 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
 	v4l2_async_nf_init(&csi2rx->notifier);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&csi2rx->notifier, fwh,
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 	of_node_put(ep);
 	if (IS_ERR(asd))
 		return PTR_ERR(asd);
diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c
index 54270d6b6f50..b848a2a9032f 100644
--- a/drivers/media/platform/intel/pxa_camera.c
+++ b/drivers/media/platform/intel/pxa_camera.c
@@ -2044,7 +2044,7 @@ static const struct video_device pxa_camera_videodev_template = {
 
 static int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier,
 		     struct v4l2_subdev *subdev,
-		     struct v4l2_async_subdev *asd)
+		     struct v4l2_async_connection *asd)
 {
 	int err;
 	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
@@ -2123,7 +2123,7 @@ static int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier,
 
 static void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier,
 		     struct v4l2_subdev *subdev,
-		     struct v4l2_async_subdev *asd)
+		     struct v4l2_async_connection *asd)
 {
 	struct pxa_camera_dev *pcdev = v4l2_dev_to_pcdev(notifier->v4l2_dev);
 
@@ -2197,7 +2197,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev,
 				    struct pxa_camera_dev *pcdev)
 {
 	u32 mclk_rate;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct device_node *np = dev->of_node;
 	struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
 	int err = of_property_read_u32(np, "clock-frequency",
@@ -2252,7 +2252,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev,
 
 	asd = v4l2_async_nf_add_fwnode_remote(&pcdev->notifier,
 					      of_fwnode_handle(np),
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 	if (IS_ERR(asd))
 		err = PTR_ERR(asd);
 out:
@@ -2293,14 +2293,14 @@ static int pxa_camera_probe(struct platform_device *pdev)
 	pcdev->res = res;
 	pcdev->pdata = pdev->dev.platform_data;
 	if (pcdev->pdata) {
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asd;
 
 		pcdev->platform_flags = pcdev->pdata->flags;
 		pcdev->mclk = pcdev->pdata->mclk_10khz * 10000;
 		asd = v4l2_async_nf_add_i2c(&pcdev->notifier,
 					    pcdev->pdata->sensor_i2c_adapter_id,
 					    pcdev->pdata->sensor_i2c_address,
-					    struct v4l2_async_subdev);
+					    struct v4l2_async_connection);
 		if (IS_ERR(asd))
 			err = PTR_ERR(asd);
 	} else if (pdev->dev.of_node) {
diff --git a/drivers/media/platform/marvell/cafe-driver.c b/drivers/media/platform/marvell/cafe-driver.c
index ae97ce4ead98..dd1bba70bd79 100644
--- a/drivers/media/platform/marvell/cafe-driver.c
+++ b/drivers/media/platform/marvell/cafe-driver.c
@@ -478,7 +478,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
 	int ret;
 	struct cafe_camera *cam;
 	struct mcam_camera *mcam;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct i2c_client *i2c_dev;
 
 	/*
@@ -540,7 +540,8 @@ static int cafe_pci_probe(struct pci_dev *pdev,
 
 	asd = v4l2_async_nf_add_i2c(&mcam->notifier,
 				    i2c_adapter_id(cam->i2c_adapter),
-				    ov7670_info.addr, struct v4l2_async_subdev);
+				    ov7670_info.addr,
+				    struct v4l2_async_connection);
 	if (IS_ERR(asd)) {
 		ret = PTR_ERR(asd);
 		goto out_smbus_shutdown;
diff --git a/drivers/media/platform/marvell/mcam-core.c b/drivers/media/platform/marvell/mcam-core.c
index ad4a7922d0d7..b74a362ec075 100644
--- a/drivers/media/platform/marvell/mcam-core.c
+++ b/drivers/media/platform/marvell/mcam-core.c
@@ -1756,7 +1756,7 @@ EXPORT_SYMBOL_GPL(mccic_irq);
  */
 
 static int mccic_notify_bound(struct v4l2_async_notifier *notifier,
-	struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd)
+	struct v4l2_subdev *subdev, struct v4l2_async_connection *asd)
 {
 	struct mcam_camera *cam = notifier_to_mcam(notifier);
 	int ret;
@@ -1801,7 +1801,7 @@ static int mccic_notify_bound(struct v4l2_async_notifier *notifier,
 }
 
 static void mccic_notify_unbind(struct v4l2_async_notifier *notifier,
-	struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd)
+	struct v4l2_subdev *subdev, struct v4l2_async_connection *asd)
 {
 	struct mcam_camera *cam = notifier_to_mcam(notifier);
 
diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c
index ef22bf8f276c..36f58ea830f3 100644
--- a/drivers/media/platform/marvell/mmp-driver.c
+++ b/drivers/media/platform/marvell/mmp-driver.c
@@ -180,7 +180,7 @@ static int mmpcam_probe(struct platform_device *pdev)
 	struct resource *res;
 	struct fwnode_handle *ep;
 	struct mmp_camera_platform_data *pdata;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	int ret;
 
 	cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL);
@@ -242,7 +242,7 @@ static int mmpcam_probe(struct platform_device *pdev)
 	v4l2_async_nf_init(&mcam->notifier);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&mcam->notifier, ep,
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 	fwnode_handle_put(ep);
 	if (IS_ERR(asd)) {
 		ret = PTR_ERR(asd);
diff --git a/drivers/media/platform/microchip/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c
index d5b359f607ae..c2b7f50520cd 100644
--- a/drivers/media/platform/microchip/microchip-csi2dc.c
+++ b/drivers/media/platform/microchip/microchip-csi2dc.c
@@ -476,7 +476,7 @@ static const struct v4l2_subdev_ops csi2dc_subdev_ops = {
 
 static int csi2dc_async_bound(struct v4l2_async_notifier *notifier,
 			      struct v4l2_subdev *subdev,
-			      struct v4l2_async_subdev *asd)
+			      struct v4l2_async_connection *asd)
 {
 	struct csi2dc_device *csi2dc = container_of(notifier,
 						struct csi2dc_device, notifier);
@@ -520,14 +520,14 @@ static const struct v4l2_async_notifier_operations csi2dc_async_ops = {
 static int csi2dc_prepare_notifier(struct csi2dc_device *csi2dc,
 				   struct fwnode_handle *input_fwnode)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	int ret = 0;
 
 	v4l2_async_nf_init(&csi2dc->notifier);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&csi2dc->notifier,
 					      input_fwnode,
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 
 	fwnode_handle_put(input_fwnode);
 
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 71758ee8474b..6fae2b4eaf02 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1711,7 +1711,7 @@ static int isc_ctrl_init(struct isc_device *isc)
 
 static int isc_async_bound(struct v4l2_async_notifier *notifier,
 			   struct v4l2_subdev *subdev,
-			   struct v4l2_async_subdev *asd)
+			   struct v4l2_async_connection *asd)
 {
 	struct isc_device *isc = container_of(notifier->v4l2_dev,
 					      struct isc_device, v4l2_dev);
@@ -1740,7 +1740,7 @@ static int isc_async_bound(struct v4l2_async_notifier *notifier,
 
 static void isc_async_unbind(struct v4l2_async_notifier *notifier,
 			     struct v4l2_subdev *subdev,
-			     struct v4l2_async_subdev *asd)
+			     struct v4l2_async_connection *asd)
 {
 	struct isc_device *isc = container_of(notifier->v4l2_dev,
 					      struct isc_device, v4l2_dev);
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index e3a6c7367e70..ad4e98a1dd8f 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -44,7 +44,7 @@ struct isc_buffer {
 
 struct isc_subdev_entity {
 	struct v4l2_subdev		*sd;
-	struct v4l2_async_subdev	*asd;
+	struct v4l2_async_connection	*asd;
 	struct device_node		*epn;
 	struct v4l2_async_notifier      notifier;
 
diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
index ac4715d91de6..4c341908d69d 100644
--- a/drivers/media/platform/microchip/microchip-sama5d2-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
@@ -525,7 +525,7 @@ static int microchip_isc_probe(struct platform_device *pdev)
 	}
 
 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asd;
 		struct fwnode_handle *fwnode =
 			of_fwnode_handle(subdev_entity->epn);
 
@@ -533,7 +533,7 @@ static int microchip_isc_probe(struct platform_device *pdev)
 
 		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
 						      fwnode,
-						      struct v4l2_async_subdev);
+						      struct v4l2_async_connection);
 
 		of_node_put(subdev_entity->epn);
 		subdev_entity->epn = NULL;
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index d583eafe5cc1..44e7818f2e5d 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -515,7 +515,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
 	}
 
 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asd;
 		struct fwnode_handle *fwnode =
 			of_fwnode_handle(subdev_entity->epn);
 
@@ -523,7 +523,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
 
 		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
 						      fwnode,
-						      struct v4l2_async_subdev);
+						      struct v4l2_async_connection);
 
 		of_node_put(subdev_entity->epn);
 		subdev_entity->epn = NULL;
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index be2768a47995..9c5407b59e8b 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -1230,7 +1230,7 @@ mipi_notifier_to_csis_state(struct v4l2_async_notifier *n)
 
 static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier,
 				  struct v4l2_subdev *sd,
-				  struct v4l2_async_subdev *asd)
+				  struct v4l2_async_connection *asd)
 {
 	struct mipi_csis_device *csis = mipi_notifier_to_csis_state(notifier);
 	struct media_pad *sink = &csis->sd.entity.pads[CSIS_PAD_SINK];
@@ -1247,7 +1247,7 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
 	struct v4l2_fwnode_endpoint vep = {
 		.bus_type = V4L2_MBUS_CSI2_DPHY,
 	};
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct fwnode_handle *ep;
 	unsigned int i;
 	int ret;
@@ -1278,7 +1278,7 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
 	dev_dbg(csis->dev, "flags: 0x%08x\n", csis->bus.flags);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&csis->notifier, ep,
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 	if (IS_ERR(asd)) {
 		ret = PTR_ERR(asd);
 		goto err_parse;
diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
index c22bf5c827e7..0c57165c4ec1 100644
--- a/drivers/media/platform/nxp/imx7-media-csi.c
+++ b/drivers/media/platform/nxp/imx7-media-csi.c
@@ -2074,7 +2074,7 @@ static const struct media_entity_operations imx7_csi_entity_ops = {
 
 static int imx7_csi_notify_bound(struct v4l2_async_notifier *notifier,
 				 struct v4l2_subdev *sd,
-				 struct v4l2_async_subdev *asd)
+				 struct v4l2_async_connection *asd)
 {
 	struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier);
 	struct media_pad *sink = &csi->sd.entity.pads[IMX7_CSI_PAD_SINK];
@@ -2099,7 +2099,7 @@ static const struct v4l2_async_notifier_operations imx7_csi_notify_ops = {
 
 static int imx7_csi_async_register(struct imx7_csi *csi)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct fwnode_handle *ep;
 	int ret;
 
@@ -2109,7 +2109,7 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
 					     FWNODE_GRAPH_ENDPOINT_NEXT);
 	if (ep) {
 		asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep,
-						      struct v4l2_async_subdev);
+						      struct v4l2_async_connection);
 
 		fwnode_handle_put(ep);
 
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 9cda284f1e71..ae13ae455b52 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -1383,7 +1383,7 @@ static void camss_unregister_entities(struct camss *camss)
 
 static int camss_subdev_notifier_bound(struct v4l2_async_notifier *async,
 				       struct v4l2_subdev *subdev,
-				       struct v4l2_async_subdev *asd)
+				       struct v4l2_async_connection *asd)
 {
 	struct camss *camss = container_of(async, struct camss, notifier);
 	struct camss_async_subdev *csd =
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 3acd2b3403e8..f6c326cb853b 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -113,7 +113,7 @@ struct camss_camera_interface {
 };
 
 struct camss_async_subdev {
-	struct v4l2_async_subdev asd; /* must be first */
+	struct v4l2_async_connection asd; /* must be first */
 	struct camss_camera_interface interface;
 };
 
diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c
index 10b3474f93a4..eb851c9686f8 100644
--- a/drivers/media/platform/renesas/rcar-isp.c
+++ b/drivers/media/platform/renesas/rcar-isp.c
@@ -326,7 +326,7 @@ static const struct v4l2_subdev_ops rcar_isp_subdev_ops = {
 
 static int risp_notify_bound(struct v4l2_async_notifier *notifier,
 			     struct v4l2_subdev *subdev,
-			     struct v4l2_async_subdev *asd)
+			     struct v4l2_async_connection *asd)
 {
 	struct rcar_isp *isp = notifier_to_isp(notifier);
 	int pad;
@@ -350,7 +350,7 @@ static int risp_notify_bound(struct v4l2_async_notifier *notifier,
 
 static void risp_notify_unbind(struct v4l2_async_notifier *notifier,
 			       struct v4l2_subdev *subdev,
-			       struct v4l2_async_subdev *asd)
+			       struct v4l2_async_connection *asd)
 {
 	struct rcar_isp *isp = notifier_to_isp(notifier);
 
@@ -366,7 +366,7 @@ static const struct v4l2_async_notifier_operations risp_notify_ops = {
 
 static int risp_parse_dt(struct rcar_isp *isp)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct fwnode_handle *fwnode;
 	struct fwnode_handle *ep;
 	unsigned int id;
@@ -396,7 +396,7 @@ static int risp_parse_dt(struct rcar_isp *isp)
 	isp->notifier.ops = &risp_notify_ops;
 
 	asd = v4l2_async_nf_add_fwnode(&isp->notifier, fwnode,
-				       struct v4l2_async_subdev);
+				       struct v4l2_async_connection);
 	fwnode_handle_put(fwnode);
 	if (IS_ERR(asd))
 		return PTR_ERR(asd);
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
index 1b530da1c341..1d64373e7cd7 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
@@ -253,7 +253,7 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier)
 
 static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
 				     struct v4l2_subdev *subdev,
-				     struct v4l2_async_subdev *asd)
+				     struct v4l2_async_connection *asd)
 {
 	struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
 	unsigned int i;
@@ -279,7 +279,7 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
 
 static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier,
 				   struct v4l2_subdev *subdev,
-				   struct v4l2_async_subdev *asd)
+				   struct v4l2_async_connection *asd)
 {
 	struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
 	unsigned int i;
@@ -312,7 +312,7 @@ static int rvin_group_parse_of(struct rvin_dev *vin, unsigned int port,
 	struct v4l2_fwnode_endpoint vep = {
 		.bus_type = V4L2_MBUS_CSI2_DPHY,
 	};
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	int ret;
 
 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), port, id, 0);
@@ -329,7 +329,7 @@ static int rvin_group_parse_of(struct rvin_dev *vin, unsigned int port,
 	}
 
 	asd = v4l2_async_nf_add_fwnode(&vin->group->notifier, fwnode,
-				       struct v4l2_async_subdev);
+				       struct v4l2_async_connection);
 	if (IS_ERR(asd)) {
 		ret = PTR_ERR(asd);
 		goto out;
@@ -397,7 +397,7 @@ static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port,
 		}
 	}
 
-	if (list_empty(&vin->group->notifier.asd_head))
+	if (list_empty(&vin->group->notifier.asc_head))
 		return 0;
 
 	vin->group->notifier.ops = &rvin_group_notify_ops;
@@ -612,7 +612,7 @@ static int rvin_parallel_notify_complete(struct v4l2_async_notifier *notifier)
 
 static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier,
 					struct v4l2_subdev *subdev,
-					struct v4l2_async_subdev *asd)
+					struct v4l2_async_connection *asd)
 {
 	struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
 
@@ -625,7 +625,7 @@ static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier,
 
 static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier,
 				      struct v4l2_subdev *subdev,
-				      struct v4l2_async_subdev *asd)
+				      struct v4l2_async_connection *asd)
 {
 	struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
 	int ret;
@@ -657,7 +657,7 @@ static int rvin_parallel_parse_of(struct rvin_dev *vin)
 	struct v4l2_fwnode_endpoint vep = {
 		.bus_type = V4L2_MBUS_UNKNOWN,
 	};
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	int ret;
 
 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 0, 0, 0);
@@ -689,7 +689,7 @@ static int rvin_parallel_parse_of(struct rvin_dev *vin)
 	}
 
 	asd = v4l2_async_nf_add_fwnode(&vin->notifier, fwnode,
-				       struct v4l2_async_subdev);
+				       struct v4l2_async_connection);
 	if (IS_ERR(asd)) {
 		ret = PTR_ERR(asd);
 		goto out;
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
index 174aa6176f54..654d56a57a00 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
@@ -968,7 +968,7 @@ static irqreturn_t rcsi2_irq_thread(int irq, void *data)
 
 static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier,
 			      struct v4l2_subdev *subdev,
-			      struct v4l2_async_subdev *asd)
+			      struct v4l2_async_connection *asd)
 {
 	struct rcar_csi2 *priv = notifier_to_csi2(notifier);
 	int pad;
@@ -993,7 +993,7 @@ static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier,
 
 static void rcsi2_notify_unbind(struct v4l2_async_notifier *notifier,
 				struct v4l2_subdev *subdev,
-				struct v4l2_async_subdev *asd)
+				struct v4l2_async_connection *asd)
 {
 	struct rcar_csi2 *priv = notifier_to_csi2(notifier);
 
@@ -1044,7 +1044,7 @@ static int rcsi2_parse_v4l2(struct rcar_csi2 *priv,
 
 static int rcsi2_parse_dt(struct rcar_csi2 *priv)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct fwnode_handle *fwnode;
 	struct fwnode_handle *ep;
 	struct v4l2_fwnode_endpoint v4l2_ep = {
@@ -1080,7 +1080,7 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv)
 	priv->notifier.ops = &rcar_csi2_notify_ops;
 
 	asd = v4l2_async_nf_add_fwnode(&priv->notifier, fwnode,
-				       struct v4l2_async_subdev);
+				       struct v4l2_async_connection);
 	fwnode_handle_put(fwnode);
 	if (IS_ERR(asd))
 		return PTR_ERR(asd);
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
index cb206d3976dd..09d8160c8b3b 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
@@ -115,7 +115,7 @@ struct rvin_video_format {
  *
  */
 struct rvin_parallel_entity {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct v4l2_subdev *subdev;
 
 	enum v4l2_mbus_type mbus_type;
@@ -291,7 +291,7 @@ struct rvin_group {
 	int (*link_setup)(struct rvin_dev *vin);
 
 	struct {
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asd;
 		struct v4l2_subdev *subdev;
 	} remotes[RVIN_REMOTES_MAX];
 };
diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c
index 3fec41f6e964..5c8f5a53eb4d 100644
--- a/drivers/media/platform/renesas/rcar_drif.c
+++ b/drivers/media/platform/renesas/rcar_drif.c
@@ -1097,7 +1097,7 @@ static void rcar_drif_sdr_unregister(struct rcar_drif_sdr *sdr)
 /* Sub-device bound callback */
 static int rcar_drif_notify_bound(struct v4l2_async_notifier *notifier,
 				   struct v4l2_subdev *subdev,
-				   struct v4l2_async_subdev *asd)
+				   struct v4l2_async_connection *asd)
 {
 	struct rcar_drif_sdr *sdr =
 		container_of(notifier, struct rcar_drif_sdr, notifier);
@@ -1112,7 +1112,7 @@ static int rcar_drif_notify_bound(struct v4l2_async_notifier *notifier,
 /* Sub-device unbind callback */
 static void rcar_drif_notify_unbind(struct v4l2_async_notifier *notifier,
 				   struct v4l2_subdev *subdev,
-				   struct v4l2_async_subdev *asd)
+				   struct v4l2_async_connection *asd)
 {
 	struct rcar_drif_sdr *sdr =
 		container_of(notifier, struct rcar_drif_sdr, notifier);
@@ -1205,7 +1205,7 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr)
 {
 	struct v4l2_async_notifier *notifier = &sdr->notifier;
 	struct fwnode_handle *fwnode, *ep;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 
 	v4l2_async_nf_init(notifier);
 
@@ -1225,7 +1225,7 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr)
 	}
 
 	asd = v4l2_async_nf_add_fwnode(notifier, fwnode,
-				       struct v4l2_async_subdev);
+				       struct v4l2_async_connection);
 	fwnode_handle_put(fwnode);
 	if (IS_ERR(asd))
 		return PTR_ERR(asd);
diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c
index f70f91b006b7..8d47910a8d11 100644
--- a/drivers/media/platform/renesas/renesas-ceu.c
+++ b/drivers/media/platform/renesas/renesas-ceu.c
@@ -152,7 +152,7 @@ static inline struct ceu_buffer *vb2_to_ceu(struct vb2_v4l2_buffer *vbuf)
  * ceu_subdev - Wraps v4l2 sub-device and provides async subdevice.
  */
 struct ceu_subdev {
-	struct v4l2_async_subdev asd;
+	struct v4l2_async_connection asd;
 	struct v4l2_subdev *v4l2_sd;
 
 	/* per-subdevice mbus configuration options */
@@ -160,7 +160,7 @@ struct ceu_subdev {
 	struct ceu_mbus_fmt mbus_fmt;
 };
 
-static struct ceu_subdev *to_ceu_subdev(struct v4l2_async_subdev *asd)
+static struct ceu_subdev *to_ceu_subdev(struct v4l2_async_connection *asd)
 {
 	return container_of(asd, struct ceu_subdev, asd);
 }
@@ -1384,7 +1384,7 @@ static void ceu_vdev_release(struct video_device *vdev)
 
 static int ceu_notify_bound(struct v4l2_async_notifier *notifier,
 			    struct v4l2_subdev *v4l2_sd,
-			    struct v4l2_async_subdev *asd)
+			    struct v4l2_async_connection *asd)
 {
 	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
 	struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index bfef297f5ec5..4abf9f1e88dc 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -93,7 +93,7 @@ static int rzg2l_cru_group_notify_complete(struct v4l2_async_notifier *notifier)
 
 static void rzg2l_cru_group_notify_unbind(struct v4l2_async_notifier *notifier,
 					  struct v4l2_subdev *subdev,
-					  struct v4l2_async_subdev *asd)
+					  struct v4l2_async_connection *asd)
 {
 	struct rzg2l_cru_dev *cru = notifier_to_cru(notifier);
 
@@ -111,7 +111,7 @@ static void rzg2l_cru_group_notify_unbind(struct v4l2_async_notifier *notifier,
 
 static int rzg2l_cru_group_notify_bound(struct v4l2_async_notifier *notifier,
 					struct v4l2_subdev *subdev,
-					struct v4l2_async_subdev *asd)
+					struct v4l2_async_connection *asd)
 {
 	struct rzg2l_cru_dev *cru = notifier_to_cru(notifier);
 
@@ -139,7 +139,7 @@ static int rzg2l_cru_mc_parse_of(struct rzg2l_cru_dev *cru)
 		.bus_type = V4L2_MBUS_CSI2_DPHY,
 	};
 	struct fwnode_handle *ep, *fwnode;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	int ret;
 
 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(cru->dev), 1, 0, 0);
@@ -163,7 +163,7 @@ static int rzg2l_cru_mc_parse_of(struct rzg2l_cru_dev *cru)
 	}
 
 	asd = v4l2_async_nf_add_fwnode(&cru->notifier, fwnode,
-				       struct v4l2_async_subdev);
+				       struct v4l2_async_connection);
 	if (IS_ERR(asd)) {
 		ret = PTR_ERR(asd);
 		goto out;
@@ -191,7 +191,7 @@ static int rzg2l_cru_mc_parse_of_graph(struct rzg2l_cru_dev *cru)
 
 	cru->notifier.ops = &rzg2l_cru_async_ops;
 
-	if (list_empty(&cru->notifier.asd_head))
+	if (list_empty(&cru->notifier.asc_head))
 		return 0;
 
 	ret = v4l2_async_nf_register(&cru->v4l2_dev, &cru->notifier);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index 0b682cbae3eb..811603f18af0 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -45,7 +45,7 @@ enum rzg2l_cru_dma_state {
 };
 
 struct rzg2l_cru_csi {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct v4l2_subdev *subdev;
 	u32 channel;
 };
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 384fb54e219a..5aa3b0239ead 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -600,7 +600,7 @@ static const struct v4l2_subdev_ops rzg2l_csi2_subdev_ops = {
 
 static int rzg2l_csi2_notify_bound(struct v4l2_async_notifier *notifier,
 				   struct v4l2_subdev *subdev,
-				   struct v4l2_async_subdev *asd)
+				   struct v4l2_async_connection *asd)
 {
 	struct rzg2l_csi2 *csi2 = notifier_to_csi2(notifier);
 
@@ -616,7 +616,7 @@ static int rzg2l_csi2_notify_bound(struct v4l2_async_notifier *notifier,
 
 static void rzg2l_csi2_notify_unbind(struct v4l2_async_notifier *notifier,
 				     struct v4l2_subdev *subdev,
-				     struct v4l2_async_subdev *asd)
+				     struct v4l2_async_connection *asd)
 {
 	struct rzg2l_csi2 *csi2 = notifier_to_csi2(notifier);
 
@@ -647,7 +647,7 @@ static int rzg2l_csi2_parse_dt(struct rzg2l_csi2 *csi2)
 	struct v4l2_fwnode_endpoint v4l2_ep = {
 		.bus_type = V4L2_MBUS_CSI2_DPHY
 	};
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct fwnode_handle *fwnode;
 	struct fwnode_handle *ep;
 	int ret;
@@ -678,7 +678,7 @@ static int rzg2l_csi2_parse_dt(struct rzg2l_csi2 *csi2)
 	csi2->notifier.ops = &rzg2l_csi2_notify_ops;
 
 	asd = v4l2_async_nf_add_fwnode(&csi2->notifier, fwnode,
-				       struct v4l2_async_subdev);
+				       struct v4l2_async_connection);
 	fwnode_handle_put(fwnode);
 	if (IS_ERR(asd))
 		return PTR_ERR(asd);
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
index a1293c45aae1..d30f0ecb1bfd 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
@@ -148,7 +148,7 @@ struct rkisp1_info {
  * @port:		port number (0: MIPI, 1: Parallel)
  */
 struct rkisp1_sensor_async {
-	struct v4l2_async_subdev asd;
+	struct v4l2_async_connection asd;
 	unsigned int index;
 	struct fwnode_handle *source_ep;
 	unsigned int lanes;
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
index f2475c6235ea..39fa98e6dbbc 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
@@ -122,7 +122,7 @@ struct rkisp1_isr_data {
 
 static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
 					struct v4l2_subdev *sd,
-					struct v4l2_async_subdev *asd)
+					struct v4l2_async_connection *asd)
 {
 	struct rkisp1_device *rkisp1 =
 		container_of(notifier, struct rkisp1_device, notifier);
@@ -165,7 +165,7 @@ static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
 	return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
 }
 
-static void rkisp1_subdev_notifier_destroy(struct v4l2_async_subdev *asd)
+static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asd)
 {
 	struct rkisp1_sensor_async *rk_asd =
 		container_of(asd, struct rkisp1_sensor_async, asd);
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c
index 98a60f01129d..8c9dad6231a6 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.c
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c
@@ -401,7 +401,7 @@ static int fimc_md_parse_one_endpoint(struct fimc_md *fmd,
 	int index = fmd->num_sensors;
 	struct fimc_source_info *pd = &fmd->sensor[index].pdata;
 	struct device_node *rem, *np;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 };
 	int ret;
 
@@ -466,7 +466,7 @@ static int fimc_md_parse_one_endpoint(struct fimc_md *fmd,
 
 	asd = v4l2_async_nf_add_fwnode_remote(&fmd->subdev_notifier,
 					      of_fwnode_handle(ep),
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 
 	of_node_put(ep);
 
@@ -1372,7 +1372,7 @@ static int fimc_md_register_clk_provider(struct fimc_md *fmd)
 
 static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
 				 struct v4l2_subdev *subdev,
-				 struct v4l2_async_subdev *asd)
+				 struct v4l2_async_connection *asd)
 {
 	struct fimc_md *fmd = notifier_to_fimc_md(notifier);
 	struct fimc_sensor_info *si = NULL;
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.h b/drivers/media/platform/samsung/exynos4-is/media-dev.h
index 079105d88bab..786264cf79dc 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.h
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.h
@@ -82,7 +82,7 @@ struct fimc_camclk_info {
  */
 struct fimc_sensor_info {
 	struct fimc_source_info pdata;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct v4l2_subdev *subdev;
 	struct fimc_dev *host;
 };
diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index ad8e9742e1ae..cf03c9529749 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -1837,7 +1837,7 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier)
 
 static void dcmi_graph_notify_unbind(struct v4l2_async_notifier *notifier,
 				     struct v4l2_subdev *sd,
-				     struct v4l2_async_subdev *asd)
+				     struct v4l2_async_connection *asd)
 {
 	struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier);
 
@@ -1849,7 +1849,7 @@ static void dcmi_graph_notify_unbind(struct v4l2_async_notifier *notifier,
 
 static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier,
 				   struct v4l2_subdev *subdev,
-				   struct v4l2_async_subdev *asd)
+				   struct v4l2_async_connection *asd)
 {
 	struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier);
 	unsigned int ret;
@@ -1887,7 +1887,7 @@ static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = {
 
 static int dcmi_graph_init(struct stm32_dcmi *dcmi)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct device_node *ep;
 	int ret;
 
@@ -1901,7 +1901,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
 
 	asd = v4l2_async_nf_add_fwnode_remote(&dcmi->notifier,
 					      of_fwnode_handle(ep),
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 
 	of_node_put(ep);
 
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
index 86c5235a0c7a..1a550713ecfb 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -42,7 +42,7 @@ static const struct media_entity_operations sun4i_csi_video_entity_ops = {
 
 static int sun4i_csi_notify_bound(struct v4l2_async_notifier *notifier,
 				  struct v4l2_subdev *subdev,
-				  struct v4l2_async_subdev *asd)
+				  struct v4l2_async_connection *asd)
 {
 	struct sun4i_csi *csi = container_of(notifier, struct sun4i_csi,
 					     notifier);
@@ -118,7 +118,7 @@ static int sun4i_csi_notifier_init(struct sun4i_csi *csi)
 	struct v4l2_fwnode_endpoint vep = {
 		.bus_type = V4L2_MBUS_PARALLEL,
 	};
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct fwnode_handle *ep;
 	int ret;
 
@@ -136,7 +136,7 @@ static int sun4i_csi_notifier_init(struct sun4i_csi *csi)
 	csi->bus = vep.bus.parallel;
 
 	asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep,
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 	if (IS_ERR(asd)) {
 		ret = PTR_ERR(asd);
 		goto out;
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
index 4db950973ce2..ebb725fc11ba 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
@@ -642,7 +642,7 @@ static int sun6i_csi_bridge_link(struct sun6i_csi_device *csi_dev,
 static int
 sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier,
 				struct v4l2_subdev *remote_subdev,
-				struct v4l2_async_subdev *async_subdev)
+				struct v4l2_async_connection *async_subdev)
 {
 	struct sun6i_csi_device *csi_dev =
 		container_of(notifier, struct sun6i_csi_device,
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
index ee592a14b9c5..44653b38f722 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h
@@ -34,7 +34,7 @@ struct sun6i_csi_bridge_source {
 };
 
 struct sun6i_csi_bridge_async_subdev {
-	struct v4l2_async_subdev	async_subdev;
+	struct v4l2_async_connection	async_subdev;
 	struct sun6i_csi_bridge_source	*source;
 };
 
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
index a220ce849b41..f2746f77aad0 100644
--- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
@@ -408,7 +408,7 @@ static const struct media_entity_operations sun6i_mipi_csi2_entity_ops = {
 static int
 sun6i_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier,
 			       struct v4l2_subdev *remote_subdev,
-			       struct v4l2_async_subdev *async_subdev)
+			       struct v4l2_async_connection *async_subdev)
 {
 	struct v4l2_subdev *subdev = notifier->sd;
 	struct sun6i_mipi_csi2_device *csi2_dev =
@@ -462,7 +462,7 @@ sun6i_mipi_csi2_bridge_source_setup(struct sun6i_mipi_csi2_device *csi2_dev)
 {
 	struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier;
 	struct v4l2_fwnode_endpoint *endpoint = &csi2_dev->bridge.endpoint;
-	struct v4l2_async_subdev *subdev_async;
+	struct v4l2_async_connection *subdev_async;
 	struct fwnode_handle *handle;
 	struct device *dev = csi2_dev->dev;
 	int ret;
@@ -480,7 +480,7 @@ sun6i_mipi_csi2_bridge_source_setup(struct sun6i_mipi_csi2_device *csi2_dev)
 
 	subdev_async =
 		v4l2_async_nf_add_fwnode_remote(notifier, handle,
-						struct v4l2_async_subdev);
+						struct v4l2_async_connection);
 	if (IS_ERR(subdev_async))
 		ret = PTR_ERR(subdev_async);
 
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
index cd2e92ae2293..e7f45673ed82 100644
--- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
@@ -445,7 +445,7 @@ static const struct media_entity_operations sun8i_a83t_mipi_csi2_entity_ops = {
 static int
 sun8i_a83t_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier,
 				    struct v4l2_subdev *remote_subdev,
-				    struct v4l2_async_subdev *async_subdev)
+				    struct v4l2_async_connection *async_subdev)
 {
 	struct v4l2_subdev *subdev = notifier->sd;
 	struct sun8i_a83t_mipi_csi2_device *csi2_dev =
@@ -499,7 +499,7 @@ sun8i_a83t_mipi_csi2_bridge_source_setup(struct sun8i_a83t_mipi_csi2_device *csi
 {
 	struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier;
 	struct v4l2_fwnode_endpoint *endpoint = &csi2_dev->bridge.endpoint;
-	struct v4l2_async_subdev *subdev_async;
+	struct v4l2_async_connection *subdev_async;
 	struct fwnode_handle *handle;
 	struct device *dev = csi2_dev->dev;
 	int ret;
@@ -517,7 +517,7 @@ sun8i_a83t_mipi_csi2_bridge_source_setup(struct sun8i_a83t_mipi_csi2_device *csi
 
 	subdev_async =
 		v4l2_async_nf_add_fwnode_remote(notifier, handle,
-						struct v4l2_async_subdev);
+						struct v4l2_async_connection);
 	if (IS_ERR(subdev_async))
 		ret = PTR_ERR(subdev_async);
 
diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c
index 2dfae9bc0bba..a21f3b91cc06 100644
--- a/drivers/media/platform/ti/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c
@@ -2142,7 +2142,7 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
 static int
 vpfe_async_bound(struct v4l2_async_notifier *notifier,
 		 struct v4l2_subdev *subdev,
-		 struct v4l2_async_subdev *asd)
+		 struct v4l2_async_connection *asd)
 {
 	struct vpfe_device *vpfe = container_of(notifier->v4l2_dev,
 					       struct vpfe_device, v4l2_dev);
@@ -2367,8 +2367,7 @@ vpfe_get_pdata(struct vpfe_device *vpfe)
 
 		pdata->asd[i] = v4l2_async_nf_add_fwnode(&vpfe->notifier,
 							 of_fwnode_handle(rem),
-							 struct
-							 v4l2_async_subdev);
+							 struct v4l2_async_connection);
 		of_node_put(rem);
 		if (IS_ERR(pdata->asd[i]))
 			goto cleanup;
diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.h b/drivers/media/platform/ti/am437x/am437x-vpfe.h
index f8b4e917b91a..50c3c793b370 100644
--- a/drivers/media/platform/ti/am437x/am437x-vpfe.h
+++ b/drivers/media/platform/ti/am437x/am437x-vpfe.h
@@ -84,7 +84,7 @@ struct vpfe_config {
 	/* information about each subdev */
 	struct vpfe_subdev_info sub_devs[VPFE_MAX_SUBDEV];
 	/* Flat array, arranged in groups */
-	struct v4l2_async_subdev *asd[VPFE_MAX_SUBDEV];
+	struct v4l2_async_connection *asd[VPFE_MAX_SUBDEV];
 };
 
 struct vpfe_cap_buffer {
diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c
index 1236215ec70e..37906c23237e 100644
--- a/drivers/media/platform/ti/cal/cal.c
+++ b/drivers/media/platform/ti/cal/cal.c
@@ -804,19 +804,19 @@ static irqreturn_t cal_irq(int irq_cal, void *data)
  */
 
 struct cal_v4l2_async_subdev {
-	struct v4l2_async_subdev asd; /* Must be first */
+	struct v4l2_async_connection asd; /* Must be first */
 	struct cal_camerarx *phy;
 };
 
 static inline struct cal_v4l2_async_subdev *
-to_cal_asd(struct v4l2_async_subdev *asd)
+to_cal_asd(struct v4l2_async_connection *asd)
 {
 	return container_of(asd, struct cal_v4l2_async_subdev, asd);
 }
 
 static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier,
 				    struct v4l2_subdev *subdev,
-				    struct v4l2_async_subdev *asd)
+				    struct v4l2_async_connection *asd)
 {
 	struct cal_camerarx *phy = to_cal_asd(asd)->phy;
 	int pad;
diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c
index 580723333fcc..2bbd7017f67c 100644
--- a/drivers/media/platform/ti/davinci/vpif_capture.c
+++ b/drivers/media/platform/ti/davinci/vpif_capture.c
@@ -1363,12 +1363,12 @@ static inline void free_vpif_objs(void)
 
 static int vpif_async_bound(struct v4l2_async_notifier *notifier,
 			    struct v4l2_subdev *subdev,
-			    struct v4l2_async_subdev *asd)
+			    struct v4l2_async_connection *asd)
 {
 	int i;
 
 	for (i = 0; i < vpif_obj.config->asd_sizes[0]; i++) {
-		struct v4l2_async_subdev *_asd = vpif_obj.config->asd[i];
+		struct v4l2_async_connection *_asd = vpif_obj.config->asd[i];
 		const struct fwnode_handle *fwnode = _asd->match.fwnode;
 
 		if (fwnode == subdev->fwnode) {
@@ -1570,8 +1570,7 @@ vpif_capture_get_pdata(struct platform_device *pdev)
 
 		pdata->asd[i] = v4l2_async_nf_add_fwnode(&vpif_obj.notifier,
 							 of_fwnode_handle(rem),
-							 struct
-							 v4l2_async_subdev);
+							 struct v4l2_async_connection);
 		if (IS_ERR(pdata->asd[i]))
 			goto err_cleanup;
 
diff --git a/drivers/media/platform/ti/omap3isp/isp.h b/drivers/media/platform/ti/omap3isp/isp.h
index a9d760fbf349..32ea70c8d2f9 100644
--- a/drivers/media/platform/ti/omap3isp/isp.h
+++ b/drivers/media/platform/ti/omap3isp/isp.h
@@ -220,7 +220,7 @@ struct isp_device {
 };
 
 struct isp_async_subdev {
-	struct v4l2_async_subdev asd;
+	struct v4l2_async_connection asd;
 	struct isp_bus_cfg bus;
 };
 
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c
index 71d97042a470..7d48fb9bc09d 100644
--- a/drivers/media/platform/video-mux.c
+++ b/drivers/media/platform/video-mux.c
@@ -343,7 +343,7 @@ static const struct v4l2_subdev_ops video_mux_subdev_ops = {
 
 static int video_mux_notify_bound(struct v4l2_async_notifier *notifier,
 				  struct v4l2_subdev *sd,
-				  struct v4l2_async_subdev *asd)
+				  struct v4l2_async_connection *asd)
 {
 	struct video_mux *vmux = notifier_to_video_mux(notifier);
 
@@ -363,7 +363,7 @@ static int video_mux_async_register(struct video_mux *vmux,
 	v4l2_async_nf_init(&vmux->notifier);
 
 	for (i = 0; i < num_input_pads; i++) {
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asd;
 		struct fwnode_handle *ep, *remote_ep;
 
 		ep = fwnode_graph_get_endpoint_by_id(
@@ -381,7 +381,7 @@ static int video_mux_async_register(struct video_mux *vmux,
 		fwnode_handle_put(remote_ep);
 
 		asd = v4l2_async_nf_add_fwnode_remote(&vmux->notifier, ep,
-						      struct v4l2_async_subdev);
+						      struct v4l2_async_connection);
 
 		fwnode_handle_put(ep);
 
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index 80157b7a28ee..70e7a1f6ed3b 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -34,13 +34,13 @@
  * @subdev: V4L2 subdev
  */
 struct xvip_graph_entity {
-	struct v4l2_async_subdev asd; /* must be first */
+	struct v4l2_async_connection asd; /* must be first */
 	struct media_entity *entity;
 	struct v4l2_subdev *subdev;
 };
 
 static inline struct xvip_graph_entity *
-to_xvip_entity(struct v4l2_async_subdev *asd)
+to_xvip_entity(struct v4l2_async_connection *asd)
 {
 	return container_of(asd, struct xvip_graph_entity, asd);
 }
@@ -54,9 +54,9 @@ xvip_graph_find_entity(struct xvip_composite_device *xdev,
 		       const struct fwnode_handle *fwnode)
 {
 	struct xvip_graph_entity *entity;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 
-	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
+	list_for_each_entry(asd, &xdev->notifier.asc_head, asc_list) {
 		entity = to_xvip_entity(asd);
 		if (entity->asd.match.fwnode == fwnode)
 			return entity;
@@ -285,13 +285,13 @@ static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier)
 	struct xvip_composite_device *xdev =
 		container_of(notifier, struct xvip_composite_device, notifier);
 	struct xvip_graph_entity *entity;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	int ret;
 
 	dev_dbg(xdev->dev, "notify complete, all subdevs registered\n");
 
 	/* Create links for every entity. */
-	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
+	list_for_each_entry(asd, &xdev->notifier.asc_head, asc_list) {
 		entity = to_xvip_entity(asd);
 		ret = xvip_graph_build_one(xdev, entity);
 		if (ret < 0)
@@ -312,17 +312,17 @@ static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier)
 
 static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
 				   struct v4l2_subdev *subdev,
-				   struct v4l2_async_subdev *unused)
+				   struct v4l2_async_connection *unused)
 {
 	struct xvip_composite_device *xdev =
 		container_of(notifier, struct xvip_composite_device, notifier);
 	struct xvip_graph_entity *entity;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 
 	/* Locate the entity corresponding to the bound subdev and store the
 	 * subdev pointer.
 	 */
-	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
+	list_for_each_entry(asd, &xdev->notifier.asc_head, asc_list) {
 		entity = to_xvip_entity(asd);
 
 		if (entity->asd.match.fwnode != subdev->fwnode)
@@ -402,7 +402,7 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev,
 static int xvip_graph_parse(struct xvip_composite_device *xdev)
 {
 	struct xvip_graph_entity *entity;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	int ret;
 
 	/*
@@ -415,7 +415,7 @@ static int xvip_graph_parse(struct xvip_composite_device *xdev)
 	if (ret < 0)
 		return 0;
 
-	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
+	list_for_each_entry(asd, &xdev->notifier.asc_head, asc_list) {
 		entity = to_xvip_entity(asd);
 		ret = xvip_graph_parse_one(xdev, entity->asd.match.fwnode);
 		if (ret < 0) {
@@ -523,7 +523,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
 		goto done;
 	}
 
-	if (list_empty(&xdev->notifier.asd_head)) {
+	if (list_empty(&xdev->notifier.asc_head)) {
 		dev_err(xdev->dev, "no subdev found in graph\n");
 		ret = -ENOENT;
 		goto done;
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index fdc995dfc15c..56ce40481ec4 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -26,22 +26,22 @@
 
 static int v4l2_async_nf_call_bound(struct v4l2_async_notifier *n,
 				    struct v4l2_subdev *subdev,
-				    struct v4l2_async_subdev *asd)
+				    struct v4l2_async_connection *asc)
 {
 	if (!n->ops || !n->ops->bound)
 		return 0;
 
-	return n->ops->bound(n, subdev, asd);
+	return n->ops->bound(n, subdev, asc);
 }
 
 static void v4l2_async_nf_call_unbind(struct v4l2_async_notifier *n,
 				      struct v4l2_subdev *subdev,
-				      struct v4l2_async_subdev *asd)
+				      struct v4l2_async_connection *asc)
 {
 	if (!n->ops || !n->ops->unbind)
 		return;
 
-	n->ops->unbind(n, subdev, asd);
+	n->ops->unbind(n, subdev, asc);
 }
 
 static int v4l2_async_nf_call_complete(struct v4l2_async_notifier *n)
@@ -53,12 +53,12 @@ static int v4l2_async_nf_call_complete(struct v4l2_async_notifier *n)
 }
 
 static void v4l2_async_nf_call_destroy(struct v4l2_async_notifier *n,
-				       struct v4l2_async_subdev *asd)
+				       struct v4l2_async_connection *asc)
 {
 	if (!n->ops || !n->ops->destroy)
 		return;
 
-	n->ops->destroy(asd);
+	n->ops->destroy(asc);
 }
 
 static bool match_i2c(struct v4l2_async_notifier *notifier,
@@ -137,17 +137,17 @@ static LIST_HEAD(subdev_head);
 static LIST_HEAD(notifier_head);
 static DEFINE_MUTEX(list_lock);
 
-static struct v4l2_async_subdev *
+static struct v4l2_async_connection *
 v4l2_async_find_match(struct v4l2_async_notifier *notifier,
 		      struct v4l2_subdev *sd)
 {
 	bool (*match)(struct v4l2_async_notifier *notifier,
 		      struct v4l2_subdev *sd, struct v4l2_async_match *match);
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asc;
 
-	list_for_each_entry(asd, &notifier->waiting_head, waiting_list) {
+	list_for_each_entry(asc, &notifier->waiting_head, waiting_list) {
 		/* bus_type has been verified valid before */
-		switch (asd->match.type) {
+		switch (asc->match.type) {
 		case V4L2_ASYNC_MATCH_I2C:
 			match = match_i2c;
 			break;
@@ -161,15 +161,15 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
 		}
 
 		/* match cannot be NULL here */
-		if (match(notifier, sd, &asd->match))
-			return asd;
+		if (match(notifier, sd, &asc->match))
+			return asc;
 	}
 
 	return NULL;
 }
 
 /* Compare two async sub-device descriptors for equivalence */
-static bool asd_equal(struct v4l2_async_match *match1,
+static bool asc_equal(struct v4l2_async_match *match1,
 		      struct v4l2_async_match *match2)
 {
 	if (match1->type != match2->type)
@@ -299,7 +299,7 @@ static int v4l2_async_create_ancillary_links(struct v4l2_async_notifier *n,
 static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 				   struct v4l2_device *v4l2_dev,
 				   struct v4l2_subdev *sd,
-				   struct v4l2_async_subdev *asd)
+				   struct v4l2_async_connection *asc)
 {
 	struct v4l2_async_notifier *subdev_notifier;
 	int ret;
@@ -308,7 +308,7 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 	if (ret < 0)
 		return ret;
 
-	ret = v4l2_async_nf_call_bound(notifier, sd, asd);
+	ret = v4l2_async_nf_call_bound(notifier, sd, asc);
 	if (ret < 0) {
 		v4l2_device_unregister_subdev(sd);
 		return ret;
@@ -322,13 +322,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 	 */
 	ret = v4l2_async_create_ancillary_links(notifier, sd);
 	if (ret) {
-		v4l2_async_nf_call_unbind(notifier, sd, asd);
+		v4l2_async_nf_call_unbind(notifier, sd, asc);
 		v4l2_device_unregister_subdev(sd);
 		return ret;
 	}
 
-	list_del(&asd->waiting_list);
-	sd->asd = asd;
+	list_del(&asc->waiting_list);
+	sd->asd = asc;
 	sd->notifier = notifier;
 
 	/* Move from the global subdevice list to notifier's done */
@@ -369,14 +369,14 @@ v4l2_async_nf_try_all_subdevs(struct v4l2_async_notifier *notifier)
 
 again:
 	list_for_each_entry(sd, &subdev_head, async_list) {
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asc;
 		int ret;
 
-		asd = v4l2_async_find_match(notifier, sd);
-		if (!asd)
+		asc = v4l2_async_find_match(notifier, sd);
+		if (!asc)
 			continue;
 
-		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
+		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asc);
 		if (ret < 0)
 			return ret;
 
@@ -434,18 +434,18 @@ static bool
 __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
 				 struct v4l2_async_match *match)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asc;
 	struct v4l2_subdev *sd;
 
-	list_for_each_entry(asd, &notifier->waiting_head, waiting_list)
-		if (asd_equal(&asd->match, match))
+	list_for_each_entry(asc, &notifier->waiting_head, waiting_list)
+		if (asc_equal(&asc->match, match))
 			return true;
 
 	list_for_each_entry(sd, &notifier->done_head, async_list) {
 		if (WARN_ON(!sd->asd))
 			continue;
 
-		if (asd_equal(&sd->asd->match, match))
+		if (asc_equal(&sd->asd->match, match))
 			return true;
 	}
 
@@ -460,19 +460,19 @@ static bool
 v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
 			       struct v4l2_async_match *match, bool skip_self)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asc;
 
 	lockdep_assert_held(&list_lock);
 
 	/* Check that an asd is not being added more than once. */
-	list_for_each_entry(asd, &notifier->asd_head, asd_list) {
-		if (&asd->match == match)
+	list_for_each_entry(asc, &notifier->asc_head, asc_list) {
+		if (&asc->match == match)
 			break;
-		if (asd_equal(&asd->match, match))
+		if (asc_equal(&asc->match, match))
 			return true;
 	}
 
-	/* Check that an asd does not exist in other notifiers. */
+	/* Check that an asc does not exist in other notifiers. */
 	list_for_each_entry(notifier, &notifier_head, notifier_list)
 		if (__v4l2_async_nf_has_async_subdev(notifier, match))
 			return true;
@@ -480,7 +480,7 @@ v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
 	return false;
 }
 
-static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
+static int v4l2_async_nf_asc_valid(struct v4l2_async_notifier *notifier,
 				   struct v4l2_async_match *match,
 				   bool skip_self)
 {
@@ -510,13 +510,13 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
 
 void v4l2_async_nf_init(struct v4l2_async_notifier *notifier)
 {
-	INIT_LIST_HEAD(&notifier->asd_head);
+	INIT_LIST_HEAD(&notifier->asc_head);
 }
 EXPORT_SYMBOL(v4l2_async_nf_init);
 
 static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asc;
 	int ret;
 
 	INIT_LIST_HEAD(&notifier->waiting_head);
@@ -524,12 +524,12 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 
 	mutex_lock(&list_lock);
 
-	list_for_each_entry(asd, &notifier->asd_head, asd_list) {
-		ret = v4l2_async_nf_asd_valid(notifier, &asd->match, true);
+	list_for_each_entry(asc, &notifier->asc_head, asc_list) {
+		ret = v4l2_async_nf_asc_valid(notifier, &asc->match, true);
 		if (ret)
 			goto err_unlock;
 
-		list_add_tail(&asd->waiting_list, &notifier->waiting_head);
+		list_add_tail(&asc->waiting_list, &notifier->waiting_head);
 	}
 
 	ret = v4l2_async_nf_try_all_subdevs(notifier);
@@ -621,23 +621,23 @@ EXPORT_SYMBOL(v4l2_async_nf_unregister);
 
 static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
 {
-	struct v4l2_async_subdev *asd, *tmp;
+	struct v4l2_async_connection *asc, *tmp;
 
-	if (!notifier || !notifier->asd_head.next)
+	if (!notifier || !notifier->asc_head.next)
 		return;
 
-	list_for_each_entry_safe(asd, tmp, &notifier->asd_head, asd_list) {
-		switch (asd->match.type) {
+	list_for_each_entry_safe(asc, tmp, &notifier->asc_head, asc_list) {
+		switch (asc->match.type) {
 		case V4L2_ASYNC_MATCH_FWNODE:
-			fwnode_handle_put(asd->match.fwnode);
+			fwnode_handle_put(asc->match.fwnode);
 			break;
 		default:
 			break;
 		}
 
-		list_del(&asd->asd_list);
-		v4l2_async_nf_call_destroy(notifier, asd);
-		kfree(asd);
+		list_del(&asc->asc_list);
+		v4l2_async_nf_call_destroy(notifier, asc);
+		kfree(asc);
 	}
 }
 
@@ -651,95 +651,95 @@ void v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
 }
 EXPORT_SYMBOL_GPL(v4l2_async_nf_cleanup);
 
-int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
-			       struct v4l2_async_subdev *asd)
+int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
+				   struct v4l2_async_connection *asc)
 {
 	int ret;
 
 	mutex_lock(&list_lock);
 
-	ret = v4l2_async_nf_asd_valid(notifier, &asd->match, false);
+	ret = v4l2_async_nf_asc_valid(notifier, &asc->match, false);
 	if (ret)
 		goto unlock;
 
-	list_add_tail(&asd->asd_list, &notifier->asd_head);
+	list_add_tail(&asc->asc_list, &notifier->asc_head);
 
 unlock:
 	mutex_unlock(&list_lock);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_subdev);
+EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_connection);
 
-struct v4l2_async_subdev *
+struct v4l2_async_connection *
 __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
 			   struct fwnode_handle *fwnode,
-			   unsigned int asd_struct_size)
+			   unsigned int asc_struct_size)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asc;
 	int ret;
 
-	asd = kzalloc(asd_struct_size, GFP_KERNEL);
-	if (!asd)
+	asc = kzalloc(asc_struct_size, GFP_KERNEL);
+	if (!asc)
 		return ERR_PTR(-ENOMEM);
 
-	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
-	asd->match.fwnode = fwnode_handle_get(fwnode);
+	asc->match.type = V4L2_ASYNC_MATCH_FWNODE;
+	asc->match.fwnode = fwnode_handle_get(fwnode);
 
-	ret = __v4l2_async_nf_add_subdev(notifier, asd);
+	ret = __v4l2_async_nf_add_connection(notifier, asc);
 	if (ret) {
 		fwnode_handle_put(fwnode);
-		kfree(asd);
+		kfree(asc);
 		return ERR_PTR(ret);
 	}
 
-	return asd;
+	return asc;
 }
 EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_fwnode);
 
-struct v4l2_async_subdev *
+struct v4l2_async_connection *
 __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
 				  struct fwnode_handle *endpoint,
-				  unsigned int asd_struct_size)
+				  unsigned int asc_struct_size)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asc;
 	struct fwnode_handle *remote;
 
 	remote = fwnode_graph_get_remote_endpoint(endpoint);
 	if (!remote)
 		return ERR_PTR(-ENOTCONN);
 
-	asd = __v4l2_async_nf_add_fwnode(notif, remote, asd_struct_size);
+	asc = __v4l2_async_nf_add_fwnode(notif, remote, asc_struct_size);
 	/*
 	 * Calling __v4l2_async_nf_add_fwnode grabs a refcount,
 	 * so drop the one we got in fwnode_graph_get_remote_port_parent.
 	 */
 	fwnode_handle_put(remote);
-	return asd;
+	return asc;
 }
 EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_fwnode_remote);
 
-struct v4l2_async_subdev *
+struct v4l2_async_connection *
 __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier, int adapter_id,
-			unsigned short address, unsigned int asd_struct_size)
+			unsigned short address, unsigned int asc_struct_size)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asc;
 	int ret;
 
-	asd = kzalloc(asd_struct_size, GFP_KERNEL);
-	if (!asd)
+	asc = kzalloc(asc_struct_size, GFP_KERNEL);
+	if (!asc)
 		return ERR_PTR(-ENOMEM);
 
-	asd->match.type = V4L2_ASYNC_MATCH_I2C;
-	asd->match.i2c.adapter_id = adapter_id;
-	asd->match.i2c.address = address;
+	asc->match.type = V4L2_ASYNC_MATCH_I2C;
+	asc->match.i2c.adapter_id = adapter_id;
+	asc->match.i2c.address = address;
 
-	ret = __v4l2_async_nf_add_subdev(notifier, asd);
+	ret = __v4l2_async_nf_add_connection(notifier, asc);
 	if (ret) {
-		kfree(asd);
+		kfree(asc);
 		return ERR_PTR(ret);
 	}
 
-	return asd;
+	return asc;
 }
 EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_i2c);
 
@@ -771,16 +771,16 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 	list_for_each_entry(notifier, &notifier_head, notifier_list) {
 		struct v4l2_device *v4l2_dev =
 			v4l2_async_nf_find_v4l2_dev(notifier);
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asc;
 
 		if (!v4l2_dev)
 			continue;
 
-		asd = v4l2_async_find_match(notifier, sd);
-		if (!asd)
+		asc = v4l2_async_find_match(notifier, sd);
+		if (!asc)
 			continue;
 
-		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
+		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asc);
 		if (ret)
 			goto err_unbind;
 
@@ -883,14 +883,14 @@ v4l2_async_nf_name(struct v4l2_async_notifier *notifier)
 static int pending_subdevs_show(struct seq_file *s, void *data)
 {
 	struct v4l2_async_notifier *notif;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asc;
 
 	mutex_lock(&list_lock);
 
 	list_for_each_entry(notif, &notifier_head, notifier_list) {
 		seq_printf(s, "%s:\n", v4l2_async_nf_name(notif));
-		list_for_each_entry(asd, &notif->waiting_head, waiting_list)
-			print_waiting_subdev(s, &asd->match);
+		list_for_each_entry(asc, &notif->waiting_head, waiting_list)
+			print_waiting_subdev(s, &asc->match);
 	}
 
 	mutex_unlock(&list_lock);
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index e6bd63364bed..e4ba04cebc9a 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -804,7 +804,7 @@ v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
 				    parse_endpoint_func parse_endpoint)
 {
 	struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	int ret;
 
 	asd = kzalloc(asd_struct_size, GFP_KERNEL);
@@ -839,7 +839,7 @@ v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
 	if (ret < 0)
 		goto out_err;
 
-	ret = __v4l2_async_nf_add_subdev(notifier, asd);
+	ret = __v4l2_async_nf_add_connection(notifier, asd);
 	if (ret < 0) {
 		/* not an error if asd already exists */
 		if (ret == -EEXIST)
@@ -865,7 +865,7 @@ v4l2_async_nf_parse_fwnode_endpoints(struct device *dev,
 	struct fwnode_handle *fwnode;
 	int ret = 0;
 
-	if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
+	if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_connection)))
 		return -EINVAL;
 
 	fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
@@ -916,10 +916,10 @@ static int v4l2_fwnode_reference_parse(struct device *dev,
 	     !(ret = fwnode_property_get_reference_args(dev_fwnode(dev), prop,
 							NULL, 0, index, &args));
 	     index++) {
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asd;
 
 		asd = v4l2_async_nf_add_fwnode(notifier, args.fwnode,
-					       struct v4l2_async_subdev);
+					       struct v4l2_async_connection);
 		fwnode_handle_put(args.fwnode);
 		if (IS_ERR(asd)) {
 			/* not an error if asd already exists */
@@ -1221,10 +1221,10 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev,
 								  props,
 								  nprops)));
 	     index++) {
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asd;
 
 		asd = v4l2_async_nf_add_fwnode(notifier, fwnode,
-					       struct v4l2_async_subdev);
+					       struct v4l2_async_connection);
 		fwnode_handle_put(fwnode);
 		if (IS_ERR(asd)) {
 			ret = PTR_ERR(asd);
diff --git a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c
index 99e61bbfc9bc..5103b60c4e77 100644
--- a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c
+++ b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c
@@ -1726,7 +1726,7 @@ static int isc_ctrl_init(struct isc_device *isc)
 
 static int isc_async_bound(struct v4l2_async_notifier *notifier,
 			    struct v4l2_subdev *subdev,
-			    struct v4l2_async_subdev *asd)
+			    struct v4l2_async_connection *asd)
 {
 	struct isc_device *isc = container_of(notifier->v4l2_dev,
 					      struct isc_device, v4l2_dev);
@@ -1745,7 +1745,7 @@ static int isc_async_bound(struct v4l2_async_notifier *notifier,
 
 static void isc_async_unbind(struct v4l2_async_notifier *notifier,
 			      struct v4l2_subdev *subdev,
-			      struct v4l2_async_subdev *asd)
+			      struct v4l2_async_connection *asd)
 {
 	struct isc_device *isc = container_of(notifier->v4l2_dev,
 					      struct isc_device, v4l2_dev);
diff --git a/drivers/staging/media/deprecated/atmel/atmel-isc.h b/drivers/staging/media/deprecated/atmel/atmel-isc.h
index dfc030b5a08f..31767ea74be6 100644
--- a/drivers/staging/media/deprecated/atmel/atmel-isc.h
+++ b/drivers/staging/media/deprecated/atmel/atmel-isc.h
@@ -44,7 +44,7 @@ struct isc_buffer {
 
 struct isc_subdev_entity {
 	struct v4l2_subdev		*sd;
-	struct v4l2_async_subdev	*asd;
+	struct v4l2_async_connection	*asd;
 	struct device_node		*epn;
 	struct v4l2_async_notifier      notifier;
 
diff --git a/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c b/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c
index ba0614f981a2..0471e7796833 100644
--- a/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c
+++ b/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c
@@ -505,7 +505,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
 	}
 
 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asd;
 		struct fwnode_handle *fwnode =
 			of_fwnode_handle(subdev_entity->epn);
 
@@ -513,7 +513,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
 
 		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
 						      fwnode,
-						      struct v4l2_async_subdev);
+						      struct v4l2_async_connection);
 
 		of_node_put(subdev_entity->epn);
 		subdev_entity->epn = NULL;
diff --git a/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c b/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c
index 01ababdfcbd9..4af5769cd425 100644
--- a/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c
+++ b/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c
@@ -495,7 +495,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
 	}
 
 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
-		struct v4l2_async_subdev *asd;
+		struct v4l2_async_connection *asd;
 		struct fwnode_handle *fwnode =
 			of_fwnode_handle(subdev_entity->epn);
 
@@ -503,7 +503,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
 
 		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
 						      fwnode,
-						      struct v4l2_async_subdev);
+						      struct v4l2_async_connection);
 
 		of_node_put(subdev_entity->epn);
 		subdev_entity->epn = NULL;
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index 44d87fe30d52..6a9052790b78 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -1892,7 +1892,7 @@ static const struct v4l2_subdev_internal_ops csi_internal_ops = {
 
 static int imx_csi_notify_bound(struct v4l2_async_notifier *notifier,
 				struct v4l2_subdev *sd,
-				struct v4l2_async_subdev *asd)
+				struct v4l2_async_connection *asd)
 {
 	struct csi_priv *priv = notifier_to_dev(notifier);
 	struct media_pad *sink = &priv->sd.entity.pads[CSI_SINK_PAD];
@@ -1913,7 +1913,7 @@ static const struct v4l2_async_notifier_operations csi_notify_ops = {
 
 static int imx_csi_async_register(struct csi_priv *priv)
 {
-	struct v4l2_async_subdev *asd = NULL;
+	struct v4l2_async_connection *asd = NULL;
 	struct fwnode_handle *ep;
 	unsigned int port;
 	int ret;
@@ -1930,7 +1930,7 @@ static int imx_csi_async_register(struct csi_priv *priv)
 					     FWNODE_GRAPH_ENDPOINT_NEXT);
 	if (ep) {
 		asd = v4l2_async_nf_add_fwnode_remote(&priv->notifier, ep,
-						      struct v4l2_async_subdev);
+						      struct v4l2_async_connection);
 
 		fwnode_handle_put(ep);
 
diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c
index eaa54848df6a..f2536016d24a 100644
--- a/drivers/staging/media/imx/imx-media-dev-common.c
+++ b/drivers/staging/media/imx/imx-media-dev-common.c
@@ -22,7 +22,7 @@ static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
 /* async subdev bound notifier */
 static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
 				  struct v4l2_subdev *sd,
-				  struct v4l2_async_subdev *asd)
+				  struct v4l2_async_connection *asd)
 {
 	struct imx_media_dev *imxmd = notifier2dev(notifier);
 
@@ -398,7 +398,7 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd,
 	int ret;
 
 	/* no subdevs? just bail */
-	if (list_empty(&imxmd->notifier.asd_head)) {
+	if (list_empty(&imxmd->notifier.asc_head)) {
 		v4l2_err(&imxmd->v4l2_dev, "no subdevs\n");
 		return -ENODEV;
 	}
diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
index f85462214e22..40f4e21571ed 100644
--- a/drivers/staging/media/imx/imx-media-dev.c
+++ b/drivers/staging/media/imx/imx-media-dev.c
@@ -20,7 +20,7 @@ static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
 /* async subdev bound notifier */
 static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
 				  struct v4l2_subdev *sd,
-				  struct v4l2_async_subdev *asd)
+				  struct v4l2_async_connection *asd)
 {
 	struct imx_media_dev *imxmd = notifier2dev(notifier);
 	int ret;
diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c
index 59f1eb7b62bc..310059d9d97e 100644
--- a/drivers/staging/media/imx/imx-media-of.c
+++ b/drivers/staging/media/imx/imx-media-of.c
@@ -19,7 +19,7 @@
 int imx_media_of_add_csi(struct imx_media_dev *imxmd,
 			 struct device_node *csi_np)
 {
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	int ret = 0;
 
 	if (!of_device_is_available(csi_np)) {
@@ -31,7 +31,7 @@ int imx_media_of_add_csi(struct imx_media_dev *imxmd,
 	/* add CSI fwnode to async notifier */
 	asd = v4l2_async_nf_add_fwnode(&imxmd->notifier,
 				       of_fwnode_handle(csi_np),
-				       struct v4l2_async_subdev);
+				       struct v4l2_async_connection);
 	if (IS_ERR(asd)) {
 		ret = PTR_ERR(asd);
 		if (ret == -EEXIST)
diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c
index c4cb558a85c6..cebf42840061 100644
--- a/drivers/staging/media/imx/imx6-mipi-csi2.c
+++ b/drivers/staging/media/imx/imx6-mipi-csi2.c
@@ -591,7 +591,7 @@ static const struct v4l2_subdev_internal_ops csi2_internal_ops = {
 
 static int csi2_notify_bound(struct v4l2_async_notifier *notifier,
 			     struct v4l2_subdev *sd,
-			     struct v4l2_async_subdev *asd)
+			     struct v4l2_async_connection *asd)
 {
 	struct csi2_dev *csi2 = notifier_to_dev(notifier);
 	struct media_pad *sink = &csi2->sd.entity.pads[CSI2_SINK_PAD];
@@ -614,7 +614,7 @@ static int csi2_notify_bound(struct v4l2_async_notifier *notifier,
 
 static void csi2_notify_unbind(struct v4l2_async_notifier *notifier,
 			       struct v4l2_subdev *sd,
-			       struct v4l2_async_subdev *asd)
+			       struct v4l2_async_connection *asd)
 {
 	struct csi2_dev *csi2 = notifier_to_dev(notifier);
 
@@ -631,7 +631,7 @@ static int csi2_async_register(struct csi2_dev *csi2)
 	struct v4l2_fwnode_endpoint vep = {
 		.bus_type = V4L2_MBUS_CSI2_DPHY,
 	};
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct fwnode_handle *ep;
 	int ret;
 
@@ -652,7 +652,7 @@ static int csi2_async_register(struct csi2_dev *csi2)
 	dev_dbg(csi2->dev, "flags: 0x%08x\n", vep.bus.mipi_csi2.flags);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&csi2->notifier, ep,
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 	fwnode_handle_put(ep);
 
 	if (IS_ERR(asd))
diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c
index 83194328d010..05b7215493af 100644
--- a/drivers/staging/media/imx/imx8mq-mipi-csi2.c
+++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c
@@ -616,7 +616,7 @@ mipi_notifier_to_csi2_state(struct v4l2_async_notifier *n)
 
 static int imx8mq_mipi_csi_notify_bound(struct v4l2_async_notifier *notifier,
 					struct v4l2_subdev *sd,
-					struct v4l2_async_subdev *asd)
+					struct v4l2_async_connection *asd)
 {
 	struct csi_state *state = mipi_notifier_to_csi2_state(notifier);
 	struct media_pad *sink = &state->sd.entity.pads[MIPI_CSI2_PAD_SINK];
@@ -636,7 +636,7 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
 	struct v4l2_fwnode_endpoint vep = {
 		.bus_type = V4L2_MBUS_CSI2_DPHY,
 	};
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct fwnode_handle *ep;
 	unsigned int i;
 	int ret;
@@ -668,7 +668,7 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
 		state->bus.flags);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&state->notifier, ep,
-					      struct v4l2_async_subdev);
+					      struct v4l2_async_connection);
 	if (IS_ERR(asd)) {
 		ret = PTR_ERR(asd);
 		goto err_parse;
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
index 1ca4673df2b3..dd7dfecb9ef3 100644
--- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
@@ -395,7 +395,7 @@ static int sun6i_isp_proc_link(struct sun6i_isp_device *isp_dev,
 
 static int sun6i_isp_proc_notifier_bound(struct v4l2_async_notifier *notifier,
 					 struct v4l2_subdev *remote_subdev,
-					 struct v4l2_async_subdev *async_subdev)
+					 struct v4l2_async_connection *async_subdev)
 {
 	struct sun6i_isp_device *isp_dev =
 		container_of(notifier, struct sun6i_isp_device, proc.notifier);
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.h b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.h
index c5c274e21ad5..db6738a39147 100644
--- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.h
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.h
@@ -34,7 +34,7 @@ struct sun6i_isp_proc_source {
 };
 
 struct sun6i_isp_proc_async_subdev {
-	struct v4l2_async_subdev	async_subdev;
+	struct v4l2_async_connection	async_subdev;
 	struct sun6i_isp_proc_source	*source;
 };
 
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 4818646fe637..eaa1e241094f 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -54,7 +54,7 @@ to_tegra_channel_buffer(struct vb2_v4l2_buffer *vb)
 }
 
 static inline struct tegra_vi_graph_entity *
-to_tegra_vi_graph_entity(struct v4l2_async_subdev *asd)
+to_tegra_vi_graph_entity(struct v4l2_async_connection *asd)
 {
 	return container_of(asd, struct tegra_vi_graph_entity, asd);
 }
@@ -1561,9 +1561,9 @@ tegra_vi_graph_find_entity(struct tegra_vi_channel *chan,
 			   const struct fwnode_handle *fwnode)
 {
 	struct tegra_vi_graph_entity *entity;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 
-	list_for_each_entry(asd, &chan->notifier.asd_head, asd_list) {
+	list_for_each_entry(asd, &chan->notifier.asc_head, asc_list) {
 		entity = to_tegra_vi_graph_entity(asd);
 		if (entity->asd.match.fwnode == fwnode)
 			return entity;
@@ -1677,7 +1677,7 @@ static int tegra_vi_graph_build(struct tegra_vi_channel *chan,
 static int tegra_vi_graph_notify_complete(struct v4l2_async_notifier *notifier)
 {
 	struct tegra_vi_graph_entity *entity;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct v4l2_subdev *subdev;
 	struct tegra_vi_channel *chan;
 	struct tegra_vi *vi;
@@ -1707,7 +1707,7 @@ static int tegra_vi_graph_notify_complete(struct v4l2_async_notifier *notifier)
 	}
 
 	/* create links between the entities */
-	list_for_each_entry(asd, &chan->notifier.asd_head, asd_list) {
+	list_for_each_entry(asd, &chan->notifier.asc_head, asc_list) {
 		entity = to_tegra_vi_graph_entity(asd);
 		ret = tegra_vi_graph_build(chan, entity);
 		if (ret < 0)
@@ -1750,7 +1750,7 @@ static int tegra_vi_graph_notify_complete(struct v4l2_async_notifier *notifier)
 
 static int tegra_vi_graph_notify_bound(struct v4l2_async_notifier *notifier,
 				       struct v4l2_subdev *subdev,
-				       struct v4l2_async_subdev *asd)
+				       struct v4l2_async_connection *asd)
 {
 	struct tegra_vi_graph_entity *entity;
 	struct tegra_vi *vi;
@@ -1874,7 +1874,7 @@ static int tegra_vi_graph_init(struct tegra_vi *vi)
 
 		ret = tegra_vi_graph_parse_one(chan, remote);
 		fwnode_handle_put(remote);
-		if (ret < 0 || list_empty(&chan->notifier.asd_head))
+		if (ret < 0 || list_empty(&chan->notifier.asc_head))
 			continue;
 
 		chan->notifier.ops = &tegra_vi_async_ops;
diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
index a68e2c02c7b0..ae49eff7536a 100644
--- a/drivers/staging/media/tegra-video/vi.h
+++ b/drivers/staging/media/tegra-video/vi.h
@@ -106,7 +106,7 @@ struct tegra_vi {
  * @subdev: V4L2 subdev
  */
 struct tegra_vi_graph_entity {
-	struct v4l2_async_subdev asd;
+	struct v4l2_async_connection asd;
 	struct media_entity *entity;
 	struct v4l2_subdev *subdev;
 };
diff --git a/include/media/davinci/vpif_types.h b/include/media/davinci/vpif_types.h
index d03e5c54347a..6cce1f09c721 100644
--- a/include/media/davinci/vpif_types.h
+++ b/include/media/davinci/vpif_types.h
@@ -72,7 +72,7 @@ struct vpif_capture_config {
 	int i2c_adapter_id;
 	const char *card_name;
 
-	struct v4l2_async_subdev *asd[VPIF_CAPTURE_MAX_CHANNELS];
+	struct v4l2_async_connection *asd[VPIF_CAPTURE_MAX_CHANNELS];
 	int asd_sizes[VPIF_CAPTURE_MAX_CHANNELS];
 };
 #endif /* _VPIF_TYPES_H */
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 425280b4d387..9cf383e81a16 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -63,23 +63,23 @@ struct v4l2_async_match {
 };
 
 /**
- * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
+ * struct v4l2_async_connection - sub-device descriptor, as known to a bridge
  *
  * @match:	struct of match type and per-bus type matching data sets
- * @asd_list:	used to add struct v4l2_async_subdev objects to the
- *		master notifier @asd_list
- * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
- *		probed, to a notifier->waiting list
+ * @asc_list:	used to add struct v4l2_async_connection objects to the
+ *		master notifier @asc_list
+ * @waiting_list: used to link struct v4l2_async_connection objects, waiting to
+ *		be probed, to a notifier->waiting list
  *
  * When this struct is used as a member in a driver specific struct,
  * the driver specific struct shall contain the &struct
- * v4l2_async_subdev as its first member.
+ * v4l2_async_connection as its first member.
  */
-struct v4l2_async_subdev {
+struct v4l2_async_connection {
 	struct v4l2_async_match match;
 
 	/* v4l2-async core private: not to be used by drivers */
-	struct list_head asd_list;
+	struct list_head asc_list;
 	struct list_head waiting_list;
 };
 
@@ -89,17 +89,17 @@ struct v4l2_async_subdev {
  * @complete:	All subdevices have been probed successfully. The complete
  *		callback is only executed for the root notifier.
  * @unbind:	a subdevice is leaving
- * @destroy:	the asd is about to be freed
+ * @destroy:	the asc is about to be freed
  */
 struct v4l2_async_notifier_operations {
 	int (*bound)(struct v4l2_async_notifier *notifier,
 		     struct v4l2_subdev *subdev,
-		     struct v4l2_async_subdev *asd);
+		     struct v4l2_async_connection *asc);
 	int (*complete)(struct v4l2_async_notifier *notifier);
 	void (*unbind)(struct v4l2_async_notifier *notifier,
 		       struct v4l2_subdev *subdev,
-		       struct v4l2_async_subdev *asd);
-	void (*destroy)(struct v4l2_async_subdev *asd);
+		       struct v4l2_async_connection *asc);
+	void (*destroy)(struct v4l2_async_connection *asc);
 };
 
 /**
@@ -109,7 +109,7 @@ struct v4l2_async_notifier_operations {
  * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
  * @sd:		sub-device that registered the notifier, NULL otherwise
  * @parent:	parent notifier
- * @asd_head:	master list of struct v4l2_async_subdev
+ * @asc_head:	master list of struct v4l2_async_subdev
  * @waiting_list: list of struct v4l2_async_subdev, waiting for their drivers
  * @done_head:	list of struct v4l2_subdev, already probed
  * @notifier_list: member in a global list of notifiers
@@ -119,7 +119,7 @@ struct v4l2_async_notifier {
 	struct v4l2_device *v4l2_dev;
 	struct v4l2_subdev *sd;
 	struct v4l2_async_notifier *parent;
-	struct list_head asd_head;
+	struct list_head asc_head;
 	struct list_head waiting_head;
 	struct list_head done_head;
 	struct list_head notifier_list;
@@ -137,75 +137,75 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
  *
  * @notifier: pointer to &struct v4l2_async_notifier
  *
- * This function initializes the notifier @asd_list. It must be called
+ * This function initializes the notifier @asc_list. It must be called
  * before adding a subdevice to a notifier, using one of:
  * v4l2_async_nf_add_fwnode_remote(),
  * v4l2_async_nf_add_fwnode(),
  * v4l2_async_nf_add_i2c(),
- * __v4l2_async_nf_add_subdev() or
+ * __v4l2_async_nf_add_connection() or
  * v4l2_async_nf_parse_fwnode_endpoints().
  */
 void v4l2_async_nf_init(struct v4l2_async_notifier *notifier);
 
 /**
- * __v4l2_async_nf_add_subdev - Add an async subdev to the
- *				notifier's master asd list.
+ * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
+ *				      master asc list.
  *
  * @notifier: pointer to &struct v4l2_async_notifier
- * @asd: pointer to &struct v4l2_async_subdev
+ * @asc: pointer to &struct v4l2_async_connection
  *
  * \warning: Drivers should avoid using this function and instead use one of:
  * v4l2_async_nf_add_fwnode(),
  * v4l2_async_nf_add_fwnode_remote() or
  * v4l2_async_nf_add_i2c().
  *
- * Call this function before registering a notifier to link the provided @asd to
- * the notifiers master @asd_list. The @asd must be allocated with k*alloc() as
+ * Call this function before registering a notifier to link the provided @asc to
+ * the notifiers master @asc_list. The @asc must be allocated with k*alloc() as
  * it will be freed by the framework when the notifier is destroyed.
  */
-int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
-			       struct v4l2_async_subdev *asd);
+int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
+				   struct v4l2_async_connection *asc);
 
-struct v4l2_async_subdev *
+struct v4l2_async_connection *
 __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
 			   struct fwnode_handle *fwnode,
-			   unsigned int asd_struct_size);
+			   unsigned int asc_struct_size);
 /**
  * v4l2_async_nf_add_fwnode - Allocate and add a fwnode async
- *				subdev to the notifier's master asd_list.
+ *				subdev to the notifier's master asc_list.
  *
  * @notifier: pointer to &struct v4l2_async_notifier
  * @fwnode: fwnode handle of the sub-device to be matched, pointer to
  *	    &struct fwnode_handle
  * @type: Type of the driver's async sub-device struct. The &struct
- *	  v4l2_async_subdev shall be the first member of the driver's async
+ *	  v4l2_async_connection shall be the first member of the driver's async
  *	  sub-device struct, i.e. both begin at the same memory address.
  *
- * Allocate a fwnode-matched asd of size asd_struct_size, and add it to the
- * notifiers @asd_list. The function also gets a reference of the fwnode which
+ * Allocate a fwnode-matched asc of size asc_struct_size, and add it to the
+ * notifiers @asc_list. The function also gets a reference of the fwnode which
  * is released later at notifier cleanup time.
  */
 #define v4l2_async_nf_add_fwnode(notifier, fwnode, type)		\
 	((type *)__v4l2_async_nf_add_fwnode(notifier, fwnode, sizeof(type)))
 
-struct v4l2_async_subdev *
+struct v4l2_async_connection *
 __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
 				  struct fwnode_handle *endpoint,
-				  unsigned int asd_struct_size);
+				  unsigned int asc_struct_size);
 /**
  * v4l2_async_nf_add_fwnode_remote - Allocate and add a fwnode
  *						  remote async subdev to the
- *						  notifier's master asd_list.
+ *						  notifier's master asc_list.
  *
  * @notifier: pointer to &struct v4l2_async_notifier
  * @ep: local endpoint pointing to the remote sub-device to be matched,
  *	pointer to &struct fwnode_handle
  * @type: Type of the driver's async sub-device struct. The &struct
- *	  v4l2_async_subdev shall be the first member of the driver's async
+ *	  v4l2_async_connection shall be the first member of the driver's async
  *	  sub-device struct, i.e. both begin at the same memory address.
  *
  * Gets the remote endpoint of a given local endpoint, set it up for fwnode
- * matching and adds the async sub-device to the notifier's @asd_list. The
+ * matching and adds the async sub-device to the notifier's @asc_list. The
  * function also gets a reference of the fwnode which is released later at
  * notifier cleanup time.
  *
@@ -215,19 +215,19 @@ __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
 #define v4l2_async_nf_add_fwnode_remote(notifier, ep, type) \
 	((type *)__v4l2_async_nf_add_fwnode_remote(notifier, ep, sizeof(type)))
 
-struct v4l2_async_subdev *
+struct v4l2_async_connection *
 __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier,
 			int adapter_id, unsigned short address,
-			unsigned int asd_struct_size);
+			unsigned int asc_struct_size);
 /**
  * v4l2_async_nf_add_i2c - Allocate and add an i2c async
- *				subdev to the notifier's master asd_list.
+ *				subdev to the notifier's master asc_list.
  *
  * @notifier: pointer to &struct v4l2_async_notifier
  * @adapter: I2C adapter ID to be matched
  * @address: I2C address of sub-device to be matched
  * @type: Type of the driver's async sub-device struct. The &struct
- *	  v4l2_async_subdev shall be the first member of the driver's async
+ *	  v4l2_async_connection shall be the first member of the driver's async
  *	  sub-device struct, i.e. both begin at the same memory address.
  *
  * Same as v4l2_async_nf_add_fwnode() but for I2C matched
@@ -275,7 +275,7 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier);
  * v4l2_async_nf_add_fwnode_remote(),
  * v4l2_async_nf_add_fwnode(),
  * v4l2_async_nf_add_i2c(),
- * __v4l2_async_nf_add_subdev() or
+ * __v4l2_async_nf_add_connection() or
  * v4l2_async_nf_parse_fwnode_endpoints().
  *
  * There is no harm from calling v4l2_async_nf_cleanup() in other
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 394d798f3dfa..ebb83154abd5 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -23,7 +23,7 @@
 
 struct fwnode_handle;
 struct v4l2_async_notifier;
-struct v4l2_async_subdev;
+struct v4l2_async_connection;
 
 /**
  * struct v4l2_fwnode_endpoint - the endpoint data structure
@@ -399,7 +399,7 @@ int v4l2_fwnode_device_parse(struct device *dev,
  *
  * @dev: pointer to &struct device
  * @vep: pointer to &struct v4l2_fwnode_endpoint
- * @asd: pointer to &struct v4l2_async_subdev
+ * @asd: pointer to &struct v4l2_async_connection
  *
  * Return:
  * * %0 on success
@@ -409,7 +409,7 @@ int v4l2_fwnode_device_parse(struct device *dev,
  */
 typedef int (*parse_endpoint_func)(struct device *dev,
 				  struct v4l2_fwnode_endpoint *vep,
-				  struct v4l2_async_subdev *asd);
+				  struct v4l2_async_connection *asd);
 
 /**
  * v4l2_async_nf_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
@@ -417,8 +417,8 @@ typedef int (*parse_endpoint_func)(struct device *dev,
  * @dev: the device the endpoints of which are to be parsed
  * @notifier: notifier for @dev
  * @asd_struct_size: size of the driver's async sub-device struct, including
- *		     sizeof(struct v4l2_async_subdev). The &struct
- *		     v4l2_async_subdev shall be the first member of
+ *		     sizeof(struct v4l2_async_connection). The &struct
+ *		     v4l2_async_connection shall be the first member of
  *		     the driver's async sub-device struct, i.e. both
  *		     begin at the same memory address.
  * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 17773be4a4ee..a2cce11dda5c 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -1021,7 +1021,7 @@ struct v4l2_subdev_platform_data {
  *	    either dev->of_node->fwnode or dev->fwnode (whichever is non-NULL).
  * @async_list: Links this subdev to a global subdev_list or @notifier->done
  *	list.
- * @asd: Pointer to respective &struct v4l2_async_subdev.
+ * @asc: Pointer to respective &struct v4l2_async_connection.
  * @notifier: Pointer to the managing notifier.
  * @subdev_notifier: A sub-device notifier implicitly registered for the sub-
  *		     device using v4l2_async_register_subdev_sensor().
@@ -1063,7 +1063,7 @@ struct v4l2_subdev {
 	struct device *dev;
 	struct fwnode_handle *fwnode;
 	struct list_head async_list;
-	struct v4l2_async_subdev *asd;
+	struct v4l2_async_connection *asd;
 	struct v4l2_async_notifier *notifier;
 	struct v4l2_async_notifier *subdev_notifier;
 	struct v4l2_subdev_platform_data *pdata;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 09/18] media: v4l: async: Differentiate connecting and creating sub-devices
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (7 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 08/18] media: v4l: async: Rename v4l2_async_subdev as v4l2_async_connection Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-14  8:52   ` Jacopo Mondi
  2023-03-30 11:58 ` [PATCH 10/18] media: pxa_camera: Register V4L2 device early, fix probe error handling Sakari Ailus
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

When the v4l2-async framework was introduced, the use case for it was to
connect a camera sensor with a parallel receiver. Both tended to be rather
simple devices with a single connection between them.

The framework has been since improved in multiple ways but there are
limitations that have remained, for instance the assumption an async
sub-device is connected towards a single notifier and via a single link
only.

This patch adds an object that represents the device while an earlier
patch in the series re-purposed the old struct v4l2_async_subdev as the
connection.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
 .../platform/rockchip/rkisp1/rkisp1-dev.c     |   8 +-
 drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
 drivers/media/v4l2-core/v4l2-async.c          | 163 ++++++++++++++++--
 include/media/v4l2-async.h                    |  32 +++-
 include/media/v4l2-subdev.h                   |   2 +-
 6 files changed, 179 insertions(+), 30 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
index d30f0ecb1bfd..a1293c45aae1 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
@@ -148,7 +148,7 @@ struct rkisp1_info {
  * @port:		port number (0: MIPI, 1: Parallel)
  */
 struct rkisp1_sensor_async {
-	struct v4l2_async_connection asd;
+	struct v4l2_async_subdev asd;
 	unsigned int index;
 	struct fwnode_handle *source_ep;
 	unsigned int lanes;
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
index 39fa98e6dbbc..5bdb1ecedf6a 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
@@ -122,12 +122,12 @@ struct rkisp1_isr_data {
 
 static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
 					struct v4l2_subdev *sd,
-					struct v4l2_async_connection *asd)
+					struct v4l2_async_connection *asc)
 {
 	struct rkisp1_device *rkisp1 =
 		container_of(notifier, struct rkisp1_device, notifier);
 	struct rkisp1_sensor_async *s_asd =
-		container_of(asd, struct rkisp1_sensor_async, asd);
+		container_of(asc->asd, struct rkisp1_sensor_async, asd);
 	int source_pad;
 	int ret;
 
@@ -165,10 +165,10 @@ static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
 	return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
 }
 
-static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asd)
+static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asc)
 {
 	struct rkisp1_sensor_async *rk_asd =
-		container_of(asd, struct rkisp1_sensor_async, asd);
+		container_of(asc->asd, struct rkisp1_sensor_async, asd);
 
 	fwnode_handle_put(rk_asd->source_ep);
 }
diff --git a/drivers/media/platform/ti/omap3isp/isp.h b/drivers/media/platform/ti/omap3isp/isp.h
index 32ea70c8d2f9..a9d760fbf349 100644
--- a/drivers/media/platform/ti/omap3isp/isp.h
+++ b/drivers/media/platform/ti/omap3isp/isp.h
@@ -220,7 +220,7 @@ struct isp_device {
 };
 
 struct isp_async_subdev {
-	struct v4l2_async_connection asd;
+	struct v4l2_async_subdev asd;
 	struct isp_bus_cfg bus;
 };
 
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 56ce40481ec4..4c3bd64d6a00 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -134,6 +134,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
 }
 
 static LIST_HEAD(subdev_head);
+static LIST_HEAD(asd_head);
 static LIST_HEAD(notifier_head);
 static DEFINE_MUTEX(list_lock);
 
@@ -304,13 +305,20 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 	struct v4l2_async_notifier *subdev_notifier;
 	int ret;
 
-	ret = v4l2_device_register_subdev(v4l2_dev, sd);
-	if (ret < 0)
-		return ret;
+	if (!asc->asd->registered) {
+		ret = v4l2_device_register_subdev(v4l2_dev, sd);
+		if (ret < 0)
+			return ret;
+	}
 
 	ret = v4l2_async_nf_call_bound(notifier, sd, asc);
 	if (ret < 0) {
-		v4l2_device_unregister_subdev(sd);
+		if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
+			dev_dbg(notifier_dev(notifier),
+				"failed binding %pfw (%d)\n",
+				asc->match.fwnode, ret);
+		if (!asc->asd->registered)
+			v4l2_device_unregister_subdev(sd);
 		return ret;
 	}
 
@@ -322,14 +330,26 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 	 */
 	ret = v4l2_async_create_ancillary_links(notifier, sd);
 	if (ret) {
+		if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
+			dev_dbg(notifier_dev(notifier),
+				"failed creating links for %pfw (%d)\n",
+				asc->match.fwnode, ret);
 		v4l2_async_nf_call_unbind(notifier, sd, asc);
-		v4l2_device_unregister_subdev(sd);
+		list_del(&asc->asc_subdev_list);
+		if (!asc->asd->registered)
+			v4l2_device_unregister_subdev(sd);
 		return ret;
 	}
 
 	list_del(&asc->waiting_list);
-	sd->asd = asc;
-	sd->notifier = notifier;
+	if (!sd->asd) {
+		WARN_ON(asc->asd->registered);
+		sd->asd = asc->asd;
+		sd->notifier = notifier;
+		asc->asd->registered = true;
+	} else {
+		WARN_ON(sd->asd != asc->asd);
+	}
 
 	/* Move from the global subdevice list to notifier's done */
 	list_move(&sd->async_list, &notifier->done_head);
@@ -403,6 +423,21 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 	sd->asd = NULL;
 }
 
+static void v4l2_async_unbind_subdev_one(struct v4l2_async_notifier *notifier,
+					 struct v4l2_subdev *sd, bool readd)
+{
+	struct v4l2_async_connection *asc, *tmp;
+
+	list_for_each_entry_safe(asc, tmp, &sd->asd->asc_head,
+				 asc_subdev_list) {
+		v4l2_async_nf_call_unbind(notifier, sd, asc);
+		list_del(&asc->asc_subdev_list);
+		if (readd)
+			list_add_tail(&asc->waiting_list,
+				      &notifier->waiting_head);
+	}
+}
+
 /* Unbind all sub-devices in the notifier tree. */
 static void
 v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
@@ -417,10 +452,8 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
 		if (subdev_notifier)
 			v4l2_async_nf_unbind_all_subdevs(subdev_notifier, true);
 
-		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
-		if (readd)
-			list_add_tail(&sd->asd->waiting_list,
-				      &notifier->waiting_head);
+		v4l2_async_unbind_subdev_one(notifier, sd, readd);
+
 		v4l2_async_cleanup(sd);
 
 		list_move(&sd->async_list, &subdev_head);
@@ -445,8 +478,9 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
 		if (WARN_ON(!sd->asd))
 			continue;
 
-		if (asc_equal(&sd->asd->match, match))
-			return true;
+		list_for_each_entry(asc, &sd->asd->asc_head, asc_list)
+			if (asc_equal(&asc->match, match))
+				return true;
 	}
 
 	return false;
@@ -619,6 +653,18 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
 }
 EXPORT_SYMBOL(v4l2_async_nf_unregister);
 
+static void release_async_subdev(struct kref *kref)
+{
+	struct v4l2_async_subdev *asd =
+		container_of_const(kref, struct v4l2_async_subdev, kref);
+
+	list_del(&asd->asd_list);
+
+	WARN_ON(!list_empty(&asd->asc_head));
+
+	kfree(asd);
+}
+
 static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_async_connection *asc, *tmp;
@@ -627,16 +673,24 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
 		return;
 
 	list_for_each_entry_safe(asc, tmp, &notifier->asc_head, asc_list) {
+		list_del(&asc->asc_list);
+		v4l2_async_nf_call_destroy(notifier, asc);
+
 		switch (asc->match.type) {
 		case V4L2_ASYNC_MATCH_FWNODE:
+			pr_debug("release async connection for fwnode %pfw\n",
+				 asc->match.fwnode);
 			fwnode_handle_put(asc->match.fwnode);
 			break;
-		default:
+		case V4L2_ASYNC_MATCH_I2C:
+			pr_debug("release I²C async connection\n");
 			break;
+		default:
+			pr_debug("release invalid async connection type %u\n",
+				 asc->match.type);
 		}
 
-		list_del(&asc->asc_list);
-		v4l2_async_nf_call_destroy(notifier, asc);
+		kref_put(&asc->asd->kref, release_async_subdev);
 		kfree(asc);
 	}
 }
@@ -651,6 +705,71 @@ void v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
 }
 EXPORT_SYMBOL_GPL(v4l2_async_nf_cleanup);
 
+static bool async_subdev_has_connection(struct v4l2_async_notifier *notifier,
+					struct v4l2_async_subdev *asd,
+					struct v4l2_async_connection *asc)
+{
+	struct v4l2_async_connection *__asc;
+
+	list_for_each_entry(__asc, &asd->asc_head, asc_subdev_list) {
+		if (__asc->match.type != V4L2_ASYNC_MATCH_FWNODE)
+			continue;
+
+		if (__asc->match.fwnode != asc->match.fwnode)
+			continue;
+
+		dev_dbg(notifier_dev(notifier), "found!\n");
+
+		return true;
+	}
+
+	return false;
+}
+
+/* Find an async sub-device for the async connection. */
+static int v4l2_async_find_async_subdev(struct v4l2_async_notifier *notifier,
+					struct v4l2_async_connection *asc)
+{
+	struct v4l2_async_subdev *asd;
+
+	lockdep_assert_held(&list_lock);
+
+	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
+		dev_dbg(notifier_dev(notifier),
+			"async: looking up subdev for %pfw\n",
+			asc->match.fwnode);
+
+	/*
+	 * Matching by endpoint nodes may mean there are multiple connections to
+	 * a single device. This is only possible with fwnode matching.
+	 */
+	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE &&
+	    fwnode_graph_is_endpoint(asc->match.fwnode)) {
+		list_for_each_entry(asd, &asd_head, asd_list) {
+			if (async_subdev_has_connection(notifier, asd, asc)) {
+				kref_get(&asd->kref);
+				goto found;
+			}
+		}
+	}
+
+	dev_dbg(notifier_dev(notifier), "not found, allocating new one\n");
+
+	asd = kzalloc(sizeof(*asd), GFP_KERNEL);
+	if (!asd)
+		return -ENOMEM;
+
+	kref_init(&asd->kref);
+	INIT_LIST_HEAD(&asd->asc_head);
+	list_add(&asd->asd_list, &asd_head);
+
+found:
+	list_add(&asc->asc_subdev_list, &asd->asc_head);
+	asc->asd = asd;
+
+	return 0;
+}
+
 int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
 				   struct v4l2_async_connection *asc)
 {
@@ -662,6 +781,10 @@ int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
 	if (ret)
 		goto unlock;
 
+	ret = v4l2_async_find_async_subdev(notifier, asc);
+	if (ret)
+		goto unlock;
+
 	list_add_tail(&asc->asc_list, &notifier->asc_head);
 
 unlock:
@@ -809,7 +932,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 		v4l2_async_nf_unbind_all_subdevs(subdev_notifier, false);
 
 	if (sd->asd)
-		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
+		v4l2_async_unbind_subdev_one(notifier, sd, true);
 	v4l2_async_cleanup(sd);
 
 	mutex_unlock(&list_lock);
@@ -832,10 +955,12 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 
 	if (sd->asd) {
 		struct v4l2_async_notifier *notifier = sd->notifier;
+		struct v4l2_async_connection *asc;
 
-		list_add(&sd->asd->waiting_list, &notifier->waiting_head);
+		list_for_each_entry(asc, &sd->asd->asc_head, asc_subdev_list)
+			list_add(&asc->waiting_list, &notifier->waiting_head);
 
-		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
+		v4l2_async_unbind_subdev_one(notifier, sd, true);
 	}
 
 	v4l2_async_cleanup(sd);
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 9cf383e81a16..750bf4ddb267 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -8,6 +8,7 @@
 #ifndef V4L2_ASYNC_H
 #define V4L2_ASYNC_H
 
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 
@@ -63,24 +64,47 @@ struct v4l2_async_match {
 };
 
 /**
- * struct v4l2_async_connection - sub-device descriptor, as known to a bridge
+ * struct v4l2_async_subdev - sub-device descriptor
  *
+ * @kref:	kref for refcounting the subdev
+ * @asd_list:	Entry in the list of async sub-devices
+ * @subdev_list: used to link struct v4l2_async_subdev objects, waiting to be
+ *		probed, to a notifier->waiting_head list
+ * @asc_head:	head for struct v4l2_async_connection.asd_list list
+ * @registered:	whether the sub-device has been registered
+ */
+struct v4l2_async_subdev {
+	struct kref kref;
+	struct list_head asd_list;
+	struct list_head subdev_list;
+	struct list_head asc_head;
+	bool registered;
+};
+
+/**
+ * struct v4l2_async_connection - sub-device connection descriptor, as known to
+ *				  a bridge
+ *
+ * @asd:	the async sub-device related to this connection
  * @match:	struct of match type and per-bus type matching data sets
  * @asc_list:	used to add struct v4l2_async_connection objects to the
  *		master notifier @asc_list
  * @waiting_list: used to link struct v4l2_async_connection objects, waiting to
  *		be probed, to a notifier->waiting list
+ * @asc_subdev_list:	entry in struct v4l2_async_subdev.asc_head list
  *
- * When this struct is used as a member in a driver specific struct,
- * the driver specific struct shall contain the &struct
- * v4l2_async_connection as its first member.
+ * When this struct is used as a member in a driver specific struct, the driver
+ * specific struct shall contain the &struct v4l2_async_connection as its first
+ * member.
  */
 struct v4l2_async_connection {
+	struct v4l2_async_subdev *asd;
 	struct v4l2_async_match match;
 
 	/* v4l2-async core private: not to be used by drivers */
 	struct list_head asc_list;
 	struct list_head waiting_list;
+	struct list_head asc_subdev_list;
 };
 
 /**
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index a2cce11dda5c..d510fe6ea243 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -1063,7 +1063,7 @@ struct v4l2_subdev {
 	struct device *dev;
 	struct fwnode_handle *fwnode;
 	struct list_head async_list;
-	struct v4l2_async_connection *asd;
+	struct v4l2_async_subdev *asd;
 	struct v4l2_async_notifier *notifier;
 	struct v4l2_async_notifier *subdev_notifier;
 	struct v4l2_subdev_platform_data *pdata;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 10/18] media: pxa_camera: Register V4L2 device early, fix probe error handling
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (8 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 09/18] media: v4l: async: Differentiate connecting and creating sub-devices Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-25  0:25   ` Laurent Pinchart
  2023-03-30 11:58 ` [PATCH 11/18] media: marvell: cafe: Register V4L2 device earlier Sakari Ailus
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Register V4L2 device before initialising the notifier. This way the device
is available to the notifier from the beginning.

Also fix error handling in probe.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/platform/intel/pxa_camera.c | 30 +++++++++++++----------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c
index b848a2a9032f..31ae220ee4f3 100644
--- a/drivers/media/platform/intel/pxa_camera.c
+++ b/drivers/media/platform/intel/pxa_camera.c
@@ -2289,6 +2289,10 @@ static int pxa_camera_probe(struct platform_device *pdev)
 	if (IS_ERR(pcdev->clk))
 		return PTR_ERR(pcdev->clk);
 
+	err = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
+	if (err)
+		return err;
+
 	v4l2_async_nf_init(&pcdev->notifier);
 	pcdev->res = res;
 	pcdev->pdata = pdev->dev.platform_data;
@@ -2306,10 +2310,10 @@ static int pxa_camera_probe(struct platform_device *pdev)
 	} else if (pdev->dev.of_node) {
 		err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev);
 	} else {
-		return -ENODEV;
+		err = -ENODEV;
 	}
 	if (err < 0)
-		return err;
+		goto exit_notifier_cleanup;
 
 	if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 |
 			PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) {
@@ -2342,8 +2346,10 @@ static int pxa_camera_probe(struct platform_device *pdev)
 	 * Request the regions.
 	 */
 	base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
+	if (IS_ERR(base)) {
+		err = PTR_ERR(base);
+		goto exit_notifier_cleanup;
+	}
 
 	pcdev->irq = irq;
 	pcdev->base = base;
@@ -2352,7 +2358,8 @@ static int pxa_camera_probe(struct platform_device *pdev)
 	pcdev->dma_chans[0] = dma_request_chan(&pdev->dev, "CI_Y");
 	if (IS_ERR(pcdev->dma_chans[0])) {
 		dev_err(&pdev->dev, "Can't request DMA for Y\n");
-		return PTR_ERR(pcdev->dma_chans[0]);
+		err = PTR_ERR(pcdev->dma_chans[0]);
+		goto exit_notifier_cleanup;
 	}
 
 	pcdev->dma_chans[1] = dma_request_chan(&pdev->dev, "CI_U");
@@ -2392,23 +2399,17 @@ static int pxa_camera_probe(struct platform_device *pdev)
 	pxa_camera_activate(pcdev);
 
 	platform_set_drvdata(pdev, pcdev);
-	err = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
-	if (err)
-		goto exit_deactivate;
 
 	err = pxa_camera_init_videobuf2(pcdev);
 	if (err)
-		goto exit_notifier_cleanup;
+		goto exit_deactivate;
 
 	pcdev->notifier.ops = &pxa_camera_sensor_ops;
 	err = v4l2_async_nf_register(&pcdev->v4l2_dev, &pcdev->notifier);
 	if (err)
-		goto exit_notifier_cleanup;
+		goto exit_deactivate;
 
 	return 0;
-exit_notifier_cleanup:
-	v4l2_async_nf_cleanup(&pcdev->notifier);
-	v4l2_device_unregister(&pcdev->v4l2_dev);
 exit_deactivate:
 	pxa_camera_deactivate(pcdev);
 	tasklet_kill(&pcdev->task_eof);
@@ -2418,6 +2419,9 @@ static int pxa_camera_probe(struct platform_device *pdev)
 	dma_release_channel(pcdev->dma_chans[1]);
 exit_free_dma_y:
 	dma_release_channel(pcdev->dma_chans[0]);
+exit_notifier_cleanup:
+	v4l2_async_nf_cleanup(&pcdev->notifier);
+	v4l2_device_unregister(&pcdev->v4l2_dev);
 	return err;
 }
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 11/18] media: marvell: cafe: Register V4L2 device earlier
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (9 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 10/18] media: pxa_camera: Register V4L2 device early, fix probe error handling Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-25  0:27   ` Laurent Pinchart
  2023-03-30 11:58 ` [PATCH 12/18] media: am437x-vpfe: Register V4L2 device early Sakari Ailus
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Register V4L2 device before the async notifier so the struct device will
be available for the notifier.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/platform/marvell/cafe-driver.c | 12 ++++++++++--
 drivers/media/platform/marvell/mcam-core.c   |  6 ------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/marvell/cafe-driver.c b/drivers/media/platform/marvell/cafe-driver.c
index dd1bba70bd79..4d8843623255 100644
--- a/drivers/media/platform/marvell/cafe-driver.c
+++ b/drivers/media/platform/marvell/cafe-driver.c
@@ -536,6 +536,11 @@ static int cafe_pci_probe(struct pci_dev *pdev,
 	if (ret)
 		goto out_pdown;
 
+	ret = v4l2_device_register(mcam->dev, &mcam->v4l2_dev);
+	if (ret)
+		goto out_smbus_shutdown;
+
+
 	v4l2_async_nf_init(&mcam->notifier);
 
 	asd = v4l2_async_nf_add_i2c(&mcam->notifier,
@@ -544,12 +549,12 @@ static int cafe_pci_probe(struct pci_dev *pdev,
 				    struct v4l2_async_connection);
 	if (IS_ERR(asd)) {
 		ret = PTR_ERR(asd);
-		goto out_smbus_shutdown;
+		goto out_v4l2_device_unregister;
 	}
 
 	ret = mccic_register(mcam);
 	if (ret)
-		goto out_smbus_shutdown;
+		goto out_v4l2_device_unregister;
 
 	clkdev_create(mcam->mclk, "xclk", "%d-%04x",
 		i2c_adapter_id(cam->i2c_adapter), ov7670_info.addr);
@@ -565,6 +570,8 @@ static int cafe_pci_probe(struct pci_dev *pdev,
 
 out_mccic_shutdown:
 	mccic_shutdown(mcam);
+out_v4l2_device_unregister:
+	v4l2_device_unregister(&mcam->v4l2_dev);
 out_smbus_shutdown:
 	cafe_smbus_shutdown(cam);
 out_pdown:
@@ -587,6 +594,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
 static void cafe_shutdown(struct cafe_camera *cam)
 {
 	mccic_shutdown(&cam->mcam);
+	v4l2_device_unregister(&cam->mcam.v4l2_dev);
 	cafe_smbus_shutdown(cam);
 	free_irq(cam->pdev->irq, cam);
 	pci_iounmap(cam->pdev, cam->mcam.regs);
diff --git a/drivers/media/platform/marvell/mcam-core.c b/drivers/media/platform/marvell/mcam-core.c
index b74a362ec075..2ecdcbcb37fd 100644
--- a/drivers/media/platform/marvell/mcam-core.c
+++ b/drivers/media/platform/marvell/mcam-core.c
@@ -1866,10 +1866,6 @@ int mccic_register(struct mcam_camera *cam)
 	/*
 	 * Register with V4L
 	 */
-	ret = v4l2_device_register(cam->dev, &cam->v4l2_dev);
-	if (ret)
-		goto out;
-
 	mutex_init(&cam->s_mutex);
 	cam->state = S_NOTREADY;
 	mcam_set_config_needed(cam, 1);
@@ -1915,7 +1911,6 @@ int mccic_register(struct mcam_camera *cam)
 
 out:
 	v4l2_async_nf_unregister(&cam->notifier);
-	v4l2_device_unregister(&cam->v4l2_dev);
 	v4l2_async_nf_cleanup(&cam->notifier);
 	return ret;
 }
@@ -1937,7 +1932,6 @@ void mccic_shutdown(struct mcam_camera *cam)
 		mcam_free_dma_bufs(cam);
 	v4l2_ctrl_handler_free(&cam->ctrl_handler);
 	v4l2_async_nf_unregister(&cam->notifier);
-	v4l2_device_unregister(&cam->v4l2_dev);
 	v4l2_async_nf_cleanup(&cam->notifier);
 }
 EXPORT_SYMBOL_GPL(mccic_shutdown);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 12/18] media: am437x-vpfe: Register V4L2 device early
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (10 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 11/18] media: marvell: cafe: Register V4L2 device earlier Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-03-30 11:58 ` [PATCH 13/18] media: omap3isp: Initialise V4L2 async notifier later Sakari Ailus
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Register V4L2 device before the async notifier so the struct device will
be available for the notifier.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 .../media/platform/ti/am437x/am437x-vpfe.c    | 28 +++++++++----------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c
index a21f3b91cc06..d5ba9b9c7e5a 100644
--- a/drivers/media/platform/ti/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c
@@ -2400,10 +2400,18 @@ static int vpfe_probe(struct platform_device *pdev)
 
 	vpfe->pdev = &pdev->dev;
 
+	ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev);
+	if (ret) {
+		vpfe_err(vpfe,
+			"Unable to register v4l2 device.\n");
+		return ret;
+	}
+
 	vpfe_cfg = vpfe_get_pdata(vpfe);
 	if (!vpfe_cfg) {
 		dev_err(&pdev->dev, "No platform data\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto probe_out_cleanup;
 	}
 
 	vpfe->cfg = vpfe_cfg;
@@ -2430,13 +2438,6 @@ static int vpfe_probe(struct platform_device *pdev)
 		goto probe_out_cleanup;
 	}
 
-	ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev);
-	if (ret) {
-		vpfe_err(vpfe,
-			"Unable to register v4l2 device.\n");
-		goto probe_out_cleanup;
-	}
-
 	/* set the driver data in platform device */
 	platform_set_drvdata(pdev, vpfe);
 	/* Enabling module functional clock */
@@ -2446,7 +2447,7 @@ static int vpfe_probe(struct platform_device *pdev)
 	ret = pm_runtime_resume_and_get(&pdev->dev);
 	if (ret < 0) {
 		vpfe_err(vpfe, "Unable to resume device.\n");
-		goto probe_out_v4l2_unregister;
+		goto probe_out_cleanup;
 	}
 
 	vpfe_ccdc_config_defaults(ccdc);
@@ -2459,7 +2460,7 @@ static int vpfe_probe(struct platform_device *pdev)
 				GFP_KERNEL);
 	if (!vpfe->sd) {
 		ret = -ENOMEM;
-		goto probe_out_v4l2_unregister;
+		goto probe_out_cleanup;
 	}
 
 	vpfe->notifier.ops = &vpfe_async_ops;
@@ -2467,15 +2468,14 @@ static int vpfe_probe(struct platform_device *pdev)
 	if (ret) {
 		vpfe_err(vpfe, "Error registering async notifier\n");
 		ret = -EINVAL;
-		goto probe_out_v4l2_unregister;
+		goto probe_out_cleanup;
 	}
 
 	return 0;
 
-probe_out_v4l2_unregister:
-	v4l2_device_unregister(&vpfe->v4l2_dev);
 probe_out_cleanup:
 	v4l2_async_nf_cleanup(&vpfe->notifier);
+	v4l2_device_unregister(&vpfe->v4l2_dev);
 	return ret;
 }
 
@@ -2490,8 +2490,8 @@ static int vpfe_remove(struct platform_device *pdev)
 
 	v4l2_async_nf_unregister(&vpfe->notifier);
 	v4l2_async_nf_cleanup(&vpfe->notifier);
-	v4l2_device_unregister(&vpfe->v4l2_dev);
 	video_unregister_device(&vpfe->video_dev);
+	v4l2_device_unregister(&vpfe->v4l2_dev);
 
 	return 0;
 }
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 13/18] media: omap3isp: Initialise V4L2 async notifier later
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (11 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 12/18] media: am437x-vpfe: Register V4L2 device early Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-03-30 11:58 ` [PATCH 14/18] media: xilinx-vipp: Init async notifier after registering V4L2 device Sakari Ailus
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Initialise V4L2 async notifier and parse DT for async sub-devices later,
just before registering the notifier. This way the V4L2 device has been
registered before initialising the notifier.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/platform/ti/omap3isp/isp.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c
index e7327e38482d..7ccc18acb429 100644
--- a/drivers/media/platform/ti/omap3isp/isp.c
+++ b/drivers/media/platform/ti/omap3isp/isp.c
@@ -2002,6 +2002,7 @@ static int isp_remove(struct platform_device *pdev)
 	struct isp_device *isp = platform_get_drvdata(pdev);
 
 	v4l2_async_nf_unregister(&isp->notifier);
+	v4l2_async_nf_cleanup(&isp->notifier);
 	isp_unregister_entities(isp);
 	isp_cleanup_modules(isp);
 	isp_xclk_cleanup(isp);
@@ -2011,7 +2012,6 @@ static int isp_remove(struct platform_device *pdev)
 	__omap3isp_put(isp, false);
 
 	media_entity_enum_cleanup(&isp->crashed);
-	v4l2_async_nf_cleanup(&isp->notifier);
 
 	kfree(isp);
 
@@ -2290,13 +2290,8 @@ static int isp_probe(struct platform_device *pdev)
 
 	mutex_init(&isp->isp_mutex);
 	spin_lock_init(&isp->stat_lock);
-	v4l2_async_nf_init(&isp->notifier);
 	isp->dev = &pdev->dev;
 
-	ret = isp_parse_of_endpoints(isp);
-	if (ret < 0)
-		goto error;
-
 	isp->ref_count = 0;
 
 	ret = dma_coerce_mask_and_coherent(isp->dev, DMA_BIT_MASK(32));
@@ -2428,6 +2423,12 @@ static int isp_probe(struct platform_device *pdev)
 
 	isp->notifier.ops = &isp_subdev_notifier_ops;
 
+	v4l2_async_nf_init(&isp->notifier);
+
+	ret = isp_parse_of_endpoints(isp);
+	if (ret < 0)
+		goto error_register_entities;
+
 	ret = v4l2_async_nf_register(&isp->v4l2_dev, &isp->notifier);
 	if (ret)
 		goto error_register_entities;
@@ -2438,6 +2439,7 @@ static int isp_probe(struct platform_device *pdev)
 	return 0;
 
 error_register_entities:
+	v4l2_async_nf_cleanup(&isp->notifier);
 	isp_unregister_entities(isp);
 error_modules:
 	isp_cleanup_modules(isp);
@@ -2447,7 +2449,6 @@ static int isp_probe(struct platform_device *pdev)
 	isp_xclk_cleanup(isp);
 	__omap3isp_put(isp, false);
 error:
-	v4l2_async_nf_cleanup(&isp->notifier);
 	mutex_destroy(&isp->isp_mutex);
 error_release_isp:
 	kfree(isp);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 14/18] media: xilinx-vipp: Init async notifier after registering V4L2 device
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (12 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 13/18] media: omap3isp: Initialise V4L2 async notifier later Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-25  0:31   ` Laurent Pinchart
  2023-03-30 11:58 ` [PATCH 15/18] media: davinci: " Sakari Ailus
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Initialise the V4L2 async notifier after registering the V4L2 device, just
before parsing DT for async sub-devices. This way struct device is
available to the notifier right from the beginning.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/platform/xilinx/xilinx-vipp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index 70e7a1f6ed3b..83430633ed28 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -516,6 +516,8 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
 		goto done;
 	}
 
+	v4l2_async_nf_init(&xdev->notifier);
+
 	/* Parse the graph to extract a list of subdevice DT nodes. */
 	ret = xvip_graph_parse(xdev);
 	if (ret < 0) {
@@ -596,7 +598,6 @@ static int xvip_composite_probe(struct platform_device *pdev)
 
 	xdev->dev = &pdev->dev;
 	INIT_LIST_HEAD(&xdev->dmas);
-	v4l2_async_nf_init(&xdev->notifier);
 
 	ret = xvip_composite_v4l2_init(xdev);
 	if (ret < 0)
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 15/18] media: davinci: Init async notifier after registering V4L2 device
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (13 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 14/18] media: xilinx-vipp: Init async notifier after registering V4L2 device Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-03-30 11:58 ` [PATCH 16/18] media: qcom: Initialise V4L2 async notifier later Sakari Ailus
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Initialise the V4L2 async notifier after registering the V4L2 device, just
before parsing DT for async sub-devices. This way struct device is
available to the notifier right from the beginning.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 .../media/platform/ti/davinci/vpif_capture.c    | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c
index 2bbd7017f67c..728865ad44b7 100644
--- a/drivers/media/platform/ti/davinci/vpif_capture.c
+++ b/drivers/media/platform/ti/davinci/vpif_capture.c
@@ -1608,18 +1608,12 @@ static __init int vpif_probe(struct platform_device *pdev)
 	int res_idx = 0;
 	int i, err;
 
-	pdev->dev.platform_data = vpif_capture_get_pdata(pdev);
-	if (!pdev->dev.platform_data) {
-		dev_warn(&pdev->dev, "Missing platform data.  Giving up.\n");
-		return -EINVAL;
-	}
-
 	vpif_dev = &pdev->dev;
 
 	err = initialize_vpif();
 	if (err) {
 		v4l2_err(vpif_dev->driver, "Error initializing vpif\n");
-		goto cleanup;
+		return err;
 	}
 
 	err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
@@ -1655,6 +1649,12 @@ static __init int vpif_probe(struct platform_device *pdev)
 		goto vpif_unregister;
 	}
 
+	pdev->dev.platform_data = vpif_capture_get_pdata(pdev);
+	if (!pdev->dev.platform_data) {
+		dev_warn(&pdev->dev, "Missing platform data.  Giving up.\n");
+		goto probe_subdev_out;
+	}
+
 	if (!vpif_obj.config->asd_sizes[0]) {
 		int i2c_id = vpif_obj.config->i2c_adapter_id;
 
@@ -1695,14 +1695,13 @@ static __init int vpif_probe(struct platform_device *pdev)
 	return 0;
 
 probe_subdev_out:
+	v4l2_async_nf_cleanup(&vpif_obj.notifier);
 	/* free sub devices memory */
 	kfree(vpif_obj.sd);
 vpif_unregister:
 	v4l2_device_unregister(&vpif_obj.v4l2_dev);
 vpif_free:
 	free_vpif_objs();
-cleanup:
-	v4l2_async_nf_cleanup(&vpif_obj.notifier);
 
 	return err;
 }
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 16/18] media: qcom: Initialise V4L2 async notifier later
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (14 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 15/18] media: davinci: " Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-03-30 11:58 ` [PATCH 17/18] media: v4l: async: Set v4l2_device in async notifier init Sakari Ailus
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Initialise V4L2 async notifier and parse DT for async sub-devices later,
just before registering the notifier. This way the V4L2 device has been
registered before initialising the notifier.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/platform/qcom/camss/camss.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index ae13ae455b52..e33db37c3eb7 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -1615,14 +1615,6 @@ static int camss_probe(struct platform_device *pdev)
 	if (!camss->vfe)
 		return -ENOMEM;
 
-	v4l2_async_nf_init(&camss->notifier);
-
-	num_subdevs = camss_of_parse_ports(camss);
-	if (num_subdevs < 0) {
-		ret = num_subdevs;
-		goto err_cleanup;
-	}
-
 	ret = camss_icc_get(camss);
 	if (ret < 0)
 		goto err_cleanup;
@@ -1648,9 +1640,17 @@ static int camss_probe(struct platform_device *pdev)
 		goto err_cleanup;
 	}
 
+	v4l2_async_nf_init(&camss->notifier);
+
+	num_subdevs = camss_of_parse_ports(camss);
+	if (num_subdevs < 0) {
+		ret = num_subdevs;
+		goto err_cleanup;
+	}
+
 	ret = camss_register_entities(camss);
 	if (ret < 0)
-		goto err_register_entities;
+		goto err_cleanup;
 
 	if (num_subdevs) {
 		camss->notifier.ops = &camss_subdev_notifier_ops;
@@ -1691,9 +1691,8 @@ static int camss_probe(struct platform_device *pdev)
 
 err_register_subdevs:
 	camss_unregister_entities(camss);
-err_register_entities:
-	v4l2_device_unregister(&camss->v4l2_dev);
 err_cleanup:
+	v4l2_device_unregister(&camss->v4l2_dev);
 	v4l2_async_nf_cleanup(&camss->notifier);
 
 	return ret;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 17/18] media: v4l: async: Set v4l2_device in async notifier init
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (15 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 16/18] media: qcom: Initialise V4L2 async notifier later Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-25  0:35   ` Laurent Pinchart
  2023-03-30 11:58 ` [PATCH 18/18] Documentation: media: Document sub-device notifiers Sakari Ailus
  2023-04-14  9:14 ` [PATCH 19/18] media: v4l: Drop v4l2_async_nf_parse_fwnode_endpoints() Jacopo Mondi
  18 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Set the v4l2_device already in async notifier init, so struct device
related to it will be available before the notifier is registered.

This patch has been mostly generated using the following command:

git grep -l v4l2_async_nf_init -- drivers/media/ drivers/staging/media/ |
	while read i; do perl -e '
	@a=<>; unlink("'$i'"); open(F, "> '$i'");
	for $f ({i=>"v4l2_async_nf_init", r=>"v4l2_async_nf_register"},
		{i=>"v4l2_async_subdev_nf_init",
		 r=>"v4l2_async_subdev_nf_register"} ) {
	my $b; @a = map { $b = "$1, $2" if
	s/$f->{r}\(([^,]*),\s*([^\)]*)\)/v4l2_async_nf_register\($2\)/;
	$_; } @a; @a = map { if (defined $b) {
	s/v4l2_async_nf_init\([^\)]*\)/$f->{i}\($b\)/;
	s/$f->{r}\(\K[^,]*,\s*//; }; $_; } @a; }; print F @a; close F;'
	< $i; done

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/i2c/max9286.c                   |  4 +-
 drivers/media/i2c/st-mipid02.c                |  4 +-
 drivers/media/i2c/tc358746.c                  |  4 +-
 drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  4 +-
 drivers/media/platform/atmel/atmel-isi.c      |  4 +-
 drivers/media/platform/cadence/cdns-csi2rx.c  |  4 +-
 drivers/media/platform/intel/pxa_camera.c     |  4 +-
 drivers/media/platform/marvell/cafe-driver.c  |  2 +-
 drivers/media/platform/marvell/mcam-core.c    |  2 +-
 drivers/media/platform/marvell/mmp-driver.c   |  2 +-
 .../platform/microchip/microchip-csi2dc.c     |  5 +--
 .../microchip/microchip-sama5d2-isc.c         |  5 +--
 .../microchip/microchip-sama7g5-isc.c         |  5 +--
 drivers/media/platform/nxp/imx-mipi-csis.c    |  4 +-
 drivers/media/platform/nxp/imx7-media-csi.c   |  4 +-
 drivers/media/platform/qcom/camss/camss.c     |  5 +--
 drivers/media/platform/renesas/rcar-isp.c     |  4 +-
 .../platform/renesas/rcar-vin/rcar-core.c     |  8 ++--
 .../platform/renesas/rcar-vin/rcar-csi2.c     |  4 +-
 drivers/media/platform/renesas/rcar_drif.c    |  4 +-
 drivers/media/platform/renesas/renesas-ceu.c  |  4 +-
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  4 +-
 .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   |  4 +-
 .../platform/rockchip/rkisp1/rkisp1-dev.c     |  4 +-
 .../platform/samsung/exynos4-is/media-dev.c   |  5 +--
 drivers/media/platform/st/stm32/stm32-dcmi.c  |  4 +-
 .../platform/sunxi/sun4i-csi/sun4i_csi.c      |  4 +-
 .../sunxi/sun6i-csi/sun6i_csi_bridge.c        |  6 +--
 .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c   |  4 +-
 .../sun8i_a83t_mipi_csi2.c                    |  4 +-
 .../media/platform/ti/am437x/am437x-vpfe.c    |  4 +-
 drivers/media/platform/ti/cal/cal.c           |  4 +-
 .../media/platform/ti/davinci/vpif_capture.c  | 11 ++---
 drivers/media/platform/ti/omap3isp/isp.c      |  4 +-
 drivers/media/platform/video-mux.c            |  4 +-
 drivers/media/platform/xilinx/xilinx-vipp.c   |  4 +-
 drivers/media/v4l2-core/v4l2-async.c          | 43 +++++++------------
 drivers/media/v4l2-core/v4l2-fwnode.c         |  4 +-
 .../deprecated/atmel/atmel-sama5d2-isc.c      |  5 +--
 drivers/staging/media/imx/imx-media-csi.c     |  4 +-
 .../staging/media/imx/imx-media-dev-common.c  |  4 +-
 drivers/staging/media/imx/imx6-mipi-csi2.c    |  4 +-
 drivers/staging/media/imx/imx8mq-mipi-csi2.c  |  4 +-
 .../media/sunxi/sun6i-isp/sun6i_isp_proc.c    |  4 +-
 drivers/staging/media/tegra-video/vi.c        |  4 +-
 include/media/v4l2-async.h                    | 35 +++++++++------
 46 files changed, 129 insertions(+), 138 deletions(-)

diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 13cb2537a06d..43e1399a3ed1 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -746,7 +746,7 @@ static int max9286_v4l2_notifier_register(struct max9286_priv *priv)
 	if (!priv->nsources)
 		return 0;
 
-	v4l2_async_nf_init(&priv->notifier);
+	v4l2_async_subdev_nf_init(&priv->sd, &priv->notifier);
 
 	for_each_source(priv, source) {
 		unsigned int i = to_index(priv, source);
@@ -766,7 +766,7 @@ static int max9286_v4l2_notifier_register(struct max9286_priv *priv)
 
 	priv->notifier.ops = &max9286_notify_ops;
 
-	ret = v4l2_async_subdev_nf_register(&priv->sd, &priv->notifier);
+	ret = v4l2_async_nf_register(&priv->notifier);
 	if (ret) {
 		dev_err(dev, "Failed to register subdev_notifier");
 		v4l2_async_nf_cleanup(&priv->notifier);
diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c
index daea4cb29ec8..ea00fb813855 100644
--- a/drivers/media/i2c/st-mipid02.c
+++ b/drivers/media/i2c/st-mipid02.c
@@ -902,7 +902,7 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge)
 	bridge->rx = ep;
 
 	/* register async notifier so we get noticed when sensor is connected */
-	v4l2_async_nf_init(&bridge->notifier);
+	v4l2_async_subdev_nf_init(&bridge->sd, &bridge->notifier);
 	asd = v4l2_async_nf_add_fwnode_remote(&bridge->notifier,
 					      of_fwnode_handle(ep_node),
 					      struct v4l2_async_connection);
@@ -915,7 +915,7 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge)
 	}
 	bridge->notifier.ops = &mipid02_notifier_ops;
 
-	ret = v4l2_async_subdev_nf_register(&bridge->sd, &bridge->notifier);
+	ret = v4l2_async_nf_register(&bridge->notifier);
 	if (ret)
 		v4l2_async_nf_cleanup(&bridge->notifier);
 
diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
index f1f747f12228..0fbb46c2962f 100644
--- a/drivers/media/i2c/tc358746.c
+++ b/drivers/media/i2c/tc358746.c
@@ -1460,7 +1460,7 @@ static int tc358746_async_register(struct tc358746 *tc358746)
 		return err;
 	}
 
-	v4l2_async_nf_init(&tc358746->notifier);
+	v4l2_async_subdev_nf_init(&tc358746->sd, &tc358746->notifier);
 	asd = v4l2_async_nf_add_fwnode_remote(&tc358746->notifier, ep,
 					      struct v4l2_async_connection);
 	fwnode_handle_put(ep);
@@ -1472,7 +1472,7 @@ static int tc358746_async_register(struct tc358746 *tc358746)
 
 	tc358746->notifier.ops = &tc358746_notify_ops;
 
-	err = v4l2_async_subdev_nf_register(&tc358746->sd, &tc358746->notifier);
+	err = v4l2_async_nf_register(&tc358746->notifier);
 	if (err)
 		goto err_cleanup;
 
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
index b70db7e20acb..fa53d0835c89 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
@@ -1501,7 +1501,7 @@ static int cio2_parse_firmware(struct cio2_device *cio2)
 	 * suspend.
 	 */
 	cio2->notifier.ops = &cio2_async_ops;
-	ret = v4l2_async_nf_register(&cio2->v4l2_dev, &cio2->notifier);
+	ret = v4l2_async_nf_register(&cio2->notifier);
 	if (ret)
 		dev_err(dev, "failed to register async notifier : %d\n", ret);
 
@@ -1796,7 +1796,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,
 	if (r)
 		goto fail_v4l2_device_unregister;
 
-	v4l2_async_nf_init(&cio2->notifier);
+	v4l2_async_nf_init(&cio2->v4l2_dev, &cio2->notifier);
 
 	/* Register notifier for subdevices we care */
 	r = cio2_parse_firmware(cio2);
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index 2da5918bbff0..4125ab31c825 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -1159,7 +1159,7 @@ static int isi_graph_init(struct atmel_isi *isi)
 	if (!ep)
 		return -EINVAL;
 
-	v4l2_async_nf_init(&isi->notifier);
+	v4l2_async_nf_init(&isi->v4l2_dev, &isi->notifier);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&isi->notifier,
 					      of_fwnode_handle(ep),
@@ -1171,7 +1171,7 @@ static int isi_graph_init(struct atmel_isi *isi)
 
 	isi->notifier.ops = &isi_graph_notify_ops;
 
-	ret = v4l2_async_nf_register(&isi->v4l2_dev, &isi->notifier);
+	ret = v4l2_async_nf_register(&isi->notifier);
 	if (ret < 0) {
 		dev_err(isi->dev, "Notifier registration failed\n");
 		v4l2_async_nf_cleanup(&isi->notifier);
diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
index 790a27205f5d..e3a3e87a02ab 100644
--- a/drivers/media/platform/cadence/cdns-csi2rx.c
+++ b/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -399,7 +399,7 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
 		return -EINVAL;
 	}
 
-	v4l2_async_nf_init(&csi2rx->notifier);
+	v4l2_async_subdev_nf_init(&csi2rx->subdev, &csi2rx->notifier);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&csi2rx->notifier, fwh,
 					      struct v4l2_async_connection);
@@ -409,7 +409,7 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
 
 	csi2rx->notifier.ops = &csi2rx_notifier_ops;
 
-	ret = v4l2_async_subdev_nf_register(&csi2rx->subdev, &csi2rx->notifier);
+	ret = v4l2_async_nf_register(&csi2rx->notifier);
 	if (ret)
 		v4l2_async_nf_cleanup(&csi2rx->notifier);
 
diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c
index 31ae220ee4f3..6972d426fd78 100644
--- a/drivers/media/platform/intel/pxa_camera.c
+++ b/drivers/media/platform/intel/pxa_camera.c
@@ -2293,7 +2293,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
 	if (err)
 		return err;
 
-	v4l2_async_nf_init(&pcdev->notifier);
+	v4l2_async_nf_init(&pcdev->v4l2_dev, &pcdev->notifier);
 	pcdev->res = res;
 	pcdev->pdata = pdev->dev.platform_data;
 	if (pcdev->pdata) {
@@ -2405,7 +2405,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
 		goto exit_deactivate;
 
 	pcdev->notifier.ops = &pxa_camera_sensor_ops;
-	err = v4l2_async_nf_register(&pcdev->v4l2_dev, &pcdev->notifier);
+	err = v4l2_async_nf_register(&pcdev->notifier);
 	if (err)
 		goto exit_deactivate;
 
diff --git a/drivers/media/platform/marvell/cafe-driver.c b/drivers/media/platform/marvell/cafe-driver.c
index 4d8843623255..bfb091295291 100644
--- a/drivers/media/platform/marvell/cafe-driver.c
+++ b/drivers/media/platform/marvell/cafe-driver.c
@@ -541,7 +541,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
 		goto out_smbus_shutdown;
 
 
-	v4l2_async_nf_init(&mcam->notifier);
+	v4l2_async_nf_init(&mcam->v4l2_dev, &mcam->notifier);
 
 	asd = v4l2_async_nf_add_i2c(&mcam->notifier,
 				    i2c_adapter_id(cam->i2c_adapter),
diff --git a/drivers/media/platform/marvell/mcam-core.c b/drivers/media/platform/marvell/mcam-core.c
index 2ecdcbcb37fd..6ed09d606cea 100644
--- a/drivers/media/platform/marvell/mcam-core.c
+++ b/drivers/media/platform/marvell/mcam-core.c
@@ -1873,7 +1873,7 @@ int mccic_register(struct mcam_camera *cam)
 	cam->mbus_code = mcam_def_mbus_code;
 
 	cam->notifier.ops = &mccic_notify_ops;
-	ret = v4l2_async_nf_register(&cam->v4l2_dev, &cam->notifier);
+	ret = v4l2_async_nf_register(&cam->notifier);
 	if (ret < 0) {
 		cam_warn(cam, "failed to register a sensor notifier");
 		goto out;
diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c
index 36f58ea830f3..c3f3b784ae3c 100644
--- a/drivers/media/platform/marvell/mmp-driver.c
+++ b/drivers/media/platform/marvell/mmp-driver.c
@@ -239,7 +239,7 @@ static int mmpcam_probe(struct platform_device *pdev)
 	if (!ep)
 		return -ENODEV;
 
-	v4l2_async_nf_init(&mcam->notifier);
+	v4l2_async_nf_init(&mcam->v4l2_dev, &mcam->notifier);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&mcam->notifier, ep,
 					      struct v4l2_async_connection);
diff --git a/drivers/media/platform/microchip/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c
index c2b7f50520cd..2952dd6f18ca 100644
--- a/drivers/media/platform/microchip/microchip-csi2dc.c
+++ b/drivers/media/platform/microchip/microchip-csi2dc.c
@@ -523,7 +523,7 @@ static int csi2dc_prepare_notifier(struct csi2dc_device *csi2dc,
 	struct v4l2_async_connection *asd;
 	int ret = 0;
 
-	v4l2_async_nf_init(&csi2dc->notifier);
+	v4l2_async_subdev_nf_init(&csi2dc->csi2dc_sd, &csi2dc->notifier);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&csi2dc->notifier,
 					      input_fwnode,
@@ -542,8 +542,7 @@ static int csi2dc_prepare_notifier(struct csi2dc_device *csi2dc,
 
 	csi2dc->notifier.ops = &csi2dc_async_ops;
 
-	ret = v4l2_async_subdev_nf_register(&csi2dc->csi2dc_sd,
-					    &csi2dc->notifier);
+	ret = v4l2_async_nf_register(&csi2dc->notifier);
 	if (ret) {
 		dev_err(csi2dc->dev, "fail to register async notifier: %d\n",
 			ret);
diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
index 4c341908d69d..f57f32d46211 100644
--- a/drivers/media/platform/microchip/microchip-sama5d2-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
@@ -529,7 +529,7 @@ static int microchip_isc_probe(struct platform_device *pdev)
 		struct fwnode_handle *fwnode =
 			of_fwnode_handle(subdev_entity->epn);
 
-		v4l2_async_nf_init(&subdev_entity->notifier);
+		v4l2_async_nf_init(&isc->v4l2_dev, &subdev_entity->notifier);
 
 		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
 						      fwnode,
@@ -545,8 +545,7 @@ static int microchip_isc_probe(struct platform_device *pdev)
 
 		subdev_entity->notifier.ops = &microchip_isc_async_ops;
 
-		ret = v4l2_async_nf_register(&isc->v4l2_dev,
-					     &subdev_entity->notifier);
+		ret = v4l2_async_nf_register(&subdev_entity->notifier);
 		if (ret) {
 			dev_err(dev, "fail to register async notifier\n");
 			goto cleanup_subdev;
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 44e7818f2e5d..2ea61b85ba5c 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -519,7 +519,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
 		struct fwnode_handle *fwnode =
 			of_fwnode_handle(subdev_entity->epn);
 
-		v4l2_async_nf_init(&subdev_entity->notifier);
+		v4l2_async_nf_init(&isc->v4l2_dev, &subdev_entity->notifier);
 
 		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
 						      fwnode,
@@ -535,8 +535,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
 
 		subdev_entity->notifier.ops = &microchip_isc_async_ops;
 
-		ret = v4l2_async_nf_register(&isc->v4l2_dev,
-					     &subdev_entity->notifier);
+		ret = v4l2_async_nf_register(&subdev_entity->notifier);
 		if (ret) {
 			dev_err(dev, "fail to register async notifier\n");
 			goto cleanup_subdev;
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 9c5407b59e8b..e0eb89428f6d 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -1252,7 +1252,7 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
 	unsigned int i;
 	int ret;
 
-	v4l2_async_nf_init(&csis->notifier);
+	v4l2_async_subdev_nf_init(&csis->sd, &csis->notifier);
 
 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0,
 					     FWNODE_GRAPH_ENDPOINT_NEXT);
@@ -1288,7 +1288,7 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis)
 
 	csis->notifier.ops = &mipi_csis_notify_ops;
 
-	ret = v4l2_async_subdev_nf_register(&csis->sd, &csis->notifier);
+	ret = v4l2_async_nf_register(&csis->notifier);
 	if (ret)
 		return ret;
 
diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
index 0c57165c4ec1..dfaaa4dd0c94 100644
--- a/drivers/media/platform/nxp/imx7-media-csi.c
+++ b/drivers/media/platform/nxp/imx7-media-csi.c
@@ -2103,7 +2103,7 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
 	struct fwnode_handle *ep;
 	int ret;
 
-	v4l2_async_nf_init(&csi->notifier);
+	v4l2_async_nf_init(&csi->v4l2_dev, &csi->notifier);
 
 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0,
 					     FWNODE_GRAPH_ENDPOINT_NEXT);
@@ -2123,7 +2123,7 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
 
 	csi->notifier.ops = &imx7_csi_notify_ops;
 
-	ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier);
+	ret = v4l2_async_nf_register(&csi->notifier);
 	if (ret)
 		goto error;
 
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index e33db37c3eb7..20aa9c6ccec6 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -1640,7 +1640,7 @@ static int camss_probe(struct platform_device *pdev)
 		goto err_cleanup;
 	}
 
-	v4l2_async_nf_init(&camss->notifier);
+	v4l2_async_nf_init(&camss->v4l2_dev, &camss->notifier);
 
 	num_subdevs = camss_of_parse_ports(camss);
 	if (num_subdevs < 0) {
@@ -1655,8 +1655,7 @@ static int camss_probe(struct platform_device *pdev)
 	if (num_subdevs) {
 		camss->notifier.ops = &camss_subdev_notifier_ops;
 
-		ret = v4l2_async_nf_register(&camss->v4l2_dev,
-					     &camss->notifier);
+		ret = v4l2_async_nf_register(&camss->notifier);
 		if (ret) {
 			dev_err(dev,
 				"Failed to register async subdev nodes: %d\n",
diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c
index eb851c9686f8..cbf2d5ba663a 100644
--- a/drivers/media/platform/renesas/rcar-isp.c
+++ b/drivers/media/platform/renesas/rcar-isp.c
@@ -392,7 +392,7 @@ static int risp_parse_dt(struct rcar_isp *isp)
 
 	dev_dbg(isp->dev, "Found '%pOF'\n", to_of_node(fwnode));
 
-	v4l2_async_nf_init(&isp->notifier);
+	v4l2_async_subdev_nf_init(&isp->subdev, &isp->notifier);
 	isp->notifier.ops = &risp_notify_ops;
 
 	asd = v4l2_async_nf_add_fwnode(&isp->notifier, fwnode,
@@ -401,7 +401,7 @@ static int risp_parse_dt(struct rcar_isp *isp)
 	if (IS_ERR(asd))
 		return PTR_ERR(asd);
 
-	ret = v4l2_async_subdev_nf_register(&isp->subdev, &isp->notifier);
+	ret = v4l2_async_nf_register(&isp->notifier);
 	if (ret)
 		v4l2_async_nf_cleanup(&isp->notifier);
 
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
index 1d64373e7cd7..e06b6dbdd0a6 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
@@ -377,7 +377,7 @@ static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port,
 
 	mutex_unlock(&vin->group->lock);
 
-	v4l2_async_nf_init(&vin->group->notifier);
+	v4l2_async_nf_init(&vin->v4l2_dev, &vin->notifier);
 
 	/*
 	 * Some subdevices may overlap but the parser function can handle it and
@@ -401,7 +401,7 @@ static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port,
 		return 0;
 
 	vin->group->notifier.ops = &rvin_group_notify_ops;
-	ret = v4l2_async_nf_register(&vin->v4l2_dev, &vin->group->notifier);
+	ret = v4l2_async_nf_register(&vin->group->notifier);
 	if (ret < 0) {
 		vin_err(vin, "Notifier registration failed\n");
 		v4l2_async_nf_cleanup(&vin->group->notifier);
@@ -714,7 +714,7 @@ static int rvin_parallel_init(struct rvin_dev *vin)
 {
 	int ret;
 
-	v4l2_async_nf_init(&vin->notifier);
+	v4l2_async_nf_init(&vin->v4l2_dev, &vin->notifier);
 
 	ret = rvin_parallel_parse_of(vin);
 	if (ret)
@@ -727,7 +727,7 @@ static int rvin_parallel_init(struct rvin_dev *vin)
 		to_of_node(vin->parallel.asd->match.fwnode));
 
 	vin->notifier.ops = &rvin_parallel_notify_ops;
-	ret = v4l2_async_nf_register(&vin->v4l2_dev, &vin->notifier);
+	ret = v4l2_async_nf_register(&vin->notifier);
 	if (ret < 0) {
 		vin_err(vin, "Notifier registration failed\n");
 		v4l2_async_nf_cleanup(&vin->notifier);
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
index 654d56a57a00..bd556cf67838 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
@@ -1076,7 +1076,7 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv)
 
 	dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode));
 
-	v4l2_async_nf_init(&priv->notifier);
+	v4l2_async_subdev_nf_init(&priv->subdev, &priv->notifier);
 	priv->notifier.ops = &rcar_csi2_notify_ops;
 
 	asd = v4l2_async_nf_add_fwnode(&priv->notifier, fwnode,
@@ -1085,7 +1085,7 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv)
 	if (IS_ERR(asd))
 		return PTR_ERR(asd);
 
-	ret = v4l2_async_subdev_nf_register(&priv->subdev, &priv->notifier);
+	ret = v4l2_async_nf_register(&priv->notifier);
 	if (ret)
 		v4l2_async_nf_cleanup(&priv->notifier);
 
diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c
index 5c8f5a53eb4d..17e4c852df80 100644
--- a/drivers/media/platform/renesas/rcar_drif.c
+++ b/drivers/media/platform/renesas/rcar_drif.c
@@ -1207,7 +1207,7 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr)
 	struct fwnode_handle *fwnode, *ep;
 	struct v4l2_async_connection *asd;
 
-	v4l2_async_nf_init(notifier);
+	v4l2_async_nf_init(&sdr->v4l2_dev, &sdr->notifier);
 
 	ep = fwnode_graph_get_next_endpoint(of_fwnode_handle(sdr->dev->of_node),
 					    NULL);
@@ -1341,7 +1341,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr)
 	sdr->notifier.ops = &rcar_drif_notify_ops;
 
 	/* Register notifier */
-	ret = v4l2_async_nf_register(&sdr->v4l2_dev, &sdr->notifier);
+	ret = v4l2_async_nf_register(&sdr->notifier);
 	if (ret < 0) {
 		dev_err(sdr->dev, "failed: notifier register ret %d\n", ret);
 		goto cleanup;
diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c
index 8d47910a8d11..e8a8ecd5c956 100644
--- a/drivers/media/platform/renesas/renesas-ceu.c
+++ b/drivers/media/platform/renesas/renesas-ceu.c
@@ -1667,7 +1667,7 @@ static int ceu_probe(struct platform_device *pdev)
 	if (ret)
 		goto error_pm_disable;
 
-	v4l2_async_nf_init(&ceudev->notifier);
+	v4l2_async_nf_init(&ceudev->v4l2_dev, &ceudev->notifier);
 
 	if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
 		ceu_data = of_device_get_match_data(dev);
@@ -1689,7 +1689,7 @@ static int ceu_probe(struct platform_device *pdev)
 
 	ceudev->notifier.v4l2_dev	= &ceudev->v4l2_dev;
 	ceudev->notifier.ops		= &ceu_notify_ops;
-	ret = v4l2_async_nf_register(&ceudev->v4l2_dev, &ceudev->notifier);
+	ret = v4l2_async_nf_register(&ceudev->notifier);
 	if (ret)
 		goto error_cleanup;
 
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 4abf9f1e88dc..7c6abb162e68 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -183,7 +183,7 @@ static int rzg2l_cru_mc_parse_of_graph(struct rzg2l_cru_dev *cru)
 {
 	int ret;
 
-	v4l2_async_nf_init(&cru->notifier);
+	v4l2_async_nf_init(&cru->v4l2_dev, &cru->notifier);
 
 	ret = rzg2l_cru_mc_parse_of(cru);
 	if (ret)
@@ -194,7 +194,7 @@ static int rzg2l_cru_mc_parse_of_graph(struct rzg2l_cru_dev *cru)
 	if (list_empty(&cru->notifier.asc_head))
 		return 0;
 
-	ret = v4l2_async_nf_register(&cru->v4l2_dev, &cru->notifier);
+	ret = v4l2_async_nf_register(&cru->notifier);
 	if (ret < 0) {
 		dev_err(cru->dev, "Notifier registration failed\n");
 		v4l2_async_nf_cleanup(&cru->notifier);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 5aa3b0239ead..1863162d7c8d 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -674,7 +674,7 @@ static int rzg2l_csi2_parse_dt(struct rzg2l_csi2 *csi2)
 	fwnode = fwnode_graph_get_remote_endpoint(ep);
 	fwnode_handle_put(ep);
 
-	v4l2_async_nf_init(&csi2->notifier);
+	v4l2_async_subdev_nf_init(&csi2->subdev, &csi2->notifier);
 	csi2->notifier.ops = &rzg2l_csi2_notify_ops;
 
 	asd = v4l2_async_nf_add_fwnode(&csi2->notifier, fwnode,
@@ -683,7 +683,7 @@ static int rzg2l_csi2_parse_dt(struct rzg2l_csi2 *csi2)
 	if (IS_ERR(asd))
 		return PTR_ERR(asd);
 
-	ret = v4l2_async_subdev_nf_register(&csi2->subdev, &csi2->notifier);
+	ret = v4l2_async_nf_register(&csi2->notifier);
 	if (ret)
 		v4l2_async_nf_cleanup(&csi2->notifier);
 
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
index 5bdb1ecedf6a..0c716839e03a 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
@@ -187,7 +187,7 @@ static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
 	unsigned int index = 0;
 	int ret = 0;
 
-	v4l2_async_nf_init(ntf);
+	v4l2_async_nf_init(&rkisp1->v4l2_dev, ntf);
 
 	ntf->ops = &rkisp1_subdev_notifier_ops;
 
@@ -287,7 +287,7 @@ static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
 	if (!index)
 		dev_dbg(rkisp1->dev, "no remote subdevice found\n");
 
-	ret = v4l2_async_nf_register(&rkisp1->v4l2_dev, ntf);
+	ret = v4l2_async_nf_register(ntf);
 	if (ret) {
 		v4l2_async_nf_cleanup(ntf);
 		return ret;
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c
index 8c9dad6231a6..5974c2d31ad6 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.c
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c
@@ -1477,7 +1477,7 @@ static int fimc_md_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, fmd);
 
-	v4l2_async_nf_init(&fmd->subdev_notifier);
+	v4l2_async_nf_init(&fmd->v4l2_dev, &fmd->subdev_notifier);
 
 	ret = fimc_md_register_platform_entities(fmd, dev->of_node);
 	if (ret)
@@ -1505,8 +1505,7 @@ static int fimc_md_probe(struct platform_device *pdev)
 		fmd->subdev_notifier.ops = &subdev_notifier_ops;
 		fmd->num_sensors = 0;
 
-		ret = v4l2_async_nf_register(&fmd->v4l2_dev,
-					     &fmd->subdev_notifier);
+		ret = v4l2_async_nf_register(&fmd->subdev_notifier);
 		if (ret)
 			goto err_clk_p;
 	}
diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index cf03c9529749..c26189584eb0 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -1897,7 +1897,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
 		return -EINVAL;
 	}
 
-	v4l2_async_nf_init(&dcmi->notifier);
+	v4l2_async_nf_init(&dcmi->v4l2_dev, &dcmi->notifier);
 
 	asd = v4l2_async_nf_add_fwnode_remote(&dcmi->notifier,
 					      of_fwnode_handle(ep),
@@ -1912,7 +1912,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
 
 	dcmi->notifier.ops = &dcmi_graph_notify_ops;
 
-	ret = v4l2_async_nf_register(&dcmi->v4l2_dev, &dcmi->notifier);
+	ret = v4l2_async_nf_register(&dcmi->notifier);
 	if (ret < 0) {
 		dev_err(dcmi->dev, "Failed to register notifier\n");
 		v4l2_async_nf_cleanup(&dcmi->notifier);
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
index 1a550713ecfb..2dce2198c20e 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -122,7 +122,7 @@ static int sun4i_csi_notifier_init(struct sun4i_csi *csi)
 	struct fwnode_handle *ep;
 	int ret;
 
-	v4l2_async_nf_init(&csi->notifier);
+	v4l2_async_nf_init(&csi->v4l, &csi->notifier);
 
 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0,
 					     FWNODE_GRAPH_ENDPOINT_NEXT);
@@ -240,7 +240,7 @@ static int sun4i_csi_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_unregister_media;
 
-	ret = v4l2_async_nf_register(&csi->v4l, &csi->notifier);
+	ret = v4l2_async_nf_register(&csi->notifier);
 	if (ret) {
 		dev_err(csi->dev, "Couldn't register our notifier.\n");
 		goto err_unregister_media;
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
index ebb725fc11ba..8fa768ab5334 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
@@ -819,7 +819,7 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev)
 
 	/* V4L2 Async */
 
-	v4l2_async_nf_init(notifier);
+	v4l2_async_subdev_nf_init(subdev, notifier);
 	notifier->ops = &sun6i_csi_bridge_notifier_ops;
 
 	sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_parallel,
@@ -829,9 +829,9 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev)
 				      SUN6I_CSI_PORT_MIPI_CSI2, NULL);
 
 	if (csi_dev->isp_available)
-		ret = v4l2_async_subdev_nf_register(subdev, notifier);
+		ret = v4l2_async_nf_register(notifier);
 	else
-		ret = v4l2_async_nf_register(v4l2_dev, notifier);
+		ret = v4l2_async_nf_register(notifier);
 	if (ret) {
 		dev_err(dev, "failed to register v4l2 async notifier: %d\n",
 			ret);
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
index f2746f77aad0..b0c7498557f4 100644
--- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
@@ -531,7 +531,7 @@ static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev)
 
 	/* V4L2 Async */
 
-	v4l2_async_nf_init(notifier);
+	v4l2_async_subdev_nf_init(subdev, notifier);
 	notifier->ops = &sun6i_mipi_csi2_notifier_ops;
 
 	ret = sun6i_mipi_csi2_bridge_source_setup(csi2_dev);
@@ -540,7 +540,7 @@ static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev)
 
 	/* Only register the notifier when a sensor is connected. */
 	if (ret != -ENODEV) {
-		ret = v4l2_async_subdev_nf_register(subdev, notifier);
+		ret = v4l2_async_nf_register(notifier);
 		if (ret < 0)
 			goto error_v4l2_notifier_cleanup;
 
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
index e7f45673ed82..5c79fc8b097b 100644
--- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
@@ -569,7 +569,7 @@ sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
 
 	/* V4L2 Async */
 
-	v4l2_async_nf_init(notifier);
+	v4l2_async_subdev_nf_init(subdev, notifier);
 	notifier->ops = &sun8i_a83t_mipi_csi2_notifier_ops;
 
 	ret = sun8i_a83t_mipi_csi2_bridge_source_setup(csi2_dev);
@@ -578,7 +578,7 @@ sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
 
 	/* Only register the notifier when a sensor is connected. */
 	if (ret != -ENODEV) {
-		ret = v4l2_async_subdev_nf_register(subdev, notifier);
+		ret = v4l2_async_nf_register(notifier);
 		if (ret < 0)
 			goto error_v4l2_notifier_cleanup;
 
diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c
index d5ba9b9c7e5a..edf81b8f7b88 100644
--- a/drivers/media/platform/ti/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c
@@ -2297,7 +2297,7 @@ vpfe_get_pdata(struct vpfe_device *vpfe)
 
 	dev_dbg(dev, "vpfe_get_pdata\n");
 
-	v4l2_async_nf_init(&vpfe->notifier);
+	v4l2_async_nf_init(&vpfe->v4l2_dev, &vpfe->notifier);
 
 	if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
 		return dev->platform_data;
@@ -2464,7 +2464,7 @@ static int vpfe_probe(struct platform_device *pdev)
 	}
 
 	vpfe->notifier.ops = &vpfe_async_ops;
-	ret = v4l2_async_nf_register(&vpfe->v4l2_dev, &vpfe->notifier);
+	ret = v4l2_async_nf_register(&vpfe->notifier);
 	if (ret) {
 		vpfe_err(vpfe, "Error registering async notifier\n");
 		ret = -EINVAL;
diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c
index 37906c23237e..579337a8d543 100644
--- a/drivers/media/platform/ti/cal/cal.c
+++ b/drivers/media/platform/ti/cal/cal.c
@@ -895,7 +895,7 @@ static int cal_async_notifier_register(struct cal_dev *cal)
 	unsigned int i;
 	int ret;
 
-	v4l2_async_nf_init(&cal->notifier);
+	v4l2_async_nf_init(&cal->v4l2_dev, &cal->notifier);
 	cal->notifier.ops = &cal_async_notifier_ops;
 
 	for (i = 0; i < cal->data->num_csi2_phy; ++i) {
@@ -919,7 +919,7 @@ static int cal_async_notifier_register(struct cal_dev *cal)
 		casd->phy = phy;
 	}
 
-	ret = v4l2_async_nf_register(&cal->v4l2_dev, &cal->notifier);
+	ret = v4l2_async_nf_register(&cal->notifier);
 	if (ret) {
 		cal_err(cal, "Error registering async notifier\n");
 		goto error;
diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c
index 728865ad44b7..c145797d6442 100644
--- a/drivers/media/platform/ti/davinci/vpif_capture.c
+++ b/drivers/media/platform/ti/davinci/vpif_capture.c
@@ -1483,7 +1483,8 @@ static const struct v4l2_async_notifier_operations vpif_async_ops = {
 };
 
 static struct vpif_capture_config *
-vpif_capture_get_pdata(struct platform_device *pdev)
+vpif_capture_get_pdata(struct platform_device *pdev,
+		       struct v4l2_device *v4l2_dev)
 {
 	struct device_node *endpoint = NULL;
 	struct device_node *rem = NULL;
@@ -1492,7 +1493,7 @@ vpif_capture_get_pdata(struct platform_device *pdev)
 	struct vpif_capture_chan_config *chan;
 	unsigned int i;
 
-	v4l2_async_nf_init(&vpif_obj.notifier);
+	v4l2_async_nf_init(v4l2_dev, &vpif_obj.notifier);
 
 	/*
 	 * DT boot: OF node from parent device contains
@@ -1649,7 +1650,8 @@ static __init int vpif_probe(struct platform_device *pdev)
 		goto vpif_unregister;
 	}
 
-	pdev->dev.platform_data = vpif_capture_get_pdata(pdev);
+	pdev->dev.platform_data =
+		vpif_capture_get_pdata(pdev, &vpif_obj.v4l2_dev);
 	if (!pdev->dev.platform_data) {
 		dev_warn(&pdev->dev, "Missing platform data.  Giving up.\n");
 		goto probe_subdev_out;
@@ -1683,8 +1685,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 			goto probe_subdev_out;
 	} else {
 		vpif_obj.notifier.ops = &vpif_async_ops;
-		err = v4l2_async_nf_register(&vpif_obj.v4l2_dev,
-					     &vpif_obj.notifier);
+		err = v4l2_async_nf_register(&vpif_obj.notifier);
 		if (err) {
 			vpif_err("Error registering async notifier\n");
 			err = -EINVAL;
diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c
index 7ccc18acb429..c162577441c1 100644
--- a/drivers/media/platform/ti/omap3isp/isp.c
+++ b/drivers/media/platform/ti/omap3isp/isp.c
@@ -2423,13 +2423,13 @@ static int isp_probe(struct platform_device *pdev)
 
 	isp->notifier.ops = &isp_subdev_notifier_ops;
 
-	v4l2_async_nf_init(&isp->notifier);
+	v4l2_async_nf_init(&isp->v4l2_dev, &isp->notifier);
 
 	ret = isp_parse_of_endpoints(isp);
 	if (ret < 0)
 		goto error_register_entities;
 
-	ret = v4l2_async_nf_register(&isp->v4l2_dev, &isp->notifier);
+	ret = v4l2_async_nf_register(&isp->notifier);
 	if (ret)
 		goto error_register_entities;
 
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c
index 7d48fb9bc09d..98eba6d7daf4 100644
--- a/drivers/media/platform/video-mux.c
+++ b/drivers/media/platform/video-mux.c
@@ -360,7 +360,7 @@ static int video_mux_async_register(struct video_mux *vmux,
 	unsigned int i;
 	int ret;
 
-	v4l2_async_nf_init(&vmux->notifier);
+	v4l2_async_subdev_nf_init(&vmux->subdev, &vmux->notifier);
 
 	for (i = 0; i < num_input_pads; i++) {
 		struct v4l2_async_connection *asd;
@@ -395,7 +395,7 @@ static int video_mux_async_register(struct video_mux *vmux,
 
 	vmux->notifier.ops = &video_mux_notify_ops;
 
-	ret = v4l2_async_subdev_nf_register(&vmux->subdev, &vmux->notifier);
+	ret = v4l2_async_nf_register(&vmux->notifier);
 	if (ret)
 		return ret;
 
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index 83430633ed28..1bf6f7f18a3f 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -516,7 +516,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
 		goto done;
 	}
 
-	v4l2_async_nf_init(&xdev->notifier);
+	v4l2_async_nf_init(&xdev->v4l2_dev, &xdev->notifier);
 
 	/* Parse the graph to extract a list of subdevice DT nodes. */
 	ret = xvip_graph_parse(xdev);
@@ -534,7 +534,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
 	/* Register the subdevices notifier. */
 	xdev->notifier.ops = &xvip_graph_notify_ops;
 
-	ret = v4l2_async_nf_register(&xdev->v4l2_dev, &xdev->notifier);
+	ret = v4l2_async_nf_register(&xdev->notifier);
 	if (ret < 0) {
 		dev_err(xdev->dev, "notifier registration failed\n");
 		goto done;
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 4c3bd64d6a00..9e10e59af8e0 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -542,12 +542,22 @@ static int v4l2_async_nf_asc_valid(struct v4l2_async_notifier *notifier,
 	return 0;
 }
 
-void v4l2_async_nf_init(struct v4l2_async_notifier *notifier)
+void v4l2_async_nf_init(struct v4l2_device *v4l2_dev,
+			struct v4l2_async_notifier *notifier)
 {
 	INIT_LIST_HEAD(&notifier->asc_head);
+	notifier->v4l2_dev = v4l2_dev;
 }
 EXPORT_SYMBOL(v4l2_async_nf_init);
 
+void v4l2_async_subdev_nf_init(struct v4l2_subdev *sd,
+			       struct v4l2_async_notifier *notifier)
+{
+	INIT_LIST_HEAD(&notifier->asc_head);
+	notifier->sd = sd;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_subdev_nf_init);
+
 static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_async_connection *asc;
@@ -593,16 +603,13 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 	return ret;
 }
 
-int v4l2_async_nf_register(struct v4l2_device *v4l2_dev,
-			   struct v4l2_async_notifier *notifier)
+int v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
 {
 	int ret;
 
-	if (WARN_ON(!v4l2_dev || notifier->sd))
+	if (WARN_ON(!notifier->v4l2_dev == !notifier->sd))
 		return -EINVAL;
 
-	notifier->v4l2_dev = v4l2_dev;
-
 	ret = __v4l2_async_nf_register(notifier);
 	if (ret)
 		notifier->v4l2_dev = NULL;
@@ -611,24 +618,6 @@ int v4l2_async_nf_register(struct v4l2_device *v4l2_dev,
 }
 EXPORT_SYMBOL(v4l2_async_nf_register);
 
-int v4l2_async_subdev_nf_register(struct v4l2_subdev *sd,
-				  struct v4l2_async_notifier *notifier)
-{
-	int ret;
-
-	if (WARN_ON(!sd || notifier->v4l2_dev))
-		return -EINVAL;
-
-	notifier->sd = sd;
-
-	ret = __v4l2_async_nf_register(notifier);
-	if (ret)
-		notifier->sd = NULL;
-
-	return ret;
-}
-EXPORT_SYMBOL(v4l2_async_subdev_nf_register);
-
 static void
 __v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
 {
@@ -637,9 +626,6 @@ __v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
 
 	v4l2_async_nf_unbind_all_subdevs(notifier, false);
 
-	notifier->sd = NULL;
-	notifier->v4l2_dev = NULL;
-
 	list_del(&notifier->notifier_list);
 }
 
@@ -693,6 +679,9 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
 		kref_put(&asc->asd->kref, release_async_subdev);
 		kfree(asc);
 	}
+
+	notifier->sd = NULL;
+	notifier->v4l2_dev = NULL;
 }
 
 void v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index e4ba04cebc9a..a02b33f94a96 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -1300,13 +1300,13 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd)
 	if (!notifier)
 		return -ENOMEM;
 
-	v4l2_async_nf_init(notifier);
+	v4l2_async_subdev_nf_init(sd, notifier);
 
 	ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier);
 	if (ret < 0)
 		goto out_cleanup;
 
-	ret = v4l2_async_subdev_nf_register(sd, notifier);
+	ret = v4l2_async_nf_register(notifier);
 	if (ret < 0)
 		goto out_cleanup;
 
diff --git a/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c b/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c
index 0471e7796833..bbca9b34db1d 100644
--- a/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c
+++ b/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c
@@ -509,7 +509,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
 		struct fwnode_handle *fwnode =
 			of_fwnode_handle(subdev_entity->epn);
 
-		v4l2_async_nf_init(&subdev_entity->notifier);
+		v4l2_async_nf_init(&isc->v4l2_dev, &subdev_entity->notifier);
 
 		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
 						      fwnode,
@@ -525,8 +525,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
 
 		subdev_entity->notifier.ops = &atmel_isc_async_ops;
 
-		ret = v4l2_async_nf_register(&isc->v4l2_dev,
-					     &subdev_entity->notifier);
+		ret = v4l2_async_nf_register(&subdev_entity->notifier);
 		if (ret) {
 			dev_err(dev, "fail to register async notifier\n");
 			goto cleanup_subdev;
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index 6a9052790b78..304467f8a196 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -1918,7 +1918,7 @@ static int imx_csi_async_register(struct csi_priv *priv)
 	unsigned int port;
 	int ret;
 
-	v4l2_async_nf_init(&priv->notifier);
+	v4l2_async_subdev_nf_init(&priv->sd, &priv->notifier);
 
 	/* get this CSI's port id */
 	ret = fwnode_property_read_u32(dev_fwnode(priv->dev), "reg", &port);
@@ -1944,7 +1944,7 @@ static int imx_csi_async_register(struct csi_priv *priv)
 
 	priv->notifier.ops = &csi_notify_ops;
 
-	ret = v4l2_async_subdev_nf_register(&priv->sd, &priv->notifier);
+	ret = v4l2_async_nf_register(&priv->notifier);
 	if (ret)
 		return ret;
 
diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c
index f2536016d24a..bc34c9b7f452 100644
--- a/drivers/staging/media/imx/imx-media-dev-common.c
+++ b/drivers/staging/media/imx/imx-media-dev-common.c
@@ -381,7 +381,7 @@ struct imx_media_dev *imx_media_dev_init(struct device *dev,
 
 	INIT_LIST_HEAD(&imxmd->vdev_list);
 
-	v4l2_async_nf_init(&imxmd->notifier);
+	v4l2_async_nf_init(&imxmd->v4l2_dev, &imxmd->notifier);
 
 	return imxmd;
 
@@ -405,7 +405,7 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd,
 
 	/* prepare the async subdev notifier and register it */
 	imxmd->notifier.ops = ops ? ops : &imx_media_notifier_ops;
-	ret = v4l2_async_nf_register(&imxmd->v4l2_dev, &imxmd->notifier);
+	ret = v4l2_async_nf_register(&imxmd->notifier);
 	if (ret) {
 		v4l2_err(&imxmd->v4l2_dev,
 			 "v4l2_async_nf_register failed with %d\n", ret);
diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c
index cebf42840061..db1e99c1e8b3 100644
--- a/drivers/staging/media/imx/imx6-mipi-csi2.c
+++ b/drivers/staging/media/imx/imx6-mipi-csi2.c
@@ -635,7 +635,7 @@ static int csi2_async_register(struct csi2_dev *csi2)
 	struct fwnode_handle *ep;
 	int ret;
 
-	v4l2_async_nf_init(&csi2->notifier);
+	v4l2_async_subdev_nf_init(&csi2->sd, &csi2->notifier);
 
 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi2->dev), 0, 0,
 					     FWNODE_GRAPH_ENDPOINT_NEXT);
@@ -660,7 +660,7 @@ static int csi2_async_register(struct csi2_dev *csi2)
 
 	csi2->notifier.ops = &csi2_notify_ops;
 
-	ret = v4l2_async_subdev_nf_register(&csi2->sd, &csi2->notifier);
+	ret = v4l2_async_nf_register(&csi2->notifier);
 	if (ret)
 		return ret;
 
diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c
index 05b7215493af..7c3ac47f8a0d 100644
--- a/drivers/staging/media/imx/imx8mq-mipi-csi2.c
+++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c
@@ -641,7 +641,7 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
 	unsigned int i;
 	int ret;
 
-	v4l2_async_nf_init(&state->notifier);
+	v4l2_async_subdev_nf_init(&state->sd, &state->notifier);
 
 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0,
 					     FWNODE_GRAPH_ENDPOINT_NEXT);
@@ -678,7 +678,7 @@ static int imx8mq_mipi_csi_async_register(struct csi_state *state)
 
 	state->notifier.ops = &imx8mq_mipi_csi_notify_ops;
 
-	ret = v4l2_async_subdev_nf_register(&state->sd, &state->notifier);
+	ret = v4l2_async_nf_register(&state->notifier);
 	if (ret)
 		return ret;
 
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
index dd7dfecb9ef3..77903ac066b2 100644
--- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
@@ -536,7 +536,7 @@ int sun6i_isp_proc_setup(struct sun6i_isp_device *isp_dev)
 
 	/* V4L2 Async */
 
-	v4l2_async_nf_init(notifier);
+	v4l2_async_nf_init(v4l2_dev, notifier);
 	notifier->ops = &sun6i_isp_proc_notifier_ops;
 
 	sun6i_isp_proc_source_setup(isp_dev, &proc->source_csi0,
@@ -544,7 +544,7 @@ int sun6i_isp_proc_setup(struct sun6i_isp_device *isp_dev)
 	sun6i_isp_proc_source_setup(isp_dev, &proc->source_csi1,
 				    SUN6I_ISP_PORT_CSI1);
 
-	ret = v4l2_async_nf_register(v4l2_dev, notifier);
+	ret = v4l2_async_nf_register(notifier);
 	if (ret) {
 		v4l2_err(v4l2_dev,
 			 "failed to register v4l2 async notifier: %d\n", ret);
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index eaa1e241094f..dc3c1eabf0d1 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -1278,7 +1278,7 @@ static int tegra_channel_init(struct tegra_vi_channel *chan)
 	}
 
 	if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
-		v4l2_async_nf_init(&chan->notifier);
+		v4l2_async_nf_init(&vid->v4l2_dev, &chan->notifier);
 
 	return 0;
 
@@ -1878,7 +1878,7 @@ static int tegra_vi_graph_init(struct tegra_vi *vi)
 			continue;
 
 		chan->notifier.ops = &tegra_vi_async_ops;
-		ret = v4l2_async_nf_register(&vid->v4l2_dev, &chan->notifier);
+		ret = v4l2_async_nf_register(&chan->notifier);
 		if (ret < 0) {
 			dev_err(vi->dev,
 				"failed to register channel %d notifier: %d\n",
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 750bf4ddb267..cf2082e17fc4 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -159,6 +159,24 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
 /**
  * v4l2_async_nf_init - Initialize a notifier.
  *
+ * @v4l2_dev: pointer to &struct v4l2_device
+ * @notifier: pointer to &struct v4l2_async_notifier
+ *
+ * This function initializes the notifier @asc_list. It must be called
+ * before adding a subdevice to a notifier, using one of:
+ * v4l2_async_nf_add_fwnode_remote(),
+ * v4l2_async_nf_add_fwnode(),
+ * v4l2_async_nf_add_i2c(),
+ * __v4l2_async_nf_add_connection() or
+ * v4l2_async_nf_parse_fwnode_endpoints().
+ */
+void v4l2_async_nf_init(struct v4l2_device *v4l2_dev,
+			struct v4l2_async_notifier *notifier);
+
+/**
+ * v4l2_async_subdev_nf_init - Initialize a sub-device notifier.
+ *
+ * @v4l2_dev: pointer to &struct v4l2_device
  * @notifier: pointer to &struct v4l2_async_notifier
  *
  * This function initializes the notifier @asc_list. It must be called
@@ -169,7 +187,8 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
  * __v4l2_async_nf_add_connection() or
  * v4l2_async_nf_parse_fwnode_endpoints().
  */
-void v4l2_async_nf_init(struct v4l2_async_notifier *notifier);
+void v4l2_async_subdev_nf_init(struct v4l2_subdev *sd,
+			       struct v4l2_async_notifier *notifier);
 
 /**
  * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
@@ -264,21 +283,9 @@ __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier,
 /**
  * v4l2_async_nf_register - registers a subdevice asynchronous notifier
  *
- * @v4l2_dev: pointer to &struct v4l2_device
- * @notifier: pointer to &struct v4l2_async_notifier
- */
-int v4l2_async_nf_register(struct v4l2_device *v4l2_dev,
-			   struct v4l2_async_notifier *notifier);
-
-/**
- * v4l2_async_subdev_nf_register - registers a subdevice asynchronous
- *					 notifier for a sub-device
- *
- * @sd: pointer to &struct v4l2_subdev
  * @notifier: pointer to &struct v4l2_async_notifier
  */
-int v4l2_async_subdev_nf_register(struct v4l2_subdev *sd,
-				  struct v4l2_async_notifier *notifier);
+int v4l2_async_nf_register(struct v4l2_async_notifier *notifier);
 
 /**
  * v4l2_async_nf_unregister - unregisters a subdevice
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* [PATCH 18/18] Documentation: media: Document sub-device notifiers
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (16 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 17/18] media: v4l: async: Set v4l2_device in async notifier init Sakari Ailus
@ 2023-03-30 11:58 ` Sakari Ailus
  2023-04-14  9:14 ` [PATCH 19/18] media: v4l: Drop v4l2_async_nf_parse_fwnode_endpoints() Jacopo Mondi
  18 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-03-30 11:58 UTC (permalink / raw)
  To: linux-media
  Cc: Philipp Zabel, Laurent Pinchart, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Document that sub-device notifiers are now registered using
v4l2_async_subdev_nf_init(). No documentation is changed as it seems that
sub-device notifiers were not documented apart from kernel-doc comments.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 Documentation/driver-api/media/v4l2-subdev.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst
index 1c5cb1a637ab..b034c35000f8 100644
--- a/Documentation/driver-api/media/v4l2-subdev.rst
+++ b/Documentation/driver-api/media/v4l2-subdev.rst
@@ -204,6 +204,12 @@ that the bridge device needs for its operation. Several functions are available
 to add subdevice descriptors to a notifier, depending on the type of device and
 the needs of the driver.
 
+For a sub-device driver to register a notifier, the process is otherwise similar
+to that of a bridge driver, apart from that the notifier is initialised using
+:c:func:`v4l2_async_subdev_nf_init` instead. A sub-device notifier may complete
+only after the V4L2 device becomes available, i.e. there's a path via async
+sub-devices and notifiers to that root notifier.
+
 :c:func:`v4l2_async_nf_add_fwnode_remote` and
 :c:func:`v4l2_async_nf_add_i2c` are for bridge and ISP drivers for
 registering their async sub-devices with the notifier.
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* Re: [PATCH 01/18] media: v4l: async: Return async sub-devices to subnotifier list
  2023-03-30 11:58 ` [PATCH 01/18] media: v4l: async: Return async sub-devices to subnotifier list Sakari Ailus
@ 2023-04-13 16:49   ` Jacopo Mondi
  2023-04-25  1:28   ` Laurent Pinchart
  1 sibling, 0 replies; 73+ messages in thread
From: Jacopo Mondi @ 2023-04-13 16:49 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari,

On Thu, Mar 30, 2023 at 02:58:36PM +0300, Sakari Ailus wrote:
> When an async notifier is unregistered, the async sub-devices in the
> notifier's done list will disappear with the notifier. However this is
> currently also done to the sub-notifiers that remain registered. Their
> sub-devices only need to be unbound while the async sub-devices themselves
> need to be returned to the sub-notifier's waiting list. Do this now.
>
> Fixes: 2cab00bb076b ("media: v4l: async: Allow binding notifiers to sub-devices")
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>

Thanks for clarifying my question on the RFC version
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

Thanks
  j

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 2f1b718a9189..008a2a3e312e 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -414,7 +414,8 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>
>  /* Unbind all sub-devices in the notifier tree. */
>  static void
> -v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
> +v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> +				 bool readd)
>  {
>  	struct v4l2_subdev *sd, *tmp;
>
> @@ -423,9 +424,11 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
>  			v4l2_async_find_subdev_notifier(sd);
>
>  		if (subdev_notifier)
> -			v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
> +			v4l2_async_nf_unbind_all_subdevs(subdev_notifier, true);
>
>  		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> +		if (readd)
> +			list_add_tail(&sd->asd->list, &notifier->waiting);
>  		v4l2_async_cleanup(sd);
>
>  		list_move(&sd->async_list, &subdev_list);
> @@ -557,7 +560,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
>  	/*
>  	 * On failure, unbind all sub-devices registered through this notifier.
>  	 */
> -	v4l2_async_nf_unbind_all_subdevs(notifier);
> +	v4l2_async_nf_unbind_all_subdevs(notifier, false);
>
>  err_unlock:
>  	mutex_unlock(&list_lock);
> @@ -607,7 +610,7 @@ __v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
>  	if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
>  		return;
>
> -	v4l2_async_nf_unbind_all_subdevs(notifier);
> +	v4l2_async_nf_unbind_all_subdevs(notifier, false);
>
>  	notifier->sd = NULL;
>  	notifier->v4l2_dev = NULL;
> @@ -805,7 +808,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	 */
>  	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
>  	if (subdev_notifier)
> -		v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
> +		v4l2_async_nf_unbind_all_subdevs(subdev_notifier, false);
>
>  	if (sd->asd)
>  		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> --
> 2.30.2
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 02/18] media: v4l: async: Add some debug prints
  2023-03-30 11:58 ` [PATCH 02/18] media: v4l: async: Add some debug prints Sakari Ailus
@ 2023-04-13 16:49   ` Jacopo Mondi
  2023-04-14 10:46     ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Jacopo Mondi @ 2023-04-13 16:49 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari

On Thu, Mar 30, 2023 at 02:58:37PM +0300, Sakari Ailus wrote:
> Just add some debug prints for V4L2 async sub-device matching process.
> These might come useful in figuring out why things don't work as expected.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c | 59 ++++++++++++++++++++++++----
>  1 file changed, 52 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 008a2a3e312e..6dd426c2ca68 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -75,6 +75,12 @@ static bool match_i2c(struct v4l2_async_notifier *notifier,
>  #endif
>  }
>
> +static struct device *notifier_dev(struct v4l2_async_notifier *notifier)
> +{
> +	return notifier->sd ? notifier->sd->dev : notifier->v4l2_dev ?
> +		notifier->v4l2_dev->dev : NULL;
> +}
> +
>  static bool
>  match_fwnode_one(struct v4l2_async_notifier *notifier,
>  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
> @@ -86,13 +92,18 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
>  	bool sd_fwnode_is_ep;
>  	struct device *dev;
>
> +	dev_dbg(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
> +		sd_fwnode, asd->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 == asd->match.fwnode)
> +	if (sd_fwnode == asd->match.fwnode) {
> +		dev_dbg(sd->dev, "async: direct match found\n");
>  		return true;
> +	}
>
>  	/*
>  	 * Otherwise, check if the sd fwnode and the asd fwnode refer to an
> @@ -105,8 +116,10 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
>  	sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd_fwnode);
>  	asd_fwnode_is_ep = fwnode_graph_is_endpoint(asd->match.fwnode);
>
> -	if (sd_fwnode_is_ep == asd_fwnode_is_ep)
> +	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
> +		dev_dbg(sd->dev, "async: matching node types\n");

"matching node type" is misleading as it suggests a match has been
found. As both sd and asd are of the same type, I would use a
message similar to the above

		dev_dbg(sd->dev, "async: direct match failed\n");

>  		return false;
> +	}
>
>  	/*
>  	 * The sd and asd fwnodes are of different types. Get the device fwnode
> @@ -120,10 +133,15 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
>  		other_fwnode = sd_fwnode;
>  	}
>
> +	dev_dbg(sd->dev, "async: fwnode compat match, need %pfw, trying %pfw\n",
> +		dev_fwnode, other_fwnode);
> +
>  	fwnode_handle_put(dev_fwnode);
>
> -	if (dev_fwnode != other_fwnode)
> +	if (dev_fwnode != other_fwnode) {
> +		dev_dbg(sd->dev, "async: compat match not found\n");

and to be more consistent: "compat match failed"

>  		return false;
> +	}
>
>  	/*
>  	 * We have a heterogeneous match. Retrieve the struct device of the side
> @@ -143,12 +161,17 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
>  			   dev->driver->name);
>  	}
>
> +	dev_dbg(sd->dev, "async: compat match found\n");
> +
>  	return true;
>  }
>
>  static bool match_fwnode(struct v4l2_async_notifier *notifier,
>  			 struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
>  {
> +	dev_dbg(sd->dev, "async: matching for notifier %pfw, sd %pfw\n",
> +		dev_fwnode(notifier_dev(notifier)), sd->fwnode);
> +
>  	if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
>  		return true;
>
> @@ -156,6 +179,8 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
>  	if (IS_ERR_OR_NULL(sd->fwnode->secondary))
>  		return false;
>
> +	dev_dbg(sd->dev, "async: trying secondary fwnode match\n");
> +
>  	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
>  }
>
> @@ -247,16 +272,21 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_subdev *sd;
>
> -	if (!list_empty(&notifier->waiting))
> +	if (!list_empty(&notifier->waiting)) {
> +		dev_dbg(notifier_dev(notifier), "async: waiting for subdevs\n");
>  		return false;
> +	}
>
>  	list_for_each_entry(sd, &notifier->done, async_list) {
>  		struct v4l2_async_notifier *subdev_notifier =
>  			v4l2_async_find_subdev_notifier(sd);
>
>  		if (subdev_notifier &&
> -		    !v4l2_async_nf_can_complete(subdev_notifier))
> +		    !v4l2_async_nf_can_complete(subdev_notifier)) {
> +			dev_dbg(notifier_dev(notifier),
> +				"async: cannot complete\n");

These two will be printed out a lot of times, don't they ?

>  			return false;
> +		}
>  	}
>
>  	return true;
> @@ -269,22 +299,32 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
>  static int
>  v4l2_async_nf_try_complete(struct v4l2_async_notifier *notifier)
>  {
> +	struct v4l2_async_notifier *__notifier = notifier;
> +
>  	/* Quick check whether there are still more sub-devices here. */
>  	if (!list_empty(&notifier->waiting))
>  		return 0;
>
> +	if (notifier->sd)
> +		dev_dbg(notifier_dev(notifier), "async: trying to complete\n");
> +
>  	/* Check the entire notifier tree; find the root notifier first. */
>  	while (notifier->parent)
>  		notifier = notifier->parent;
>
>  	/* This is root if it has v4l2_dev. */
> -	if (!notifier->v4l2_dev)
> +	if (!notifier->v4l2_dev) {
> +		dev_dbg(notifier_dev(__notifier),
> +			"async: V4L2 device not available\n");

is this a BUG() ?

>  		return 0;
> +	}
>
>  	/* Is everything ready? */
>  	if (!v4l2_async_nf_can_complete(notifier))
>  		return 0;
>
> +	dev_dbg(notifier_dev(__notifier), "async: complete\n");
> +
>  	return v4l2_async_nf_call_complete(notifier);
>  }
>
> @@ -362,7 +402,12 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  	 */
>  	subdev_notifier->parent = notifier;
>
> -	return v4l2_async_nf_try_all_subdevs(subdev_notifier);
> +	ret = v4l2_async_nf_try_all_subdevs(subdev_notifier);
> +
> +	dev_dbg(sd->dev, "async: bound to %s's notifier (ret %d)\n",
> +		dev_name(notifier_dev(notifier)), ret);
> +
> +	return ret;

This will only be print out if there's no subnotifier as a few lines
above we return early. Is this intentional ?

>  }
>
>  /* Test all async sub-devices in a notifier for a match. */
> --
> 2.30.2
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching
  2023-03-30 11:58 ` [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching Sakari Ailus
@ 2023-04-13 16:50   ` Jacopo Mondi
  2023-04-14 11:07     ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Jacopo Mondi @ 2023-04-13 16:50 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari

On Thu, Mar 30, 2023 at 02:58:38PM +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.
>

As you know I'm a bit debated.

Strict endpoint-matching requires one subdev to be registed per each
endpoint, and this is tedious for drivers that have to register a
subdev for each of its endpoints

Allowing a subdev to be matched multiple times on different endpoints
gives a way for lazy drivers to take a shortcut and simplify their
topologies to a single subdev, when they would actually need more.

Also, knowing where this series is going, I wonder if this wouldn't be
a good time to enforce all async subdevices to be registered with an
endpoint. From a very quick look at the drivers we have in mainline
only a few still use v4l2_async_nf_add_fwnode() and only 4 of them
(camss, rcar_drif, am437x-vpfe, vpif_capture, xilinx_vipp) use as
match.fwnode what the remote port parent.

I wonder if this would be a good occasione to enforce with a WARN() if
!fwnode_graph_is_endpoint(fwnode) in v4l2_async_nf_add_fwnode() (or
possibily, even remove that function and port all drivers to use
vl2_async_nf_add_fwnode_remote(). I can help, if the above makes sense
to you as well.

> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/i2c/adv748x/adv748x-csi2.c |  3 -
>  drivers/media/i2c/max9286.c              | 14 +---
>  drivers/media/i2c/rdacm20.c              | 15 +----
>  drivers/media/i2c/rdacm21.c              | 15 +----
>  drivers/media/i2c/tc358746.c             |  3 -
>  drivers/media/v4l2-core/v4l2-async.c     | 86 ++++++------------------
>  6 files changed, 24 insertions(+), 112 deletions(-)
>
> diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
> index bd4f3fe0e309..3d830816243f 100644
> --- a/drivers/media/i2c/adv748x/adv748x-csi2.c
> +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
> @@ -300,9 +300,6 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
>  			    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 701038d6d19b..2d0f43e3fb9f 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;
> -


You should also remove the fwnode_handle_put() call from

static void max9286_v4l2_unregister(struct max9286_priv *priv)
{
	fwnode_handle_put(priv->sd.fwnode);
	v4l2_async_unregister_subdev(&priv->sd);
	max9286_v4l2_notifier_unregister(priv);
}

>  	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 a2263fa825b5..ea1111152285 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;

Same for this driver and for rdacm21

> -
>  	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:
> diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> index 9ccc56c30d3b..d67cfcb2e05a 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 4063754a6732..56f2b43d4edf 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;
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 6dd426c2ca68..13fe0bdc70b6 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -86,84 +86,33 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
>  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
>  		 struct v4l2_async_subdev *asd)
>  {
> -	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(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
>  		sd_fwnode, asd->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 == asd->match.fwnode) {
>  		dev_dbg(sd->dev, "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(asd->match.fwnode);
> -
> -	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
> -		dev_dbg(sd->dev, "async: matching node types\n");
> +	if (!fwnode_graph_is_endpoint(asd->match.fwnode)) {
> +		dev_dbg(sd->dev,
> +			"async: async subdev fwnode not endpoint, no match\n");

As per the previous patch I would just say "direct match failed";

>  		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 = asd->match.fwnode;
> -	} else {
> -		dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
> -		other_fwnode = sd_fwnode;
> -	}
> -
> -	dev_dbg(sd->dev, "async: fwnode compat match, need %pfw, trying %pfw\n",
> -		dev_fwnode, other_fwnode);
> +	asd_dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
>
> -	fwnode_handle_put(dev_fwnode);
> +	ret = sd_fwnode == asd_dev_fwnode;
>
> -	if (dev_fwnode != other_fwnode) {
> -		dev_dbg(sd->dev, "async: compat match not found\n");
> -		return false;
> -	}
> +	fwnode_handle_put(asd_dev_fwnode);
>
> -	/*
> -	 * 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(sd->dev, "async: compat match found\n");
> +	dev_dbg(sd->dev, "async: device--endpoint match %sfound\n",

double '--'

However now that I think about it, a subdev will be matched agains a
rather large number of async subdevs and most attempts will fail.. do
we want a printout for each of them ?


> +		ret ? "" : "not ");
>
> -	return true;
> +	return ret;
>  }
>
>  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> @@ -804,12 +753,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. Issue a warning in that case. Once there is
> +	 * certainty no driver no longer does this, remove the warning (and
> +	 * compatibility code) below.
>  	 */
>  	if (!sd->fwnode && sd->dev)
>  		sd->fwnode = dev_fwnode(sd->dev);
> +	else if (WARN_ON(fwnode_graph_is_endpoint(sd->fwnode)))
> +		sd->fwnode = fwnode_graph_get_port_parent(sd->fwnode);
>
>  	mutex_lock(&list_lock);
>
> --
> 2.30.2
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 04/18] media: v4l: async: Make V4L2 async match information a struct
  2023-03-30 11:58 ` [PATCH 04/18] media: v4l: async: Make V4L2 async match information a struct Sakari Ailus
@ 2023-04-13 16:51   ` Jacopo Mondi
  2023-04-27 10:47     ` Sakari Ailus
  2023-04-25  1:10   ` Laurent Pinchart
  1 sibling, 1 reply; 73+ messages in thread
From: Jacopo Mondi @ 2023-04-13 16:51 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari

On Thu, Mar 30, 2023 at 02:58:39PM +0300, Sakari Ailus wrote:
> Make V4L2 async match information a struct, making it easier to use it
> elsewhere outside the scope of struct v4l2_async_subdev.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c  | 18 ++++++-------
>  drivers/media/v4l2-core/v4l2-fwnode.c |  2 +-
>  include/media/v4l2-async.h            | 39 ++++++++++++++++-----------
>  3 files changed, 33 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 13fe0bdc70b6..bb78e3618ab5 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -147,7 +147,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>
>  	list_for_each_entry(asd, &notifier->waiting, list) {
>  		/* bus_type has been verified valid before */
> -		switch (asd->match_type) {
> +		switch (asd->match.type) {
>  		case V4L2_ASYNC_MATCH_I2C:
>  			match = match_i2c;
>  			break;
> @@ -172,10 +172,10 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>  static bool asd_equal(struct v4l2_async_subdev *asd_x,
>  		      struct v4l2_async_subdev *asd_y)
>  {
> -	if (asd_x->match_type != asd_y->match_type)
> +	if (asd_x->match.type != asd_y->match.type)
>  		return false;
>
> -	switch (asd_x->match_type) {
> +	switch (asd_x->match.type) {
>  	case V4L2_ASYNC_MATCH_I2C:
>  		return asd_x->match.i2c.adapter_id ==
>  			asd_y->match.i2c.adapter_id &&
> @@ -494,7 +494,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
>  	if (!asd)
>  		return -EINVAL;
>
> -	switch (asd->match_type) {
> +	switch (asd->match.type) {
>  	case V4L2_ASYNC_MATCH_I2C:
>  	case V4L2_ASYNC_MATCH_FWNODE:
>  		if (v4l2_async_nf_has_async_subdev(notifier, asd, this_index)) {
> @@ -504,7 +504,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
>  		break;
>  	default:
>  		dev_err(dev, "Invalid match type %u on %p\n",
> -			asd->match_type, asd);
> +			asd->match.type, asd);
>  		return -EINVAL;
>  	}
>
> @@ -630,7 +630,7 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
>  		return;
>
>  	list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
> -		switch (asd->match_type) {
> +		switch (asd->match.type) {
>  		case V4L2_ASYNC_MATCH_FWNODE:
>  			fwnode_handle_put(asd->match.fwnode);
>  			break;
> @@ -685,7 +685,7 @@ __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
>  	if (!asd)
>  		return ERR_PTR(-ENOMEM);
>
> -	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> +	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
>  	asd->match.fwnode = fwnode_handle_get(fwnode);
>
>  	ret = __v4l2_async_nf_add_subdev(notifier, asd);
> @@ -732,7 +732,7 @@ __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier, int adapter_id,
>  	if (!asd)
>  		return ERR_PTR(-ENOMEM);
>
> -	asd->match_type = V4L2_ASYNC_MATCH_I2C;
> +	asd->match.type = V4L2_ASYNC_MATCH_I2C;
>  	asd->match.i2c.adapter_id = adapter_id;
>  	asd->match.i2c.address = address;
>
> @@ -850,7 +850,7 @@ EXPORT_SYMBOL(v4l2_async_unregister_subdev);
>  static void print_waiting_subdev(struct seq_file *s,
>  				 struct v4l2_async_subdev *asd)
>  {
> -	switch (asd->match_type) {
> +	switch (asd->match.type) {
>  	case V4L2_ASYNC_MATCH_I2C:
>  		seq_printf(s, " [i2c] dev=%d-%04x\n", asd->match.i2c.adapter_id,
>  			   asd->match.i2c.address);
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 3d9533c1b202..e6bd63364bed 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -811,7 +811,7 @@ v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
>  	if (!asd)
>  		return -ENOMEM;
>
> -	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> +	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
>  	asd->match.fwnode =
>  		fwnode_graph_get_remote_port_parent(endpoint);
>  	if (!asd->match.fwnode) {
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 25eb1d138c06..0c4cffd081c9 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -34,23 +34,38 @@ enum v4l2_async_match_type {
>  };
>
>  /**
> - * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> + * struct v4l2_async_match - async sub-device match information
>   *
> - * @match_type:	type of match that will be used
> - * @match:	union of per-bus type matching data sets
> - * @match.fwnode:
> + * @type:	type of match that will be used
> + * @fwnode:
>   *		pointer to &struct fwnode_handle to be matched.

These two could be on a single line

>   *		Used if @match_type is %V4L2_ASYNC_MATCH_FWNODE.
> - * @match.i2c:	embedded struct with I2C parameters to be matched.
> + * @i2c:	embedded struct with I2C parameters to be matched.
>   *		Both @match.i2c.adapter_id and @match.i2c.address
>   *		should be matched.
>   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> - * @match.i2c.adapter_id:
> + * @i2c.adapter_id:
>   *		I2C adapter ID to be matched.
>   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> - * @match.i2c.address:
> + * @i2c.address:
>   *		I2C address to be matched.
>   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> + */
> +struct v4l2_async_match {
> +	enum v4l2_async_match_type type;
> +	union {
> +		struct fwnode_handle *fwnode;
> +		struct {
> +			int adapter_id;
> +			unsigned short address;
> +		} i2c;
> +	};
> +};
> +
> +/**
> + * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> + *
> + * @match:	struct of match type and per-bus type matching data sets
>   * @asd_list:	used to add struct v4l2_async_subdev objects to the
>   *		master notifier @asd_list
>   * @list:	used to link struct v4l2_async_subdev objects, waiting to be
> @@ -61,15 +76,7 @@ enum v4l2_async_match_type {
>   * v4l2_async_subdev as its first member.
>   */
>  struct v4l2_async_subdev {
> -	enum v4l2_async_match_type match_type;
> -	union {
> -		struct fwnode_handle *fwnode;
> -		struct {
> -			int adapter_id;
> -			unsigned short address;
> -		} i2c;
> -	} match;
> -
> +	struct v4l2_async_match match;

nit: I would maintain a blank line

Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

Thanks
   j

>  	/* v4l2-async core private: not to be used by drivers */
>  	struct list_head list;
>  	struct list_head asd_list;
> --
> 2.30.2
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 05/18] media: v4l: async: Clean testing for duplicated async subdevs
  2023-03-30 11:58 ` [PATCH 05/18] media: v4l: async: Clean testing for duplicated async subdevs Sakari Ailus
@ 2023-04-13 16:58   ` Jacopo Mondi
  2023-04-14 11:16     ` Sakari Ailus
  2023-04-25  1:15   ` Laurent Pinchart
  1 sibling, 1 reply; 73+ messages in thread
From: Jacopo Mondi @ 2023-04-13 16:58 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari

On Thu, Mar 30, 2023 at 02:58:40PM +0300, Sakari Ailus wrote:
> There's a need to verify that a single async sub-device isn't being added
> multiple times, this would be an error. This takes place at the time of
> adding the async sub-device to the notifier's list as well as when the
> notifier is added to the global notifier's list.
>
> Use the pointer to the sub-device for testing this instead of an index to
> an array that is long gone.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c | 18 ++++++++----------
>  1 file changed, 8 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index bb78e3618ab5..fc9ae22e2b47 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -456,21 +456,19 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
>
>  /*
>   * Find out whether an async sub-device was set up already or
> - * whether it exists in a given notifier before @this_index.
> - * If @this_index < 0, search the notifier's entire @asd_list.
> + * whether it exists in a given notifier.
>   */
>  static bool
>  v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> -			       struct v4l2_async_subdev *asd, int this_index)
> +			       struct v4l2_async_subdev *asd, bool skip_self)

is skip_self used ?

>  {
>  	struct v4l2_async_subdev *asd_y;
> -	int j = 0;
>
>  	lockdep_assert_held(&list_lock);
>
>  	/* Check that an asd is not being added more than once. */
>  	list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
> -		if (this_index >= 0 && j++ >= this_index)
> +		if (asd == asd_y)
>  			break;
>  		if (asd_equal(asd, asd_y))
>  			return true;
> @@ -486,7 +484,7 @@ v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
>
>  static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
>  				   struct v4l2_async_subdev *asd,
> -				   int this_index)
> +				   bool skip_self)
>  {
>  	struct device *dev =
>  		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
> @@ -497,7 +495,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
>  	switch (asd->match.type) {
>  	case V4L2_ASYNC_MATCH_I2C:
>  	case V4L2_ASYNC_MATCH_FWNODE:
> -		if (v4l2_async_nf_has_async_subdev(notifier, asd, this_index)) {
> +		if (v4l2_async_nf_has_async_subdev(notifier, asd, skip_self)) {
>  			dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
>  			return -EEXIST;
>  		}
> @@ -520,7 +518,7 @@ EXPORT_SYMBOL(v4l2_async_nf_init);
>  static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_async_subdev *asd;
> -	int ret, i = 0;
> +	int ret;
>
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
> @@ -528,7 +526,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
>  	mutex_lock(&list_lock);
>
>  	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
> -		ret = v4l2_async_nf_asd_valid(notifier, asd, i++);
> +		ret = v4l2_async_nf_asd_valid(notifier, asd, true);
>  		if (ret)
>  			goto err_unlock;
>
> @@ -661,7 +659,7 @@ int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
>
>  	mutex_lock(&list_lock);
>
> -	ret = v4l2_async_nf_asd_valid(notifier, asd, -1);
> +	ret = v4l2_async_nf_asd_valid(notifier, asd, false);
>  	if (ret)
>  		goto unlock;
>
> --
> 2.30.2
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 06/18] media: v4l: async: Only pass match information for async subdev validation
  2023-03-30 11:58 ` [PATCH 06/18] media: v4l: async: Only pass match information for async subdev validation Sakari Ailus
@ 2023-04-14  7:15   ` Jacopo Mondi
  2023-04-14 11:39     ` Sakari Ailus
  2023-04-25  1:24   ` Laurent Pinchart
  1 sibling, 1 reply; 73+ messages in thread
From: Jacopo Mondi @ 2023-04-14  7:15 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari

On Thu, Mar 30, 2023 at 02:58:41PM +0300, Sakari Ailus wrote:
> Pass only information required for sub-device matching to functions
> checking whether the async sub-device already exists. Do the same for
> debug message printing. This makes further changes to other aspects of
> async sub-devices easier.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c | 93 ++++++++++++++--------------
>  1 file changed, 46 insertions(+), 47 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index fc9ae22e2b47..224ebf50f2d0 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -62,14 +62,14 @@ static void v4l2_async_nf_call_destroy(struct v4l2_async_notifier *n,
>  }
>
>  static bool match_i2c(struct v4l2_async_notifier *notifier,
> -		      struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> +		      struct v4l2_subdev *sd, struct v4l2_async_match *match)
>  {
>  #if IS_ENABLED(CONFIG_I2C)
>  	struct i2c_client *client = i2c_verify_client(sd->dev);
>
>  	return client &&
> -		asd->match.i2c.adapter_id == client->adapter->nr &&
> -		asd->match.i2c.address == client->addr;
> +		match->i2c.adapter_id == client->adapter->nr &&
> +		match->i2c.address == client->addr;
>  #else
>  	return false;
>  #endif
> @@ -84,26 +84,26 @@ static struct device *notifier_dev(struct v4l2_async_notifier *notifier)
>  static bool
>  match_fwnode_one(struct v4l2_async_notifier *notifier,
>  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
> -		 struct v4l2_async_subdev *asd)
> +		 struct v4l2_async_match *match)
>  {
>  	struct fwnode_handle *asd_dev_fwnode;
>  	bool ret;
>
>  	dev_dbg(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
> -		sd_fwnode, asd->match.fwnode);
> +		sd_fwnode, match->fwnode);
>
> -	if (sd_fwnode == asd->match.fwnode) {
> +	if (sd_fwnode == match->fwnode) {
>  		dev_dbg(sd->dev, "async: direct match found\n");
>  		return true;
>  	}
>
> -	if (!fwnode_graph_is_endpoint(asd->match.fwnode)) {
> +	if (!fwnode_graph_is_endpoint(match->fwnode)) {
>  		dev_dbg(sd->dev,
>  			"async: async subdev fwnode not endpoint, no match\n");
>  		return false;
>  	}
>
> -	asd_dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
> +	asd_dev_fwnode = fwnode_graph_get_port_parent(match->fwnode);
>
>  	ret = sd_fwnode == asd_dev_fwnode;
>
> @@ -116,12 +116,12 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
>  }
>
>  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> -			 struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> +			 struct v4l2_subdev *sd, struct v4l2_async_match *match)
>  {
>  	dev_dbg(sd->dev, "async: matching for notifier %pfw, sd %pfw\n",
>  		dev_fwnode(notifier_dev(notifier)), sd->fwnode);
>
> -	if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
> +	if (match_fwnode_one(notifier, sd, sd->fwnode, match))
>  		return true;
>
>  	/* Also check the secondary fwnode. */
> @@ -130,7 +130,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
>
>  	dev_dbg(sd->dev, "async: trying secondary fwnode match\n");
>
> -	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
> +	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, match);
>  }
>
>  static LIST_HEAD(subdev_list);
> @@ -142,7 +142,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>  		      struct v4l2_subdev *sd)
>  {
>  	bool (*match)(struct v4l2_async_notifier *notifier,
> -		      struct v4l2_subdev *sd, struct v4l2_async_subdev *asd);
> +		      struct v4l2_subdev *sd, struct v4l2_async_match *match);
>  	struct v4l2_async_subdev *asd;
>
>  	list_for_each_entry(asd, &notifier->waiting, list) {
> @@ -161,7 +161,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>  		}
>
>  		/* match cannot be NULL here */
> -		if (match(notifier, sd, asd))
> +		if (match(notifier, sd, &asd->match))
>  			return asd;
>  	}
>
> @@ -169,20 +169,18 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>  }
>
>  /* Compare two async sub-device descriptors for equivalence */
> -static bool asd_equal(struct v4l2_async_subdev *asd_x,
> -		      struct v4l2_async_subdev *asd_y)
> +static bool asd_equal(struct v4l2_async_match *match1,
> +		      struct v4l2_async_match *match2)
>  {
> -	if (asd_x->match.type != asd_y->match.type)
> +	if (match1->type != match2->type)
>  		return false;
>
> -	switch (asd_x->match.type) {
> +	switch (match1->type) {
>  	case V4L2_ASYNC_MATCH_I2C:
> -		return asd_x->match.i2c.adapter_id ==
> -			asd_y->match.i2c.adapter_id &&
> -			asd_x->match.i2c.address ==
> -			asd_y->match.i2c.address;
> +		return match1->i2c.adapter_id == match2->i2c.adapter_id &&
> +			match1->i2c.address == match2->i2c.address;
>  	case V4L2_ASYNC_MATCH_FWNODE:
> -		return asd_x->match.fwnode == asd_y->match.fwnode;
> +		return match1->fwnode == match2->fwnode;
>  	default:
>  		break;
>  	}
> @@ -434,20 +432,20 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
>  /* See if an async sub-device can be found in a notifier's lists. */
>  static bool
>  __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> -				 struct v4l2_async_subdev *asd)
> +				 struct v4l2_async_match *match)
>  {
> -	struct v4l2_async_subdev *asd_y;
> +	struct v4l2_async_subdev *asd;
>  	struct v4l2_subdev *sd;
>
> -	list_for_each_entry(asd_y, &notifier->waiting, list)
> -		if (asd_equal(asd, asd_y))
> +	list_for_each_entry(asd, &notifier->waiting, list)
> +		if (asd_equal(&asd->match, match))
>  			return true;
>
>  	list_for_each_entry(sd, &notifier->done, async_list) {
>  		if (WARN_ON(!sd->asd))
>  			continue;
>
> -		if (asd_equal(asd, sd->asd))
> +		if (asd_equal(&sd->asd->match, match))
>  			return true;
>  	}
>
> @@ -460,49 +458,50 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
>   */
>  static bool
>  v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> -			       struct v4l2_async_subdev *asd, bool skip_self)
> +			       struct v4l2_async_match *match, bool skip_self)
>  {
> -	struct v4l2_async_subdev *asd_y;
> +	struct v4l2_async_subdev *asd;
>
>  	lockdep_assert_held(&list_lock);
>
>  	/* Check that an asd is not being added more than once. */
> -	list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
> -		if (asd == asd_y)
> +	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
> +		if (&asd->match == match)
>  			break;
> -		if (asd_equal(asd, asd_y))
> +		if (asd_equal(&asd->match, match))
>  			return true;
>  	}
>
>  	/* Check that an asd does not exist in other notifiers. */
>  	list_for_each_entry(notifier, &notifier_list, list)
> -		if (__v4l2_async_nf_has_async_subdev(notifier, asd))
> +		if (__v4l2_async_nf_has_async_subdev(notifier, match))
>  			return true;
>
>  	return false;
>  }
>
>  static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
> -				   struct v4l2_async_subdev *asd,
> +				   struct v4l2_async_match *match,

I would have kept the asd here, but I presume having match here makes
things easier in the next patches


>  				   bool skip_self)
>  {
>  	struct device *dev =
>  		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
>
> -	if (!asd)
> +	if (!match)
>  		return -EINVAL;

Match cannot be null, as it's a member of struct v4l2_async_subdev

>
> -	switch (asd->match.type) {
> +	switch (match->type) {
>  	case V4L2_ASYNC_MATCH_I2C:
>  	case V4L2_ASYNC_MATCH_FWNODE:
> -		if (v4l2_async_nf_has_async_subdev(notifier, asd, skip_self)) {
> +		if (v4l2_async_nf_has_async_subdev(notifier, match,
> +						   skip_self)) {
>  			dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
>  			return -EEXIST;
>  		}
>  		break;
>  	default:
> -		dev_err(dev, "Invalid match type %u on %p\n",
> -			asd->match.type, asd);
> +		dev_err(dev, "Invalid match type %u on %p\n", match->type,
> +			match);
>  		return -EINVAL;
>  	}
>
> @@ -526,7 +525,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
>  	mutex_lock(&list_lock);
>
>  	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
> -		ret = v4l2_async_nf_asd_valid(notifier, asd, true);
> +		ret = v4l2_async_nf_asd_valid(notifier, &asd->match, true);
>  		if (ret)
>  			goto err_unlock;
>
> @@ -659,7 +658,7 @@ int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
>
>  	mutex_lock(&list_lock);
>
> -	ret = v4l2_async_nf_asd_valid(notifier, asd, false);
> +	ret = v4l2_async_nf_asd_valid(notifier, &asd->match, false);
>  	if (ret)
>  		goto unlock;
>
> @@ -846,15 +845,15 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  EXPORT_SYMBOL(v4l2_async_unregister_subdev);
>
>  static void print_waiting_subdev(struct seq_file *s,
> -				 struct v4l2_async_subdev *asd)
> +				 struct v4l2_async_match *match)
>  {
> -	switch (asd->match.type) {
> +	switch (match->type) {
>  	case V4L2_ASYNC_MATCH_I2C:
> -		seq_printf(s, " [i2c] dev=%d-%04x\n", asd->match.i2c.adapter_id,
> -			   asd->match.i2c.address);
> +		seq_printf(s, " [i2c] dev=%d-%04x\n", match->i2c.adapter_id,
> +			   match->i2c.address);
>  		break;
>  	case V4L2_ASYNC_MATCH_FWNODE: {
> -		struct fwnode_handle *devnode, *fwnode = asd->match.fwnode;
> +		struct fwnode_handle *devnode, *fwnode = match->fwnode;
>
>  		devnode = fwnode_graph_is_endpoint(fwnode) ?
>  			  fwnode_graph_get_port_parent(fwnode) :
> @@ -891,7 +890,7 @@ static int pending_subdevs_show(struct seq_file *s, void *data)
>  	list_for_each_entry(notif, &notifier_list, list) {
>  		seq_printf(s, "%s:\n", v4l2_async_nf_name(notif));
>  		list_for_each_entry(asd, &notif->waiting, list)
> -			print_waiting_subdev(s, asd);
> +			print_waiting_subdev(s, &asd->match);
>  	}
>
>  	mutex_unlock(&list_lock);
> --
> 2.30.2
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 07/18] media: v4l: async: Clean up list heads and entries
  2023-03-30 11:58 ` [PATCH 07/18] media: v4l: async: Clean up list heads and entries Sakari Ailus
@ 2023-04-14  7:26   ` Jacopo Mondi
  2023-04-14 11:54     ` Sakari Ailus
  2023-04-25  0:49   ` Laurent Pinchart
  1 sibling, 1 reply; 73+ messages in thread
From: Jacopo Mondi @ 2023-04-14  7:26 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari

On Thu, Mar 30, 2023 at 02:58:42PM +0300, Sakari Ailus wrote:
> The naming of list heads and list entries is confusing as they're named
> similarly. Use _head for list head and _list for list entries.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  2 +-
>  .../platform/renesas/rcar-vin/rcar-core.c     |  2 +-
>  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  2 +-
>  drivers/media/platform/xilinx/xilinx-vipp.c   | 10 +--
>  drivers/media/v4l2-core/v4l2-async.c          | 66 +++++++++----------
>  .../staging/media/imx/imx-media-dev-common.c  |  2 +-
>  drivers/staging/media/tegra-video/vi.c        |  6 +-
>  include/media/v4l2-async.h                    | 21 +++---
>  8 files changed, 56 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
> index 3b76a9d0383a..8b37c2ec8643 100644
> --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
> +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
> @@ -1419,7 +1419,7 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier)
>  	unsigned int pad;
>  	int ret;
>
> -	list_for_each_entry(asd, &cio2->notifier.asd_list, asd_list) {
> +	list_for_each_entry(asd, &cio2->notifier.asd_head, asd_list) {
>  		s_asd = to_sensor_asd(asd);
>  		q = &cio2->queue[s_asd->csi2.port];
>
> diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
> index 5e53d6b7036c..1b530da1c341 100644
> --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c
> +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
> @@ -397,7 +397,7 @@ static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port,
>  		}
>  	}
>
> -	if (list_empty(&vin->group->notifier.asd_list))
> +	if (list_empty(&vin->group->notifier.asd_head))
>  		return 0;
>
>  	vin->group->notifier.ops = &rvin_group_notify_ops;
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index 5939f5165a5e..bfef297f5ec5 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -191,7 +191,7 @@ static int rzg2l_cru_mc_parse_of_graph(struct rzg2l_cru_dev *cru)
>
>  	cru->notifier.ops = &rzg2l_cru_async_ops;
>
> -	if (list_empty(&cru->notifier.asd_list))
> +	if (list_empty(&cru->notifier.asd_head))
>  		return 0;
>
>  	ret = v4l2_async_nf_register(&cru->v4l2_dev, &cru->notifier);
> diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
> index 0a16c218a50a..80157b7a28ee 100644
> --- a/drivers/media/platform/xilinx/xilinx-vipp.c
> +++ b/drivers/media/platform/xilinx/xilinx-vipp.c
> @@ -56,7 +56,7 @@ xvip_graph_find_entity(struct xvip_composite_device *xdev,
>  	struct xvip_graph_entity *entity;
>  	struct v4l2_async_subdev *asd;
>
> -	list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
> +	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
>  		entity = to_xvip_entity(asd);
>  		if (entity->asd.match.fwnode == fwnode)
>  			return entity;
> @@ -291,7 +291,7 @@ static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier)
>  	dev_dbg(xdev->dev, "notify complete, all subdevs registered\n");
>
>  	/* Create links for every entity. */
> -	list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
> +	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
>  		entity = to_xvip_entity(asd);
>  		ret = xvip_graph_build_one(xdev, entity);
>  		if (ret < 0)
> @@ -322,7 +322,7 @@ static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
>  	/* Locate the entity corresponding to the bound subdev and store the
>  	 * subdev pointer.
>  	 */
> -	list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
> +	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
>  		entity = to_xvip_entity(asd);
>
>  		if (entity->asd.match.fwnode != subdev->fwnode)
> @@ -415,7 +415,7 @@ static int xvip_graph_parse(struct xvip_composite_device *xdev)
>  	if (ret < 0)
>  		return 0;
>
> -	list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
> +	list_for_each_entry(asd, &xdev->notifier.asd_head, asd_list) {
>  		entity = to_xvip_entity(asd);
>  		ret = xvip_graph_parse_one(xdev, entity->asd.match.fwnode);
>  		if (ret < 0) {
> @@ -523,7 +523,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
>  		goto done;
>  	}
>
> -	if (list_empty(&xdev->notifier.asd_list)) {
> +	if (list_empty(&xdev->notifier.asd_head)) {
>  		dev_err(xdev->dev, "no subdev found in graph\n");
>  		ret = -ENOENT;
>  		goto done;
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 224ebf50f2d0..fdc995dfc15c 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -133,8 +133,8 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
>  	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, match);
>  }
>
> -static LIST_HEAD(subdev_list);
> -static LIST_HEAD(notifier_list);
> +static LIST_HEAD(subdev_head);
> +static LIST_HEAD(notifier_head);
>  static DEFINE_MUTEX(list_lock);
>
>  static struct v4l2_async_subdev *
> @@ -145,7 +145,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>  		      struct v4l2_subdev *sd, struct v4l2_async_match *match);
>  	struct v4l2_async_subdev *asd;
>
> -	list_for_each_entry(asd, &notifier->waiting, list) {
> +	list_for_each_entry(asd, &notifier->waiting_head, waiting_list) {
>  		/* bus_type has been verified valid before */
>  		switch (asd->match.type) {
>  		case V4L2_ASYNC_MATCH_I2C:
> @@ -194,7 +194,7 @@ v4l2_async_find_subdev_notifier(struct v4l2_subdev *sd)
>  {
>  	struct v4l2_async_notifier *n;
>
> -	list_for_each_entry(n, &notifier_list, list)
> +	list_for_each_entry(n, &notifier_head, notifier_list)
>  		if (n->sd == sd)
>  			return n;
>
> @@ -219,12 +219,12 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_subdev *sd;
>
> -	if (!list_empty(&notifier->waiting)) {
> +	if (!list_empty(&notifier->waiting_head)) {
>  		dev_dbg(notifier_dev(notifier), "async: waiting for subdevs\n");
>  		return false;
>  	}
>
> -	list_for_each_entry(sd, &notifier->done, async_list) {
> +	list_for_each_entry(sd, &notifier->done_head, async_list) {
>  		struct v4l2_async_notifier *subdev_notifier =
>  			v4l2_async_find_subdev_notifier(sd);
>
> @@ -249,7 +249,7 @@ v4l2_async_nf_try_complete(struct v4l2_async_notifier *notifier)
>  	struct v4l2_async_notifier *__notifier = notifier;
>
>  	/* Quick check whether there are still more sub-devices here. */
> -	if (!list_empty(&notifier->waiting))
> +	if (!list_empty(&notifier->waiting_head))
>  		return 0;
>
>  	if (notifier->sd)
> @@ -327,13 +327,12 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  		return ret;
>  	}
>
> -	/* Remove from the waiting list */
> -	list_del(&asd->list);
> +	list_del(&asd->waiting_list);
>  	sd->asd = asd;
>  	sd->notifier = notifier;
>
>  	/* Move from the global subdevice list to notifier's done */
> -	list_move(&sd->async_list, &notifier->done);
> +	list_move(&sd->async_list, &notifier->done_head);
>
>  	/*
>  	 * See if the sub-device has a notifier. If not, return here.
> @@ -369,7 +368,7 @@ v4l2_async_nf_try_all_subdevs(struct v4l2_async_notifier *notifier)
>  		return 0;
>
>  again:
> -	list_for_each_entry(sd, &subdev_list, async_list) {
> +	list_for_each_entry(sd, &subdev_head, async_list) {
>  		struct v4l2_async_subdev *asd;
>  		int ret;
>
> @@ -411,7 +410,7 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
>  {
>  	struct v4l2_subdev *sd, *tmp;
>
> -	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> +	list_for_each_entry_safe(sd, tmp, &notifier->done_head, async_list) {
>  		struct v4l2_async_notifier *subdev_notifier =
>  			v4l2_async_find_subdev_notifier(sd);
>
> @@ -420,10 +419,11 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
>
>  		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
>  		if (readd)
> -			list_add_tail(&sd->asd->list, &notifier->waiting);
> +			list_add_tail(&sd->asd->waiting_list,
> +				      &notifier->waiting_head);
>  		v4l2_async_cleanup(sd);
>
> -		list_move(&sd->async_list, &subdev_list);
> +		list_move(&sd->async_list, &subdev_head);
>  	}
>
>  	notifier->parent = NULL;
> @@ -437,11 +437,11 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
>  	struct v4l2_async_subdev *asd;
>  	struct v4l2_subdev *sd;
>
> -	list_for_each_entry(asd, &notifier->waiting, list)
> +	list_for_each_entry(asd, &notifier->waiting_head, waiting_list)
>  		if (asd_equal(&asd->match, match))
>  			return true;
>
> -	list_for_each_entry(sd, &notifier->done, async_list) {
> +	list_for_each_entry(sd, &notifier->done_head, async_list) {
>  		if (WARN_ON(!sd->asd))
>  			continue;
>
> @@ -465,7 +465,7 @@ v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
>  	lockdep_assert_held(&list_lock);
>
>  	/* Check that an asd is not being added more than once. */
> -	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
> +	list_for_each_entry(asd, &notifier->asd_head, asd_list) {
>  		if (&asd->match == match)
>  			break;
>  		if (asd_equal(&asd->match, match))
> @@ -473,7 +473,7 @@ v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
>  	}
>
>  	/* Check that an asd does not exist in other notifiers. */
> -	list_for_each_entry(notifier, &notifier_list, list)
> +	list_for_each_entry(notifier, &notifier_head, notifier_list)
>  		if (__v4l2_async_nf_has_async_subdev(notifier, match))
>  			return true;
>
> @@ -510,7 +510,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
>
>  void v4l2_async_nf_init(struct v4l2_async_notifier *notifier)
>  {
> -	INIT_LIST_HEAD(&notifier->asd_list);
> +	INIT_LIST_HEAD(&notifier->asd_head);
>  }
>  EXPORT_SYMBOL(v4l2_async_nf_init);
>
> @@ -519,17 +519,17 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
>  	struct v4l2_async_subdev *asd;
>  	int ret;
>
> -	INIT_LIST_HEAD(&notifier->waiting);
> -	INIT_LIST_HEAD(&notifier->done);
> +	INIT_LIST_HEAD(&notifier->waiting_head);
> +	INIT_LIST_HEAD(&notifier->done_head);
>
>  	mutex_lock(&list_lock);
>
> -	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
> +	list_for_each_entry(asd, &notifier->asd_head, asd_list) {
>  		ret = v4l2_async_nf_asd_valid(notifier, &asd->match, true);
>  		if (ret)
>  			goto err_unlock;
>
> -		list_add_tail(&asd->list, &notifier->waiting);
> +		list_add_tail(&asd->waiting_list, &notifier->waiting_head);
>  	}
>
>  	ret = v4l2_async_nf_try_all_subdevs(notifier);
> @@ -541,7 +541,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
>  		goto err_unbind;
>
>  	/* Keep also completed notifiers on the list */
> -	list_add(&notifier->list, &notifier_list);
> +	list_add(&notifier->notifier_list, &notifier_head);
>
>  	mutex_unlock(&list_lock);
>
> @@ -606,7 +606,7 @@ __v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
>  	notifier->sd = NULL;
>  	notifier->v4l2_dev = NULL;
>
> -	list_del(&notifier->list);
> +	list_del(&notifier->notifier_list);
>  }
>
>  void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
> @@ -623,10 +623,10 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_async_subdev *asd, *tmp;
>
> -	if (!notifier || !notifier->asd_list.next)
> +	if (!notifier || !notifier->asd_head.next)
>  		return;
>
> -	list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
> +	list_for_each_entry_safe(asd, tmp, &notifier->asd_head, asd_list) {
>  		switch (asd->match.type) {
>  		case V4L2_ASYNC_MATCH_FWNODE:
>  			fwnode_handle_put(asd->match.fwnode);
> @@ -662,7 +662,7 @@ int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
>  	if (ret)
>  		goto unlock;
>
> -	list_add_tail(&asd->asd_list, &notifier->asd_list);
> +	list_add_tail(&asd->asd_list, &notifier->asd_head);
>
>  unlock:
>  	mutex_unlock(&list_lock);
> @@ -768,7 +768,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>
>  	INIT_LIST_HEAD(&sd->async_list);
>
> -	list_for_each_entry(notifier, &notifier_list, list) {
> +	list_for_each_entry(notifier, &notifier_head, notifier_list) {
>  		struct v4l2_device *v4l2_dev =
>  			v4l2_async_nf_find_v4l2_dev(notifier);
>  		struct v4l2_async_subdev *asd;
> @@ -792,7 +792,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	}
>
>  	/* None matched, wait for hot-plugging */
> -	list_add(&sd->async_list, &subdev_list);
> +	list_add(&sd->async_list, &subdev_head);
>
>  out_unlock:
>  	mutex_unlock(&list_lock);
> @@ -833,7 +833,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  	if (sd->asd) {
>  		struct v4l2_async_notifier *notifier = sd->notifier;
>
> -		list_add(&sd->asd->list, &notifier->waiting);
> +		list_add(&sd->asd->waiting_list, &notifier->waiting_head);
>
>  		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
>  	}
> @@ -887,9 +887,9 @@ static int pending_subdevs_show(struct seq_file *s, void *data)
>
>  	mutex_lock(&list_lock);
>
> -	list_for_each_entry(notif, &notifier_list, list) {
> +	list_for_each_entry(notif, &notifier_head, notifier_list) {
>  		seq_printf(s, "%s:\n", v4l2_async_nf_name(notif));
> -		list_for_each_entry(asd, &notif->waiting, list)
> +		list_for_each_entry(asd, &notif->waiting_head, waiting_list)
>  			print_waiting_subdev(s, &asd->match);
>  	}
>
> diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c
> index e6d6ed3b1161..eaa54848df6a 100644
> --- a/drivers/staging/media/imx/imx-media-dev-common.c
> +++ b/drivers/staging/media/imx/imx-media-dev-common.c
> @@ -398,7 +398,7 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd,
>  	int ret;
>
>  	/* no subdevs? just bail */
> -	if (list_empty(&imxmd->notifier.asd_list)) {
> +	if (list_empty(&imxmd->notifier.asd_head)) {
>  		v4l2_err(&imxmd->v4l2_dev, "no subdevs\n");
>  		return -ENODEV;
>  	}
> diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
> index 11dd142c98c5..4818646fe637 100644
> --- a/drivers/staging/media/tegra-video/vi.c
> +++ b/drivers/staging/media/tegra-video/vi.c
> @@ -1563,7 +1563,7 @@ tegra_vi_graph_find_entity(struct tegra_vi_channel *chan,
>  	struct tegra_vi_graph_entity *entity;
>  	struct v4l2_async_subdev *asd;
>
> -	list_for_each_entry(asd, &chan->notifier.asd_list, asd_list) {
> +	list_for_each_entry(asd, &chan->notifier.asd_head, asd_list) {
>  		entity = to_tegra_vi_graph_entity(asd);
>  		if (entity->asd.match.fwnode == fwnode)
>  			return entity;
> @@ -1707,7 +1707,7 @@ static int tegra_vi_graph_notify_complete(struct v4l2_async_notifier *notifier)
>  	}
>
>  	/* create links between the entities */
> -	list_for_each_entry(asd, &chan->notifier.asd_list, asd_list) {
> +	list_for_each_entry(asd, &chan->notifier.asd_head, asd_list) {
>  		entity = to_tegra_vi_graph_entity(asd);
>  		ret = tegra_vi_graph_build(chan, entity);
>  		if (ret < 0)
> @@ -1874,7 +1874,7 @@ static int tegra_vi_graph_init(struct tegra_vi *vi)
>
>  		ret = tegra_vi_graph_parse_one(chan, remote);
>  		fwnode_handle_put(remote);
> -		if (ret < 0 || list_empty(&chan->notifier.asd_list))
> +		if (ret < 0 || list_empty(&chan->notifier.asd_head))
>  			continue;
>
>  		chan->notifier.ops = &tegra_vi_async_ops;
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 0c4cffd081c9..425280b4d387 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -68,7 +68,7 @@ struct v4l2_async_match {
>   * @match:	struct of match type and per-bus type matching data sets
>   * @asd_list:	used to add struct v4l2_async_subdev objects to the
>   *		master notifier @asd_list
> - * @list:	used to link struct v4l2_async_subdev objects, waiting to be
> + * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
>   *		probed, to a notifier->waiting list

notifier->waiting_head

>   *
>   * When this struct is used as a member in a driver specific struct,
> @@ -77,9 +77,10 @@ struct v4l2_async_match {
>   */
>  struct v4l2_async_subdev {
>  	struct v4l2_async_match match;
> +
>  	/* v4l2-async core private: not to be used by drivers */
> -	struct list_head list;
>  	struct list_head asd_list;
> +	struct list_head waiting_list;
>  };
>
>  /**
> @@ -108,20 +109,20 @@ struct v4l2_async_notifier_operations {
>   * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
>   * @sd:		sub-device that registered the notifier, NULL otherwise
>   * @parent:	parent notifier
> - * @asd_list:	master list of struct v4l2_async_subdev
> - * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
> - * @done:	list of struct v4l2_subdev, already probed
> - * @list:	member in a global list of notifiers
> + * @asd_head:	master list of struct v4l2_async_subdev
> + * @waiting_list: list of struct v4l2_async_subdev, waiting for their drivers

waiting_head

> + * @done_head:	list of struct v4l2_subdev, already probed
> + * @notifier_list: member in a global list of notifiers
>   */
>  struct v4l2_async_notifier {
>  	const struct v4l2_async_notifier_operations *ops;
>  	struct v4l2_device *v4l2_dev;
>  	struct v4l2_subdev *sd;
>  	struct v4l2_async_notifier *parent;
> -	struct list_head asd_list;
> -	struct list_head waiting;
> -	struct list_head done;
> -	struct list_head list;
> +	struct list_head asd_head;
> +	struct list_head waiting_head;
> +	struct list_head done_head;
> +	struct list_head notifier_list;
>  };
>
>  /**
> --
> 2.30.2
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 08/18] media: v4l: async: Rename v4l2_async_subdev as v4l2_async_connection
  2023-03-30 11:58 ` [PATCH 08/18] media: v4l: async: Rename v4l2_async_subdev as v4l2_async_connection Sakari Ailus
@ 2023-04-14  8:22   ` Jacopo Mondi
  2023-04-14 12:17     ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Jacopo Mondi @ 2023-04-14  8:22 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari

On Thu, Mar 30, 2023 at 02:58:43PM +0300, Sakari Ailus wrote:
> This patch has been generated by:
>
> 	git grep -l v4l2_async_subdev | \
> 		while read i; do \
> 			spatch --sp-file async.spatch --in-place $i; done \
> 			perl -i -pe 's/v4l2_async_\Ksubdev/connection/g' $i \
> 		done
>
> While async.spatch looks like:
>
> @ name @
> @@
> - struct v4l2_async_subdev
> + struct v4l2_async_connection
>
> Additionally, __v4l2_async_nf_add_subdev() has been renamed as
> __v4l2_async_nf_add_connection(). Some manual editing has been performed
> as well.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  .../driver-api/media/v4l2-subdev.rst          |  10 +-
>  drivers/media/i2c/max9286.c                   |   9 +-
>  drivers/media/i2c/st-mipid02.c                |   8 +-
>  drivers/media/i2c/tc358746.c                  |   6 +-
>  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  10 +-
>  drivers/media/platform/atmel/atmel-isi.c      |   8 +-
>  drivers/media/platform/atmel/atmel-isi.h      |   2 +-
>  drivers/media/platform/cadence/cdns-csi2rx.c  |   6 +-
>  drivers/media/platform/intel/pxa_camera.c     |  12 +-
>  drivers/media/platform/marvell/cafe-driver.c  |   5 +-
>  drivers/media/platform/marvell/mcam-core.c    |   4 +-
>  drivers/media/platform/marvell/mmp-driver.c   |   4 +-
>  .../platform/microchip/microchip-csi2dc.c     |   6 +-
>  .../platform/microchip/microchip-isc-base.c   |   4 +-
>  .../media/platform/microchip/microchip-isc.h  |   2 +-
>  .../microchip/microchip-sama5d2-isc.c         |   4 +-
>  .../microchip/microchip-sama7g5-isc.c         |   4 +-
>  drivers/media/platform/nxp/imx-mipi-csis.c    |   6 +-
>  drivers/media/platform/nxp/imx7-media-csi.c   |   6 +-
>  drivers/media/platform/qcom/camss/camss.c     |   2 +-
>  drivers/media/platform/qcom/camss/camss.h     |   2 +-
>  drivers/media/platform/renesas/rcar-isp.c     |   8 +-
>  .../platform/renesas/rcar-vin/rcar-core.c     |  18 +-
>  .../platform/renesas/rcar-vin/rcar-csi2.c     |   8 +-
>  .../platform/renesas/rcar-vin/rcar-vin.h      |   4 +-
>  drivers/media/platform/renesas/rcar_drif.c    |   8 +-
>  drivers/media/platform/renesas/renesas-ceu.c  |   6 +-
>  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  10 +-
>  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |   2 +-
>  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   |   8 +-
>  .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
>  .../platform/rockchip/rkisp1/rkisp1-dev.c     |   4 +-
>  .../platform/samsung/exynos4-is/media-dev.c   |   6 +-
>  .../platform/samsung/exynos4-is/media-dev.h   |   2 +-
>  drivers/media/platform/st/stm32/stm32-dcmi.c  |   8 +-
>  .../platform/sunxi/sun4i-csi/sun4i_csi.c      |   6 +-
>  .../sunxi/sun6i-csi/sun6i_csi_bridge.c        |   2 +-
>  .../sunxi/sun6i-csi/sun6i_csi_bridge.h        |   2 +-
>  .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c   |   6 +-
>  .../sun8i_a83t_mipi_csi2.c                    |   6 +-
>  .../media/platform/ti/am437x/am437x-vpfe.c    |   5 +-
>  .../media/platform/ti/am437x/am437x-vpfe.h    |   2 +-
>  drivers/media/platform/ti/cal/cal.c           |   6 +-
>  .../media/platform/ti/davinci/vpif_capture.c  |   7 +-
>  drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
>  drivers/media/platform/video-mux.c            |   6 +-
>  drivers/media/platform/xilinx/xilinx-vipp.c   |  24 +--
>  drivers/media/v4l2-core/v4l2-async.c          | 166 +++++++++---------
>  drivers/media/v4l2-core/v4l2-fwnode.c         |  14 +-
>  .../media/deprecated/atmel/atmel-isc-base.c   |   4 +-
>  .../media/deprecated/atmel/atmel-isc.h        |   2 +-
>  .../deprecated/atmel/atmel-sama5d2-isc.c      |   4 +-
>  .../deprecated/atmel/atmel-sama7g5-isc.c      |   4 +-
>  drivers/staging/media/imx/imx-media-csi.c     |   6 +-
>  .../staging/media/imx/imx-media-dev-common.c  |   4 +-
>  drivers/staging/media/imx/imx-media-dev.c     |   2 +-
>  drivers/staging/media/imx/imx-media-of.c      |   4 +-
>  drivers/staging/media/imx/imx6-mipi-csi2.c    |   8 +-
>  drivers/staging/media/imx/imx8mq-mipi-csi2.c  |   6 +-
>  .../media/sunxi/sun6i-isp/sun6i_isp_proc.c    |   2 +-
>  .../media/sunxi/sun6i-isp/sun6i_isp_proc.h    |   2 +-
>  drivers/staging/media/tegra-video/vi.c        |  14 +-
>  drivers/staging/media/tegra-video/vi.h        |   2 +-
>  include/media/davinci/vpif_types.h            |   2 +-
>  include/media/v4l2-async.h                    |  78 ++++----
>  include/media/v4l2-fwnode.h                   |  10 +-
>  include/media/v4l2-subdev.h                   |   4 +-
>  67 files changed, 313 insertions(+), 313 deletions(-)
>
> diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst
> index 260cfa8c3f3d..1c5cb1a637ab 100644
> --- a/Documentation/driver-api/media/v4l2-subdev.rst
> +++ b/Documentation/driver-api/media/v4l2-subdev.rst
> @@ -215,13 +215,13 @@ found in firmware. The notifier for the sub-device is unregistered with the
>  async sub-device.
>
>  These functions allocate an async sub-device descriptor which is of type struct
> -:c:type:`v4l2_async_subdev` embedded in a driver-specific struct. The &struct
> -:c:type:`v4l2_async_subdev` shall be the first member of this struct:
> +:c:type:`v4l2_async_connection` embedded in a driver-specific struct. The &struct
> +:c:type:`v4l2_async_connection` shall be the first member of this struct:
>
>  .. code-block:: c
>
>  	struct my_async_subdev {
> -		struct v4l2_async_subdev asd;
> +		struct v4l2_async_connection asd;
>  		...
>  	};
>
> @@ -244,10 +244,10 @@ notifier callback is called. After all subdevices have been located the
>  system the .unbind() method is called. All three callbacks are optional.
>
>  Drivers can store any type of custom data in their driver-specific
> -:c:type:`v4l2_async_subdev` wrapper. If any of that data requires special
> +:c:type:`v4l2_async_connection` wrapper. If any of that data requires special
>  handling when the structure is freed, drivers must implement the ``.destroy()``
>  notifier callback. The framework will call it right before freeing the
> -:c:type:`v4l2_async_subdev`.
> +:c:type:`v4l2_async_connection`.
>
>  Calling subdev operations
>  ~~~~~~~~~~~~~~~~~~~~~~~~~
> diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
> index 2d0f43e3fb9f..13cb2537a06d 100644


[snip: I'll only comment framework changes as I presume if driver
changes compile, they're good]


> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 425280b4d387..9cf383e81a16 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -63,23 +63,23 @@ struct v4l2_async_match {
>  };
>
>  /**
> - * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> + * struct v4l2_async_connection - sub-device descriptor, as known to a bridge
>   *
>   * @match:	struct of match type and per-bus type matching data sets
> - * @asd_list:	used to add struct v4l2_async_subdev objects to the
> - *		master notifier @asd_list
> - * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
> - *		probed, to a notifier->waiting list
> + * @asc_list:	used to add struct v4l2_async_connection objects to the
> + *		master notifier @asc_list

notifier asc_head

> + * @waiting_list: used to link struct v4l2_async_connection objects, waiting to
> + *		be probed, to a notifier->waiting list
>   *
>   * When this struct is used as a member in a driver specific struct,
>   * the driver specific struct shall contain the &struct
> - * v4l2_async_subdev as its first member.
> + * v4l2_async_connection as its first member.
>   */
> -struct v4l2_async_subdev {
> +struct v4l2_async_connection {
>  	struct v4l2_async_match match;
>
>  	/* v4l2-async core private: not to be used by drivers */
> -	struct list_head asd_list;
> +	struct list_head asc_list;
>  	struct list_head waiting_list;
>  };
>
> @@ -89,17 +89,17 @@ struct v4l2_async_subdev {

For more context:

    * @bound:	        a subdevice driver has successfully probed one of the subdevices
>   * @complete:	All subdevices have been probed successfully. The complete

the usage of the term "subdevice" when referring to connection is
spread everywhere in documentation :/

But I mostly wonder, and I guess this is a comment on the next patch:
do we now get multiple 'bound' calls for the same subdevice when
matched on multiple connections ?


>   *		callback is only executed for the root notifier.
>   * @unbind:	a subdevice is leaving
> - * @destroy:	the asd is about to be freed
> + * @destroy:	the asc is about to be freed
>   */
>  struct v4l2_async_notifier_operations {
>  	int (*bound)(struct v4l2_async_notifier *notifier,
>  		     struct v4l2_subdev *subdev,
> -		     struct v4l2_async_subdev *asd);
> +		     struct v4l2_async_connection *asc);
>  	int (*complete)(struct v4l2_async_notifier *notifier);
>  	void (*unbind)(struct v4l2_async_notifier *notifier,
>  		       struct v4l2_subdev *subdev,
> -		       struct v4l2_async_subdev *asd);
> -	void (*destroy)(struct v4l2_async_subdev *asd);
> +		       struct v4l2_async_connection *asc);
> +	void (*destroy)(struct v4l2_async_connection *asc);
>  };
>
>  /**
> @@ -109,7 +109,7 @@ struct v4l2_async_notifier_operations {
>   * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
>   * @sd:		sub-device that registered the notifier, NULL otherwise
>   * @parent:	parent notifier
> - * @asd_head:	master list of struct v4l2_async_subdev
> + * @asc_head:	master list of struct v4l2_async_subdev
>   * @waiting_list: list of struct v4l2_async_subdev, waiting for their drivers
>   * @done_head:	list of struct v4l2_subdev, already probed
>   * @notifier_list: member in a global list of notifiers
> @@ -119,7 +119,7 @@ struct v4l2_async_notifier {
>  	struct v4l2_device *v4l2_dev;
>  	struct v4l2_subdev *sd;
>  	struct v4l2_async_notifier *parent;
> -	struct list_head asd_head;
> +	struct list_head asc_head;
>  	struct list_head waiting_head;
>  	struct list_head done_head;
>  	struct list_head notifier_list;
> @@ -137,75 +137,75 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
>   *
>   * @notifier: pointer to &struct v4l2_async_notifier
>   *
> - * This function initializes the notifier @asd_list. It must be called
> + * This function initializes the notifier @asc_list. It must be called
>   * before adding a subdevice to a notifier, using one of:
>   * v4l2_async_nf_add_fwnode_remote(),
>   * v4l2_async_nf_add_fwnode(),
>   * v4l2_async_nf_add_i2c(),
> - * __v4l2_async_nf_add_subdev() or
> + * __v4l2_async_nf_add_connection() or
>   * v4l2_async_nf_parse_fwnode_endpoints().
>   */
>  void v4l2_async_nf_init(struct v4l2_async_notifier *notifier);
>
>  /**
> - * __v4l2_async_nf_add_subdev - Add an async subdev to the
> - *				notifier's master asd list.
> + * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
> + *				      master asc list.
>   *
>   * @notifier: pointer to &struct v4l2_async_notifier
> - * @asd: pointer to &struct v4l2_async_subdev
> + * @asc: pointer to &struct v4l2_async_connection
>   *
>   * \warning: Drivers should avoid using this function and instead use one of:
>   * v4l2_async_nf_add_fwnode(),
>   * v4l2_async_nf_add_fwnode_remote() or
>   * v4l2_async_nf_add_i2c().
>   *
> - * Call this function before registering a notifier to link the provided @asd to
> - * the notifiers master @asd_list. The @asd must be allocated with k*alloc() as
> + * Call this function before registering a notifier to link the provided @asc to
> + * the notifiers master @asc_list. The @asc must be allocated with k*alloc() as
>   * it will be freed by the framework when the notifier is destroyed.
>   */
> -int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
> -			       struct v4l2_async_subdev *asd);
> +int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> +				   struct v4l2_async_connection *asc);
>
> -struct v4l2_async_subdev *
> +struct v4l2_async_connection *
>  __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
>  			   struct fwnode_handle *fwnode,
> -			   unsigned int asd_struct_size);
> +			   unsigned int asc_struct_size);
>  /**
>   * v4l2_async_nf_add_fwnode - Allocate and add a fwnode async
> - *				subdev to the notifier's master asd_list.
> + *				subdev to the notifier's master asc_list.
>   *
>   * @notifier: pointer to &struct v4l2_async_notifier
>   * @fwnode: fwnode handle of the sub-device to be matched, pointer to
>   *	    &struct fwnode_handle
>   * @type: Type of the driver's async sub-device struct. The &struct
> - *	  v4l2_async_subdev shall be the first member of the driver's async
> + *	  v4l2_async_connection shall be the first member of the driver's async
>   *	  sub-device struct, i.e. both begin at the same memory address.
>   *
> - * Allocate a fwnode-matched asd of size asd_struct_size, and add it to the
> - * notifiers @asd_list. The function also gets a reference of the fwnode which
> + * Allocate a fwnode-matched asc of size asc_struct_size, and add it to the
> + * notifiers @asc_list. The function also gets a reference of the fwnode which
>   * is released later at notifier cleanup time.
>   */
>  #define v4l2_async_nf_add_fwnode(notifier, fwnode, type)		\
>  	((type *)__v4l2_async_nf_add_fwnode(notifier, fwnode, sizeof(type)))
>
> -struct v4l2_async_subdev *
> +struct v4l2_async_connection *
>  __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
>  				  struct fwnode_handle *endpoint,
> -				  unsigned int asd_struct_size);
> +				  unsigned int asc_struct_size);
>  /**
>   * v4l2_async_nf_add_fwnode_remote - Allocate and add a fwnode
>   *						  remote async subdev to the
> - *						  notifier's master asd_list.
> + *						  notifier's master asc_list.
>   *
>   * @notifier: pointer to &struct v4l2_async_notifier
>   * @ep: local endpoint pointing to the remote sub-device to be matched,
>   *	pointer to &struct fwnode_handle
>   * @type: Type of the driver's async sub-device struct. The &struct
> - *	  v4l2_async_subdev shall be the first member of the driver's async
> + *	  v4l2_async_connection shall be the first member of the driver's async
>   *	  sub-device struct, i.e. both begin at the same memory address.
>   *
>   * Gets the remote endpoint of a given local endpoint, set it up for fwnode
> - * matching and adds the async sub-device to the notifier's @asd_list. The
> + * matching and adds the async sub-device to the notifier's @asc_list. The
>   * function also gets a reference of the fwnode which is released later at
>   * notifier cleanup time.
>   *
> @@ -215,19 +215,19 @@ __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
>  #define v4l2_async_nf_add_fwnode_remote(notifier, ep, type) \
>  	((type *)__v4l2_async_nf_add_fwnode_remote(notifier, ep, sizeof(type)))
>
> -struct v4l2_async_subdev *
> +struct v4l2_async_connection *
>  __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier,
>  			int adapter_id, unsigned short address,
> -			unsigned int asd_struct_size);
> +			unsigned int asc_struct_size);
>  /**
>   * v4l2_async_nf_add_i2c - Allocate and add an i2c async
> - *				subdev to the notifier's master asd_list.
> + *				subdev to the notifier's master asc_list.
>   *
>   * @notifier: pointer to &struct v4l2_async_notifier
>   * @adapter: I2C adapter ID to be matched
>   * @address: I2C address of sub-device to be matched
>   * @type: Type of the driver's async sub-device struct. The &struct
> - *	  v4l2_async_subdev shall be the first member of the driver's async
> + *	  v4l2_async_connection shall be the first member of the driver's async
>   *	  sub-device struct, i.e. both begin at the same memory address.
>   *
>   * Same as v4l2_async_nf_add_fwnode() but for I2C matched
> @@ -275,7 +275,7 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier);
>   * v4l2_async_nf_add_fwnode_remote(),
>   * v4l2_async_nf_add_fwnode(),
>   * v4l2_async_nf_add_i2c(),
> - * __v4l2_async_nf_add_subdev() or
> + * __v4l2_async_nf_add_connection() or
>   * v4l2_async_nf_parse_fwnode_endpoints().
>   *
>   * There is no harm from calling v4l2_async_nf_cleanup() in other
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index 394d798f3dfa..ebb83154abd5 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -23,7 +23,7 @@
>
>  struct fwnode_handle;
>  struct v4l2_async_notifier;
> -struct v4l2_async_subdev;
> +struct v4l2_async_connection;
>
>  /**
>   * struct v4l2_fwnode_endpoint - the endpoint data structure
> @@ -399,7 +399,7 @@ int v4l2_fwnode_device_parse(struct device *dev,
>   *
>   * @dev: pointer to &struct device
>   * @vep: pointer to &struct v4l2_fwnode_endpoint
> - * @asd: pointer to &struct v4l2_async_subdev
> + * @asd: pointer to &struct v4l2_async_connection
>   *
>   * Return:
>   * * %0 on success
> @@ -409,7 +409,7 @@ int v4l2_fwnode_device_parse(struct device *dev,
>   */
>  typedef int (*parse_endpoint_func)(struct device *dev,
>  				  struct v4l2_fwnode_endpoint *vep,
> -				  struct v4l2_async_subdev *asd);
> +				  struct v4l2_async_connection *asd);
>
>  /**
>   * v4l2_async_nf_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a

Ah nice this function is DEPRECATED and not used anywhere anymore.
I'll send a patch on top of this series to drop it

> @@ -417,8 +417,8 @@ typedef int (*parse_endpoint_func)(struct device *dev,
>   * @dev: the device the endpoints of which are to be parsed
>   * @notifier: notifier for @dev
>   * @asd_struct_size: size of the driver's async sub-device struct, including
> - *		     sizeof(struct v4l2_async_subdev). The &struct
> - *		     v4l2_async_subdev shall be the first member of
> + *		     sizeof(struct v4l2_async_connection). The &struct
> + *		     v4l2_async_connection shall be the first member of
>   *		     the driver's async sub-device struct, i.e. both
>   *		     begin at the same memory address.
>   * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index 17773be4a4ee..a2cce11dda5c 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -1021,7 +1021,7 @@ struct v4l2_subdev_platform_data {
>   *	    either dev->of_node->fwnode or dev->fwnode (whichever is non-NULL).
>   * @async_list: Links this subdev to a global subdev_list or @notifier->done
>   *	list.
> - * @asd: Pointer to respective &struct v4l2_async_subdev.
> + * @asc: Pointer to respective &struct v4l2_async_connection.

this is still named 'asd' in code


>   * @notifier: Pointer to the managing notifier.
>   * @subdev_notifier: A sub-device notifier implicitly registered for the sub-
>   *		     device using v4l2_async_register_subdev_sensor().
> @@ -1063,7 +1063,7 @@ struct v4l2_subdev {
>  	struct device *dev;
>  	struct fwnode_handle *fwnode;
>  	struct list_head async_list;
> -	struct v4l2_async_subdev *asd;
> +	struct v4l2_async_connection *asd;
>  	struct v4l2_async_notifier *notifier;
>  	struct v4l2_async_notifier *subdev_notifier;
>  	struct v4l2_subdev_platform_data *pdata;
> --
> 2.30.2
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 09/18] media: v4l: async: Differentiate connecting and creating sub-devices
  2023-03-30 11:58 ` [PATCH 09/18] media: v4l: async: Differentiate connecting and creating sub-devices Sakari Ailus
@ 2023-04-14  8:52   ` Jacopo Mondi
  2023-04-14 13:35     ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Jacopo Mondi @ 2023-04-14  8:52 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari

On Thu, Mar 30, 2023 at 02:58:44PM +0300, Sakari Ailus wrote:
> When the v4l2-async framework was introduced, the use case for it was to
> connect a camera sensor with a parallel receiver. Both tended to be rather
> simple devices with a single connection between them.
>
> The framework has been since improved in multiple ways but there are
> limitations that have remained, for instance the assumption an async
> sub-device is connected towards a single notifier and via a single link
> only.
>
> This patch adds an object that represents the device while an earlier
> patch in the series re-purposed the old struct v4l2_async_subdev as the
> connection.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
>  .../platform/rockchip/rkisp1/rkisp1-dev.c     |   8 +-
>  drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
>  drivers/media/v4l2-core/v4l2-async.c          | 163 ++++++++++++++++--
>  include/media/v4l2-async.h                    |  32 +++-
>  include/media/v4l2-subdev.h                   |   2 +-
>  6 files changed, 179 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> index d30f0ecb1bfd..a1293c45aae1 100644
> --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> @@ -148,7 +148,7 @@ struct rkisp1_info {
>   * @port:		port number (0: MIPI, 1: Parallel)
>   */
>  struct rkisp1_sensor_async {
> -	struct v4l2_async_connection asd;
> +	struct v4l2_async_subdev asd;
>  	unsigned int index;
>  	struct fwnode_handle *source_ep;
>  	unsigned int lanes;
> diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> index 39fa98e6dbbc..5bdb1ecedf6a 100644
> --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> @@ -122,12 +122,12 @@ struct rkisp1_isr_data {
>
>  static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
>  					struct v4l2_subdev *sd,
> -					struct v4l2_async_connection *asd)
> +					struct v4l2_async_connection *asc)
>  {
>  	struct rkisp1_device *rkisp1 =
>  		container_of(notifier, struct rkisp1_device, notifier);
>  	struct rkisp1_sensor_async *s_asd =
> -		container_of(asd, struct rkisp1_sensor_async, asd);
> +		container_of(asc->asd, struct rkisp1_sensor_async, asd);
>  	int source_pad;
>  	int ret;
>
> @@ -165,10 +165,10 @@ static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
>  	return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
>  }
>
> -static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asd)
> +static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asc)
>  {
>  	struct rkisp1_sensor_async *rk_asd =
> -		container_of(asd, struct rkisp1_sensor_async, asd);
> +		container_of(asc->asd, struct rkisp1_sensor_async, asd);
>
>  	fwnode_handle_put(rk_asd->source_ep);
>  }
> diff --git a/drivers/media/platform/ti/omap3isp/isp.h b/drivers/media/platform/ti/omap3isp/isp.h
> index 32ea70c8d2f9..a9d760fbf349 100644
> --- a/drivers/media/platform/ti/omap3isp/isp.h
> +++ b/drivers/media/platform/ti/omap3isp/isp.h
> @@ -220,7 +220,7 @@ struct isp_device {
>  };
>
>  struct isp_async_subdev {
> -	struct v4l2_async_connection asd;
> +	struct v4l2_async_subdev asd;
>  	struct isp_bus_cfg bus;
>  };
>
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 56ce40481ec4..4c3bd64d6a00 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -134,6 +134,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
>  }
>
>  static LIST_HEAD(subdev_head);
> +static LIST_HEAD(asd_head);
>  static LIST_HEAD(notifier_head);
>  static DEFINE_MUTEX(list_lock);
>
> @@ -304,13 +305,20 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  	struct v4l2_async_notifier *subdev_notifier;
>  	int ret;
>
> -	ret = v4l2_device_register_subdev(v4l2_dev, sd);
> -	if (ret < 0)
> -		return ret;
> +	if (!asc->asd->registered) {
> +		ret = v4l2_device_register_subdev(v4l2_dev, sd);
> +		if (ret < 0)
> +			return ret;
> +	}
>
>  	ret = v4l2_async_nf_call_bound(notifier, sd, asc);

This is the part that puzzles me the most: are we going to receive
multiple bound() calls for the same subdevice when matched on multiple
connections ? If that's the case, is this desirable ?

>  	if (ret < 0) {
> -		v4l2_device_unregister_subdev(sd);
> +		if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> +			dev_dbg(notifier_dev(notifier),
> +				"failed binding %pfw (%d)\n",
> +				asc->match.fwnode, ret);
> +		if (!asc->asd->registered)

This should probably be
		if (asc->asd->registered)
> +			v4l2_device_unregister_subdev(sd);
>  		return ret;
>  	}
>
> @@ -322,14 +330,26 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  	 */
>  	ret = v4l2_async_create_ancillary_links(notifier, sd);

Also this part seems suspicious if called multiple times for the same
subdevice when matched on multiple connections

Do we need to refcount the connections for each async sub-dev,
decrement at each match, and only when all of them are matched
operated on the subdevice ?
:

>  	if (ret) {
> +		if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> +			dev_dbg(notifier_dev(notifier),
> +				"failed creating links for %pfw (%d)\n",
> +				asc->match.fwnode, ret);
>  		v4l2_async_nf_call_unbind(notifier, sd, asc);
> -		v4l2_device_unregister_subdev(sd);
> +		list_del(&asc->asc_subdev_list);
> +		if (!asc->asd->registered)
> +			v4l2_device_unregister_subdev(sd);
>  		return ret;
>  	}
>
>  	list_del(&asc->waiting_list);
> -	sd->asd = asc;
> -	sd->notifier = notifier;
> +	if (!sd->asd) {
> +		WARN_ON(asc->asd->registered);
> +		sd->asd = asc->asd;
> +		sd->notifier = notifier;
> +		asc->asd->registered = true;
> +	} else {
> +		WARN_ON(sd->asd != asc->asd);
> +	}
>
>  	/* Move from the global subdevice list to notifier's done */
>  	list_move(&sd->async_list, &notifier->done_head);
> @@ -403,6 +423,21 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  	sd->asd = NULL;
>  }
>
> +static void v4l2_async_unbind_subdev_one(struct v4l2_async_notifier *notifier,
> +					 struct v4l2_subdev *sd, bool readd)
> +{
> +	struct v4l2_async_connection *asc, *tmp;
> +
> +	list_for_each_entry_safe(asc, tmp, &sd->asd->asc_head,
> +				 asc_subdev_list) {
> +		v4l2_async_nf_call_unbind(notifier, sd, asc);
> +		list_del(&asc->asc_subdev_list);
> +		if (readd)
> +			list_add_tail(&asc->waiting_list,
> +				      &notifier->waiting_head);
> +	}
> +}
> +
>  /* Unbind all sub-devices in the notifier tree. */
>  static void
>  v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> @@ -417,10 +452,8 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
>  		if (subdev_notifier)
>  			v4l2_async_nf_unbind_all_subdevs(subdev_notifier, true);
>
> -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> -		if (readd)
> -			list_add_tail(&sd->asd->waiting_list,
> -				      &notifier->waiting_head);
> +		v4l2_async_unbind_subdev_one(notifier, sd, readd);
> +
>  		v4l2_async_cleanup(sd);
>
>  		list_move(&sd->async_list, &subdev_head);
> @@ -445,8 +478,9 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
>  		if (WARN_ON(!sd->asd))
>  			continue;
>
> -		if (asc_equal(&sd->asd->match, match))
> -			return true;
> +		list_for_each_entry(asc, &sd->asd->asc_head, asc_list)
> +			if (asc_equal(&asc->match, match))
> +				return true;
>  	}
>
>  	return false;
> @@ -619,6 +653,18 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
>  }
>  EXPORT_SYMBOL(v4l2_async_nf_unregister);
>
> +static void release_async_subdev(struct kref *kref)
> +{
> +	struct v4l2_async_subdev *asd =
> +		container_of_const(kref, struct v4l2_async_subdev, kref);
> +
> +	list_del(&asd->asd_list);
> +
> +	WARN_ON(!list_empty(&asd->asc_head));
> +
> +	kfree(asd);
> +}
> +
>  static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_async_connection *asc, *tmp;
> @@ -627,16 +673,24 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
>  		return;
>
>  	list_for_each_entry_safe(asc, tmp, &notifier->asc_head, asc_list) {
> +		list_del(&asc->asc_list);
> +		v4l2_async_nf_call_destroy(notifier, asc);
> +
>  		switch (asc->match.type) {
>  		case V4L2_ASYNC_MATCH_FWNODE:
> +			pr_debug("release async connection for fwnode %pfw\n",
> +				 asc->match.fwnode);

Why pr_debug ? Can't you use notifier_dev() ?

>  			fwnode_handle_put(asc->match.fwnode);
>  			break;
> -		default:
> +		case V4L2_ASYNC_MATCH_I2C:
> +			pr_debug("release I²C async connection\n");
>  			break;
> +		default:
> +			pr_debug("release invalid async connection type %u\n",
> +				 asc->match.type);
>  		}
>
> -		list_del(&asc->asc_list);
> -		v4l2_async_nf_call_destroy(notifier, asc);
> +		kref_put(&asc->asd->kref, release_async_subdev);
>  		kfree(asc);
>  	}
>  }
> @@ -651,6 +705,71 @@ void v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
>  }
>  EXPORT_SYMBOL_GPL(v4l2_async_nf_cleanup);
>
> +static bool async_subdev_has_connection(struct v4l2_async_notifier *notifier,
> +					struct v4l2_async_subdev *asd,
> +					struct v4l2_async_connection *asc)
> +{
> +	struct v4l2_async_connection *__asc;
> +
> +	list_for_each_entry(__asc, &asd->asc_head, asc_subdev_list) {
> +		if (__asc->match.type != V4L2_ASYNC_MATCH_FWNODE)
> +			continue;
> +
> +		if (__asc->match.fwnode != asc->match.fwnode)
> +			continue;
> +
> +		dev_dbg(notifier_dev(notifier), "found!\n");

Such message without much context can quickly become noise

> +
> +		return true;
> +	}
> +
> +	return false;
> +}
> +
> +/* Find an async sub-device for the async connection. */
> +static int v4l2_async_find_async_subdev(struct v4l2_async_notifier *notifier,
> +					struct v4l2_async_connection *asc)
> +{
> +	struct v4l2_async_subdev *asd;
> +
> +	lockdep_assert_held(&list_lock);
> +
> +	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> +		dev_dbg(notifier_dev(notifier),
> +			"async: looking up subdev for %pfw\n",
> +			asc->match.fwnode);
> +
> +	/*
> +	 * Matching by endpoint nodes may mean there are multiple connections to
> +	 * a single device. This is only possible with fwnode matching.
> +	 */
> +	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE &&
> +	    fwnode_graph_is_endpoint(asc->match.fwnode)) {
> +		list_for_each_entry(asd, &asd_head, asd_list) {
> +			if (async_subdev_has_connection(notifier, asd, asc)) {
> +				kref_get(&asd->kref);
> +				goto found;
> +			}
> +		}
> +	}
> +
> +	dev_dbg(notifier_dev(notifier), "not found, allocating new one\n");
> +
> +	asd = kzalloc(sizeof(*asd), GFP_KERNEL);
> +	if (!asd)
> +		return -ENOMEM;
> +
> +	kref_init(&asd->kref);
> +	INIT_LIST_HEAD(&asd->asc_head);
> +	list_add(&asd->asd_list, &asd_head);
> +
> +found:
> +	list_add(&asc->asc_subdev_list, &asd->asc_head);
> +	asc->asd = asd;
> +
> +	return 0;
> +}
> +
>  int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
>  				   struct v4l2_async_connection *asc)
>  {
> @@ -662,6 +781,10 @@ int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
>  	if (ret)
>  		goto unlock;
>
> +	ret = v4l2_async_find_async_subdev(notifier, asc);
> +	if (ret)
> +		goto unlock;
> +
>  	list_add_tail(&asc->asc_list, &notifier->asc_head);
>
>  unlock:
> @@ -809,7 +932,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  		v4l2_async_nf_unbind_all_subdevs(subdev_notifier, false);
>
>  	if (sd->asd)
> -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> +		v4l2_async_unbind_subdev_one(notifier, sd, true);
>  	v4l2_async_cleanup(sd);
>
>  	mutex_unlock(&list_lock);
> @@ -832,10 +955,12 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>
>  	if (sd->asd) {
>  		struct v4l2_async_notifier *notifier = sd->notifier;
> +		struct v4l2_async_connection *asc;
>
> -		list_add(&sd->asd->waiting_list, &notifier->waiting_head);
> +		list_for_each_entry(asc, &sd->asd->asc_head, asc_subdev_list)
> +			list_add(&asc->waiting_list, &notifier->waiting_head);
>
> -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> +		v4l2_async_unbind_subdev_one(notifier, sd, true);
>  	}
>
>  	v4l2_async_cleanup(sd);
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 9cf383e81a16..750bf4ddb267 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -8,6 +8,7 @@
>  #ifndef V4L2_ASYNC_H
>  #define V4L2_ASYNC_H
>
> +#include <linux/kref.h>
>  #include <linux/list.h>
>  #include <linux/mutex.h>
>
> @@ -63,24 +64,47 @@ struct v4l2_async_match {
>  };
>
>  /**
> - * struct v4l2_async_connection - sub-device descriptor, as known to a bridge
> + * struct v4l2_async_subdev - sub-device descriptor
>   *
> + * @kref:	kref for refcounting the subdev
> + * @asd_list:	Entry in the list of async sub-devices
> + * @subdev_list: used to link struct v4l2_async_subdev objects, waiting to be
> + *		probed, to a notifier->waiting_head list
> + * @asc_head:	head for struct v4l2_async_connection.asd_list list
> + * @registered:	whether the sub-device has been registered
> + */
> +struct v4l2_async_subdev {
> +	struct kref kref;
> +	struct list_head asd_list;
> +	struct list_head subdev_list;

subdev_list is not used

> +	struct list_head asc_head;
> +	bool registered;
> +};
> +
> +/**
> + * struct v4l2_async_connection - sub-device connection descriptor, as known to
> + *				  a bridge
> + *
> + * @asd:	the async sub-device related to this connection
>   * @match:	struct of match type and per-bus type matching data sets
>   * @asc_list:	used to add struct v4l2_async_connection objects to the
>   *		master notifier @asc_list
>   * @waiting_list: used to link struct v4l2_async_connection objects, waiting to
>   *		be probed, to a notifier->waiting list
> + * @asc_subdev_list:	entry in struct v4l2_async_subdev.asc_head list
>   *
> - * When this struct is used as a member in a driver specific struct,
> - * the driver specific struct shall contain the &struct
> - * v4l2_async_connection as its first member.
> + * When this struct is used as a member in a driver specific struct, the driver
> + * specific struct shall contain the &struct v4l2_async_connection as its first
> + * member.
>   */
>  struct v4l2_async_connection {
> +	struct v4l2_async_subdev *asd;
>  	struct v4l2_async_match match;
>
>  	/* v4l2-async core private: not to be used by drivers */
>  	struct list_head asc_list;
>  	struct list_head waiting_list;
> +	struct list_head asc_subdev_list;
>  };
>
>  /**
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index a2cce11dda5c..d510fe6ea243 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -1063,7 +1063,7 @@ struct v4l2_subdev {
>  	struct device *dev;
>  	struct fwnode_handle *fwnode;
>  	struct list_head async_list;
> -	struct v4l2_async_connection *asd;
> +	struct v4l2_async_subdev *asd;
>  	struct v4l2_async_notifier *notifier;
>  	struct v4l2_async_notifier *subdev_notifier;
>  	struct v4l2_subdev_platform_data *pdata;
> --
> 2.30.2
>

^ permalink raw reply	[flat|nested] 73+ messages in thread

* [PATCH 19/18] media: v4l: Drop v4l2_async_nf_parse_fwnode_endpoints()
  2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
                   ` (17 preceding siblings ...)
  2023-03-30 11:58 ` [PATCH 18/18] Documentation: media: Document sub-device notifiers Sakari Ailus
@ 2023-04-14  9:14 ` Jacopo Mondi
  2023-04-25  1:06   ` Laurent Pinchart
  18 siblings, 1 reply; 73+ messages in thread
From: Jacopo Mondi @ 2023-04-14  9:14 UTC (permalink / raw)
  To: Sakari Ailus, linux-media
  Cc: Jacopo Mondi, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

The v4l2_async_nf_parse_fwnode_endpoints() function, part of
v4l2-fwnode.c, was an helper meant to register one async sub-dev
for each fwnode endpoint of a device.

The function is marked as deprecated in the documentation and is
actually not used anywhere anymore. Drop it and remove the helper
function v4l2_async_nf_fwnode_parse_endpoint() from v4l2-fwnode.c.

This change allows to make the helper function
__v4l2_async_nf_add_connection() visibility private to v4l2-async.c so
that there is no risk drivers can mistakenly use it.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 drivers/media/v4l2-core/v4l2-async.c  |  1 -
 drivers/media/v4l2-core/v4l2-fwnode.c | 97 ---------------------------
 include/media/v4l2-async.h            | 25 -------
 include/media/v4l2-fwnode.h           | 65 ------------------
 4 files changed, 188 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index c9874b3f411e..e4cd70da4814 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -782,7 +782,6 @@ int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
 	mutex_unlock(&list_lock);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_connection);
 
 struct v4l2_async_connection *
 __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 7f4fb6208b1f..a84af48ed4e3 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -798,103 +798,6 @@ int v4l2_fwnode_device_parse(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
 
-static int
-v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
-				    struct v4l2_async_notifier *notifier,
-				    struct fwnode_handle *endpoint,
-				    unsigned int asd_struct_size,
-				    parse_endpoint_func parse_endpoint)
-{
-	struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
-	struct v4l2_async_connection *asd;
-	int ret;
-
-	asd = kzalloc(asd_struct_size, GFP_KERNEL);
-	if (!asd)
-		return -ENOMEM;
-
-	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
-	asd->match.fwnode =
-		fwnode_graph_get_remote_port_parent(endpoint);
-	if (!asd->match.fwnode) {
-		dev_dbg(dev, "no remote endpoint found\n");
-		ret = -ENOTCONN;
-		goto out_err;
-	}
-
-	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
-	if (ret) {
-		dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
-			 ret);
-		goto out_err;
-	}
-
-	ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
-	if (ret == -ENOTCONN)
-		dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
-			vep.base.id);
-	else if (ret < 0)
-		dev_warn(dev,
-			 "driver could not parse port@%u/endpoint@%u (%d)\n",
-			 vep.base.port, vep.base.id, ret);
-	v4l2_fwnode_endpoint_free(&vep);
-	if (ret < 0)
-		goto out_err;
-
-	ret = __v4l2_async_nf_add_connection(notifier, asd);
-	if (ret < 0) {
-		/* not an error if asd already exists */
-		if (ret == -EEXIST)
-			ret = 0;
-		goto out_err;
-	}
-
-	return 0;
-
-out_err:
-	fwnode_handle_put(asd->match.fwnode);
-	kfree(asd);
-
-	return ret == -ENOTCONN ? 0 : ret;
-}
-
-int
-v4l2_async_nf_parse_fwnode_endpoints(struct device *dev,
-				     struct v4l2_async_notifier *notifier,
-				     size_t asd_struct_size,
-				     parse_endpoint_func parse_endpoint)
-{
-	struct fwnode_handle *fwnode;
-	int ret = 0;
-
-	if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_connection)))
-		return -EINVAL;
-
-	fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
-		struct fwnode_handle *dev_fwnode;
-		bool is_available;
-
-		dev_fwnode = fwnode_graph_get_port_parent(fwnode);
-		is_available = fwnode_device_is_available(dev_fwnode);
-		fwnode_handle_put(dev_fwnode);
-		if (!is_available)
-			continue;
-
-
-		ret = v4l2_async_nf_fwnode_parse_endpoint(dev, notifier,
-							  fwnode,
-							  asd_struct_size,
-							  parse_endpoint);
-		if (ret < 0)
-			break;
-	}
-
-	fwnode_handle_put(fwnode);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(v4l2_async_nf_parse_fwnode_endpoints);
-
 /*
  * v4l2_fwnode_reference_parse - parse references for async sub-devices
  * @dev: the device node the properties of which are parsed for references
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index cf2082e17fc4..44080543e1b9 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -167,8 +167,6 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
  * v4l2_async_nf_add_fwnode_remote(),
  * v4l2_async_nf_add_fwnode(),
  * v4l2_async_nf_add_i2c(),
- * __v4l2_async_nf_add_connection() or
- * v4l2_async_nf_parse_fwnode_endpoints().
  */
 void v4l2_async_nf_init(struct v4l2_device *v4l2_dev,
 			struct v4l2_async_notifier *notifier);
@@ -184,31 +182,10 @@ void v4l2_async_nf_init(struct v4l2_device *v4l2_dev,
  * v4l2_async_nf_add_fwnode_remote(),
  * v4l2_async_nf_add_fwnode(),
  * v4l2_async_nf_add_i2c(),
- * __v4l2_async_nf_add_connection() or
- * v4l2_async_nf_parse_fwnode_endpoints().
  */
 void v4l2_async_subdev_nf_init(struct v4l2_subdev *sd,
 			       struct v4l2_async_notifier *notifier);
 
-/**
- * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
- *				      master asc list.
- *
- * @notifier: pointer to &struct v4l2_async_notifier
- * @asc: pointer to &struct v4l2_async_connection
- *
- * \warning: Drivers should avoid using this function and instead use one of:
- * v4l2_async_nf_add_fwnode(),
- * v4l2_async_nf_add_fwnode_remote() or
- * v4l2_async_nf_add_i2c().
- *
- * Call this function before registering a notifier to link the provided @asc to
- * the notifiers master @asc_list. The @asc must be allocated with k*alloc() as
- * it will be freed by the framework when the notifier is destroyed.
- */
-int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
-				   struct v4l2_async_connection *asc);
-
 struct v4l2_async_connection *
 __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
 			   struct fwnode_handle *fwnode,
@@ -306,8 +283,6 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier);
  * v4l2_async_nf_add_fwnode_remote(),
  * v4l2_async_nf_add_fwnode(),
  * v4l2_async_nf_add_i2c(),
- * __v4l2_async_nf_add_connection() or
- * v4l2_async_nf_parse_fwnode_endpoints().
  *
  * There is no harm from calling v4l2_async_nf_cleanup() in other
  * cases as long as its memory has been zeroed after it has been
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index ebb83154abd5..f84fa73f041c 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -393,71 +393,6 @@ int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
 int v4l2_fwnode_device_parse(struct device *dev,
 			     struct v4l2_fwnode_device_properties *props);
 
-/**
- * typedef parse_endpoint_func - Driver's callback function to be called on
- *	each V4L2 fwnode endpoint.
- *
- * @dev: pointer to &struct device
- * @vep: pointer to &struct v4l2_fwnode_endpoint
- * @asd: pointer to &struct v4l2_async_connection
- *
- * Return:
- * * %0 on success
- * * %-ENOTCONN if the endpoint is to be skipped but this
- *   should not be considered as an error
- * * %-EINVAL if the endpoint configuration is invalid
- */
-typedef int (*parse_endpoint_func)(struct device *dev,
-				  struct v4l2_fwnode_endpoint *vep,
-				  struct v4l2_async_connection *asd);
-
-/**
- * v4l2_async_nf_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
- *						device node
- * @dev: the device the endpoints of which are to be parsed
- * @notifier: notifier for @dev
- * @asd_struct_size: size of the driver's async sub-device struct, including
- *		     sizeof(struct v4l2_async_connection). The &struct
- *		     v4l2_async_connection shall be the first member of
- *		     the driver's async sub-device struct, i.e. both
- *		     begin at the same memory address.
- * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
- *		    endpoint. Optional.
- *
- * DEPRECATED! This function is deprecated. Don't use it in new drivers.
- * Instead see an example in cio2_parse_firmware() function in
- * drivers/media/pci/intel/ipu3/ipu3-cio2.c .
- *
- * Parse the fwnode endpoints of the @dev device and populate the async sub-
- * devices list in the notifier. The @parse_endpoint callback function is
- * called for each endpoint with the corresponding async sub-device pointer to
- * let the caller initialize the driver-specific part of the async sub-device
- * structure.
- *
- * The notifier memory shall be zeroed before this function is called on the
- * notifier.
- *
- * This function may not be called on a registered notifier and may be called on
- * a notifier only once.
- *
- * The &struct v4l2_fwnode_endpoint passed to the callback function
- * @parse_endpoint is released once the function is finished. If there is a need
- * to retain that configuration, the user needs to allocate memory for it.
- *
- * Any notifier populated using this function must be released with a call to
- * v4l2_async_nf_cleanup() after it has been unregistered and the async
- * sub-devices are no longer in use, even if the function returned an error.
- *
- * Return: %0 on success, including when no async sub-devices are found
- *	   %-ENOMEM if memory allocation failed
- *	   %-EINVAL if graph or endpoint parsing failed
- *	   Other error codes as returned by @parse_endpoint
- */
-int
-v4l2_async_nf_parse_fwnode_endpoints(struct device *dev,
-				     struct v4l2_async_notifier *notifier,
-				     size_t asd_struct_size,
-				     parse_endpoint_func parse_endpoint);
 
 /* Helper macros to access the connector links. */
 
-- 
2.40.0


^ permalink raw reply related	[flat|nested] 73+ messages in thread

* Re: [PATCH 02/18] media: v4l: async: Add some debug prints
  2023-04-13 16:49   ` Jacopo Mondi
@ 2023-04-14 10:46     ` Sakari Ailus
  2023-04-21  8:18       ` Laurent Pinchart
  0 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-04-14 10:46 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Jacopo,

Many thanks for the review!

On Thu, Apr 13, 2023 at 06:49:52PM +0200, Jacopo Mondi wrote:
> Hi Sakari
> 
> On Thu, Mar 30, 2023 at 02:58:37PM +0300, Sakari Ailus wrote:
> > Just add some debug prints for V4L2 async sub-device matching process.
> > These might come useful in figuring out why things don't work as expected.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/v4l2-core/v4l2-async.c | 59 ++++++++++++++++++++++++----
> >  1 file changed, 52 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index 008a2a3e312e..6dd426c2ca68 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -75,6 +75,12 @@ static bool match_i2c(struct v4l2_async_notifier *notifier,
> >  #endif
> >  }
> >
> > +static struct device *notifier_dev(struct v4l2_async_notifier *notifier)
> > +{
> > +	return notifier->sd ? notifier->sd->dev : notifier->v4l2_dev ?
> > +		notifier->v4l2_dev->dev : NULL;
> > +}
> > +
> >  static bool
> >  match_fwnode_one(struct v4l2_async_notifier *notifier,
> >  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
> > @@ -86,13 +92,18 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> >  	bool sd_fwnode_is_ep;
> >  	struct device *dev;
> >
> > +	dev_dbg(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
> > +		sd_fwnode, asd->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 == asd->match.fwnode)
> > +	if (sd_fwnode == asd->match.fwnode) {
> > +		dev_dbg(sd->dev, "async: direct match found\n");
> >  		return true;
> > +	}
> >
> >  	/*
> >  	 * Otherwise, check if the sd fwnode and the asd fwnode refer to an
> > @@ -105,8 +116,10 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> >  	sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd_fwnode);
> >  	asd_fwnode_is_ep = fwnode_graph_is_endpoint(asd->match.fwnode);
> >
> > -	if (sd_fwnode_is_ep == asd_fwnode_is_ep)
> > +	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
> > +		dev_dbg(sd->dev, "async: matching node types\n");
> 
> "matching node type" is misleading as it suggests a match has been
> found. As both sd and asd are of the same type, I would use a
> message similar to the above
> 
> 		dev_dbg(sd->dev, "async: direct match failed\n");

As it seems further matching attempts will always produce more debug
prints, I'll just drop this altogether.

> 
> >  		return false;
> > +	}
> >
> >  	/*
> >  	 * The sd and asd fwnodes are of different types. Get the device fwnode
> > @@ -120,10 +133,15 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> >  		other_fwnode = sd_fwnode;
> >  	}
> >
> > +	dev_dbg(sd->dev, "async: fwnode compat match, need %pfw, trying %pfw\n",
> > +		dev_fwnode, other_fwnode);
> > +
> >  	fwnode_handle_put(dev_fwnode);
> >
> > -	if (dev_fwnode != other_fwnode)
> > +	if (dev_fwnode != other_fwnode) {
> > +		dev_dbg(sd->dev, "async: compat match not found\n");
> 
> and to be more consistent: "compat match failed"

I think it's in all cases either "found" or "not found" in this patch.

> 
> >  		return false;
> > +	}
> >
> >  	/*
> >  	 * We have a heterogeneous match. Retrieve the struct device of the side
> > @@ -143,12 +161,17 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> >  			   dev->driver->name);
> >  	}
> >
> > +	dev_dbg(sd->dev, "async: compat match found\n");
> > +
> >  	return true;
> >  }
> >
> >  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> >  			 struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> >  {
> > +	dev_dbg(sd->dev, "async: matching for notifier %pfw, sd %pfw\n",
> > +		dev_fwnode(notifier_dev(notifier)), sd->fwnode);
> > +
> >  	if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
> >  		return true;
> >
> > @@ -156,6 +179,8 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
> >  	if (IS_ERR_OR_NULL(sd->fwnode->secondary))
> >  		return false;
> >
> > +	dev_dbg(sd->dev, "async: trying secondary fwnode match\n");
> > +
> >  	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
> >  }
> >
> > @@ -247,16 +272,21 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
> >  {
> >  	struct v4l2_subdev *sd;
> >
> > -	if (!list_empty(&notifier->waiting))
> > +	if (!list_empty(&notifier->waiting)) {
> > +		dev_dbg(notifier_dev(notifier), "async: waiting for subdevs\n");
> >  		return false;
> > +	}
> >
> >  	list_for_each_entry(sd, &notifier->done, async_list) {
> >  		struct v4l2_async_notifier *subdev_notifier =
> >  			v4l2_async_find_subdev_notifier(sd);
> >
> >  		if (subdev_notifier &&
> > -		    !v4l2_async_nf_can_complete(subdev_notifier))
> > +		    !v4l2_async_nf_can_complete(subdev_notifier)) {
> > +			dev_dbg(notifier_dev(notifier),
> > +				"async: cannot complete\n");
> 
> These two will be printed out a lot of times, don't they ?

That may be, if you have many async sub-devices. Perhaps these could be
dropped --- the user will be able to find what is still pending via sysfs.

> 
> >  			return false;
> > +		}
> >  	}
> >
> >  	return true;
> > @@ -269,22 +299,32 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
> >  static int
> >  v4l2_async_nf_try_complete(struct v4l2_async_notifier *notifier)
> >  {
> > +	struct v4l2_async_notifier *__notifier = notifier;
> > +
> >  	/* Quick check whether there are still more sub-devices here. */
> >  	if (!list_empty(&notifier->waiting))
> >  		return 0;
> >
> > +	if (notifier->sd)
> > +		dev_dbg(notifier_dev(notifier), "async: trying to complete\n");
> > +
> >  	/* Check the entire notifier tree; find the root notifier first. */
> >  	while (notifier->parent)
> >  		notifier = notifier->parent;
> >
> >  	/* This is root if it has v4l2_dev. */
> > -	if (!notifier->v4l2_dev)
> > +	if (!notifier->v4l2_dev) {
> > +		dev_dbg(notifier_dev(__notifier),
> > +			"async: V4L2 device not available\n");
> 
> is this a BUG() ?

No. It's that we haven't got the root notifier with the V4L2 device. It
will presumably be found later on.

> 
> >  		return 0;
> > +	}
> >
> >  	/* Is everything ready? */
> >  	if (!v4l2_async_nf_can_complete(notifier))
> >  		return 0;
> >
> > +	dev_dbg(notifier_dev(__notifier), "async: complete\n");
> > +
> >  	return v4l2_async_nf_call_complete(notifier);
> >  }
> >
> > @@ -362,7 +402,12 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> >  	 */
> >  	subdev_notifier->parent = notifier;
> >
> > -	return v4l2_async_nf_try_all_subdevs(subdev_notifier);
> > +	ret = v4l2_async_nf_try_all_subdevs(subdev_notifier);
> > +
> > +	dev_dbg(sd->dev, "async: bound to %s's notifier (ret %d)\n",
> > +		dev_name(notifier_dev(notifier)), ret);
> > +
> > +	return ret;
> 
> This will only be print out if there's no subnotifier as a few lines
> above we return early. Is this intentional ?

Good point. I'll move it up, this is about the sub-device itself, not its
notifier.

> 
> >  }
> >
> >  /* Test all async sub-devices in a notifier for a match. */

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching
  2023-04-13 16:50   ` Jacopo Mondi
@ 2023-04-14 11:07     ` Sakari Ailus
  2023-04-24 19:20       ` Niklas Söderlund
  0 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-04-14 11:07 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon, niklas.soderlund

Hi Jacopo,

On Thu, Apr 13, 2023 at 06:50:04PM +0200, Jacopo Mondi wrote:
> Hi Sakari
> 
> On Thu, Mar 30, 2023 at 02:58:38PM +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.
> >
> 
> As you know I'm a bit debated.
> 
> Strict endpoint-matching requires one subdev to be registed per each
> endpoint, and this is tedious for drivers that have to register a
> subdev for each of its endpoints
> 
> Allowing a subdev to be matched multiple times on different endpoints
> gives a way for lazy drivers to take a shortcut and simplify their
> topologies to a single subdev, when they would actually need more.

I'd say this is really about interface design, not being "lazy". It depends
on the sub-device. Ideally the framework should be also as easy for drivers
drivers to use as possible.

What is not supported, though, is multiple sub-devices with a single device
node. Do we need that? At least I don't think I came across a driver that
would.

Although it would be relatively easy add this in form of a list of
endpoints, if there's a need to.

Also cc Niklas.

> 
> Also, knowing where this series is going, I wonder if this wouldn't be
> a good time to enforce all async subdevices to be registered with an
> endpoint. From a very quick look at the drivers we have in mainline
> only a few still use v4l2_async_nf_add_fwnode() and only 4 of them
> (camss, rcar_drif, am437x-vpfe, vpif_capture, xilinx_vipp) use as
> match.fwnode what the remote port parent.
> 
> I wonder if this would be a good occasione to enforce with a WARN() if
> !fwnode_graph_is_endpoint(fwnode) in v4l2_async_nf_add_fwnode() (or
> possibily, even remove that function and port all drivers to use
> vl2_async_nf_add_fwnode_remote(). I can help, if the above makes sense
> to you as well.

I prefer to keep things simple for drivers if possible, and this patch does
that by removing a noticeable number of lines from a few drivers.

> 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/i2c/adv748x/adv748x-csi2.c |  3 -
> >  drivers/media/i2c/max9286.c              | 14 +---
> >  drivers/media/i2c/rdacm20.c              | 15 +----
> >  drivers/media/i2c/rdacm21.c              | 15 +----
> >  drivers/media/i2c/tc358746.c             |  3 -
> >  drivers/media/v4l2-core/v4l2-async.c     | 86 ++++++------------------
> >  6 files changed, 24 insertions(+), 112 deletions(-)
> >
> > diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
> > index bd4f3fe0e309..3d830816243f 100644
> > --- a/drivers/media/i2c/adv748x/adv748x-csi2.c
> > +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
> > @@ -300,9 +300,6 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
> >  			    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 701038d6d19b..2d0f43e3fb9f 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;
> > -
> 
> 
> You should also remove the fwnode_handle_put() call from
> 
> static void max9286_v4l2_unregister(struct max9286_priv *priv)
> {
> 	fwnode_handle_put(priv->sd.fwnode);
> 	v4l2_async_unregister_subdev(&priv->sd);
> 	max9286_v4l2_notifier_unregister(priv);
> }

Thanks, I'll address these in v2.

> 
> >  	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 a2263fa825b5..ea1111152285 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;
> 
> Same for this driver and for rdacm21
> 
> > -
> >  	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:
> > diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> > index 9ccc56c30d3b..d67cfcb2e05a 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 4063754a6732..56f2b43d4edf 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;
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index 6dd426c2ca68..13fe0bdc70b6 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -86,84 +86,33 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> >  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
> >  		 struct v4l2_async_subdev *asd)
> >  {
> > -	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(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
> >  		sd_fwnode, asd->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 == asd->match.fwnode) {
> >  		dev_dbg(sd->dev, "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(asd->match.fwnode);
> > -
> > -	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
> > -		dev_dbg(sd->dev, "async: matching node types\n");
> > +	if (!fwnode_graph_is_endpoint(asd->match.fwnode)) {
> > +		dev_dbg(sd->dev,
> > +			"async: async subdev fwnode not endpoint, no match\n");
> 
> As per the previous patch I would just say "direct match failed";
> 
> >  		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 = asd->match.fwnode;
> > -	} else {
> > -		dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
> > -		other_fwnode = sd_fwnode;
> > -	}
> > -
> > -	dev_dbg(sd->dev, "async: fwnode compat match, need %pfw, trying %pfw\n",
> > -		dev_fwnode, other_fwnode);
> > +	asd_dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
> >
> > -	fwnode_handle_put(dev_fwnode);
> > +	ret = sd_fwnode == asd_dev_fwnode;
> >
> > -	if (dev_fwnode != other_fwnode) {
> > -		dev_dbg(sd->dev, "async: compat match not found\n");
> > -		return false;
> > -	}
> > +	fwnode_handle_put(asd_dev_fwnode);
> >
> > -	/*
> > -	 * 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(sd->dev, "async: compat match found\n");
> > +	dev_dbg(sd->dev, "async: device--endpoint match %sfound\n",
> 
> double '--'
> 
> However now that I think about it, a subdev will be matched agains a
> rather large number of async subdevs and most attempts will fail.. do
> we want a printout for each of them ?

Note that this will only happen if these debug prints are enabled. There
was recently a case where they would have been useful.

> 
> 
> > +		ret ? "" : "not ");
> >
> > -	return true;
> > +	return ret;
> >  }
> >
> >  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > @@ -804,12 +753,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. Issue a warning in that case. Once there is
> > +	 * certainty no driver no longer does this, remove the warning (and
> > +	 * compatibility code) below.
> >  	 */
> >  	if (!sd->fwnode && sd->dev)
> >  		sd->fwnode = dev_fwnode(sd->dev);
> > +	else if (WARN_ON(fwnode_graph_is_endpoint(sd->fwnode)))
> > +		sd->fwnode = fwnode_graph_get_port_parent(sd->fwnode);
> >
> >  	mutex_lock(&list_lock);
> >

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 05/18] media: v4l: async: Clean testing for duplicated async subdevs
  2023-04-13 16:58   ` Jacopo Mondi
@ 2023-04-14 11:16     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-14 11:16 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Jacopo,

On Thu, Apr 13, 2023 at 06:58:56PM +0200, Jacopo Mondi wrote:
> Hi Sakari
> 
> On Thu, Mar 30, 2023 at 02:58:40PM +0300, Sakari Ailus wrote:
> > There's a need to verify that a single async sub-device isn't being added
> > multiple times, this would be an error. This takes place at the time of
> > adding the async sub-device to the notifier's list as well as when the
> > notifier is added to the global notifier's list.
> >
> > Use the pointer to the sub-device for testing this instead of an index to
> > an array that is long gone.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/v4l2-core/v4l2-async.c | 18 ++++++++----------
> >  1 file changed, 8 insertions(+), 10 deletions(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index bb78e3618ab5..fc9ae22e2b47 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -456,21 +456,19 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> >
> >  /*
> >   * Find out whether an async sub-device was set up already or
> > - * whether it exists in a given notifier before @this_index.
> > - * If @this_index < 0, search the notifier's entire @asd_list.
> > + * whether it exists in a given notifier.
> >   */
> >  static bool
> >  v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> > -			       struct v4l2_async_subdev *asd, int this_index)
> > +			       struct v4l2_async_subdev *asd, bool skip_self)
> 
> is skip_self used ?

Yes, it should have been there. I'll add it for v2.

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 06/18] media: v4l: async: Only pass match information for async subdev validation
  2023-04-14  7:15   ` Jacopo Mondi
@ 2023-04-14 11:39     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-14 11:39 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Jacopo,

On Fri, Apr 14, 2023 at 09:15:23AM +0200, Jacopo Mondi wrote:
> >  static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
> > -				   struct v4l2_async_subdev *asd,
> > +				   struct v4l2_async_match *match,
> 
> I would have kept the asd here, but I presume having match here makes
> things easier in the next patches

The other fields won't be needed there, that's why I'd pass just the match
information.

> 
> 
> >  				   bool skip_self)
> >  {
> >  	struct device *dev =
> >  		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
> >
> > -	if (!asd)
> > +	if (!match)
> >  		return -EINVAL;
> 
> Match cannot be null, as it's a member of struct v4l2_async_subdev

Indeed. I'll add another patch to drop the check, it doesn't seem to be
needed to begin with.

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 07/18] media: v4l: async: Clean up list heads and entries
  2023-04-14  7:26   ` Jacopo Mondi
@ 2023-04-14 11:54     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-14 11:54 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Jacopo,

On Fri, Apr 14, 2023 at 09:26:21AM +0200, Jacopo Mondi wrote:
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index 0c4cffd081c9..425280b4d387 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -68,7 +68,7 @@ struct v4l2_async_match {
> >   * @match:	struct of match type and per-bus type matching data sets
> >   * @asd_list:	used to add struct v4l2_async_subdev objects to the
> >   *		master notifier @asd_list
> > - * @list:	used to link struct v4l2_async_subdev objects, waiting to be
> > + * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
> >   *		probed, to a notifier->waiting list
> 
> notifier->waiting_head

Thanks, I'll fix these for v2.

-- 
Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 08/18] media: v4l: async: Rename v4l2_async_subdev as v4l2_async_connection
  2023-04-14  8:22   ` Jacopo Mondi
@ 2023-04-14 12:17     ` Sakari Ailus
  2023-04-25  0:59       ` Laurent Pinchart
  0 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-04-14 12:17 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Jacopo,

On Fri, Apr 14, 2023 at 10:22:41AM +0200, Jacopo Mondi wrote:
> Hi Sakari
> 
> On Thu, Mar 30, 2023 at 02:58:43PM +0300, Sakari Ailus wrote:
> > This patch has been generated by:
> >
> > 	git grep -l v4l2_async_subdev | \
> > 		while read i; do \
> > 			spatch --sp-file async.spatch --in-place $i; done \
> > 			perl -i -pe 's/v4l2_async_\Ksubdev/connection/g' $i \
> > 		done
> >
> > While async.spatch looks like:
> >
> > @ name @
> > @@
> > - struct v4l2_async_subdev
> > + struct v4l2_async_connection
> >
> > Additionally, __v4l2_async_nf_add_subdev() has been renamed as
> > __v4l2_async_nf_add_connection(). Some manual editing has been performed
> > as well.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  .../driver-api/media/v4l2-subdev.rst          |  10 +-
> >  drivers/media/i2c/max9286.c                   |   9 +-
> >  drivers/media/i2c/st-mipid02.c                |   8 +-
> >  drivers/media/i2c/tc358746.c                  |   6 +-
> >  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  10 +-
> >  drivers/media/platform/atmel/atmel-isi.c      |   8 +-
> >  drivers/media/platform/atmel/atmel-isi.h      |   2 +-
> >  drivers/media/platform/cadence/cdns-csi2rx.c  |   6 +-
> >  drivers/media/platform/intel/pxa_camera.c     |  12 +-
> >  drivers/media/platform/marvell/cafe-driver.c  |   5 +-
> >  drivers/media/platform/marvell/mcam-core.c    |   4 +-
> >  drivers/media/platform/marvell/mmp-driver.c   |   4 +-
> >  .../platform/microchip/microchip-csi2dc.c     |   6 +-
> >  .../platform/microchip/microchip-isc-base.c   |   4 +-
> >  .../media/platform/microchip/microchip-isc.h  |   2 +-
> >  .../microchip/microchip-sama5d2-isc.c         |   4 +-
> >  .../microchip/microchip-sama7g5-isc.c         |   4 +-
> >  drivers/media/platform/nxp/imx-mipi-csis.c    |   6 +-
> >  drivers/media/platform/nxp/imx7-media-csi.c   |   6 +-
> >  drivers/media/platform/qcom/camss/camss.c     |   2 +-
> >  drivers/media/platform/qcom/camss/camss.h     |   2 +-
> >  drivers/media/platform/renesas/rcar-isp.c     |   8 +-
> >  .../platform/renesas/rcar-vin/rcar-core.c     |  18 +-
> >  .../platform/renesas/rcar-vin/rcar-csi2.c     |   8 +-
> >  .../platform/renesas/rcar-vin/rcar-vin.h      |   4 +-
> >  drivers/media/platform/renesas/rcar_drif.c    |   8 +-
> >  drivers/media/platform/renesas/renesas-ceu.c  |   6 +-
> >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  10 +-
> >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |   2 +-
> >  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   |   8 +-
> >  .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
> >  .../platform/rockchip/rkisp1/rkisp1-dev.c     |   4 +-
> >  .../platform/samsung/exynos4-is/media-dev.c   |   6 +-
> >  .../platform/samsung/exynos4-is/media-dev.h   |   2 +-
> >  drivers/media/platform/st/stm32/stm32-dcmi.c  |   8 +-
> >  .../platform/sunxi/sun4i-csi/sun4i_csi.c      |   6 +-
> >  .../sunxi/sun6i-csi/sun6i_csi_bridge.c        |   2 +-
> >  .../sunxi/sun6i-csi/sun6i_csi_bridge.h        |   2 +-
> >  .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c   |   6 +-
> >  .../sun8i_a83t_mipi_csi2.c                    |   6 +-
> >  .../media/platform/ti/am437x/am437x-vpfe.c    |   5 +-
> >  .../media/platform/ti/am437x/am437x-vpfe.h    |   2 +-
> >  drivers/media/platform/ti/cal/cal.c           |   6 +-
> >  .../media/platform/ti/davinci/vpif_capture.c  |   7 +-
> >  drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
> >  drivers/media/platform/video-mux.c            |   6 +-
> >  drivers/media/platform/xilinx/xilinx-vipp.c   |  24 +--
> >  drivers/media/v4l2-core/v4l2-async.c          | 166 +++++++++---------
> >  drivers/media/v4l2-core/v4l2-fwnode.c         |  14 +-
> >  .../media/deprecated/atmel/atmel-isc-base.c   |   4 +-
> >  .../media/deprecated/atmel/atmel-isc.h        |   2 +-
> >  .../deprecated/atmel/atmel-sama5d2-isc.c      |   4 +-
> >  .../deprecated/atmel/atmel-sama7g5-isc.c      |   4 +-
> >  drivers/staging/media/imx/imx-media-csi.c     |   6 +-
> >  .../staging/media/imx/imx-media-dev-common.c  |   4 +-
> >  drivers/staging/media/imx/imx-media-dev.c     |   2 +-
> >  drivers/staging/media/imx/imx-media-of.c      |   4 +-
> >  drivers/staging/media/imx/imx6-mipi-csi2.c    |   8 +-
> >  drivers/staging/media/imx/imx8mq-mipi-csi2.c  |   6 +-
> >  .../media/sunxi/sun6i-isp/sun6i_isp_proc.c    |   2 +-
> >  .../media/sunxi/sun6i-isp/sun6i_isp_proc.h    |   2 +-
> >  drivers/staging/media/tegra-video/vi.c        |  14 +-
> >  drivers/staging/media/tegra-video/vi.h        |   2 +-
> >  include/media/davinci/vpif_types.h            |   2 +-
> >  include/media/v4l2-async.h                    |  78 ++++----
> >  include/media/v4l2-fwnode.h                   |  10 +-
> >  include/media/v4l2-subdev.h                   |   4 +-
> >  67 files changed, 313 insertions(+), 313 deletions(-)
> >
> > diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst
> > index 260cfa8c3f3d..1c5cb1a637ab 100644
> > --- a/Documentation/driver-api/media/v4l2-subdev.rst
> > +++ b/Documentation/driver-api/media/v4l2-subdev.rst
> > @@ -215,13 +215,13 @@ found in firmware. The notifier for the sub-device is unregistered with the
> >  async sub-device.
> >
> >  These functions allocate an async sub-device descriptor which is of type struct
> > -:c:type:`v4l2_async_subdev` embedded in a driver-specific struct. The &struct
> > -:c:type:`v4l2_async_subdev` shall be the first member of this struct:
> > +:c:type:`v4l2_async_connection` embedded in a driver-specific struct. The &struct
> > +:c:type:`v4l2_async_connection` shall be the first member of this struct:
> >
> >  .. code-block:: c
> >
> >  	struct my_async_subdev {
> > -		struct v4l2_async_subdev asd;
> > +		struct v4l2_async_connection asd;
> >  		...
> >  	};
> >
> > @@ -244,10 +244,10 @@ notifier callback is called. After all subdevices have been located the
> >  system the .unbind() method is called. All three callbacks are optional.
> >
> >  Drivers can store any type of custom data in their driver-specific
> > -:c:type:`v4l2_async_subdev` wrapper. If any of that data requires special
> > +:c:type:`v4l2_async_connection` wrapper. If any of that data requires special
> >  handling when the structure is freed, drivers must implement the ``.destroy()``
> >  notifier callback. The framework will call it right before freeing the
> > -:c:type:`v4l2_async_subdev`.
> > +:c:type:`v4l2_async_connection`.
> >
> >  Calling subdev operations
> >  ~~~~~~~~~~~~~~~~~~~~~~~~~
> > diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
> > index 2d0f43e3fb9f..13cb2537a06d 100644
> 
> 
> [snip: I'll only comment framework changes as I presume if driver
> changes compile, they're good]
> 
> 
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index 425280b4d387..9cf383e81a16 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -63,23 +63,23 @@ struct v4l2_async_match {
> >  };
> >
> >  /**
> > - * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> > + * struct v4l2_async_connection - sub-device descriptor, as known to a bridge
> >   *
> >   * @match:	struct of match type and per-bus type matching data sets
> > - * @asd_list:	used to add struct v4l2_async_subdev objects to the
> > - *		master notifier @asd_list
> > - * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
> > - *		probed, to a notifier->waiting list
> > + * @asc_list:	used to add struct v4l2_async_connection objects to the
> > + *		master notifier @asc_list
> 
> notifier asc_head

Thanks!

> 
> > + * @waiting_list: used to link struct v4l2_async_connection objects, waiting to
> > + *		be probed, to a notifier->waiting list
> >   *
> >   * When this struct is used as a member in a driver specific struct,
> >   * the driver specific struct shall contain the &struct
> > - * v4l2_async_subdev as its first member.
> > + * v4l2_async_connection as its first member.
> >   */
> > -struct v4l2_async_subdev {
> > +struct v4l2_async_connection {
> >  	struct v4l2_async_match match;
> >
> >  	/* v4l2-async core private: not to be used by drivers */
> > -	struct list_head asd_list;
> > +	struct list_head asc_list;
> >  	struct list_head waiting_list;
> >  };
> >
> > @@ -89,17 +89,17 @@ struct v4l2_async_subdev {
> 
> For more context:
> 
>     * @bound:	        a subdevice driver has successfully probed one of the subdevices
> >   * @complete:	All subdevices have been probed successfully. The complete
> 
> the usage of the term "subdevice" when referring to connection is
> spread everywhere in documentation :/
> 
> But I mostly wonder, and I guess this is a comment on the next patch:
> do we now get multiple 'bound' calls for the same subdevice when
> matched on multiple connections ?

Correct. That isn't an issue for current drivers as the API before this set
only allowed a single downstream link per async sub-device. Some more of
the documentation probably needs to be reworked due to this.

> 
> 
> >   *		callback is only executed for the root notifier.
> >   * @unbind:	a subdevice is leaving
> > - * @destroy:	the asd is about to be freed
> > + * @destroy:	the asc is about to be freed
> >   */
> >  struct v4l2_async_notifier_operations {
> >  	int (*bound)(struct v4l2_async_notifier *notifier,
> >  		     struct v4l2_subdev *subdev,
> > -		     struct v4l2_async_subdev *asd);
> > +		     struct v4l2_async_connection *asc);
> >  	int (*complete)(struct v4l2_async_notifier *notifier);
> >  	void (*unbind)(struct v4l2_async_notifier *notifier,
> >  		       struct v4l2_subdev *subdev,
> > -		       struct v4l2_async_subdev *asd);
> > -	void (*destroy)(struct v4l2_async_subdev *asd);
> > +		       struct v4l2_async_connection *asc);
> > +	void (*destroy)(struct v4l2_async_connection *asc);
> >  };
> >
> >  /**
> > @@ -109,7 +109,7 @@ struct v4l2_async_notifier_operations {
> >   * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
> >   * @sd:		sub-device that registered the notifier, NULL otherwise
> >   * @parent:	parent notifier
> > - * @asd_head:	master list of struct v4l2_async_subdev
> > + * @asc_head:	master list of struct v4l2_async_subdev
> >   * @waiting_list: list of struct v4l2_async_subdev, waiting for their drivers
> >   * @done_head:	list of struct v4l2_subdev, already probed
> >   * @notifier_list: member in a global list of notifiers
> > @@ -119,7 +119,7 @@ struct v4l2_async_notifier {
> >  	struct v4l2_device *v4l2_dev;
> >  	struct v4l2_subdev *sd;
> >  	struct v4l2_async_notifier *parent;
> > -	struct list_head asd_head;
> > +	struct list_head asc_head;
> >  	struct list_head waiting_head;
> >  	struct list_head done_head;
> >  	struct list_head notifier_list;
> > @@ -137,75 +137,75 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
> >   *
> >   * @notifier: pointer to &struct v4l2_async_notifier
> >   *
> > - * This function initializes the notifier @asd_list. It must be called
> > + * This function initializes the notifier @asc_list. It must be called
> >   * before adding a subdevice to a notifier, using one of:
> >   * v4l2_async_nf_add_fwnode_remote(),
> >   * v4l2_async_nf_add_fwnode(),
> >   * v4l2_async_nf_add_i2c(),
> > - * __v4l2_async_nf_add_subdev() or
> > + * __v4l2_async_nf_add_connection() or
> >   * v4l2_async_nf_parse_fwnode_endpoints().
> >   */
> >  void v4l2_async_nf_init(struct v4l2_async_notifier *notifier);
> >
> >  /**
> > - * __v4l2_async_nf_add_subdev - Add an async subdev to the
> > - *				notifier's master asd list.
> > + * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
> > + *				      master asc list.
> >   *
> >   * @notifier: pointer to &struct v4l2_async_notifier
> > - * @asd: pointer to &struct v4l2_async_subdev
> > + * @asc: pointer to &struct v4l2_async_connection
> >   *
> >   * \warning: Drivers should avoid using this function and instead use one of:
> >   * v4l2_async_nf_add_fwnode(),
> >   * v4l2_async_nf_add_fwnode_remote() or
> >   * v4l2_async_nf_add_i2c().
> >   *
> > - * Call this function before registering a notifier to link the provided @asd to
> > - * the notifiers master @asd_list. The @asd must be allocated with k*alloc() as
> > + * Call this function before registering a notifier to link the provided @asc to
> > + * the notifiers master @asc_list. The @asc must be allocated with k*alloc() as
> >   * it will be freed by the framework when the notifier is destroyed.
> >   */
> > -int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
> > -			       struct v4l2_async_subdev *asd);
> > +int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> > +				   struct v4l2_async_connection *asc);
> >
> > -struct v4l2_async_subdev *
> > +struct v4l2_async_connection *
> >  __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
> >  			   struct fwnode_handle *fwnode,
> > -			   unsigned int asd_struct_size);
> > +			   unsigned int asc_struct_size);
> >  /**
> >   * v4l2_async_nf_add_fwnode - Allocate and add a fwnode async
> > - *				subdev to the notifier's master asd_list.
> > + *				subdev to the notifier's master asc_list.
> >   *
> >   * @notifier: pointer to &struct v4l2_async_notifier
> >   * @fwnode: fwnode handle of the sub-device to be matched, pointer to
> >   *	    &struct fwnode_handle
> >   * @type: Type of the driver's async sub-device struct. The &struct
> > - *	  v4l2_async_subdev shall be the first member of the driver's async
> > + *	  v4l2_async_connection shall be the first member of the driver's async
> >   *	  sub-device struct, i.e. both begin at the same memory address.
> >   *
> > - * Allocate a fwnode-matched asd of size asd_struct_size, and add it to the
> > - * notifiers @asd_list. The function also gets a reference of the fwnode which
> > + * Allocate a fwnode-matched asc of size asc_struct_size, and add it to the
> > + * notifiers @asc_list. The function also gets a reference of the fwnode which
> >   * is released later at notifier cleanup time.
> >   */
> >  #define v4l2_async_nf_add_fwnode(notifier, fwnode, type)		\
> >  	((type *)__v4l2_async_nf_add_fwnode(notifier, fwnode, sizeof(type)))
> >
> > -struct v4l2_async_subdev *
> > +struct v4l2_async_connection *
> >  __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
> >  				  struct fwnode_handle *endpoint,
> > -				  unsigned int asd_struct_size);
> > +				  unsigned int asc_struct_size);
> >  /**
> >   * v4l2_async_nf_add_fwnode_remote - Allocate and add a fwnode
> >   *						  remote async subdev to the
> > - *						  notifier's master asd_list.
> > + *						  notifier's master asc_list.
> >   *
> >   * @notifier: pointer to &struct v4l2_async_notifier
> >   * @ep: local endpoint pointing to the remote sub-device to be matched,
> >   *	pointer to &struct fwnode_handle
> >   * @type: Type of the driver's async sub-device struct. The &struct
> > - *	  v4l2_async_subdev shall be the first member of the driver's async
> > + *	  v4l2_async_connection shall be the first member of the driver's async
> >   *	  sub-device struct, i.e. both begin at the same memory address.
> >   *
> >   * Gets the remote endpoint of a given local endpoint, set it up for fwnode
> > - * matching and adds the async sub-device to the notifier's @asd_list. The
> > + * matching and adds the async sub-device to the notifier's @asc_list. The
> >   * function also gets a reference of the fwnode which is released later at
> >   * notifier cleanup time.
> >   *
> > @@ -215,19 +215,19 @@ __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
> >  #define v4l2_async_nf_add_fwnode_remote(notifier, ep, type) \
> >  	((type *)__v4l2_async_nf_add_fwnode_remote(notifier, ep, sizeof(type)))
> >
> > -struct v4l2_async_subdev *
> > +struct v4l2_async_connection *
> >  __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier,
> >  			int adapter_id, unsigned short address,
> > -			unsigned int asd_struct_size);
> > +			unsigned int asc_struct_size);
> >  /**
> >   * v4l2_async_nf_add_i2c - Allocate and add an i2c async
> > - *				subdev to the notifier's master asd_list.
> > + *				subdev to the notifier's master asc_list.
> >   *
> >   * @notifier: pointer to &struct v4l2_async_notifier
> >   * @adapter: I2C adapter ID to be matched
> >   * @address: I2C address of sub-device to be matched
> >   * @type: Type of the driver's async sub-device struct. The &struct
> > - *	  v4l2_async_subdev shall be the first member of the driver's async
> > + *	  v4l2_async_connection shall be the first member of the driver's async
> >   *	  sub-device struct, i.e. both begin at the same memory address.
> >   *
> >   * Same as v4l2_async_nf_add_fwnode() but for I2C matched
> > @@ -275,7 +275,7 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier);
> >   * v4l2_async_nf_add_fwnode_remote(),
> >   * v4l2_async_nf_add_fwnode(),
> >   * v4l2_async_nf_add_i2c(),
> > - * __v4l2_async_nf_add_subdev() or
> > + * __v4l2_async_nf_add_connection() or
> >   * v4l2_async_nf_parse_fwnode_endpoints().
> >   *
> >   * There is no harm from calling v4l2_async_nf_cleanup() in other
> > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > index 394d798f3dfa..ebb83154abd5 100644
> > --- a/include/media/v4l2-fwnode.h
> > +++ b/include/media/v4l2-fwnode.h
> > @@ -23,7 +23,7 @@
> >
> >  struct fwnode_handle;
> >  struct v4l2_async_notifier;
> > -struct v4l2_async_subdev;
> > +struct v4l2_async_connection;
> >
> >  /**
> >   * struct v4l2_fwnode_endpoint - the endpoint data structure
> > @@ -399,7 +399,7 @@ int v4l2_fwnode_device_parse(struct device *dev,
> >   *
> >   * @dev: pointer to &struct device
> >   * @vep: pointer to &struct v4l2_fwnode_endpoint
> > - * @asd: pointer to &struct v4l2_async_subdev
> > + * @asd: pointer to &struct v4l2_async_connection
> >   *
> >   * Return:
> >   * * %0 on success
> > @@ -409,7 +409,7 @@ int v4l2_fwnode_device_parse(struct device *dev,
> >   */
> >  typedef int (*parse_endpoint_func)(struct device *dev,
> >  				  struct v4l2_fwnode_endpoint *vep,
> > -				  struct v4l2_async_subdev *asd);
> > +				  struct v4l2_async_connection *asd);
> >
> >  /**
> >   * v4l2_async_nf_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
> 
> Ah nice this function is DEPRECATED and not used anywhere anymore.
> I'll send a patch on top of this series to drop it

Thanks! I'll toss it in.

> 
> > @@ -417,8 +417,8 @@ typedef int (*parse_endpoint_func)(struct device *dev,
> >   * @dev: the device the endpoints of which are to be parsed
> >   * @notifier: notifier for @dev
> >   * @asd_struct_size: size of the driver's async sub-device struct, including
> > - *		     sizeof(struct v4l2_async_subdev). The &struct
> > - *		     v4l2_async_subdev shall be the first member of
> > + *		     sizeof(struct v4l2_async_connection). The &struct
> > + *		     v4l2_async_connection shall be the first member of
> >   *		     the driver's async sub-device struct, i.e. both
> >   *		     begin at the same memory address.
> >   * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > index 17773be4a4ee..a2cce11dda5c 100644
> > --- a/include/media/v4l2-subdev.h
> > +++ b/include/media/v4l2-subdev.h
> > @@ -1021,7 +1021,7 @@ struct v4l2_subdev_platform_data {
> >   *	    either dev->of_node->fwnode or dev->fwnode (whichever is non-NULL).
> >   * @async_list: Links this subdev to a global subdev_list or @notifier->done
> >   *	list.
> > - * @asd: Pointer to respective &struct v4l2_async_subdev.
> > + * @asc: Pointer to respective &struct v4l2_async_connection.
> 
> this is still named 'asd' in code
> 

Fixed.

> 
> >   * @notifier: Pointer to the managing notifier.
> >   * @subdev_notifier: A sub-device notifier implicitly registered for the sub-
> >   *		     device using v4l2_async_register_subdev_sensor().
> > @@ -1063,7 +1063,7 @@ struct v4l2_subdev {
> >  	struct device *dev;
> >  	struct fwnode_handle *fwnode;
> >  	struct list_head async_list;
> > -	struct v4l2_async_subdev *asd;
> > +	struct v4l2_async_connection *asd;
> >  	struct v4l2_async_notifier *notifier;
> >  	struct v4l2_async_notifier *subdev_notifier;
> >  	struct v4l2_subdev_platform_data *pdata;

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 09/18] media: v4l: async: Differentiate connecting and creating sub-devices
  2023-04-14  8:52   ` Jacopo Mondi
@ 2023-04-14 13:35     ` Sakari Ailus
  2023-04-25  2:14       ` Laurent Pinchart
  0 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-04-14 13:35 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Jacopo,

Thanks for the thorough review.

On Fri, Apr 14, 2023 at 10:52:25AM +0200, Jacopo Mondi wrote:
> Hi Sakari
> 
> On Thu, Mar 30, 2023 at 02:58:44PM +0300, Sakari Ailus wrote:
> > When the v4l2-async framework was introduced, the use case for it was to
> > connect a camera sensor with a parallel receiver. Both tended to be rather
> > simple devices with a single connection between them.
> >
> > The framework has been since improved in multiple ways but there are
> > limitations that have remained, for instance the assumption an async
> > sub-device is connected towards a single notifier and via a single link
> > only.
> >
> > This patch adds an object that represents the device while an earlier
> > patch in the series re-purposed the old struct v4l2_async_subdev as the
> > connection.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
> >  .../platform/rockchip/rkisp1/rkisp1-dev.c     |   8 +-
> >  drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
> >  drivers/media/v4l2-core/v4l2-async.c          | 163 ++++++++++++++++--
> >  include/media/v4l2-async.h                    |  32 +++-
> >  include/media/v4l2-subdev.h                   |   2 +-
> >  6 files changed, 179 insertions(+), 30 deletions(-)
> >
> > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > index d30f0ecb1bfd..a1293c45aae1 100644
> > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > @@ -148,7 +148,7 @@ struct rkisp1_info {
> >   * @port:		port number (0: MIPI, 1: Parallel)
> >   */
> >  struct rkisp1_sensor_async {
> > -	struct v4l2_async_connection asd;
> > +	struct v4l2_async_subdev asd;
> >  	unsigned int index;
> >  	struct fwnode_handle *source_ep;
> >  	unsigned int lanes;
> > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > index 39fa98e6dbbc..5bdb1ecedf6a 100644
> > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > @@ -122,12 +122,12 @@ struct rkisp1_isr_data {
> >
> >  static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
> >  					struct v4l2_subdev *sd,
> > -					struct v4l2_async_connection *asd)
> > +					struct v4l2_async_connection *asc)
> >  {
> >  	struct rkisp1_device *rkisp1 =
> >  		container_of(notifier, struct rkisp1_device, notifier);
> >  	struct rkisp1_sensor_async *s_asd =
> > -		container_of(asd, struct rkisp1_sensor_async, asd);
> > +		container_of(asc->asd, struct rkisp1_sensor_async, asd);
> >  	int source_pad;
> >  	int ret;
> >
> > @@ -165,10 +165,10 @@ static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
> >  	return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
> >  }
> >
> > -static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asd)
> > +static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asc)
> >  {
> >  	struct rkisp1_sensor_async *rk_asd =
> > -		container_of(asd, struct rkisp1_sensor_async, asd);
> > +		container_of(asc->asd, struct rkisp1_sensor_async, asd);
> >
> >  	fwnode_handle_put(rk_asd->source_ep);
> >  }
> > diff --git a/drivers/media/platform/ti/omap3isp/isp.h b/drivers/media/platform/ti/omap3isp/isp.h
> > index 32ea70c8d2f9..a9d760fbf349 100644
> > --- a/drivers/media/platform/ti/omap3isp/isp.h
> > +++ b/drivers/media/platform/ti/omap3isp/isp.h
> > @@ -220,7 +220,7 @@ struct isp_device {
> >  };
> >
> >  struct isp_async_subdev {
> > -	struct v4l2_async_connection asd;
> > +	struct v4l2_async_subdev asd;
> >  	struct isp_bus_cfg bus;
> >  };
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index 56ce40481ec4..4c3bd64d6a00 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -134,6 +134,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
> >  }
> >
> >  static LIST_HEAD(subdev_head);
> > +static LIST_HEAD(asd_head);
> >  static LIST_HEAD(notifier_head);
> >  static DEFINE_MUTEX(list_lock);
> >
> > @@ -304,13 +305,20 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> >  	struct v4l2_async_notifier *subdev_notifier;
> >  	int ret;
> >
> > -	ret = v4l2_device_register_subdev(v4l2_dev, sd);
> > -	if (ret < 0)
> > -		return ret;
> > +	if (!asc->asd->registered) {
> > +		ret = v4l2_device_register_subdev(v4l2_dev, sd);
> > +		if (ret < 0)
> > +			return ret;
> > +	}
> >
> >  	ret = v4l2_async_nf_call_bound(notifier, sd, asc);
> 
> This is the part that puzzles me the most: are we going to receive
> multiple bound() calls for the same subdevice when matched on multiple
> connections ? If that's the case, is this desirable ?

Yes, that is the intent: we're dealing with connections, not to much
sub-devices as such. That is what the current bound callbacks generally do.
Some also deal with sub-devices but that's fine: driver changes may be
needed to add support for new functionality.

> 
> >  	if (ret < 0) {
> > -		v4l2_device_unregister_subdev(sd);
> > +		if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> > +			dev_dbg(notifier_dev(notifier),
> > +				"failed binding %pfw (%d)\n",
> > +				asc->match.fwnode, ret);
> > +		if (!asc->asd->registered)
> 
> This should probably be
> 		if (asc->asd->registered)

Oops! Well, almost. The sub-device should only be unregistered here if it
was just registered. But I'll fix it for v2.

> > +			v4l2_device_unregister_subdev(sd);
> >  		return ret;
> >  	}
> >
> > @@ -322,14 +330,26 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> >  	 */
> >  	ret = v4l2_async_create_ancillary_links(notifier, sd);
> 
> Also this part seems suspicious if called multiple times for the same
> subdevice when matched on multiple connections
> 
> Do we need to refcount the connections for each async sub-dev,
> decrement at each match, and only when all of them are matched
> operated on the subdevice ?
> :

The ancillary link can be created when the sub-device is registered so I
don't think we'll need to refcount it. I'll address this in v2.

> 
> >  	if (ret) {
> > +		if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> > +			dev_dbg(notifier_dev(notifier),
> > +				"failed creating links for %pfw (%d)\n",
> > +				asc->match.fwnode, ret);
> >  		v4l2_async_nf_call_unbind(notifier, sd, asc);
> > -		v4l2_device_unregister_subdev(sd);
> > +		list_del(&asc->asc_subdev_list);
> > +		if (!asc->asd->registered)
> > +			v4l2_device_unregister_subdev(sd);
> >  		return ret;
> >  	}
> >
> >  	list_del(&asc->waiting_list);
> > -	sd->asd = asc;
> > -	sd->notifier = notifier;
> > +	if (!sd->asd) {
> > +		WARN_ON(asc->asd->registered);
> > +		sd->asd = asc->asd;
> > +		sd->notifier = notifier;
> > +		asc->asd->registered = true;
> > +	} else {
> > +		WARN_ON(sd->asd != asc->asd);
> > +	}
> >
> >  	/* Move from the global subdevice list to notifier's done */
> >  	list_move(&sd->async_list, &notifier->done_head);
> > @@ -403,6 +423,21 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
> >  	sd->asd = NULL;
> >  }
> >
> > +static void v4l2_async_unbind_subdev_one(struct v4l2_async_notifier *notifier,
> > +					 struct v4l2_subdev *sd, bool readd)
> > +{
> > +	struct v4l2_async_connection *asc, *tmp;
> > +
> > +	list_for_each_entry_safe(asc, tmp, &sd->asd->asc_head,
> > +				 asc_subdev_list) {
> > +		v4l2_async_nf_call_unbind(notifier, sd, asc);
> > +		list_del(&asc->asc_subdev_list);
> > +		if (readd)
> > +			list_add_tail(&asc->waiting_list,
> > +				      &notifier->waiting_head);
> > +	}
> > +}
> > +
> >  /* Unbind all sub-devices in the notifier tree. */
> >  static void
> >  v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> > @@ -417,10 +452,8 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> >  		if (subdev_notifier)
> >  			v4l2_async_nf_unbind_all_subdevs(subdev_notifier, true);
> >
> > -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> > -		if (readd)
> > -			list_add_tail(&sd->asd->waiting_list,
> > -				      &notifier->waiting_head);
> > +		v4l2_async_unbind_subdev_one(notifier, sd, readd);
> > +
> >  		v4l2_async_cleanup(sd);
> >
> >  		list_move(&sd->async_list, &subdev_head);
> > @@ -445,8 +478,9 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> >  		if (WARN_ON(!sd->asd))
> >  			continue;
> >
> > -		if (asc_equal(&sd->asd->match, match))
> > -			return true;
> > +		list_for_each_entry(asc, &sd->asd->asc_head, asc_list)
> > +			if (asc_equal(&asc->match, match))
> > +				return true;
> >  	}
> >
> >  	return false;
> > @@ -619,6 +653,18 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
> >  }
> >  EXPORT_SYMBOL(v4l2_async_nf_unregister);
> >
> > +static void release_async_subdev(struct kref *kref)
> > +{
> > +	struct v4l2_async_subdev *asd =
> > +		container_of_const(kref, struct v4l2_async_subdev, kref);
> > +
> > +	list_del(&asd->asd_list);
> > +
> > +	WARN_ON(!list_empty(&asd->asc_head));
> > +
> > +	kfree(asd);
> > +}
> > +
> >  static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> >  {
> >  	struct v4l2_async_connection *asc, *tmp;
> > @@ -627,16 +673,24 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> >  		return;
> >
> >  	list_for_each_entry_safe(asc, tmp, &notifier->asc_head, asc_list) {
> > +		list_del(&asc->asc_list);
> > +		v4l2_async_nf_call_destroy(notifier, asc);
> > +
> >  		switch (asc->match.type) {
> >  		case V4L2_ASYNC_MATCH_FWNODE:
> > +			pr_debug("release async connection for fwnode %pfw\n",
> > +				 asc->match.fwnode);
> 
> Why pr_debug ? Can't you use notifier_dev() ?

The notifier is being cleaned up. We should have dev still around though,
so I'll change this.

> 
> >  			fwnode_handle_put(asc->match.fwnode);
> >  			break;
> > -		default:
> > +		case V4L2_ASYNC_MATCH_I2C:
> > +			pr_debug("release I²C async connection\n");
> >  			break;
> > +		default:
> > +			pr_debug("release invalid async connection type %u\n",
> > +				 asc->match.type);
> >  		}
> >
> > -		list_del(&asc->asc_list);
> > -		v4l2_async_nf_call_destroy(notifier, asc);
> > +		kref_put(&asc->asd->kref, release_async_subdev);
> >  		kfree(asc);
> >  	}
> >  }
> > @@ -651,6 +705,71 @@ void v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> >  }
> >  EXPORT_SYMBOL_GPL(v4l2_async_nf_cleanup);
> >
> > +static bool async_subdev_has_connection(struct v4l2_async_notifier *notifier,
> > +					struct v4l2_async_subdev *asd,
> > +					struct v4l2_async_connection *asc)
> > +{
> > +	struct v4l2_async_connection *__asc;
> > +
> > +	list_for_each_entry(__asc, &asd->asc_head, asc_subdev_list) {
> > +		if (__asc->match.type != V4L2_ASYNC_MATCH_FWNODE)
> > +			continue;
> > +
> > +		if (__asc->match.fwnode != asc->match.fwnode)
> > +			continue;
> > +
> > +		dev_dbg(notifier_dev(notifier), "found!\n");
> 
> Such message without much context can quickly become noise

I think I'll just drop it.

> 
> > +
> > +		return true;
> > +	}
> > +
> > +	return false;
> > +}
> > +
> > +/* Find an async sub-device for the async connection. */
> > +static int v4l2_async_find_async_subdev(struct v4l2_async_notifier *notifier,
> > +					struct v4l2_async_connection *asc)
> > +{
> > +	struct v4l2_async_subdev *asd;
> > +
> > +	lockdep_assert_held(&list_lock);
> > +
> > +	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> > +		dev_dbg(notifier_dev(notifier),
> > +			"async: looking up subdev for %pfw\n",
> > +			asc->match.fwnode);
> > +
> > +	/*
> > +	 * Matching by endpoint nodes may mean there are multiple connections to
> > +	 * a single device. This is only possible with fwnode matching.
> > +	 */
> > +	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE &&
> > +	    fwnode_graph_is_endpoint(asc->match.fwnode)) {
> > +		list_for_each_entry(asd, &asd_head, asd_list) {
> > +			if (async_subdev_has_connection(notifier, asd, asc)) {
> > +				kref_get(&asd->kref);
> > +				goto found;
> > +			}
> > +		}
> > +	}
> > +
> > +	dev_dbg(notifier_dev(notifier), "not found, allocating new one\n");
> > +
> > +	asd = kzalloc(sizeof(*asd), GFP_KERNEL);
> > +	if (!asd)
> > +		return -ENOMEM;
> > +
> > +	kref_init(&asd->kref);
> > +	INIT_LIST_HEAD(&asd->asc_head);
> > +	list_add(&asd->asd_list, &asd_head);
> > +
> > +found:
> > +	list_add(&asc->asc_subdev_list, &asd->asc_head);
> > +	asc->asd = asd;
> > +
> > +	return 0;
> > +}
> > +
> >  int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> >  				   struct v4l2_async_connection *asc)
> >  {
> > @@ -662,6 +781,10 @@ int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> >  	if (ret)
> >  		goto unlock;
> >
> > +	ret = v4l2_async_find_async_subdev(notifier, asc);
> > +	if (ret)
> > +		goto unlock;
> > +
> >  	list_add_tail(&asc->asc_list, &notifier->asc_head);
> >
> >  unlock:
> > @@ -809,7 +932,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
> >  		v4l2_async_nf_unbind_all_subdevs(subdev_notifier, false);
> >
> >  	if (sd->asd)
> > -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> > +		v4l2_async_unbind_subdev_one(notifier, sd, true);
> >  	v4l2_async_cleanup(sd);
> >
> >  	mutex_unlock(&list_lock);
> > @@ -832,10 +955,12 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
> >
> >  	if (sd->asd) {
> >  		struct v4l2_async_notifier *notifier = sd->notifier;
> > +		struct v4l2_async_connection *asc;
> >
> > -		list_add(&sd->asd->waiting_list, &notifier->waiting_head);
> > +		list_for_each_entry(asc, &sd->asd->asc_head, asc_subdev_list)
> > +			list_add(&asc->waiting_list, &notifier->waiting_head);
> >
> > -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> > +		v4l2_async_unbind_subdev_one(notifier, sd, true);
> >  	}
> >
> >  	v4l2_async_cleanup(sd);
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index 9cf383e81a16..750bf4ddb267 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -8,6 +8,7 @@
> >  #ifndef V4L2_ASYNC_H
> >  #define V4L2_ASYNC_H
> >
> > +#include <linux/kref.h>
> >  #include <linux/list.h>
> >  #include <linux/mutex.h>
> >
> > @@ -63,24 +64,47 @@ struct v4l2_async_match {
> >  };
> >
> >  /**
> > - * struct v4l2_async_connection - sub-device descriptor, as known to a bridge
> > + * struct v4l2_async_subdev - sub-device descriptor
> >   *
> > + * @kref:	kref for refcounting the subdev
> > + * @asd_list:	Entry in the list of async sub-devices
> > + * @subdev_list: used to link struct v4l2_async_subdev objects, waiting to be
> > + *		probed, to a notifier->waiting_head list
> > + * @asc_head:	head for struct v4l2_async_connection.asd_list list
> > + * @registered:	whether the sub-device has been registered
> > + */
> > +struct v4l2_async_subdev {
> > +	struct kref kref;
> > +	struct list_head asd_list;
> > +	struct list_head subdev_list;
> 
> subdev_list is not used

Thanks, I think I just forgot this here when splitting the two.

> 
> > +	struct list_head asc_head;
> > +	bool registered;
> > +};
> > +
> > +/**
> > + * struct v4l2_async_connection - sub-device connection descriptor, as known to
> > + *				  a bridge
> > + *
> > + * @asd:	the async sub-device related to this connection
> >   * @match:	struct of match type and per-bus type matching data sets
> >   * @asc_list:	used to add struct v4l2_async_connection objects to the
> >   *		master notifier @asc_list
> >   * @waiting_list: used to link struct v4l2_async_connection objects, waiting to
> >   *		be probed, to a notifier->waiting list
> > + * @asc_subdev_list:	entry in struct v4l2_async_subdev.asc_head list
> >   *
> > - * When this struct is used as a member in a driver specific struct,
> > - * the driver specific struct shall contain the &struct
> > - * v4l2_async_connection as its first member.
> > + * When this struct is used as a member in a driver specific struct, the driver
> > + * specific struct shall contain the &struct v4l2_async_connection as its first
> > + * member.
> >   */
> >  struct v4l2_async_connection {
> > +	struct v4l2_async_subdev *asd;
> >  	struct v4l2_async_match match;
> >
> >  	/* v4l2-async core private: not to be used by drivers */
> >  	struct list_head asc_list;
> >  	struct list_head waiting_list;
> > +	struct list_head asc_subdev_list;
> >  };
> >
> >  /**
> > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > index a2cce11dda5c..d510fe6ea243 100644
> > --- a/include/media/v4l2-subdev.h
> > +++ b/include/media/v4l2-subdev.h
> > @@ -1063,7 +1063,7 @@ struct v4l2_subdev {
> >  	struct device *dev;
> >  	struct fwnode_handle *fwnode;
> >  	struct list_head async_list;
> > -	struct v4l2_async_connection *asd;
> > +	struct v4l2_async_subdev *asd;
> >  	struct v4l2_async_notifier *notifier;
> >  	struct v4l2_async_notifier *subdev_notifier;
> >  	struct v4l2_subdev_platform_data *pdata;

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 02/18] media: v4l: async: Add some debug prints
  2023-04-14 10:46     ` Sakari Ailus
@ 2023-04-21  8:18       ` Laurent Pinchart
  2023-04-27  9:18         ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-21  8:18 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hello,

On Fri, Apr 14, 2023 at 01:46:54PM +0300, Sakari Ailus wrote:
> On Thu, Apr 13, 2023 at 06:49:52PM +0200, Jacopo Mondi wrote:
> > On Thu, Mar 30, 2023 at 02:58:37PM +0300, Sakari Ailus wrote:
> > > Just add some debug prints for V4L2 async sub-device matching process.
> > > These might come useful in figuring out why things don't work as expected.
> > >
> > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > ---
> > >  drivers/media/v4l2-core/v4l2-async.c | 59 ++++++++++++++++++++++++----
> > >  1 file changed, 52 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > > index 008a2a3e312e..6dd426c2ca68 100644
> > > --- a/drivers/media/v4l2-core/v4l2-async.c
> > > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > > @@ -75,6 +75,12 @@ static bool match_i2c(struct v4l2_async_notifier *notifier,
> > >  #endif
> > >  }
> > >
> > > +static struct device *notifier_dev(struct v4l2_async_notifier *notifier)
> > > +{
> > > +	return notifier->sd ? notifier->sd->dev : notifier->v4l2_dev ?
> > > +		notifier->v4l2_dev->dev : NULL;

Nested ?: operators can be confusing, I'd write

	if (notifier->sd)
		return notifier->sd->dev
	if (notifier->v4l2_dev)
		return notifier->v4l2_dev->dev;
	return NULL;

> > > +}
> > > +
> > >  static bool
> > >  match_fwnode_one(struct v4l2_async_notifier *notifier,
> > >  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
> > > @@ -86,13 +92,18 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > >  	bool sd_fwnode_is_ep;
> > >  	struct device *dev;
> > >
> > > +	dev_dbg(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",

"async:" is a bit too generic as a prefix. Maybe "v4l2_async:" or
"async_nf:" instead ?

> > > +		sd_fwnode, asd->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 == asd->match.fwnode)
> > > +	if (sd_fwnode == asd->match.fwnode) {
> > > +		dev_dbg(sd->dev, "async: direct match found\n");
> > >  		return true;
> > > +	}
> > >
> > >  	/*
> > >  	 * Otherwise, check if the sd fwnode and the asd fwnode refer to an
> > > @@ -105,8 +116,10 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > >  	sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd_fwnode);
> > >  	asd_fwnode_is_ep = fwnode_graph_is_endpoint(asd->match.fwnode);
> > >
> > > -	if (sd_fwnode_is_ep == asd_fwnode_is_ep)
> > > +	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
> > > +		dev_dbg(sd->dev, "async: matching node types\n");
> > 
> > "matching node type" is misleading as it suggests a match has been
> > found. As both sd and asd are of the same type, I would use a
> > message similar to the above
> > 
> > 		dev_dbg(sd->dev, "async: direct match failed\n");
> 
> As it seems further matching attempts will always produce more debug
> prints, I'll just drop this altogether.

I'm not sure what you mean here. Isn't it useful to have an explicit
message on failure ? I like Jacopo's proposal.

> > >  		return false;
> > > +	}
> > >
> > >  	/*
> > >  	 * The sd and asd fwnodes are of different types. Get the device fwnode
> > > @@ -120,10 +133,15 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > >  		other_fwnode = sd_fwnode;
> > >  	}
> > >
> > > +	dev_dbg(sd->dev, "async: fwnode compat match, need %pfw, trying %pfw\n",
> > > +		dev_fwnode, other_fwnode);
> > > +
> > >  	fwnode_handle_put(dev_fwnode);
> > >
> > > -	if (dev_fwnode != other_fwnode)
> > > +	if (dev_fwnode != other_fwnode) {
> > > +		dev_dbg(sd->dev, "async: compat match not found\n");
> > 
> > and to be more consistent: "compat match failed"
> 
> I think it's in all cases either "found" or "not found" in this patch.
> 
> > >  		return false;
> > > +	}
> > >
> > >  	/*
> > >  	 * We have a heterogeneous match. Retrieve the struct device of the side
> > > @@ -143,12 +161,17 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > >  			   dev->driver->name);
> > >  	}
> > >
> > > +	dev_dbg(sd->dev, "async: compat match found\n");
> > > +
> > >  	return true;
> > >  }
> > >
> > >  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > >  			 struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> > >  {
> > > +	dev_dbg(sd->dev, "async: matching for notifier %pfw, sd %pfw\n",

Maybe mentioning "fwnode" here ?

> > > +		dev_fwnode(notifier_dev(notifier)), sd->fwnode);

Is there a reason to print the notifier dev as a fwnode instead of using
dev_name() ?

I'm also wondering, wouldn't it be better to use notifier_dev(notifier)
as the dev argument to dev_dbg(), and print dev_name(sd->dev) in the
format string ? That's what you're doing below.

Also, sd->fwnode is printed in match_fwnode_one(), so you could possibly
drop it from here.

> > > +
> > >  	if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
> > >  		return true;
> > >
> > > @@ -156,6 +179,8 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > >  	if (IS_ERR_OR_NULL(sd->fwnode->secondary))
> > >  		return false;
> > >
> > > +	dev_dbg(sd->dev, "async: trying secondary fwnode match\n");
> > > +
> > >  	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
> > >  }
> > >
> > > @@ -247,16 +272,21 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
> > >  {
> > >  	struct v4l2_subdev *sd;
> > >
> > > -	if (!list_empty(&notifier->waiting))
> > > +	if (!list_empty(&notifier->waiting)) {
> > > +		dev_dbg(notifier_dev(notifier), "async: waiting for subdevs\n");
> > >  		return false;
> > > +	}
> > >
> > >  	list_for_each_entry(sd, &notifier->done, async_list) {
> > >  		struct v4l2_async_notifier *subdev_notifier =
> > >  			v4l2_async_find_subdev_notifier(sd);
> > >
> > >  		if (subdev_notifier &&
> > > -		    !v4l2_async_nf_can_complete(subdev_notifier))
> > > +		    !v4l2_async_nf_can_complete(subdev_notifier)) {
> > > +			dev_dbg(notifier_dev(notifier),
> > > +				"async: cannot complete\n");
> > 
> > These two will be printed out a lot of times, don't they ?
> 
> That may be, if you have many async sub-devices. Perhaps these could be
> dropped --- the user will be able to find what is still pending via sysfs.

I'm fine with that. If you want to keep the message, can you print the
subdev_notifier dev in the message here ?

> > >  			return false;
> > > +		}
> > >  	}
> > >
> > >  	return true;
> > > @@ -269,22 +299,32 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
> > >  static int
> > >  v4l2_async_nf_try_complete(struct v4l2_async_notifier *notifier)
> > >  {
> > > +	struct v4l2_async_notifier *__notifier = notifier;
> > > +
> > >  	/* Quick check whether there are still more sub-devices here. */
> > >  	if (!list_empty(&notifier->waiting))
> > >  		return 0;
> > >
> > > +	if (notifier->sd)
> > > +		dev_dbg(notifier_dev(notifier), "async: trying to complete\n");
> > > +
> > >  	/* Check the entire notifier tree; find the root notifier first. */
> > >  	while (notifier->parent)
> > >  		notifier = notifier->parent;
> > >
> > >  	/* This is root if it has v4l2_dev. */
> > > -	if (!notifier->v4l2_dev)
> > > +	if (!notifier->v4l2_dev) {
> > > +		dev_dbg(notifier_dev(__notifier),
> > > +			"async: V4L2 device not available\n");
> > 
> > is this a BUG() ?
> 
> No. It's that we haven't got the root notifier with the V4L2 device. It
> will presumably be found later on.
> 
> > >  		return 0;
> > > +	}
> > >
> > >  	/* Is everything ready? */
> > >  	if (!v4l2_async_nf_can_complete(notifier))
> > >  		return 0;
> > >
> > > +	dev_dbg(notifier_dev(__notifier), "async: complete\n");
> > > +
> > >  	return v4l2_async_nf_call_complete(notifier);
> > >  }
> > >
> > > @@ -362,7 +402,12 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> > >  	 */
> > >  	subdev_notifier->parent = notifier;
> > >
> > > -	return v4l2_async_nf_try_all_subdevs(subdev_notifier);
> > > +	ret = v4l2_async_nf_try_all_subdevs(subdev_notifier);
> > > +
> > > +	dev_dbg(sd->dev, "async: bound to %s's notifier (ret %d)\n",
> > > +		dev_name(notifier_dev(notifier)), ret);
> > > +
> > > +	return ret;
> > 
> > This will only be print out if there's no subnotifier as a few lines
> > above we return early. Is this intentional ?
> 
> Good point. I'll move it up, this is about the sub-device itself, not its
> notifier.
> 
> > >  }
> > >
> > >  /* Test all async sub-devices in a notifier for a match. */

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching
  2023-04-14 11:07     ` Sakari Ailus
@ 2023-04-24 19:20       ` Niklas Söderlund
  2023-04-24 19:33         ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Niklas Söderlund @ 2023-04-24 19:20 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, Laurent Pinchart,
	hverkuil, Francesco Dolcini, aishwarya.kothari, Robert Foss,
	Todor Tomov, Hyun Kwon

Hi Sakari,

On 2023-04-14 14:07:40 +0300, Sakari Ailus wrote:
> Hi Jacopo,
> 
> On Thu, Apr 13, 2023 at 06:50:04PM +0200, Jacopo Mondi wrote:
> > Hi Sakari
> > 
> > On Thu, Mar 30, 2023 at 02:58:38PM +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.
> > >
> > 
> > As you know I'm a bit debated.
> > 
> > Strict endpoint-matching requires one subdev to be registed per each
> > endpoint, and this is tedious for drivers that have to register a
> > subdev for each of its endpoints
> > 
> > Allowing a subdev to be matched multiple times on different endpoints
> > gives a way for lazy drivers to take a shortcut and simplify their
> > topologies to a single subdev, when they would actually need more.
> 
> I'd say this is really about interface design, not being "lazy". It depends
> on the sub-device. Ideally the framework should be also as easy for drivers
> drivers to use as possible.
> 
> What is not supported, though, is multiple sub-devices with a single device
> node. Do we need that? At least I don't think I came across a driver that
> would.

If I understand you correctly about multiple sub-device from a single 
device node, this exists today. The ADV748x driver have a single device 
node in DT and register multiple sub-devices, one for each source 
endpoint.

The ADV748x have two CSI-2 transmitters, one 4-lane and one 1-lane as 
well as two different video capture "ports" one HDMI and one CVBS. Both 
capture ports can be active at the same time and routed internally 
inside the ADV748x to the two different CSI-2 transmitters.

In order todo this the ADV748x register multiple subdevices and modifies 
the fwnode to be the endpoint instead of the device node. So the change 
in this patch for ADV748x driver would break that driver.

> 
> Although it would be relatively easy add this in form of a list of
> endpoints, if there's a need to.
> 
> Also cc Niklas.
> 
> > 
> > Also, knowing where this series is going, I wonder if this wouldn't be
> > a good time to enforce all async subdevices to be registered with an
> > endpoint. From a very quick look at the drivers we have in mainline
> > only a few still use v4l2_async_nf_add_fwnode() and only 4 of them
> > (camss, rcar_drif, am437x-vpfe, vpif_capture, xilinx_vipp) use as
> > match.fwnode what the remote port parent.
> > 
> > I wonder if this would be a good occasione to enforce with a WARN() if
> > !fwnode_graph_is_endpoint(fwnode) in v4l2_async_nf_add_fwnode() (or
> > possibily, even remove that function and port all drivers to use
> > vl2_async_nf_add_fwnode_remote(). I can help, if the above makes sense
> > to you as well.
> 
> I prefer to keep things simple for drivers if possible, and this patch does
> that by removing a noticeable number of lines from a few drivers.
> 
> > 
> > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > ---
> > >  drivers/media/i2c/adv748x/adv748x-csi2.c |  3 -
> > >  drivers/media/i2c/max9286.c              | 14 +---
> > >  drivers/media/i2c/rdacm20.c              | 15 +----
> > >  drivers/media/i2c/rdacm21.c              | 15 +----
> > >  drivers/media/i2c/tc358746.c             |  3 -
> > >  drivers/media/v4l2-core/v4l2-async.c     | 86 ++++++------------------
> > >  6 files changed, 24 insertions(+), 112 deletions(-)
> > >
> > > diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
> > > index bd4f3fe0e309..3d830816243f 100644
> > > --- a/drivers/media/i2c/adv748x/adv748x-csi2.c
> > > +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
> > > @@ -300,9 +300,6 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
> > >  			    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]);

I agree it's not nice, but dropping this would break this driver :-(

Nacked-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>

> > > -
> > >  	/* 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 701038d6d19b..2d0f43e3fb9f 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;
> > > -
> > 
> > 
> > You should also remove the fwnode_handle_put() call from
> > 
> > static void max9286_v4l2_unregister(struct max9286_priv *priv)
> > {
> > 	fwnode_handle_put(priv->sd.fwnode);
> > 	v4l2_async_unregister_subdev(&priv->sd);
> > 	max9286_v4l2_notifier_unregister(priv);
> > }
> 
> Thanks, I'll address these in v2.
> 
> > 
> > >  	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 a2263fa825b5..ea1111152285 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;
> > 
> > Same for this driver and for rdacm21
> > 
> > > -
> > >  	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:
> > > diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
> > > index 9ccc56c30d3b..d67cfcb2e05a 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 4063754a6732..56f2b43d4edf 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;
> > > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > > index 6dd426c2ca68..13fe0bdc70b6 100644
> > > --- a/drivers/media/v4l2-core/v4l2-async.c
> > > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > > @@ -86,84 +86,33 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > >  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
> > >  		 struct v4l2_async_subdev *asd)
> > >  {
> > > -	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(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
> > >  		sd_fwnode, asd->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 == asd->match.fwnode) {
> > >  		dev_dbg(sd->dev, "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(asd->match.fwnode);
> > > -
> > > -	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
> > > -		dev_dbg(sd->dev, "async: matching node types\n");
> > > +	if (!fwnode_graph_is_endpoint(asd->match.fwnode)) {
> > > +		dev_dbg(sd->dev,
> > > +			"async: async subdev fwnode not endpoint, no match\n");
> > 
> > As per the previous patch I would just say "direct match failed";
> > 
> > >  		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 = asd->match.fwnode;
> > > -	} else {
> > > -		dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
> > > -		other_fwnode = sd_fwnode;
> > > -	}
> > > -
> > > -	dev_dbg(sd->dev, "async: fwnode compat match, need %pfw, trying %pfw\n",
> > > -		dev_fwnode, other_fwnode);
> > > +	asd_dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
> > >
> > > -	fwnode_handle_put(dev_fwnode);
> > > +	ret = sd_fwnode == asd_dev_fwnode;
> > >
> > > -	if (dev_fwnode != other_fwnode) {
> > > -		dev_dbg(sd->dev, "async: compat match not found\n");
> > > -		return false;
> > > -	}
> > > +	fwnode_handle_put(asd_dev_fwnode);
> > >
> > > -	/*
> > > -	 * 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(sd->dev, "async: compat match found\n");
> > > +	dev_dbg(sd->dev, "async: device--endpoint match %sfound\n",
> > 
> > double '--'
> > 
> > However now that I think about it, a subdev will be matched agains a
> > rather large number of async subdevs and most attempts will fail.. do
> > we want a printout for each of them ?
> 
> Note that this will only happen if these debug prints are enabled. There
> was recently a case where they would have been useful.
> 
> > 
> > 
> > > +		ret ? "" : "not ");
> > >
> > > -	return true;
> > > +	return ret;
> > >  }
> > >
> > >  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > > @@ -804,12 +753,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. Issue a warning in that case. Once there is
> > > +	 * certainty no driver no longer does this, remove the warning (and
> > > +	 * compatibility code) below.
> > >  	 */
> > >  	if (!sd->fwnode && sd->dev)
> > >  		sd->fwnode = dev_fwnode(sd->dev);
> > > +	else if (WARN_ON(fwnode_graph_is_endpoint(sd->fwnode)))
> > > +		sd->fwnode = fwnode_graph_get_port_parent(sd->fwnode);
> > >
> > >  	mutex_lock(&list_lock);
> > >
> 
> -- 
> Kind regards,
> 
> Sakari Ailus

-- 
Kind Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching
  2023-04-24 19:20       ` Niklas Söderlund
@ 2023-04-24 19:33         ` Sakari Ailus
  2023-04-25  1:37           ` Laurent Pinchart
  0 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-04-24 19:33 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, Laurent Pinchart,
	hverkuil, Francesco Dolcini, aishwarya.kothari, Robert Foss,
	Todor Tomov, Hyun Kwon

Hi Niklas,

On Mon, Apr 24, 2023 at 09:20:22PM +0200, Niklas Söderlund wrote:
> Hi Sakari,
> 
> On 2023-04-14 14:07:40 +0300, Sakari Ailus wrote:
> > Hi Jacopo,
> > 
> > On Thu, Apr 13, 2023 at 06:50:04PM +0200, Jacopo Mondi wrote:
> > > Hi Sakari
> > > 
> > > On Thu, Mar 30, 2023 at 02:58:38PM +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.
> > > >
> > > 
> > > As you know I'm a bit debated.
> > > 
> > > Strict endpoint-matching requires one subdev to be registed per each
> > > endpoint, and this is tedious for drivers that have to register a
> > > subdev for each of its endpoints
> > > 
> > > Allowing a subdev to be matched multiple times on different endpoints
> > > gives a way for lazy drivers to take a shortcut and simplify their
> > > topologies to a single subdev, when they would actually need more.
> > 
> > I'd say this is really about interface design, not being "lazy". It depends
> > on the sub-device. Ideally the framework should be also as easy for drivers
> > drivers to use as possible.
> > 
> > What is not supported, though, is multiple sub-devices with a single device
> > node. Do we need that? At least I don't think I came across a driver that
> > would.
> 
> If I understand you correctly about multiple sub-device from a single 
> device node, this exists today. The ADV748x driver have a single device 
> node in DT and register multiple sub-devices, one for each source 
> endpoint.
> 
> The ADV748x have two CSI-2 transmitters, one 4-lane and one 1-lane as 
> well as two different video capture "ports" one HDMI and one CVBS. Both 
> capture ports can be active at the same time and routed internally 
> inside the ADV748x to the two different CSI-2 transmitters.
> 
> In order todo this the ADV748x register multiple subdevices and modifies 
> the fwnode to be the endpoint instead of the device node. So the change 
> in this patch for ADV748x driver would break that driver.

Ah, indeed. I guess I'll need to support that case as well then. It doesn't
seem to be troublesome to implement, but I'm tempted making it a special
case: every other driver would apparently be fine matching with device
fwnode whereas doing endpoint-to-endpoint matching adds complexity to the
drivers. This patch removes about 100 lines of rather ugly code largely
from v4l2-async.

There are other issues in the set with connection-subdev relations, I'll
post v2 to address those as well.

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 10/18] media: pxa_camera: Register V4L2 device early, fix probe error handling
  2023-03-30 11:58 ` [PATCH 10/18] media: pxa_camera: Register V4L2 device early, fix probe error handling Sakari Ailus
@ 2023-04-25  0:25   ` Laurent Pinchart
  2023-04-28 11:21     ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  0:25 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Sakari,

Thank you for the patch.

On Thu, Mar 30, 2023 at 02:58:45PM +0300, Sakari Ailus wrote:
> Register V4L2 device before initialising the notifier. This way the device
> is available to the notifier from the beginning.

Could you please explain in the commit message why this is needed ? Same
comment for subsequent patches in this series.

> Also fix error handling in probe.

Splitting this in two patches, with the fix first, would make it easier
to review.

> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/platform/intel/pxa_camera.c | 30 +++++++++++++----------
>  1 file changed, 17 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c
> index b848a2a9032f..31ae220ee4f3 100644
> --- a/drivers/media/platform/intel/pxa_camera.c
> +++ b/drivers/media/platform/intel/pxa_camera.c
> @@ -2289,6 +2289,10 @@ static int pxa_camera_probe(struct platform_device *pdev)
>  	if (IS_ERR(pcdev->clk))
>  		return PTR_ERR(pcdev->clk);
>  
> +	err = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
> +	if (err)
> +		return err;
> +
>  	v4l2_async_nf_init(&pcdev->notifier);
>  	pcdev->res = res;
>  	pcdev->pdata = pdev->dev.platform_data;
> @@ -2306,10 +2310,10 @@ static int pxa_camera_probe(struct platform_device *pdev)
>  	} else if (pdev->dev.of_node) {
>  		err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev);
>  	} else {
> -		return -ENODEV;
> +		err = -ENODEV;
>  	}
>  	if (err < 0)
> -		return err;
> +		goto exit_notifier_cleanup;
>  
>  	if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 |
>  			PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) {
> @@ -2342,8 +2346,10 @@ static int pxa_camera_probe(struct platform_device *pdev)
>  	 * Request the regions.
>  	 */
>  	base = devm_ioremap_resource(&pdev->dev, res);
> -	if (IS_ERR(base))
> -		return PTR_ERR(base);
> +	if (IS_ERR(base)) {
> +		err = PTR_ERR(base);
> +		goto exit_notifier_cleanup;
> +	}
>  
>  	pcdev->irq = irq;
>  	pcdev->base = base;
> @@ -2352,7 +2358,8 @@ static int pxa_camera_probe(struct platform_device *pdev)
>  	pcdev->dma_chans[0] = dma_request_chan(&pdev->dev, "CI_Y");
>  	if (IS_ERR(pcdev->dma_chans[0])) {
>  		dev_err(&pdev->dev, "Can't request DMA for Y\n");
> -		return PTR_ERR(pcdev->dma_chans[0]);
> +		err = PTR_ERR(pcdev->dma_chans[0]);
> +		goto exit_notifier_cleanup;
>  	}
>  
>  	pcdev->dma_chans[1] = dma_request_chan(&pdev->dev, "CI_U");
> @@ -2392,23 +2399,17 @@ static int pxa_camera_probe(struct platform_device *pdev)
>  	pxa_camera_activate(pcdev);
>  
>  	platform_set_drvdata(pdev, pcdev);
> -	err = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
> -	if (err)
> -		goto exit_deactivate;
>  
>  	err = pxa_camera_init_videobuf2(pcdev);
>  	if (err)
> -		goto exit_notifier_cleanup;
> +		goto exit_deactivate;
>  
>  	pcdev->notifier.ops = &pxa_camera_sensor_ops;
>  	err = v4l2_async_nf_register(&pcdev->v4l2_dev, &pcdev->notifier);
>  	if (err)
> -		goto exit_notifier_cleanup;
> +		goto exit_deactivate;
>  
>  	return 0;
> -exit_notifier_cleanup:
> -	v4l2_async_nf_cleanup(&pcdev->notifier);
> -	v4l2_device_unregister(&pcdev->v4l2_dev);
>  exit_deactivate:
>  	pxa_camera_deactivate(pcdev);
>  	tasklet_kill(&pcdev->task_eof);
> @@ -2418,6 +2419,9 @@ static int pxa_camera_probe(struct platform_device *pdev)
>  	dma_release_channel(pcdev->dma_chans[1]);
>  exit_free_dma_y:
>  	dma_release_channel(pcdev->dma_chans[0]);
> +exit_notifier_cleanup:
> +	v4l2_async_nf_cleanup(&pcdev->notifier);
> +	v4l2_device_unregister(&pcdev->v4l2_dev);
>  	return err;
>  }
>  

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 11/18] media: marvell: cafe: Register V4L2 device earlier
  2023-03-30 11:58 ` [PATCH 11/18] media: marvell: cafe: Register V4L2 device earlier Sakari Ailus
@ 2023-04-25  0:27   ` Laurent Pinchart
  2023-04-28 11:22     ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  0:27 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Sakari,

Thank you for the patch.

On Thu, Mar 30, 2023 at 02:58:46PM +0300, Sakari Ailus wrote:
> Register V4L2 device before the async notifier so the struct device will
> be available for the notifier.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/platform/marvell/cafe-driver.c | 12 ++++++++++--
>  drivers/media/platform/marvell/mcam-core.c   |  6 ------
>  2 files changed, 10 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/platform/marvell/cafe-driver.c b/drivers/media/platform/marvell/cafe-driver.c
> index dd1bba70bd79..4d8843623255 100644
> --- a/drivers/media/platform/marvell/cafe-driver.c
> +++ b/drivers/media/platform/marvell/cafe-driver.c
> @@ -536,6 +536,11 @@ static int cafe_pci_probe(struct pci_dev *pdev,
>  	if (ret)
>  		goto out_pdown;
>  
> +	ret = v4l2_device_register(mcam->dev, &mcam->v4l2_dev);
> +	if (ret)
> +		goto out_smbus_shutdown;
> +
> +
>  	v4l2_async_nf_init(&mcam->notifier);
>  
>  	asd = v4l2_async_nf_add_i2c(&mcam->notifier,
> @@ -544,12 +549,12 @@ static int cafe_pci_probe(struct pci_dev *pdev,
>  				    struct v4l2_async_connection);
>  	if (IS_ERR(asd)) {
>  		ret = PTR_ERR(asd);
> -		goto out_smbus_shutdown;
> +		goto out_v4l2_device_unregister;
>  	}
>  
>  	ret = mccic_register(mcam);
>  	if (ret)
> -		goto out_smbus_shutdown;
> +		goto out_v4l2_device_unregister;
>  
>  	clkdev_create(mcam->mclk, "xclk", "%d-%04x",
>  		i2c_adapter_id(cam->i2c_adapter), ov7670_info.addr);
> @@ -565,6 +570,8 @@ static int cafe_pci_probe(struct pci_dev *pdev,
>  
>  out_mccic_shutdown:
>  	mccic_shutdown(mcam);
> +out_v4l2_device_unregister:
> +	v4l2_device_unregister(&mcam->v4l2_dev);
>  out_smbus_shutdown:
>  	cafe_smbus_shutdown(cam);
>  out_pdown:
> @@ -587,6 +594,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
>  static void cafe_shutdown(struct cafe_camera *cam)
>  {
>  	mccic_shutdown(&cam->mcam);
> +	v4l2_device_unregister(&cam->mcam.v4l2_dev);
>  	cafe_smbus_shutdown(cam);
>  	free_irq(cam->pdev->irq, cam);
>  	pci_iounmap(cam->pdev, cam->mcam.regs);
> diff --git a/drivers/media/platform/marvell/mcam-core.c b/drivers/media/platform/marvell/mcam-core.c
> index b74a362ec075..2ecdcbcb37fd 100644
> --- a/drivers/media/platform/marvell/mcam-core.c
> +++ b/drivers/media/platform/marvell/mcam-core.c
> @@ -1866,10 +1866,6 @@ int mccic_register(struct mcam_camera *cam)
>  	/*
>  	 * Register with V4L
>  	 */
> -	ret = v4l2_device_register(cam->dev, &cam->v4l2_dev);
> -	if (ret)
> -		goto out;
> -
>  	mutex_init(&cam->s_mutex);
>  	cam->state = S_NOTREADY;
>  	mcam_set_config_needed(cam, 1);
> @@ -1915,7 +1911,6 @@ int mccic_register(struct mcam_camera *cam)
>  
>  out:
>  	v4l2_async_nf_unregister(&cam->notifier);
> -	v4l2_device_unregister(&cam->v4l2_dev);
>  	v4l2_async_nf_cleanup(&cam->notifier);

Wouldn't the v4l2_async_nf_* calls be better placed in cafe-driver.c,
given that v4l2_async_nf_init() is called there too ? Same below.

>  	return ret;
>  }
> @@ -1937,7 +1932,6 @@ void mccic_shutdown(struct mcam_camera *cam)
>  		mcam_free_dma_bufs(cam);
>  	v4l2_ctrl_handler_free(&cam->ctrl_handler);
>  	v4l2_async_nf_unregister(&cam->notifier);
> -	v4l2_device_unregister(&cam->v4l2_dev);
>  	v4l2_async_nf_cleanup(&cam->notifier);
>  }
>  EXPORT_SYMBOL_GPL(mccic_shutdown);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 14/18] media: xilinx-vipp: Init async notifier after registering V4L2 device
  2023-03-30 11:58 ` [PATCH 14/18] media: xilinx-vipp: Init async notifier after registering V4L2 device Sakari Ailus
@ 2023-04-25  0:31   ` Laurent Pinchart
  0 siblings, 0 replies; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  0:31 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Sakari,

Thank you for the patch.

On Thu, Mar 30, 2023 at 02:58:49PM +0300, Sakari Ailus wrote:
> Initialise the V4L2 async notifier after registering the V4L2 device, just
> before parsing DT for async sub-devices. This way struct device is
> available to the notifier right from the beginning.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
>  drivers/media/platform/xilinx/xilinx-vipp.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
> index 70e7a1f6ed3b..83430633ed28 100644
> --- a/drivers/media/platform/xilinx/xilinx-vipp.c
> +++ b/drivers/media/platform/xilinx/xilinx-vipp.c
> @@ -516,6 +516,8 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
>  		goto done;
>  	}
>  
> +	v4l2_async_nf_init(&xdev->notifier);
> +
>  	/* Parse the graph to extract a list of subdevice DT nodes. */
>  	ret = xvip_graph_parse(xdev);
>  	if (ret < 0) {
> @@ -596,7 +598,6 @@ static int xvip_composite_probe(struct platform_device *pdev)
>  
>  	xdev->dev = &pdev->dev;
>  	INIT_LIST_HEAD(&xdev->dmas);
> -	v4l2_async_nf_init(&xdev->notifier);
>  
>  	ret = xvip_composite_v4l2_init(xdev);
>  	if (ret < 0)

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 17/18] media: v4l: async: Set v4l2_device in async notifier init
  2023-03-30 11:58 ` [PATCH 17/18] media: v4l: async: Set v4l2_device in async notifier init Sakari Ailus
@ 2023-04-25  0:35   ` Laurent Pinchart
  2023-04-25  2:00     ` Laurent Pinchart
  2023-04-28 10:33     ` Sakari Ailus
  0 siblings, 2 replies; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  0:35 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Sakari,

Thank you for the patch.

On Thu, Mar 30, 2023 at 02:58:52PM +0300, Sakari Ailus wrote:
> Set the v4l2_device already in async notifier init, so struct device
> related to it will be available before the notifier is registered.
> 
> This patch has been mostly generated using the following command:
> 
> git grep -l v4l2_async_nf_init -- drivers/media/ drivers/staging/media/ |
> 	while read i; do perl -e '
> 	@a=<>; unlink("'$i'"); open(F, "> '$i'");
> 	for $f ({i=>"v4l2_async_nf_init", r=>"v4l2_async_nf_register"},
> 		{i=>"v4l2_async_subdev_nf_init",
> 		 r=>"v4l2_async_subdev_nf_register"} ) {
> 	my $b; @a = map { $b = "$1, $2" if
> 	s/$f->{r}\(([^,]*),\s*([^\)]*)\)/v4l2_async_nf_register\($2\)/;
> 	$_; } @a; @a = map { if (defined $b) {
> 	s/v4l2_async_nf_init\([^\)]*\)/$f->{i}\($b\)/;
> 	s/$f->{r}\(\K[^,]*,\s*//; }; $_; } @a; }; print F @a; close F;'
> 	< $i; done

You should learn coccinelle at some point :-)

> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/i2c/max9286.c                   |  4 +-
>  drivers/media/i2c/st-mipid02.c                |  4 +-
>  drivers/media/i2c/tc358746.c                  |  4 +-
>  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  4 +-
>  drivers/media/platform/atmel/atmel-isi.c      |  4 +-
>  drivers/media/platform/cadence/cdns-csi2rx.c  |  4 +-
>  drivers/media/platform/intel/pxa_camera.c     |  4 +-
>  drivers/media/platform/marvell/cafe-driver.c  |  2 +-
>  drivers/media/platform/marvell/mcam-core.c    |  2 +-
>  drivers/media/platform/marvell/mmp-driver.c   |  2 +-
>  .../platform/microchip/microchip-csi2dc.c     |  5 +--
>  .../microchip/microchip-sama5d2-isc.c         |  5 +--
>  .../microchip/microchip-sama7g5-isc.c         |  5 +--
>  drivers/media/platform/nxp/imx-mipi-csis.c    |  4 +-
>  drivers/media/platform/nxp/imx7-media-csi.c   |  4 +-
>  drivers/media/platform/qcom/camss/camss.c     |  5 +--
>  drivers/media/platform/renesas/rcar-isp.c     |  4 +-
>  .../platform/renesas/rcar-vin/rcar-core.c     |  8 ++--
>  .../platform/renesas/rcar-vin/rcar-csi2.c     |  4 +-
>  drivers/media/platform/renesas/rcar_drif.c    |  4 +-
>  drivers/media/platform/renesas/renesas-ceu.c  |  4 +-
>  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  4 +-
>  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   |  4 +-
>  .../platform/rockchip/rkisp1/rkisp1-dev.c     |  4 +-
>  .../platform/samsung/exynos4-is/media-dev.c   |  5 +--
>  drivers/media/platform/st/stm32/stm32-dcmi.c  |  4 +-
>  .../platform/sunxi/sun4i-csi/sun4i_csi.c      |  4 +-
>  .../sunxi/sun6i-csi/sun6i_csi_bridge.c        |  6 +--
>  .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c   |  4 +-
>  .../sun8i_a83t_mipi_csi2.c                    |  4 +-
>  .../media/platform/ti/am437x/am437x-vpfe.c    |  4 +-
>  drivers/media/platform/ti/cal/cal.c           |  4 +-
>  .../media/platform/ti/davinci/vpif_capture.c  | 11 ++---
>  drivers/media/platform/ti/omap3isp/isp.c      |  4 +-
>  drivers/media/platform/video-mux.c            |  4 +-
>  drivers/media/platform/xilinx/xilinx-vipp.c   |  4 +-
>  drivers/media/v4l2-core/v4l2-async.c          | 43 +++++++------------
>  drivers/media/v4l2-core/v4l2-fwnode.c         |  4 +-
>  .../deprecated/atmel/atmel-sama5d2-isc.c      |  5 +--
>  drivers/staging/media/imx/imx-media-csi.c     |  4 +-
>  .../staging/media/imx/imx-media-dev-common.c  |  4 +-
>  drivers/staging/media/imx/imx6-mipi-csi2.c    |  4 +-
>  drivers/staging/media/imx/imx8mq-mipi-csi2.c  |  4 +-
>  .../media/sunxi/sun6i-isp/sun6i_isp_proc.c    |  4 +-
>  drivers/staging/media/tegra-video/vi.c        |  4 +-
>  include/media/v4l2-async.h                    | 35 +++++++++------
>  46 files changed, 129 insertions(+), 138 deletions(-)

[snip]

> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 750bf4ddb267..cf2082e17fc4 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -159,6 +159,24 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
>  /**
>   * v4l2_async_nf_init - Initialize a notifier.
>   *
> + * @v4l2_dev: pointer to &struct v4l2_device
> + * @notifier: pointer to &struct v4l2_async_notifier
> + *
> + * This function initializes the notifier @asc_list. It must be called
> + * before adding a subdevice to a notifier, using one of:
> + * v4l2_async_nf_add_fwnode_remote(),
> + * v4l2_async_nf_add_fwnode(),
> + * v4l2_async_nf_add_i2c(),
> + * __v4l2_async_nf_add_connection() or
> + * v4l2_async_nf_parse_fwnode_endpoints().
> + */
> +void v4l2_async_nf_init(struct v4l2_device *v4l2_dev,
> +			struct v4l2_async_notifier *notifier);

The function operates on a notifier, could we make it the first argument
? Same for v4l2_async_subdev_nf_init().

> +
> +/**
> + * v4l2_async_subdev_nf_init - Initialize a sub-device notifier.
> + *
> + * @v4l2_dev: pointer to &struct v4l2_device
>   * @notifier: pointer to &struct v4l2_async_notifier
>   *
>   * This function initializes the notifier @asc_list. It must be called
> @@ -169,7 +187,8 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
>   * __v4l2_async_nf_add_connection() or
>   * v4l2_async_nf_parse_fwnode_endpoints().
>   */
> -void v4l2_async_nf_init(struct v4l2_async_notifier *notifier);
> +void v4l2_async_subdev_nf_init(struct v4l2_subdev *sd,
> +			       struct v4l2_async_notifier *notifier);
>  
>  /**
>   * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
> @@ -264,21 +283,9 @@ __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier,
>  /**
>   * v4l2_async_nf_register - registers a subdevice asynchronous notifier
>   *
> - * @v4l2_dev: pointer to &struct v4l2_device
> - * @notifier: pointer to &struct v4l2_async_notifier
> - */
> -int v4l2_async_nf_register(struct v4l2_device *v4l2_dev,
> -			   struct v4l2_async_notifier *notifier);
> -
> -/**
> - * v4l2_async_subdev_nf_register - registers a subdevice asynchronous
> - *					 notifier for a sub-device
> - *
> - * @sd: pointer to &struct v4l2_subdev
>   * @notifier: pointer to &struct v4l2_async_notifier
>   */
> -int v4l2_async_subdev_nf_register(struct v4l2_subdev *sd,
> -				  struct v4l2_async_notifier *notifier);
> +int v4l2_async_nf_register(struct v4l2_async_notifier *notifier);
>  
>  /**
>   * v4l2_async_nf_unregister - unregisters a subdevice

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 07/18] media: v4l: async: Clean up list heads and entries
  2023-03-30 11:58 ` [PATCH 07/18] media: v4l: async: Clean up list heads and entries Sakari Ailus
  2023-04-14  7:26   ` Jacopo Mondi
@ 2023-04-25  0:49   ` Laurent Pinchart
  2023-04-27 11:52     ` Sakari Ailus
  1 sibling, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  0:49 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Sakari,

Thank you for the patch.

On Thu, Mar 30, 2023 at 02:58:42PM +0300, Sakari Ailus wrote:
> The naming of list heads and list entries is confusing as they're named
> similarly. Use _head for list head and _list for list entries.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  2 +-
>  .../platform/renesas/rcar-vin/rcar-core.c     |  2 +-
>  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  2 +-
>  drivers/media/platform/xilinx/xilinx-vipp.c   | 10 +--
>  drivers/media/v4l2-core/v4l2-async.c          | 66 +++++++++----------
>  .../staging/media/imx/imx-media-dev-common.c  |  2 +-
>  drivers/staging/media/tegra-video/vi.c        |  6 +-
>  include/media/v4l2-async.h                    | 21 +++---
>  8 files changed, 56 insertions(+), 55 deletions(-)

[snip]

> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 0c4cffd081c9..425280b4d387 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -68,7 +68,7 @@ struct v4l2_async_match {
>   * @match:	struct of match type and per-bus type matching data sets
>   * @asd_list:	used to add struct v4l2_async_subdev objects to the
>   *		master notifier @asd_list

It's now called @asd_head.

> - * @list:	used to link struct v4l2_async_subdev objects, waiting to be
> + * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
>   *		probed, to a notifier->waiting list

It's now called notifier->waiting_head.

Please double-check comments and documentation to catch other
occurrences.

>   *
>   * When this struct is used as a member in a driver specific struct,
> @@ -77,9 +77,10 @@ struct v4l2_async_match {
>   */
>  struct v4l2_async_subdev {
>  	struct v4l2_async_match match;
> +
>  	/* v4l2-async core private: not to be used by drivers */
> -	struct list_head list;
>  	struct list_head asd_list;
> +	struct list_head waiting_list;
>  };
>  
>  /**
> @@ -108,20 +109,20 @@ struct v4l2_async_notifier_operations {
>   * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
>   * @sd:		sub-device that registered the notifier, NULL otherwise
>   * @parent:	parent notifier
> - * @asd_list:	master list of struct v4l2_async_subdev
> - * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
> - * @done:	list of struct v4l2_subdev, already probed
> - * @list:	member in a global list of notifiers
> + * @asd_head:	master list of struct v4l2_async_subdev
> + * @waiting_list: list of struct v4l2_async_subdev, waiting for their drivers
> + * @done_head:	list of struct v4l2_subdev, already probed
> + * @notifier_list: member in a global list of notifiers
>   */
>  struct v4l2_async_notifier {
>  	const struct v4l2_async_notifier_operations *ops;
>  	struct v4l2_device *v4l2_dev;
>  	struct v4l2_subdev *sd;
>  	struct v4l2_async_notifier *parent;
> -	struct list_head asd_list;
> -	struct list_head waiting;
> -	struct list_head done;
> -	struct list_head list;
> +	struct list_head asd_head;
> +	struct list_head waiting_head;
> +	struct list_head done_head;
> +	struct list_head notifier_list;

I find the _head suffix to still be confusing. How about the following ?

	struct {
		struct list_head all;
		struct list_head waiting;
		struct list_head done;
	} asds;

>  };
>  
>  /**

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 08/18] media: v4l: async: Rename v4l2_async_subdev as v4l2_async_connection
  2023-04-14 12:17     ` Sakari Ailus
@ 2023-04-25  0:59       ` Laurent Pinchart
  2023-04-28  9:33         ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  0:59 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari

On Fri, Apr 14, 2023 at 03:17:56PM +0300, Sakari Ailus wrote:
> On Fri, Apr 14, 2023 at 10:22:41AM +0200, Jacopo Mondi wrote:
> > On Thu, Mar 30, 2023 at 02:58:43PM +0300, Sakari Ailus wrote:
> > > This patch has been generated by:
> > >
> > > 	git grep -l v4l2_async_subdev | \
> > > 		while read i; do \
> > > 			spatch --sp-file async.spatch --in-place $i; done \
> > > 			perl -i -pe 's/v4l2_async_\Ksubdev/connection/g' $i \
> > > 		done
> > >
> > > While async.spatch looks like:
> > >
> > > @ name @
> > > @@
> > > - struct v4l2_async_subdev
> > > + struct v4l2_async_connection
> > >
> > > Additionally, __v4l2_async_nf_add_subdev() has been renamed as
> > > __v4l2_async_nf_add_connection(). Some manual editing has been performed
> > > as well.

The commit message fails to explain why.

> > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > ---
> > >  .../driver-api/media/v4l2-subdev.rst          |  10 +-
> > >  drivers/media/i2c/max9286.c                   |   9 +-
> > >  drivers/media/i2c/st-mipid02.c                |   8 +-
> > >  drivers/media/i2c/tc358746.c                  |   6 +-
> > >  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  10 +-
> > >  drivers/media/platform/atmel/atmel-isi.c      |   8 +-
> > >  drivers/media/platform/atmel/atmel-isi.h      |   2 +-
> > >  drivers/media/platform/cadence/cdns-csi2rx.c  |   6 +-
> > >  drivers/media/platform/intel/pxa_camera.c     |  12 +-
> > >  drivers/media/platform/marvell/cafe-driver.c  |   5 +-
> > >  drivers/media/platform/marvell/mcam-core.c    |   4 +-
> > >  drivers/media/platform/marvell/mmp-driver.c   |   4 +-
> > >  .../platform/microchip/microchip-csi2dc.c     |   6 +-
> > >  .../platform/microchip/microchip-isc-base.c   |   4 +-
> > >  .../media/platform/microchip/microchip-isc.h  |   2 +-
> > >  .../microchip/microchip-sama5d2-isc.c         |   4 +-
> > >  .../microchip/microchip-sama7g5-isc.c         |   4 +-
> > >  drivers/media/platform/nxp/imx-mipi-csis.c    |   6 +-
> > >  drivers/media/platform/nxp/imx7-media-csi.c   |   6 +-
> > >  drivers/media/platform/qcom/camss/camss.c     |   2 +-
> > >  drivers/media/platform/qcom/camss/camss.h     |   2 +-
> > >  drivers/media/platform/renesas/rcar-isp.c     |   8 +-
> > >  .../platform/renesas/rcar-vin/rcar-core.c     |  18 +-
> > >  .../platform/renesas/rcar-vin/rcar-csi2.c     |   8 +-
> > >  .../platform/renesas/rcar-vin/rcar-vin.h      |   4 +-
> > >  drivers/media/platform/renesas/rcar_drif.c    |   8 +-
> > >  drivers/media/platform/renesas/renesas-ceu.c  |   6 +-
> > >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  10 +-
> > >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |   2 +-
> > >  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   |   8 +-
> > >  .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
> > >  .../platform/rockchip/rkisp1/rkisp1-dev.c     |   4 +-
> > >  .../platform/samsung/exynos4-is/media-dev.c   |   6 +-
> > >  .../platform/samsung/exynos4-is/media-dev.h   |   2 +-
> > >  drivers/media/platform/st/stm32/stm32-dcmi.c  |   8 +-
> > >  .../platform/sunxi/sun4i-csi/sun4i_csi.c      |   6 +-
> > >  .../sunxi/sun6i-csi/sun6i_csi_bridge.c        |   2 +-
> > >  .../sunxi/sun6i-csi/sun6i_csi_bridge.h        |   2 +-
> > >  .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c   |   6 +-
> > >  .../sun8i_a83t_mipi_csi2.c                    |   6 +-
> > >  .../media/platform/ti/am437x/am437x-vpfe.c    |   5 +-
> > >  .../media/platform/ti/am437x/am437x-vpfe.h    |   2 +-
> > >  drivers/media/platform/ti/cal/cal.c           |   6 +-
> > >  .../media/platform/ti/davinci/vpif_capture.c  |   7 +-
> > >  drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
> > >  drivers/media/platform/video-mux.c            |   6 +-
> > >  drivers/media/platform/xilinx/xilinx-vipp.c   |  24 +--
> > >  drivers/media/v4l2-core/v4l2-async.c          | 166 +++++++++---------
> > >  drivers/media/v4l2-core/v4l2-fwnode.c         |  14 +-
> > >  .../media/deprecated/atmel/atmel-isc-base.c   |   4 +-
> > >  .../media/deprecated/atmel/atmel-isc.h        |   2 +-
> > >  .../deprecated/atmel/atmel-sama5d2-isc.c      |   4 +-
> > >  .../deprecated/atmel/atmel-sama7g5-isc.c      |   4 +-
> > >  drivers/staging/media/imx/imx-media-csi.c     |   6 +-
> > >  .../staging/media/imx/imx-media-dev-common.c  |   4 +-
> > >  drivers/staging/media/imx/imx-media-dev.c     |   2 +-
> > >  drivers/staging/media/imx/imx-media-of.c      |   4 +-
> > >  drivers/staging/media/imx/imx6-mipi-csi2.c    |   8 +-
> > >  drivers/staging/media/imx/imx8mq-mipi-csi2.c  |   6 +-
> > >  .../media/sunxi/sun6i-isp/sun6i_isp_proc.c    |   2 +-
> > >  .../media/sunxi/sun6i-isp/sun6i_isp_proc.h    |   2 +-
> > >  drivers/staging/media/tegra-video/vi.c        |  14 +-
> > >  drivers/staging/media/tegra-video/vi.h        |   2 +-
> > >  include/media/davinci/vpif_types.h            |   2 +-
> > >  include/media/v4l2-async.h                    |  78 ++++----
> > >  include/media/v4l2-fwnode.h                   |  10 +-
> > >  include/media/v4l2-subdev.h                   |   4 +-
> > >  67 files changed, 313 insertions(+), 313 deletions(-)
> > >
> > > diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst
> > > index 260cfa8c3f3d..1c5cb1a637ab 100644
> > > --- a/Documentation/driver-api/media/v4l2-subdev.rst
> > > +++ b/Documentation/driver-api/media/v4l2-subdev.rst
> > > @@ -215,13 +215,13 @@ found in firmware. The notifier for the sub-device is unregistered with the
> > >  async sub-device.
> > >
> > >  These functions allocate an async sub-device descriptor which is of type struct
> > > -:c:type:`v4l2_async_subdev` embedded in a driver-specific struct. The &struct
> > > -:c:type:`v4l2_async_subdev` shall be the first member of this struct:
> > > +:c:type:`v4l2_async_connection` embedded in a driver-specific struct. The &struct
> > > +:c:type:`v4l2_async_connection` shall be the first member of this struct:
> > >
> > >  .. code-block:: c
> > >
> > >  	struct my_async_subdev {
> > > -		struct v4l2_async_subdev asd;
> > > +		struct v4l2_async_connection asd;

s/asd/asc/

> > >  		...
> > >  	};
> > >
> > > @@ -244,10 +244,10 @@ notifier callback is called. After all subdevices have been located the
> > >  system the .unbind() method is called. All three callbacks are optional.
> > >
> > >  Drivers can store any type of custom data in their driver-specific
> > > -:c:type:`v4l2_async_subdev` wrapper. If any of that data requires special
> > > +:c:type:`v4l2_async_connection` wrapper. If any of that data requires special
> > >  handling when the structure is freed, drivers must implement the ``.destroy()``
> > >  notifier callback. The framework will call it right before freeing the
> > > -:c:type:`v4l2_async_subdev`.
> > > +:c:type:`v4l2_async_connection`.
> > >
> > >  Calling subdev operations
> > >  ~~~~~~~~~~~~~~~~~~~~~~~~~
> > > diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
> > > index 2d0f43e3fb9f..13cb2537a06d 100644
> > 
> > [snip: I'll only comment framework changes as I presume if driver
> > changes compile, they're good]
> > 
> > > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > > index 425280b4d387..9cf383e81a16 100644
> > > --- a/include/media/v4l2-async.h
> > > +++ b/include/media/v4l2-async.h
> > > @@ -63,23 +63,23 @@ struct v4l2_async_match {
> > >  };
> > >
> > >  /**
> > > - * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> > > + * struct v4l2_async_connection - sub-device descriptor, as known to a bridge
> > >   *
> > >   * @match:	struct of match type and per-bus type matching data sets
> > > - * @asd_list:	used to add struct v4l2_async_subdev objects to the
> > > - *		master notifier @asd_list
> > > - * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
> > > - *		probed, to a notifier->waiting list
> > > + * @asc_list:	used to add struct v4l2_async_connection objects to the
> > > + *		master notifier @asc_list
> > 
> > notifier asc_head
> 
> Thanks!
> 
> > > + * @waiting_list: used to link struct v4l2_async_connection objects, waiting to
> > > + *		be probed, to a notifier->waiting list
> > >   *
> > >   * When this struct is used as a member in a driver specific struct,
> > >   * the driver specific struct shall contain the &struct
> > > - * v4l2_async_subdev as its first member.
> > > + * v4l2_async_connection as its first member.
> > >   */
> > > -struct v4l2_async_subdev {
> > > +struct v4l2_async_connection {
> > >  	struct v4l2_async_match match;
> > >
> > >  	/* v4l2-async core private: not to be used by drivers */
> > > -	struct list_head asd_list;
> > > +	struct list_head asc_list;
> > >  	struct list_head waiting_list;
> > >  };
> > >
> > > @@ -89,17 +89,17 @@ struct v4l2_async_subdev {
> > 
> > For more context:
> > 
> >     * @bound:	        a subdevice driver has successfully probed one of the subdevices
> > >   * @complete:	All subdevices have been probed successfully. The complete
> > 
> > the usage of the term "subdevice" when referring to connection is
> > spread everywhere in documentation :/

I don't think I really like the name "connection" :-S Maybe that's
because it's not explained properly here, neither in the commit message
nor in the documentation. I may have better ideas when reviewing the
next patch, but I wonder if v4l2_async_nf_entry or v4l2_async_entry
would be a better name. It would also allow renaming the "asd" variables
to something more explicit.

> > But I mostly wonder, and I guess this is a comment on the next patch:
> > do we now get multiple 'bound' calls for the same subdevice when
> > matched on multiple connections ?
> 
> Correct. That isn't an issue for current drivers as the API before this set
> only allowed a single downstream link per async sub-device. Some more of
> the documentation probably needs to be reworked due to this.
> 
> > >   *		callback is only executed for the root notifier.
> > >   * @unbind:	a subdevice is leaving
> > > - * @destroy:	the asd is about to be freed
> > > + * @destroy:	the asc is about to be freed
> > >   */
> > >  struct v4l2_async_notifier_operations {
> > >  	int (*bound)(struct v4l2_async_notifier *notifier,
> > >  		     struct v4l2_subdev *subdev,
> > > -		     struct v4l2_async_subdev *asd);
> > > +		     struct v4l2_async_connection *asc);
> > >  	int (*complete)(struct v4l2_async_notifier *notifier);
> > >  	void (*unbind)(struct v4l2_async_notifier *notifier,
> > >  		       struct v4l2_subdev *subdev,
> > > -		       struct v4l2_async_subdev *asd);
> > > -	void (*destroy)(struct v4l2_async_subdev *asd);
> > > +		       struct v4l2_async_connection *asc);
> > > +	void (*destroy)(struct v4l2_async_connection *asc);
> > >  };
> > >
> > >  /**
> > > @@ -109,7 +109,7 @@ struct v4l2_async_notifier_operations {
> > >   * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
> > >   * @sd:		sub-device that registered the notifier, NULL otherwise
> > >   * @parent:	parent notifier
> > > - * @asd_head:	master list of struct v4l2_async_subdev
> > > + * @asc_head:	master list of struct v4l2_async_subdev
> > >   * @waiting_list: list of struct v4l2_async_subdev, waiting for their drivers
> > >   * @done_head:	list of struct v4l2_subdev, already probed
> > >   * @notifier_list: member in a global list of notifiers
> > > @@ -119,7 +119,7 @@ struct v4l2_async_notifier {
> > >  	struct v4l2_device *v4l2_dev;
> > >  	struct v4l2_subdev *sd;
> > >  	struct v4l2_async_notifier *parent;
> > > -	struct list_head asd_head;
> > > +	struct list_head asc_head;
> > >  	struct list_head waiting_head;
> > >  	struct list_head done_head;
> > >  	struct list_head notifier_list;
> > > @@ -137,75 +137,75 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
> > >   *
> > >   * @notifier: pointer to &struct v4l2_async_notifier
> > >   *
> > > - * This function initializes the notifier @asd_list. It must be called
> > > + * This function initializes the notifier @asc_list. It must be called
> > >   * before adding a subdevice to a notifier, using one of:
> > >   * v4l2_async_nf_add_fwnode_remote(),
> > >   * v4l2_async_nf_add_fwnode(),
> > >   * v4l2_async_nf_add_i2c(),
> > > - * __v4l2_async_nf_add_subdev() or
> > > + * __v4l2_async_nf_add_connection() or
> > >   * v4l2_async_nf_parse_fwnode_endpoints().
> > >   */
> > >  void v4l2_async_nf_init(struct v4l2_async_notifier *notifier);
> > >
> > >  /**
> > > - * __v4l2_async_nf_add_subdev - Add an async subdev to the
> > > - *				notifier's master asd list.
> > > + * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
> > > + *				      master asc list.
> > >   *
> > >   * @notifier: pointer to &struct v4l2_async_notifier
> > > - * @asd: pointer to &struct v4l2_async_subdev
> > > + * @asc: pointer to &struct v4l2_async_connection
> > >   *
> > >   * \warning: Drivers should avoid using this function and instead use one of:
> > >   * v4l2_async_nf_add_fwnode(),
> > >   * v4l2_async_nf_add_fwnode_remote() or
> > >   * v4l2_async_nf_add_i2c().
> > >   *
> > > - * Call this function before registering a notifier to link the provided @asd to
> > > - * the notifiers master @asd_list. The @asd must be allocated with k*alloc() as
> > > + * Call this function before registering a notifier to link the provided @asc to
> > > + * the notifiers master @asc_list. The @asc must be allocated with k*alloc() as
> > >   * it will be freed by the framework when the notifier is destroyed.
> > >   */
> > > -int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
> > > -			       struct v4l2_async_subdev *asd);
> > > +int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> > > +				   struct v4l2_async_connection *asc);
> > >
> > > -struct v4l2_async_subdev *
> > > +struct v4l2_async_connection *
> > >  __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
> > >  			   struct fwnode_handle *fwnode,
> > > -			   unsigned int asd_struct_size);
> > > +			   unsigned int asc_struct_size);
> > >  /**
> > >   * v4l2_async_nf_add_fwnode - Allocate and add a fwnode async
> > > - *				subdev to the notifier's master asd_list.
> > > + *				subdev to the notifier's master asc_list.
> > >   *
> > >   * @notifier: pointer to &struct v4l2_async_notifier
> > >   * @fwnode: fwnode handle of the sub-device to be matched, pointer to
> > >   *	    &struct fwnode_handle
> > >   * @type: Type of the driver's async sub-device struct. The &struct
> > > - *	  v4l2_async_subdev shall be the first member of the driver's async
> > > + *	  v4l2_async_connection shall be the first member of the driver's async
> > >   *	  sub-device struct, i.e. both begin at the same memory address.
> > >   *
> > > - * Allocate a fwnode-matched asd of size asd_struct_size, and add it to the
> > > - * notifiers @asd_list. The function also gets a reference of the fwnode which
> > > + * Allocate a fwnode-matched asc of size asc_struct_size, and add it to the
> > > + * notifiers @asc_list. The function also gets a reference of the fwnode which
> > >   * is released later at notifier cleanup time.
> > >   */
> > >  #define v4l2_async_nf_add_fwnode(notifier, fwnode, type)		\
> > >  	((type *)__v4l2_async_nf_add_fwnode(notifier, fwnode, sizeof(type)))
> > >
> > > -struct v4l2_async_subdev *
> > > +struct v4l2_async_connection *
> > >  __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
> > >  				  struct fwnode_handle *endpoint,
> > > -				  unsigned int asd_struct_size);
> > > +				  unsigned int asc_struct_size);
> > >  /**
> > >   * v4l2_async_nf_add_fwnode_remote - Allocate and add a fwnode
> > >   *						  remote async subdev to the
> > > - *						  notifier's master asd_list.
> > > + *						  notifier's master asc_list.
> > >   *
> > >   * @notifier: pointer to &struct v4l2_async_notifier
> > >   * @ep: local endpoint pointing to the remote sub-device to be matched,
> > >   *	pointer to &struct fwnode_handle
> > >   * @type: Type of the driver's async sub-device struct. The &struct
> > > - *	  v4l2_async_subdev shall be the first member of the driver's async
> > > + *	  v4l2_async_connection shall be the first member of the driver's async
> > >   *	  sub-device struct, i.e. both begin at the same memory address.
> > >   *
> > >   * Gets the remote endpoint of a given local endpoint, set it up for fwnode
> > > - * matching and adds the async sub-device to the notifier's @asd_list. The
> > > + * matching and adds the async sub-device to the notifier's @asc_list. The
> > >   * function also gets a reference of the fwnode which is released later at
> > >   * notifier cleanup time.
> > >   *
> > > @@ -215,19 +215,19 @@ __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
> > >  #define v4l2_async_nf_add_fwnode_remote(notifier, ep, type) \
> > >  	((type *)__v4l2_async_nf_add_fwnode_remote(notifier, ep, sizeof(type)))
> > >
> > > -struct v4l2_async_subdev *
> > > +struct v4l2_async_connection *
> > >  __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier,
> > >  			int adapter_id, unsigned short address,
> > > -			unsigned int asd_struct_size);
> > > +			unsigned int asc_struct_size);
> > >  /**
> > >   * v4l2_async_nf_add_i2c - Allocate and add an i2c async
> > > - *				subdev to the notifier's master asd_list.
> > > + *				subdev to the notifier's master asc_list.
> > >   *
> > >   * @notifier: pointer to &struct v4l2_async_notifier
> > >   * @adapter: I2C adapter ID to be matched
> > >   * @address: I2C address of sub-device to be matched
> > >   * @type: Type of the driver's async sub-device struct. The &struct
> > > - *	  v4l2_async_subdev shall be the first member of the driver's async
> > > + *	  v4l2_async_connection shall be the first member of the driver's async
> > >   *	  sub-device struct, i.e. both begin at the same memory address.
> > >   *
> > >   * Same as v4l2_async_nf_add_fwnode() but for I2C matched
> > > @@ -275,7 +275,7 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier);
> > >   * v4l2_async_nf_add_fwnode_remote(),
> > >   * v4l2_async_nf_add_fwnode(),
> > >   * v4l2_async_nf_add_i2c(),
> > > - * __v4l2_async_nf_add_subdev() or
> > > + * __v4l2_async_nf_add_connection() or
> > >   * v4l2_async_nf_parse_fwnode_endpoints().
> > >   *
> > >   * There is no harm from calling v4l2_async_nf_cleanup() in other
> > > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > > index 394d798f3dfa..ebb83154abd5 100644
> > > --- a/include/media/v4l2-fwnode.h
> > > +++ b/include/media/v4l2-fwnode.h
> > > @@ -23,7 +23,7 @@
> > >
> > >  struct fwnode_handle;
> > >  struct v4l2_async_notifier;
> > > -struct v4l2_async_subdev;
> > > +struct v4l2_async_connection;
> > >
> > >  /**
> > >   * struct v4l2_fwnode_endpoint - the endpoint data structure
> > > @@ -399,7 +399,7 @@ int v4l2_fwnode_device_parse(struct device *dev,
> > >   *
> > >   * @dev: pointer to &struct device
> > >   * @vep: pointer to &struct v4l2_fwnode_endpoint
> > > - * @asd: pointer to &struct v4l2_async_subdev
> > > + * @asd: pointer to &struct v4l2_async_connection

s/asd/asc/

> > >   *
> > >   * Return:
> > >   * * %0 on success
> > > @@ -409,7 +409,7 @@ int v4l2_fwnode_device_parse(struct device *dev,
> > >   */
> > >  typedef int (*parse_endpoint_func)(struct device *dev,
> > >  				  struct v4l2_fwnode_endpoint *vep,
> > > -				  struct v4l2_async_subdev *asd);
> > > +				  struct v4l2_async_connection *asd);

s/asd/asc/

> > >
> > >  /**
> > >   * v4l2_async_nf_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
> > 
> > Ah nice this function is DEPRECATED and not used anywhere anymore.
> > I'll send a patch on top of this series to drop it
> 
> Thanks! I'll toss it in.
> 
> > > @@ -417,8 +417,8 @@ typedef int (*parse_endpoint_func)(struct device *dev,
> > >   * @dev: the device the endpoints of which are to be parsed
> > >   * @notifier: notifier for @dev
> > >   * @asd_struct_size: size of the driver's async sub-device struct, including
> > > - *		     sizeof(struct v4l2_async_subdev). The &struct
> > > - *		     v4l2_async_subdev shall be the first member of
> > > + *		     sizeof(struct v4l2_async_connection). The &struct
> > > + *		     v4l2_async_connection shall be the first member of
> > >   *		     the driver's async sub-device struct, i.e. both
> > >   *		     begin at the same memory address.
> > >   * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> > > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > > index 17773be4a4ee..a2cce11dda5c 100644
> > > --- a/include/media/v4l2-subdev.h
> > > +++ b/include/media/v4l2-subdev.h
> > > @@ -1021,7 +1021,7 @@ struct v4l2_subdev_platform_data {
> > >   *	    either dev->of_node->fwnode or dev->fwnode (whichever is non-NULL).
> > >   * @async_list: Links this subdev to a global subdev_list or @notifier->done
> > >   *	list.
> > > - * @asd: Pointer to respective &struct v4l2_async_subdev.
> > > + * @asc: Pointer to respective &struct v4l2_async_connection.
> > 
> > this is still named 'asd' in code
> 
> Fixed.

"asd" used to stand for "Async SubDev". "asc" could be argued to stand
for "ASync Connection", but that's a weird acronym. Would "connection"
or "conn" be a better variable name ?

I'm also sure you'll dislike this, but I'd like driver code to be
changed to rename the variables too.

> > >   * @notifier: Pointer to the managing notifier.
> > >   * @subdev_notifier: A sub-device notifier implicitly registered for the sub-
> > >   *		     device using v4l2_async_register_subdev_sensor().
> > > @@ -1063,7 +1063,7 @@ struct v4l2_subdev {
> > >  	struct device *dev;
> > >  	struct fwnode_handle *fwnode;
> > >  	struct list_head async_list;
> > > -	struct v4l2_async_subdev *asd;
> > > +	struct v4l2_async_connection *asd;
> > >  	struct v4l2_async_notifier *notifier;
> > >  	struct v4l2_async_notifier *subdev_notifier;
> > >  	struct v4l2_subdev_platform_data *pdata;

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 19/18] media: v4l: Drop v4l2_async_nf_parse_fwnode_endpoints()
  2023-04-14  9:14 ` [PATCH 19/18] media: v4l: Drop v4l2_async_nf_parse_fwnode_endpoints() Jacopo Mondi
@ 2023-04-25  1:06   ` Laurent Pinchart
  2023-04-28 11:30     ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  1:06 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: Sakari Ailus, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Jacopo,

Thank you for the patch.

On Fri, Apr 14, 2023 at 11:14:37AM +0200, Jacopo Mondi wrote:
> The v4l2_async_nf_parse_fwnode_endpoints() function, part of
> v4l2-fwnode.c, was an helper meant to register one async sub-dev

s/an helper/a helper/

> for each fwnode endpoint of a device.
> 
> The function is marked as deprecated in the documentation and is
> actually not used anywhere anymore. Drop it and remove the helper
> function v4l2_async_nf_fwnode_parse_endpoint() from v4l2-fwnode.c.
> 
> This change allows to make the helper function
> __v4l2_async_nf_add_connection() visibility private to v4l2-async.c so
> that there is no risk drivers can mistakenly use it.
> 
> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c  |  1 -
>  drivers/media/v4l2-core/v4l2-fwnode.c | 97 ---------------------------
>  include/media/v4l2-async.h            | 25 -------
>  include/media/v4l2-fwnode.h           | 65 ------------------
>  4 files changed, 188 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index c9874b3f411e..e4cd70da4814 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -782,7 +782,6 @@ int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
>  	mutex_unlock(&list_lock);
>  	return ret;
>  }
> -EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_connection);
>  
>  struct v4l2_async_connection *
>  __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 7f4fb6208b1f..a84af48ed4e3 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -798,103 +798,6 @@ int v4l2_fwnode_device_parse(struct device *dev,
>  }
>  EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
>  
> -static int
> -v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
> -				    struct v4l2_async_notifier *notifier,
> -				    struct fwnode_handle *endpoint,
> -				    unsigned int asd_struct_size,
> -				    parse_endpoint_func parse_endpoint)
> -{
> -	struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
> -	struct v4l2_async_connection *asd;
> -	int ret;
> -
> -	asd = kzalloc(asd_struct_size, GFP_KERNEL);
> -	if (!asd)
> -		return -ENOMEM;
> -
> -	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
> -	asd->match.fwnode =
> -		fwnode_graph_get_remote_port_parent(endpoint);
> -	if (!asd->match.fwnode) {
> -		dev_dbg(dev, "no remote endpoint found\n");
> -		ret = -ENOTCONN;
> -		goto out_err;
> -	}
> -
> -	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
> -	if (ret) {
> -		dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
> -			 ret);
> -		goto out_err;
> -	}
> -
> -	ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
> -	if (ret == -ENOTCONN)
> -		dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
> -			vep.base.id);
> -	else if (ret < 0)
> -		dev_warn(dev,
> -			 "driver could not parse port@%u/endpoint@%u (%d)\n",
> -			 vep.base.port, vep.base.id, ret);
> -	v4l2_fwnode_endpoint_free(&vep);
> -	if (ret < 0)
> -		goto out_err;
> -
> -	ret = __v4l2_async_nf_add_connection(notifier, asd);
> -	if (ret < 0) {
> -		/* not an error if asd already exists */
> -		if (ret == -EEXIST)
> -			ret = 0;
> -		goto out_err;
> -	}
> -
> -	return 0;
> -
> -out_err:
> -	fwnode_handle_put(asd->match.fwnode);
> -	kfree(asd);
> -
> -	return ret == -ENOTCONN ? 0 : ret;
> -}
> -
> -int
> -v4l2_async_nf_parse_fwnode_endpoints(struct device *dev,
> -				     struct v4l2_async_notifier *notifier,
> -				     size_t asd_struct_size,
> -				     parse_endpoint_func parse_endpoint)
> -{
> -	struct fwnode_handle *fwnode;
> -	int ret = 0;
> -
> -	if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_connection)))
> -		return -EINVAL;
> -
> -	fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
> -		struct fwnode_handle *dev_fwnode;
> -		bool is_available;
> -
> -		dev_fwnode = fwnode_graph_get_port_parent(fwnode);
> -		is_available = fwnode_device_is_available(dev_fwnode);
> -		fwnode_handle_put(dev_fwnode);
> -		if (!is_available)
> -			continue;
> -
> -
> -		ret = v4l2_async_nf_fwnode_parse_endpoint(dev, notifier,
> -							  fwnode,
> -							  asd_struct_size,
> -							  parse_endpoint);
> -		if (ret < 0)
> -			break;
> -	}
> -
> -	fwnode_handle_put(fwnode);
> -
> -	return ret;
> -}
> -EXPORT_SYMBOL_GPL(v4l2_async_nf_parse_fwnode_endpoints);
> -
>  /*
>   * v4l2_fwnode_reference_parse - parse references for async sub-devices
>   * @dev: the device node the properties of which are parsed for references
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index cf2082e17fc4..44080543e1b9 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -167,8 +167,6 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
>   * v4l2_async_nf_add_fwnode_remote(),
>   * v4l2_async_nf_add_fwnode(),
>   * v4l2_async_nf_add_i2c(),

s/,/./

> - * __v4l2_async_nf_add_connection() or
> - * v4l2_async_nf_parse_fwnode_endpoints().
>   */
>  void v4l2_async_nf_init(struct v4l2_device *v4l2_dev,
>  			struct v4l2_async_notifier *notifier);
> @@ -184,31 +182,10 @@ void v4l2_async_nf_init(struct v4l2_device *v4l2_dev,
>   * v4l2_async_nf_add_fwnode_remote(),
>   * v4l2_async_nf_add_fwnode(),
>   * v4l2_async_nf_add_i2c(),

s/,/./

> - * __v4l2_async_nf_add_connection() or
> - * v4l2_async_nf_parse_fwnode_endpoints().
>   */
>  void v4l2_async_subdev_nf_init(struct v4l2_subdev *sd,
>  			       struct v4l2_async_notifier *notifier);
>  
> -/**
> - * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
> - *				      master asc list.
> - *
> - * @notifier: pointer to &struct v4l2_async_notifier
> - * @asc: pointer to &struct v4l2_async_connection
> - *
> - * \warning: Drivers should avoid using this function and instead use one of:
> - * v4l2_async_nf_add_fwnode(),
> - * v4l2_async_nf_add_fwnode_remote() or
> - * v4l2_async_nf_add_i2c().
> - *
> - * Call this function before registering a notifier to link the provided @asc to
> - * the notifiers master @asc_list. The @asc must be allocated with k*alloc() as
> - * it will be freed by the framework when the notifier is destroyed.
> - */

You could move this documentation to the .c file (dropping the warning).
There's little documentation of internal function for v4l2-async, which
makes the code hard to understand. Let's not make it worse by dropping
existing documentation :-)

> -int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> -				   struct v4l2_async_connection *asc);
> -
>  struct v4l2_async_connection *
>  __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
>  			   struct fwnode_handle *fwnode,
> @@ -306,8 +283,6 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier);
>   * v4l2_async_nf_add_fwnode_remote(),
>   * v4l2_async_nf_add_fwnode(),
>   * v4l2_async_nf_add_i2c(),

s/,/./

> - * __v4l2_async_nf_add_connection() or
> - * v4l2_async_nf_parse_fwnode_endpoints().
>   *
>   * There is no harm from calling v4l2_async_nf_cleanup() in other
>   * cases as long as its memory has been zeroed after it has been
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index ebb83154abd5..f84fa73f041c 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -393,71 +393,6 @@ int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
>  int v4l2_fwnode_device_parse(struct device *dev,
>  			     struct v4l2_fwnode_device_properties *props);
>  
> -/**
> - * typedef parse_endpoint_func - Driver's callback function to be called on
> - *	each V4L2 fwnode endpoint.
> - *
> - * @dev: pointer to &struct device
> - * @vep: pointer to &struct v4l2_fwnode_endpoint
> - * @asd: pointer to &struct v4l2_async_connection
> - *
> - * Return:
> - * * %0 on success
> - * * %-ENOTCONN if the endpoint is to be skipped but this
> - *   should not be considered as an error
> - * * %-EINVAL if the endpoint configuration is invalid
> - */
> -typedef int (*parse_endpoint_func)(struct device *dev,
> -				  struct v4l2_fwnode_endpoint *vep,
> -				  struct v4l2_async_connection *asd);
> -
> -/**
> - * v4l2_async_nf_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
> - *						device node
> - * @dev: the device the endpoints of which are to be parsed
> - * @notifier: notifier for @dev
> - * @asd_struct_size: size of the driver's async sub-device struct, including
> - *		     sizeof(struct v4l2_async_connection). The &struct
> - *		     v4l2_async_connection shall be the first member of
> - *		     the driver's async sub-device struct, i.e. both
> - *		     begin at the same memory address.
> - * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> - *		    endpoint. Optional.
> - *
> - * DEPRECATED! This function is deprecated. Don't use it in new drivers.
> - * Instead see an example in cio2_parse_firmware() function in
> - * drivers/media/pci/intel/ipu3/ipu3-cio2.c .
> - *
> - * Parse the fwnode endpoints of the @dev device and populate the async sub-
> - * devices list in the notifier. The @parse_endpoint callback function is
> - * called for each endpoint with the corresponding async sub-device pointer to
> - * let the caller initialize the driver-specific part of the async sub-device
> - * structure.
> - *
> - * The notifier memory shall be zeroed before this function is called on the
> - * notifier.
> - *
> - * This function may not be called on a registered notifier and may be called on
> - * a notifier only once.
> - *
> - * The &struct v4l2_fwnode_endpoint passed to the callback function
> - * @parse_endpoint is released once the function is finished. If there is a need
> - * to retain that configuration, the user needs to allocate memory for it.
> - *
> - * Any notifier populated using this function must be released with a call to
> - * v4l2_async_nf_cleanup() after it has been unregistered and the async
> - * sub-devices are no longer in use, even if the function returned an error.
> - *
> - * Return: %0 on success, including when no async sub-devices are found
> - *	   %-ENOMEM if memory allocation failed
> - *	   %-EINVAL if graph or endpoint parsing failed
> - *	   Other error codes as returned by @parse_endpoint
> - */
> -int
> -v4l2_async_nf_parse_fwnode_endpoints(struct device *dev,
> -				     struct v4l2_async_notifier *notifier,
> -				     size_t asd_struct_size,
> -				     parse_endpoint_func parse_endpoint);
>  
>  /* Helper macros to access the connector links. */
>  

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 04/18] media: v4l: async: Make V4L2 async match information a struct
  2023-03-30 11:58 ` [PATCH 04/18] media: v4l: async: Make V4L2 async match information a struct Sakari Ailus
  2023-04-13 16:51   ` Jacopo Mondi
@ 2023-04-25  1:10   ` Laurent Pinchart
  2023-04-27 10:36     ` Sakari Ailus
  1 sibling, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  1:10 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Sakari,

Thank you for the patch.

On Thu, Mar 30, 2023 at 02:58:39PM +0300, Sakari Ailus wrote:
> Make V4L2 async match information a struct, making it easier to use it
> elsewhere outside the scope of struct v4l2_async_subdev.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c  | 18 ++++++-------
>  drivers/media/v4l2-core/v4l2-fwnode.c |  2 +-
>  include/media/v4l2-async.h            | 39 ++++++++++++++++-----------
>  3 files changed, 33 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 13fe0bdc70b6..bb78e3618ab5 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -147,7 +147,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>  
>  	list_for_each_entry(asd, &notifier->waiting, list) {
>  		/* bus_type has been verified valid before */
> -		switch (asd->match_type) {
> +		switch (asd->match.type) {
>  		case V4L2_ASYNC_MATCH_I2C:

Renaming V4L2_ASYNC_MATCH_* to V4L2_ASYNC_MATCH_TYPE_* would be nice in
a separate patch.

>  			match = match_i2c;
>  			break;
> @@ -172,10 +172,10 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>  static bool asd_equal(struct v4l2_async_subdev *asd_x,
>  		      struct v4l2_async_subdev *asd_y)
>  {
> -	if (asd_x->match_type != asd_y->match_type)
> +	if (asd_x->match.type != asd_y->match.type)
>  		return false;
>  
> -	switch (asd_x->match_type) {
> +	switch (asd_x->match.type) {
>  	case V4L2_ASYNC_MATCH_I2C:
>  		return asd_x->match.i2c.adapter_id ==
>  			asd_y->match.i2c.adapter_id &&
> @@ -494,7 +494,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
>  	if (!asd)
>  		return -EINVAL;
>  
> -	switch (asd->match_type) {
> +	switch (asd->match.type) {
>  	case V4L2_ASYNC_MATCH_I2C:
>  	case V4L2_ASYNC_MATCH_FWNODE:
>  		if (v4l2_async_nf_has_async_subdev(notifier, asd, this_index)) {
> @@ -504,7 +504,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
>  		break;
>  	default:
>  		dev_err(dev, "Invalid match type %u on %p\n",
> -			asd->match_type, asd);
> +			asd->match.type, asd);
>  		return -EINVAL;
>  	}
>  
> @@ -630,7 +630,7 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
>  		return;
>  
>  	list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
> -		switch (asd->match_type) {
> +		switch (asd->match.type) {
>  		case V4L2_ASYNC_MATCH_FWNODE:
>  			fwnode_handle_put(asd->match.fwnode);
>  			break;
> @@ -685,7 +685,7 @@ __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
>  	if (!asd)
>  		return ERR_PTR(-ENOMEM);
>  
> -	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> +	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
>  	asd->match.fwnode = fwnode_handle_get(fwnode);
>  
>  	ret = __v4l2_async_nf_add_subdev(notifier, asd);
> @@ -732,7 +732,7 @@ __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier, int adapter_id,
>  	if (!asd)
>  		return ERR_PTR(-ENOMEM);
>  
> -	asd->match_type = V4L2_ASYNC_MATCH_I2C;
> +	asd->match.type = V4L2_ASYNC_MATCH_I2C;
>  	asd->match.i2c.adapter_id = adapter_id;
>  	asd->match.i2c.address = address;
>  
> @@ -850,7 +850,7 @@ EXPORT_SYMBOL(v4l2_async_unregister_subdev);
>  static void print_waiting_subdev(struct seq_file *s,
>  				 struct v4l2_async_subdev *asd)
>  {
> -	switch (asd->match_type) {
> +	switch (asd->match.type) {
>  	case V4L2_ASYNC_MATCH_I2C:
>  		seq_printf(s, " [i2c] dev=%d-%04x\n", asd->match.i2c.adapter_id,
>  			   asd->match.i2c.address);
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 3d9533c1b202..e6bd63364bed 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -811,7 +811,7 @@ v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
>  	if (!asd)
>  		return -ENOMEM;
>  
> -	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> +	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
>  	asd->match.fwnode =
>  		fwnode_graph_get_remote_port_parent(endpoint);
>  	if (!asd->match.fwnode) {
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 25eb1d138c06..0c4cffd081c9 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -34,23 +34,38 @@ enum v4l2_async_match_type {
>  };
>  
>  /**
> - * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> + * struct v4l2_async_match - async sub-device match information

The new structure name sounds like it stores data about an actual match,
while in reality it stores information for matching subdevs with
notifier entries. How about naming the structure v4l2_async_match_info,
or v4l2_async_match_descriptor or v4l2_async_match_desc ?

>   *
> - * @match_type:	type of match that will be used
> - * @match:	union of per-bus type matching data sets
> - * @match.fwnode:
> + * @type:	type of match that will be used
> + * @fwnode:
>   *		pointer to &struct fwnode_handle to be matched.
>   *		Used if @match_type is %V4L2_ASYNC_MATCH_FWNODE.
> - * @match.i2c:	embedded struct with I2C parameters to be matched.
> + * @i2c:	embedded struct with I2C parameters to be matched.
>   *		Both @match.i2c.adapter_id and @match.i2c.address
>   *		should be matched.
>   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> - * @match.i2c.adapter_id:
> + * @i2c.adapter_id:
>   *		I2C adapter ID to be matched.
>   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> - * @match.i2c.address:
> + * @i2c.address:
>   *		I2C address to be matched.
>   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> + */
> +struct v4l2_async_match {
> +	enum v4l2_async_match_type type;
> +	union {
> +		struct fwnode_handle *fwnode;
> +		struct {
> +			int adapter_id;
> +			unsigned short address;
> +		} i2c;
> +	};
> +};
> +
> +/**
> + * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> + *
> + * @match:	struct of match type and per-bus type matching data sets
>   * @asd_list:	used to add struct v4l2_async_subdev objects to the
>   *		master notifier @asd_list
>   * @list:	used to link struct v4l2_async_subdev objects, waiting to be
> @@ -61,15 +76,7 @@ enum v4l2_async_match_type {
>   * v4l2_async_subdev as its first member.
>   */
>  struct v4l2_async_subdev {
> -	enum v4l2_async_match_type match_type;
> -	union {
> -		struct fwnode_handle *fwnode;
> -		struct {
> -			int adapter_id;
> -			unsigned short address;
> -		} i2c;
> -	} match;
> -
> +	struct v4l2_async_match match;
>  	/* v4l2-async core private: not to be used by drivers */
>  	struct list_head list;
>  	struct list_head asd_list;

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 05/18] media: v4l: async: Clean testing for duplicated async subdevs
  2023-03-30 11:58 ` [PATCH 05/18] media: v4l: async: Clean testing for duplicated async subdevs Sakari Ailus
  2023-04-13 16:58   ` Jacopo Mondi
@ 2023-04-25  1:15   ` Laurent Pinchart
  2023-04-27 11:06     ` Sakari Ailus
  1 sibling, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  1:15 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Sakari,

Thank you for the patch.

On Thu, Mar 30, 2023 at 02:58:40PM +0300, Sakari Ailus wrote:
> There's a need to verify that a single async sub-device isn't being added
> multiple times, this would be an error. This takes place at the time of
> adding the async sub-device to the notifier's list as well as when the
> notifier is added to the global notifier's list.
> 
> Use the pointer to the sub-device for testing this instead of an index to
> an array that is long gone.

Reading the patch, I have no idea what the "long gone array" is. Could
you please expand the commit message to make this easier to review ?
v4l2-async is very difficult to follow in general, reviewing this series
is painful :-S Let's try to improve it with better commit messages.

> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c | 18 ++++++++----------
>  1 file changed, 8 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index bb78e3618ab5..fc9ae22e2b47 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -456,21 +456,19 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
>  
>  /*
>   * Find out whether an async sub-device was set up already or
> - * whether it exists in a given notifier before @this_index.
> - * If @this_index < 0, search the notifier's entire @asd_list.
> + * whether it exists in a given notifier.
>   */
>  static bool
>  v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> -			       struct v4l2_async_subdev *asd, int this_index)
> +			       struct v4l2_async_subdev *asd, bool skip_self)
>  {
>  	struct v4l2_async_subdev *asd_y;
> -	int j = 0;
>  
>  	lockdep_assert_held(&list_lock);
>  
>  	/* Check that an asd is not being added more than once. */
>  	list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
> -		if (this_index >= 0 && j++ >= this_index)
> +		if (asd == asd_y)
>  			break;
>  		if (asd_equal(asd, asd_y))
>  			return true;
> @@ -486,7 +484,7 @@ v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
>  
>  static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
>  				   struct v4l2_async_subdev *asd,
> -				   int this_index)
> +				   bool skip_self)
>  {
>  	struct device *dev =
>  		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
> @@ -497,7 +495,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
>  	switch (asd->match.type) {
>  	case V4L2_ASYNC_MATCH_I2C:
>  	case V4L2_ASYNC_MATCH_FWNODE:
> -		if (v4l2_async_nf_has_async_subdev(notifier, asd, this_index)) {
> +		if (v4l2_async_nf_has_async_subdev(notifier, asd, skip_self)) {
>  			dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
>  			return -EEXIST;
>  		}
> @@ -520,7 +518,7 @@ EXPORT_SYMBOL(v4l2_async_nf_init);
>  static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_async_subdev *asd;
> -	int ret, i = 0;
> +	int ret;
>  
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
> @@ -528,7 +526,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
>  	mutex_lock(&list_lock);
>  
>  	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
> -		ret = v4l2_async_nf_asd_valid(notifier, asd, i++);
> +		ret = v4l2_async_nf_asd_valid(notifier, asd, true);
>  		if (ret)
>  			goto err_unlock;
>  
> @@ -661,7 +659,7 @@ int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
>  
>  	mutex_lock(&list_lock);
>  
> -	ret = v4l2_async_nf_asd_valid(notifier, asd, -1);
> +	ret = v4l2_async_nf_asd_valid(notifier, asd, false);
>  	if (ret)
>  		goto unlock;
>  

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 06/18] media: v4l: async: Only pass match information for async subdev validation
  2023-03-30 11:58 ` [PATCH 06/18] media: v4l: async: Only pass match information for async subdev validation Sakari Ailus
  2023-04-14  7:15   ` Jacopo Mondi
@ 2023-04-25  1:24   ` Laurent Pinchart
  2023-04-27 11:45     ` Sakari Ailus
  1 sibling, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  1:24 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Sakari,

Thank you for the patch.

On Thu, Mar 30, 2023 at 02:58:41PM +0300, Sakari Ailus wrote:
> Pass only information required for sub-device matching to functions
> checking whether the async sub-device already exists. Do the same for
> debug message printing. This makes further changes to other aspects of
> async sub-devices easier.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c | 93 ++++++++++++++--------------
>  1 file changed, 46 insertions(+), 47 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index fc9ae22e2b47..224ebf50f2d0 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -62,14 +62,14 @@ static void v4l2_async_nf_call_destroy(struct v4l2_async_notifier *n,
>  }
>  
>  static bool match_i2c(struct v4l2_async_notifier *notifier,
> -		      struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> +		      struct v4l2_subdev *sd, struct v4l2_async_match *match)
>  {
>  #if IS_ENABLED(CONFIG_I2C)
>  	struct i2c_client *client = i2c_verify_client(sd->dev);
>  
>  	return client &&
> -		asd->match.i2c.adapter_id == client->adapter->nr &&
> -		asd->match.i2c.address == client->addr;
> +		match->i2c.adapter_id == client->adapter->nr &&
> +		match->i2c.address == client->addr;
>  #else
>  	return false;
>  #endif
> @@ -84,26 +84,26 @@ static struct device *notifier_dev(struct v4l2_async_notifier *notifier)
>  static bool
>  match_fwnode_one(struct v4l2_async_notifier *notifier,
>  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
> -		 struct v4l2_async_subdev *asd)
> +		 struct v4l2_async_match *match)
>  {
>  	struct fwnode_handle *asd_dev_fwnode;

match_dev_node, to remove references to asd ?

>  	bool ret;
>  
>  	dev_dbg(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
> -		sd_fwnode, asd->match.fwnode);
> +		sd_fwnode, match->fwnode);
>  
> -	if (sd_fwnode == asd->match.fwnode) {
> +	if (sd_fwnode == match->fwnode) {
>  		dev_dbg(sd->dev, "async: direct match found\n");
>  		return true;
>  	}
>  
> -	if (!fwnode_graph_is_endpoint(asd->match.fwnode)) {
> +	if (!fwnode_graph_is_endpoint(match->fwnode)) {
>  		dev_dbg(sd->dev,
>  			"async: async subdev fwnode not endpoint, no match\n");

The reference to "subdev" could be dropped here too.

>  		return false;
>  	}
>  
> -	asd_dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
> +	asd_dev_fwnode = fwnode_graph_get_port_parent(match->fwnode);
>  
>  	ret = sd_fwnode == asd_dev_fwnode;
>  
> @@ -116,12 +116,12 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
>  }
>  
>  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> -			 struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> +			 struct v4l2_subdev *sd, struct v4l2_async_match *match)
>  {
>  	dev_dbg(sd->dev, "async: matching for notifier %pfw, sd %pfw\n",
>  		dev_fwnode(notifier_dev(notifier)), sd->fwnode);
>  
> -	if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
> +	if (match_fwnode_one(notifier, sd, sd->fwnode, match))
>  		return true;
>  
>  	/* Also check the secondary fwnode. */
> @@ -130,7 +130,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
>  
>  	dev_dbg(sd->dev, "async: trying secondary fwnode match\n");
>  
> -	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
> +	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, match);
>  }
>  
>  static LIST_HEAD(subdev_list);
> @@ -142,7 +142,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>  		      struct v4l2_subdev *sd)
>  {
>  	bool (*match)(struct v4l2_async_notifier *notifier,
> -		      struct v4l2_subdev *sd, struct v4l2_async_subdev *asd);
> +		      struct v4l2_subdev *sd, struct v4l2_async_match *match);
>  	struct v4l2_async_subdev *asd;
>  
>  	list_for_each_entry(asd, &notifier->waiting, list) {
> @@ -161,7 +161,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>  		}
>  
>  		/* match cannot be NULL here */
> -		if (match(notifier, sd, asd))
> +		if (match(notifier, sd, &asd->match))
>  			return asd;
>  	}
>  
> @@ -169,20 +169,18 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
>  }
>  
>  /* Compare two async sub-device descriptors for equivalence */
> -static bool asd_equal(struct v4l2_async_subdev *asd_x,
> -		      struct v4l2_async_subdev *asd_y)
> +static bool asd_equal(struct v4l2_async_match *match1,
> +		      struct v4l2_async_match *match2)

The function doesn't deal with asds anymore, let's rename it.
v4l2_async_match_equal() could be a good name. Please also update the
comment above the function.

>  {
> -	if (asd_x->match.type != asd_y->match.type)
> +	if (match1->type != match2->type)
>  		return false;
>  
> -	switch (asd_x->match.type) {
> +	switch (match1->type) {
>  	case V4L2_ASYNC_MATCH_I2C:
> -		return asd_x->match.i2c.adapter_id ==
> -			asd_y->match.i2c.adapter_id &&
> -			asd_x->match.i2c.address ==
> -			asd_y->match.i2c.address;
> +		return match1->i2c.adapter_id == match2->i2c.adapter_id &&
> +			match1->i2c.address == match2->i2c.address;
>  	case V4L2_ASYNC_MATCH_FWNODE:
> -		return asd_x->match.fwnode == asd_y->match.fwnode;
> +		return match1->fwnode == match2->fwnode;
>  	default:
>  		break;
>  	}
> @@ -434,20 +432,20 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
>  /* See if an async sub-device can be found in a notifier's lists. */
>  static bool
>  __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> -				 struct v4l2_async_subdev *asd)
> +				 struct v4l2_async_match *match)

This function should be renamed to drop "subdev" as well.
__v4l2_async_nf_has_match() is a candidate,
__v4l2_async_nf_has_match_entry() is also an option to avoid implying
that the function tests for a match between a subdev and a match entry.

>  {
> -	struct v4l2_async_subdev *asd_y;
> +	struct v4l2_async_subdev *asd;
>  	struct v4l2_subdev *sd;
>  
> -	list_for_each_entry(asd_y, &notifier->waiting, list)
> -		if (asd_equal(asd, asd_y))
> +	list_for_each_entry(asd, &notifier->waiting, list)
> +		if (asd_equal(&asd->match, match))
>  			return true;
>  
>  	list_for_each_entry(sd, &notifier->done, async_list) {
>  		if (WARN_ON(!sd->asd))
>  			continue;
>  
> -		if (asd_equal(asd, sd->asd))
> +		if (asd_equal(&sd->asd->match, match))
>  			return true;
>  	}
>  
> @@ -460,49 +458,50 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
>   */
>  static bool
>  v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> -			       struct v4l2_async_subdev *asd, bool skip_self)
> +			       struct v4l2_async_match *match, bool skip_self)

Same here.

>  {
> -	struct v4l2_async_subdev *asd_y;
> +	struct v4l2_async_subdev *asd;
>  
>  	lockdep_assert_held(&list_lock);
>  
>  	/* Check that an asd is not being added more than once. */
> -	list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
> -		if (asd == asd_y)
> +	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
> +		if (&asd->match == match)
>  			break;
> -		if (asd_equal(asd, asd_y))
> +		if (asd_equal(&asd->match, match))
>  			return true;
>  	}
>  
>  	/* Check that an asd does not exist in other notifiers. */
>  	list_for_each_entry(notifier, &notifier_list, list)
> -		if (__v4l2_async_nf_has_async_subdev(notifier, asd))
> +		if (__v4l2_async_nf_has_async_subdev(notifier, match))
>  			return true;
>  
>  	return false;
>  }
>  
>  static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
> -				   struct v4l2_async_subdev *asd,
> +				   struct v4l2_async_match *match,
>  				   bool skip_self)

And here.

>  {
>  	struct device *dev =
>  		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
>  
> -	if (!asd)
> +	if (!match)
>  		return -EINVAL;
>  
> -	switch (asd->match.type) {
> +	switch (match->type) {
>  	case V4L2_ASYNC_MATCH_I2C:
>  	case V4L2_ASYNC_MATCH_FWNODE:
> -		if (v4l2_async_nf_has_async_subdev(notifier, asd, skip_self)) {
> +		if (v4l2_async_nf_has_async_subdev(notifier, match,
> +						   skip_self)) {
>  			dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");

"match descriptor" ?

>  			return -EEXIST;
>  		}
>  		break;
>  	default:
> -		dev_err(dev, "Invalid match type %u on %p\n",
> -			asd->match.type, asd);
> +		dev_err(dev, "Invalid match type %u on %p\n", match->type,
> +			match);
>  		return -EINVAL;
>  	}
>  
> @@ -526,7 +525,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
>  	mutex_lock(&list_lock);
>  
>  	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
> -		ret = v4l2_async_nf_asd_valid(notifier, asd, true);
> +		ret = v4l2_async_nf_asd_valid(notifier, &asd->match, true);
>  		if (ret)
>  			goto err_unlock;
>  
> @@ -659,7 +658,7 @@ int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
>  
>  	mutex_lock(&list_lock);
>  
> -	ret = v4l2_async_nf_asd_valid(notifier, asd, false);
> +	ret = v4l2_async_nf_asd_valid(notifier, &asd->match, false);
>  	if (ret)
>  		goto unlock;
>  
> @@ -846,15 +845,15 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  EXPORT_SYMBOL(v4l2_async_unregister_subdev);
>  
>  static void print_waiting_subdev(struct seq_file *s,

Same here. v4l2_async_print_match() or v4l2_async_print_match_entry()
could be good names.

In general, it would be useful to have a glossary of terms used in
v4l2-async, and make sure they're used consistently.

> -				 struct v4l2_async_subdev *asd)
> +				 struct v4l2_async_match *match)
>  {
> -	switch (asd->match.type) {
> +	switch (match->type) {
>  	case V4L2_ASYNC_MATCH_I2C:
> -		seq_printf(s, " [i2c] dev=%d-%04x\n", asd->match.i2c.adapter_id,
> -			   asd->match.i2c.address);
> +		seq_printf(s, " [i2c] dev=%d-%04x\n", match->i2c.adapter_id,
> +			   match->i2c.address);
>  		break;
>  	case V4L2_ASYNC_MATCH_FWNODE: {
> -		struct fwnode_handle *devnode, *fwnode = asd->match.fwnode;
> +		struct fwnode_handle *devnode, *fwnode = match->fwnode;
>  
>  		devnode = fwnode_graph_is_endpoint(fwnode) ?
>  			  fwnode_graph_get_port_parent(fwnode) :
> @@ -891,7 +890,7 @@ static int pending_subdevs_show(struct seq_file *s, void *data)
>  	list_for_each_entry(notif, &notifier_list, list) {
>  		seq_printf(s, "%s:\n", v4l2_async_nf_name(notif));
>  		list_for_each_entry(asd, &notif->waiting, list)
> -			print_waiting_subdev(s, asd);
> +			print_waiting_subdev(s, &asd->match);
>  	}
>  
>  	mutex_unlock(&list_lock);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 01/18] media: v4l: async: Return async sub-devices to subnotifier list
  2023-03-30 11:58 ` [PATCH 01/18] media: v4l: async: Return async sub-devices to subnotifier list Sakari Ailus
  2023-04-13 16:49   ` Jacopo Mondi
@ 2023-04-25  1:28   ` Laurent Pinchart
  2023-04-25  8:32     ` Sakari Ailus
  1 sibling, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  1:28 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Sakari,

Thank you for the patch.

On Thu, Mar 30, 2023 at 02:58:36PM +0300, Sakari Ailus wrote:
> When an async notifier is unregistered, the async sub-devices in the
> notifier's done list will disappear with the notifier. However this is
> currently also done to the sub-notifiers that remain registered. Their
> sub-devices only need to be unbound while the async sub-devices themselves
> need to be returned to the sub-notifier's waiting list. Do this now.
> 
> Fixes: 2cab00bb076b ("media: v4l: async: Allow binding notifiers to sub-devices")
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 2f1b718a9189..008a2a3e312e 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -414,7 +414,8 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  
>  /* Unbind all sub-devices in the notifier tree. */
>  static void
> -v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
> +v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> +				 bool readd)

I've read this as "read d" and was wondering what it meant. Maybe
"re_add" would be a better variable name ?

Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

>  {
>  	struct v4l2_subdev *sd, *tmp;
>  
> @@ -423,9 +424,11 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
>  			v4l2_async_find_subdev_notifier(sd);
>  
>  		if (subdev_notifier)
> -			v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
> +			v4l2_async_nf_unbind_all_subdevs(subdev_notifier, true);
>  
>  		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> +		if (readd)
> +			list_add_tail(&sd->asd->list, &notifier->waiting);
>  		v4l2_async_cleanup(sd);
>  
>  		list_move(&sd->async_list, &subdev_list);
> @@ -557,7 +560,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
>  	/*
>  	 * On failure, unbind all sub-devices registered through this notifier.
>  	 */
> -	v4l2_async_nf_unbind_all_subdevs(notifier);
> +	v4l2_async_nf_unbind_all_subdevs(notifier, false);
>  
>  err_unlock:
>  	mutex_unlock(&list_lock);
> @@ -607,7 +610,7 @@ __v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
>  	if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
>  		return;
>  
> -	v4l2_async_nf_unbind_all_subdevs(notifier);
> +	v4l2_async_nf_unbind_all_subdevs(notifier, false);
>  
>  	notifier->sd = NULL;
>  	notifier->v4l2_dev = NULL;
> @@ -805,7 +808,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	 */
>  	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
>  	if (subdev_notifier)
> -		v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
> +		v4l2_async_nf_unbind_all_subdevs(subdev_notifier, false);
>  
>  	if (sd->asd)
>  		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching
  2023-04-24 19:33         ` Sakari Ailus
@ 2023-04-25  1:37           ` Laurent Pinchart
  2023-04-27  9:23             ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  1:37 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Niklas Söderlund, Jacopo Mondi, linux-media, Philipp Zabel,
	hverkuil, Francesco Dolcini, aishwarya.kothari, Robert Foss,
	Todor Tomov, Hyun Kwon

Hi Sakari,

On Mon, Apr 24, 2023 at 10:33:06PM +0300, Sakari Ailus wrote:
> On Mon, Apr 24, 2023 at 09:20:22PM +0200, Niklas Söderlund wrote:
> > On 2023-04-14 14:07:40 +0300, Sakari Ailus wrote:
> > > On Thu, Apr 13, 2023 at 06:50:04PM +0200, Jacopo Mondi wrote:
> > > > On Thu, Mar 30, 2023 at 02:58:38PM +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.
> > > > 
> > > > As you know I'm a bit debated.
> > > > 
> > > > Strict endpoint-matching requires one subdev to be registed per each
> > > > endpoint, and this is tedious for drivers that have to register a
> > > > subdev for each of its endpoints
> > > > 
> > > > Allowing a subdev to be matched multiple times on different endpoints
> > > > gives a way for lazy drivers to take a shortcut and simplify their
> > > > topologies to a single subdev, when they would actually need more.
> > > 
> > > I'd say this is really about interface design, not being "lazy". It depends
> > > on the sub-device. Ideally the framework should be also as easy for drivers
> > > drivers to use as possible.
> > > 
> > > What is not supported, though, is multiple sub-devices with a single device
> > > node. Do we need that? At least I don't think I came across a driver that
> > > would.
> > 
> > If I understand you correctly about multiple sub-device from a single 
> > device node, this exists today. The ADV748x driver have a single device 
> > node in DT and register multiple sub-devices, one for each source 
> > endpoint.
> > 
> > The ADV748x have two CSI-2 transmitters, one 4-lane and one 1-lane as 
> > well as two different video capture "ports" one HDMI and one CVBS. Both 
> > capture ports can be active at the same time and routed internally 
> > inside the ADV748x to the two different CSI-2 transmitters.
> > 
> > In order todo this the ADV748x register multiple subdevices and modifies 
> > the fwnode to be the endpoint instead of the device node. So the change 
> > in this patch for ADV748x driver would break that driver.
> 
> Ah, indeed. I guess I'll need to support that case as well then. It doesn't
> seem to be troublesome to implement, but I'm tempted making it a special
> case: every other driver would apparently be fine matching with device
> fwnode whereas doing endpoint-to-endpoint matching adds complexity to the
> drivers. This patch removes about 100 lines of rather ugly code largely
> from v4l2-async.

It's only 50 lines from v4l2-async, and I don't think the code is uglier
than the rest of the file :-) In general, I prefer implementing tricky
code in the framework and simplifying drivers. I think our goals align
there, the framework should do the right thing by default for the
majority of cases. However, as Niklas pointed out, endpoint matching is
needed for drivers that register multiple subdevs with external
connections (such as the adv742x), and that's exactly why endpoint
matching was added in the first place. I think this needs to be kept.

> There are other issues in the set with connection-subdev relations, I'll
> post v2 to address those as well.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 17/18] media: v4l: async: Set v4l2_device in async notifier init
  2023-04-25  0:35   ` Laurent Pinchart
@ 2023-04-25  2:00     ` Laurent Pinchart
  2023-04-28 10:35       ` Sakari Ailus
  2023-04-28 10:33     ` Sakari Ailus
  1 sibling, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  2:00 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

On Tue, Apr 25, 2023 at 03:35:26AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Thu, Mar 30, 2023 at 02:58:52PM +0300, Sakari Ailus wrote:
> > Set the v4l2_device already in async notifier init, so struct device
> > related to it will be available before the notifier is registered.

Also, please explain why this is needed.

> > This patch has been mostly generated using the following command:
> > 
> > git grep -l v4l2_async_nf_init -- drivers/media/ drivers/staging/media/ |
> > 	while read i; do perl -e '
> > 	@a=<>; unlink("'$i'"); open(F, "> '$i'");
> > 	for $f ({i=>"v4l2_async_nf_init", r=>"v4l2_async_nf_register"},
> > 		{i=>"v4l2_async_subdev_nf_init",
> > 		 r=>"v4l2_async_subdev_nf_register"} ) {
> > 	my $b; @a = map { $b = "$1, $2" if
> > 	s/$f->{r}\(([^,]*),\s*([^\)]*)\)/v4l2_async_nf_register\($2\)/;
> > 	$_; } @a; @a = map { if (defined $b) {
> > 	s/v4l2_async_nf_init\([^\)]*\)/$f->{i}\($b\)/;
> > 	s/$f->{r}\(\K[^,]*,\s*//; }; $_; } @a; }; print F @a; close F;'
> > 	< $i; done
> 
> You should learn coccinelle at some point :-)
> 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/i2c/max9286.c                   |  4 +-
> >  drivers/media/i2c/st-mipid02.c                |  4 +-
> >  drivers/media/i2c/tc358746.c                  |  4 +-
> >  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  4 +-
> >  drivers/media/platform/atmel/atmel-isi.c      |  4 +-
> >  drivers/media/platform/cadence/cdns-csi2rx.c  |  4 +-
> >  drivers/media/platform/intel/pxa_camera.c     |  4 +-
> >  drivers/media/platform/marvell/cafe-driver.c  |  2 +-
> >  drivers/media/platform/marvell/mcam-core.c    |  2 +-
> >  drivers/media/platform/marvell/mmp-driver.c   |  2 +-
> >  .../platform/microchip/microchip-csi2dc.c     |  5 +--
> >  .../microchip/microchip-sama5d2-isc.c         |  5 +--
> >  .../microchip/microchip-sama7g5-isc.c         |  5 +--
> >  drivers/media/platform/nxp/imx-mipi-csis.c    |  4 +-
> >  drivers/media/platform/nxp/imx7-media-csi.c   |  4 +-
> >  drivers/media/platform/qcom/camss/camss.c     |  5 +--
> >  drivers/media/platform/renesas/rcar-isp.c     |  4 +-
> >  .../platform/renesas/rcar-vin/rcar-core.c     |  8 ++--
> >  .../platform/renesas/rcar-vin/rcar-csi2.c     |  4 +-
> >  drivers/media/platform/renesas/rcar_drif.c    |  4 +-
> >  drivers/media/platform/renesas/renesas-ceu.c  |  4 +-
> >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  4 +-
> >  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   |  4 +-
> >  .../platform/rockchip/rkisp1/rkisp1-dev.c     |  4 +-
> >  .../platform/samsung/exynos4-is/media-dev.c   |  5 +--
> >  drivers/media/platform/st/stm32/stm32-dcmi.c  |  4 +-
> >  .../platform/sunxi/sun4i-csi/sun4i_csi.c      |  4 +-
> >  .../sunxi/sun6i-csi/sun6i_csi_bridge.c        |  6 +--
> >  .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c   |  4 +-
> >  .../sun8i_a83t_mipi_csi2.c                    |  4 +-
> >  .../media/platform/ti/am437x/am437x-vpfe.c    |  4 +-
> >  drivers/media/platform/ti/cal/cal.c           |  4 +-
> >  .../media/platform/ti/davinci/vpif_capture.c  | 11 ++---
> >  drivers/media/platform/ti/omap3isp/isp.c      |  4 +-
> >  drivers/media/platform/video-mux.c            |  4 +-
> >  drivers/media/platform/xilinx/xilinx-vipp.c   |  4 +-
> >  drivers/media/v4l2-core/v4l2-async.c          | 43 +++++++------------
> >  drivers/media/v4l2-core/v4l2-fwnode.c         |  4 +-
> >  .../deprecated/atmel/atmel-sama5d2-isc.c      |  5 +--
> >  drivers/staging/media/imx/imx-media-csi.c     |  4 +-
> >  .../staging/media/imx/imx-media-dev-common.c  |  4 +-
> >  drivers/staging/media/imx/imx6-mipi-csi2.c    |  4 +-
> >  drivers/staging/media/imx/imx8mq-mipi-csi2.c  |  4 +-
> >  .../media/sunxi/sun6i-isp/sun6i_isp_proc.c    |  4 +-
> >  drivers/staging/media/tegra-video/vi.c        |  4 +-
> >  include/media/v4l2-async.h                    | 35 +++++++++------
> >  46 files changed, 129 insertions(+), 138 deletions(-)
> 
> [snip]
> 
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index 750bf4ddb267..cf2082e17fc4 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -159,6 +159,24 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
> >  /**
> >   * v4l2_async_nf_init - Initialize a notifier.
> >   *
> > + * @v4l2_dev: pointer to &struct v4l2_device
> > + * @notifier: pointer to &struct v4l2_async_notifier
> > + *
> > + * This function initializes the notifier @asc_list. It must be called
> > + * before adding a subdevice to a notifier, using one of:
> > + * v4l2_async_nf_add_fwnode_remote(),
> > + * v4l2_async_nf_add_fwnode(),
> > + * v4l2_async_nf_add_i2c(),
> > + * __v4l2_async_nf_add_connection() or
> > + * v4l2_async_nf_parse_fwnode_endpoints().
> > + */
> > +void v4l2_async_nf_init(struct v4l2_device *v4l2_dev,
> > +			struct v4l2_async_notifier *notifier);
> 
> The function operates on a notifier, could we make it the first argument
> ? Same for v4l2_async_subdev_nf_init().
> 
> > +
> > +/**
> > + * v4l2_async_subdev_nf_init - Initialize a sub-device notifier.
> > + *
> > + * @v4l2_dev: pointer to &struct v4l2_device
> >   * @notifier: pointer to &struct v4l2_async_notifier
> >   *
> >   * This function initializes the notifier @asc_list. It must be called
> > @@ -169,7 +187,8 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
> >   * __v4l2_async_nf_add_connection() or
> >   * v4l2_async_nf_parse_fwnode_endpoints().
> >   */
> > -void v4l2_async_nf_init(struct v4l2_async_notifier *notifier);
> > +void v4l2_async_subdev_nf_init(struct v4l2_subdev *sd,
> > +			       struct v4l2_async_notifier *notifier);
> >  
> >  /**
> >   * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
> > @@ -264,21 +283,9 @@ __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier,
> >  /**
> >   * v4l2_async_nf_register - registers a subdevice asynchronous notifier
> >   *
> > - * @v4l2_dev: pointer to &struct v4l2_device
> > - * @notifier: pointer to &struct v4l2_async_notifier
> > - */
> > -int v4l2_async_nf_register(struct v4l2_device *v4l2_dev,
> > -			   struct v4l2_async_notifier *notifier);
> > -
> > -/**
> > - * v4l2_async_subdev_nf_register - registers a subdevice asynchronous
> > - *					 notifier for a sub-device
> > - *
> > - * @sd: pointer to &struct v4l2_subdev
> >   * @notifier: pointer to &struct v4l2_async_notifier
> >   */
> > -int v4l2_async_subdev_nf_register(struct v4l2_subdev *sd,
> > -				  struct v4l2_async_notifier *notifier);
> > +int v4l2_async_nf_register(struct v4l2_async_notifier *notifier);
> >  
> >  /**
> >   * v4l2_async_nf_unregister - unregisters a subdevice

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 09/18] media: v4l: async: Differentiate connecting and creating sub-devices
  2023-04-14 13:35     ` Sakari Ailus
@ 2023-04-25  2:14       ` Laurent Pinchart
  2023-04-28  9:46         ` Sakari Ailus
  2023-04-28 10:29         ` Sakari Ailus
  0 siblings, 2 replies; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-25  2:14 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Sakari,

Thank you for the patch.

On Fri, Apr 14, 2023 at 04:35:00PM +0300, Sakari Ailus wrote:
> On Fri, Apr 14, 2023 at 10:52:25AM +0200, Jacopo Mondi wrote:
> > On Thu, Mar 30, 2023 at 02:58:44PM +0300, Sakari Ailus wrote:
> > > When the v4l2-async framework was introduced, the use case for it was to
> > > connect a camera sensor with a parallel receiver. Both tended to be rather
> > > simple devices with a single connection between them.
> > >
> > > The framework has been since improved in multiple ways but there are
> > > limitations that have remained, for instance the assumption an async
> > > sub-device is connected towards a single notifier and via a single link
> > > only.
> > >
> > > This patch adds an object that represents the device while an earlier
> > > patch in the series re-purposed the old struct v4l2_async_subdev as the
> > > connection.
> > >
> > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > ---
> > >  .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
> > >  .../platform/rockchip/rkisp1/rkisp1-dev.c     |   8 +-
> > >  drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
> > >  drivers/media/v4l2-core/v4l2-async.c          | 163 ++++++++++++++++--
> > >  include/media/v4l2-async.h                    |  32 +++-
> > >  include/media/v4l2-subdev.h                   |   2 +-

We the introduction of such a new core concept, Documentation/ should
also be updated.

> > >  6 files changed, 179 insertions(+), 30 deletions(-)
> > >
> > > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > index d30f0ecb1bfd..a1293c45aae1 100644
> > > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > @@ -148,7 +148,7 @@ struct rkisp1_info {
> > >   * @port:		port number (0: MIPI, 1: Parallel)
> > >   */
> > >  struct rkisp1_sensor_async {
> > > -	struct v4l2_async_connection asd;
> > > +	struct v4l2_async_subdev asd;

Ah, we're back to "asd" naming... There's no point in going back and
forth in drivers, so you can ignore my comment about renaming the
variables in drivers. Please however record the reason why variables are
not renamed in the commit message of patch 08/18.

On second thought, why does patch 08/18 switch to v4l2_async_connection
in a very large number of drivers, and this patch only moves back to
v4l2_async_subdev in rkisp1 and omap3isp ? What's special about these
two drivers ?

And on third thought this seems completely wrong,
v4l2_async_nf_add_fwnode() will return a pointer to a struct
v4l2_async_connection that is expected to be the first member of the
driver-specific async structure.

> > >  	unsigned int index;
> > >  	struct fwnode_handle *source_ep;
> > >  	unsigned int lanes;
> > > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > > index 39fa98e6dbbc..5bdb1ecedf6a 100644
> > > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > > @@ -122,12 +122,12 @@ struct rkisp1_isr_data {
> > >
> > >  static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
> > >  					struct v4l2_subdev *sd,
> > > -					struct v4l2_async_connection *asd)
> > > +					struct v4l2_async_connection *asc)

This belongs to a previous patch. Same for other changes below.

> > >  {
> > >  	struct rkisp1_device *rkisp1 =
> > >  		container_of(notifier, struct rkisp1_device, notifier);
> > >  	struct rkisp1_sensor_async *s_asd =
> > > -		container_of(asd, struct rkisp1_sensor_async, asd);
> > > +		container_of(asc->asd, struct rkisp1_sensor_async, asd);
> > >  	int source_pad;
> > >  	int ret;
> > >
> > > @@ -165,10 +165,10 @@ static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
> > >  	return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
> > >  }
> > >
> > > -static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asd)
> > > +static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asc)
> > >  {
> > >  	struct rkisp1_sensor_async *rk_asd =
> > > -		container_of(asd, struct rkisp1_sensor_async, asd);
> > > +		container_of(asc->asd, struct rkisp1_sensor_async, asd);
> > >
> > >  	fwnode_handle_put(rk_asd->source_ep);
> > >  }
> > > diff --git a/drivers/media/platform/ti/omap3isp/isp.h b/drivers/media/platform/ti/omap3isp/isp.h
> > > index 32ea70c8d2f9..a9d760fbf349 100644
> > > --- a/drivers/media/platform/ti/omap3isp/isp.h
> > > +++ b/drivers/media/platform/ti/omap3isp/isp.h
> > > @@ -220,7 +220,7 @@ struct isp_device {
> > >  };
> > >
> > >  struct isp_async_subdev {
> > > -	struct v4l2_async_connection asd;
> > > +	struct v4l2_async_subdev asd;
> > >  	struct isp_bus_cfg bus;
> > >  };
> > >
> > > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > > index 56ce40481ec4..4c3bd64d6a00 100644
> > > --- a/drivers/media/v4l2-core/v4l2-async.c
> > > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > > @@ -134,6 +134,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > >  }
> > >
> > >  static LIST_HEAD(subdev_head);
> > > +static LIST_HEAD(asd_head);
> > >  static LIST_HEAD(notifier_head);
> > >  static DEFINE_MUTEX(list_lock);
> > >
> > > @@ -304,13 +305,20 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> > >  	struct v4l2_async_notifier *subdev_notifier;
> > >  	int ret;
> > >
> > > -	ret = v4l2_device_register_subdev(v4l2_dev, sd);
> > > -	if (ret < 0)
> > > -		return ret;
> > > +	if (!asc->asd->registered) {
> > > +		ret = v4l2_device_register_subdev(v4l2_dev, sd);
> > > +		if (ret < 0)
> > > +			return ret;
> > > +	}
> > >
> > >  	ret = v4l2_async_nf_call_bound(notifier, sd, asc);
> > 
> > This is the part that puzzles me the most: are we going to receive
> > multiple bound() calls for the same subdevice when matched on multiple
> > connections ? If that's the case, is this desirable ?
> 
> Yes, that is the intent: we're dealing with connections, not to much
> sub-devices as such. That is what the current bound callbacks generally do.
> Some also deal with sub-devices but that's fine: driver changes may be
> needed to add support for new functionality.

Do I understand correctly that this change is meant to support the needs
of the i.MX6 media drivers ? If so, I'd like to see them using this new
capability of v4l2-async, to make sure it works as expected.

> > >  	if (ret < 0) {
> > > -		v4l2_device_unregister_subdev(sd);
> > > +		if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> > > +			dev_dbg(notifier_dev(notifier),
> > > +				"failed binding %pfw (%d)\n",
> > > +				asc->match.fwnode, ret);
> > > +		if (!asc->asd->registered)
> > 
> > This should probably be
> > 		if (asc->asd->registered)
> 
> Oops! Well, almost. The sub-device should only be unregistered here if it
> was just registered. But I'll fix it for v2.
> 
> > > +			v4l2_device_unregister_subdev(sd);
> > >  		return ret;
> > >  	}
> > >
> > > @@ -322,14 +330,26 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> > >  	 */
> > >  	ret = v4l2_async_create_ancillary_links(notifier, sd);
> > 
> > Also this part seems suspicious if called multiple times for the same
> > subdevice when matched on multiple connections
> > 
> > Do we need to refcount the connections for each async sub-dev,
> > decrement at each match, and only when all of them are matched
> > operated on the subdevice ?
> > :
> 
> The ancillary link can be created when the sub-device is registered so I
> don't think we'll need to refcount it. I'll address this in v2.
> 
> > >  	if (ret) {
> > > +		if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> > > +			dev_dbg(notifier_dev(notifier),
> > > +				"failed creating links for %pfw (%d)\n",
> > > +				asc->match.fwnode, ret);
> > >  		v4l2_async_nf_call_unbind(notifier, sd, asc);
> > > -		v4l2_device_unregister_subdev(sd);
> > > +		list_del(&asc->asc_subdev_list);
> > > +		if (!asc->asd->registered)
> > > +			v4l2_device_unregister_subdev(sd);
> > >  		return ret;
> > >  	}
> > >
> > >  	list_del(&asc->waiting_list);
> > > -	sd->asd = asc;
> > > -	sd->notifier = notifier;
> > > +	if (!sd->asd) {
> > > +		WARN_ON(asc->asd->registered);
> > > +		sd->asd = asc->asd;
> > > +		sd->notifier = notifier;
> > > +		asc->asd->registered = true;
> > > +	} else {
> > > +		WARN_ON(sd->asd != asc->asd);
> > > +	}
> > >
> > >  	/* Move from the global subdevice list to notifier's done */
> > >  	list_move(&sd->async_list, &notifier->done_head);
> > > @@ -403,6 +423,21 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
> > >  	sd->asd = NULL;
> > >  }
> > >
> > > +static void v4l2_async_unbind_subdev_one(struct v4l2_async_notifier *notifier,
> > > +					 struct v4l2_subdev *sd, bool readd)
> > > +{
> > > +	struct v4l2_async_connection *asc, *tmp;
> > > +
> > > +	list_for_each_entry_safe(asc, tmp, &sd->asd->asc_head,
> > > +				 asc_subdev_list) {
> > > +		v4l2_async_nf_call_unbind(notifier, sd, asc);
> > > +		list_del(&asc->asc_subdev_list);
> > > +		if (readd)
> > > +			list_add_tail(&asc->waiting_list,
> > > +				      &notifier->waiting_head);
> > > +	}
> > > +}
> > > +
> > >  /* Unbind all sub-devices in the notifier tree. */
> > >  static void
> > >  v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> > > @@ -417,10 +452,8 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> > >  		if (subdev_notifier)
> > >  			v4l2_async_nf_unbind_all_subdevs(subdev_notifier, true);
> > >
> > > -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> > > -		if (readd)
> > > -			list_add_tail(&sd->asd->waiting_list,
> > > -				      &notifier->waiting_head);
> > > +		v4l2_async_unbind_subdev_one(notifier, sd, readd);
> > > +
> > >  		v4l2_async_cleanup(sd);
> > >
> > >  		list_move(&sd->async_list, &subdev_head);
> > > @@ -445,8 +478,9 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> > >  		if (WARN_ON(!sd->asd))
> > >  			continue;
> > >
> > > -		if (asc_equal(&sd->asd->match, match))
> > > -			return true;
> > > +		list_for_each_entry(asc, &sd->asd->asc_head, asc_list)
> > > +			if (asc_equal(&asc->match, match))
> > > +				return true;
> > >  	}
> > >
> > >  	return false;
> > > @@ -619,6 +653,18 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
> > >  }
> > >  EXPORT_SYMBOL(v4l2_async_nf_unregister);
> > >
> > > +static void release_async_subdev(struct kref *kref)
> > > +{
> > > +	struct v4l2_async_subdev *asd =
> > > +		container_of_const(kref, struct v4l2_async_subdev, kref);
> > > +
> > > +	list_del(&asd->asd_list);
> > > +
> > > +	WARN_ON(!list_empty(&asd->asc_head));
> > > +
> > > +	kfree(asd);
> > > +}
> > > +
> > >  static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> > >  {
> > >  	struct v4l2_async_connection *asc, *tmp;
> > > @@ -627,16 +673,24 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> > >  		return;
> > >
> > >  	list_for_each_entry_safe(asc, tmp, &notifier->asc_head, asc_list) {
> > > +		list_del(&asc->asc_list);
> > > +		v4l2_async_nf_call_destroy(notifier, asc);
> > > +
> > >  		switch (asc->match.type) {
> > >  		case V4L2_ASYNC_MATCH_FWNODE:
> > > +			pr_debug("release async connection for fwnode %pfw\n",
> > > +				 asc->match.fwnode);
> > 
> > Why pr_debug ? Can't you use notifier_dev() ?
> 
> The notifier is being cleaned up. We should have dev still around though,
> so I'll change this.
> 
> > >  			fwnode_handle_put(asc->match.fwnode);
> > >  			break;
> > > -		default:
> > > +		case V4L2_ASYNC_MATCH_I2C:
> > > +			pr_debug("release I²C async connection\n");
> > >  			break;
> > > +		default:
> > > +			pr_debug("release invalid async connection type %u\n",
> > > +				 asc->match.type);
> > >  		}
> > >
> > > -		list_del(&asc->asc_list);
> > > -		v4l2_async_nf_call_destroy(notifier, asc);
> > > +		kref_put(&asc->asd->kref, release_async_subdev);
> > >  		kfree(asc);
> > >  	}
> > >  }
> > > @@ -651,6 +705,71 @@ void v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> > >  }
> > >  EXPORT_SYMBOL_GPL(v4l2_async_nf_cleanup);
> > >
> > > +static bool async_subdev_has_connection(struct v4l2_async_notifier *notifier,
> > > +					struct v4l2_async_subdev *asd,
> > > +					struct v4l2_async_connection *asc)
> > > +{
> > > +	struct v4l2_async_connection *__asc;
> > > +
> > > +	list_for_each_entry(__asc, &asd->asc_head, asc_subdev_list) {
> > > +		if (__asc->match.type != V4L2_ASYNC_MATCH_FWNODE)
> > > +			continue;
> > > +
> > > +		if (__asc->match.fwnode != asc->match.fwnode)
> > > +			continue;
> > > +
> > > +		dev_dbg(notifier_dev(notifier), "found!\n");
> > 
> > Such message without much context can quickly become noise
> 
> I think I'll just drop it.
> 
> > > +
> > > +		return true;
> > > +	}
> > > +
> > > +	return false;
> > > +}
> > > +
> > > +/* Find an async sub-device for the async connection. */
> > > +static int v4l2_async_find_async_subdev(struct v4l2_async_notifier *notifier,
> > > +					struct v4l2_async_connection *asc)
> > > +{
> > > +	struct v4l2_async_subdev *asd;
> > > +
> > > +	lockdep_assert_held(&list_lock);
> > > +
> > > +	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> > > +		dev_dbg(notifier_dev(notifier),
> > > +			"async: looking up subdev for %pfw\n",
> > > +			asc->match.fwnode);
> > > +
> > > +	/*
> > > +	 * Matching by endpoint nodes may mean there are multiple connections to
> > > +	 * a single device. This is only possible with fwnode matching.
> > > +	 */
> > > +	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE &&
> > > +	    fwnode_graph_is_endpoint(asc->match.fwnode)) {

Maybe

	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE) {
		dev_dbg(notifier_dev(notifier),
			"async: looking up subdev for %pfw\n",
			asc->match.fwnode);

		if (fwnode_graph_is_endpoint(asc->match.fwnode)) {
			list_for_each_entry(asd, &asd_head, asd_list) {
				if (async_subdev_has_connection(notifier, asd, asc)) {
					kref_get(&asd->kref);
					goto found;
				}
			}
		}
	}

> > > +		list_for_each_entry(asd, &asd_head, asd_list) {
> > > +			if (async_subdev_has_connection(notifier, asd, asc)) {
> > > +				kref_get(&asd->kref);
> > > +				goto found;
> > > +			}
> > > +		}
> > > +	}
> > > +
> > > +	dev_dbg(notifier_dev(notifier), "not found, allocating new one\n");
> > > +
> > > +	asd = kzalloc(sizeof(*asd), GFP_KERNEL);
> > > +	if (!asd)
> > > +		return -ENOMEM;
> > > +
> > > +	kref_init(&asd->kref);
> > > +	INIT_LIST_HEAD(&asd->asc_head);
> > > +	list_add(&asd->asd_list, &asd_head);

There may be something I'm missing, but it seems that this function will
allocate a v4l2_async_subdev

> > > +
> > > +found:
> > > +	list_add(&asc->asc_subdev_list, &asd->asc_head);
> > > +	asc->asd = asd;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> > >  				   struct v4l2_async_connection *asc)
> > >  {
> > > @@ -662,6 +781,10 @@ int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> > >  	if (ret)
> > >  		goto unlock;
> > >
> > > +	ret = v4l2_async_find_async_subdev(notifier, asc);
> > > +	if (ret)
> > > +		goto unlock;
> > > +
> > >  	list_add_tail(&asc->asc_list, &notifier->asc_head);
> > >
> > >  unlock:
> > > @@ -809,7 +932,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
> > >  		v4l2_async_nf_unbind_all_subdevs(subdev_notifier, false);
> > >
> > >  	if (sd->asd)
> > > -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> > > +		v4l2_async_unbind_subdev_one(notifier, sd, true);
> > >  	v4l2_async_cleanup(sd);
> > >
> > >  	mutex_unlock(&list_lock);
> > > @@ -832,10 +955,12 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
> > >
> > >  	if (sd->asd) {
> > >  		struct v4l2_async_notifier *notifier = sd->notifier;
> > > +		struct v4l2_async_connection *asc;
> > >
> > > -		list_add(&sd->asd->waiting_list, &notifier->waiting_head);
> > > +		list_for_each_entry(asc, &sd->asd->asc_head, asc_subdev_list)
> > > +			list_add(&asc->waiting_list, &notifier->waiting_head);
> > >
> > > -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> > > +		v4l2_async_unbind_subdev_one(notifier, sd, true);
> > >  	}
> > >
> > >  	v4l2_async_cleanup(sd);
> > > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > > index 9cf383e81a16..750bf4ddb267 100644
> > > --- a/include/media/v4l2-async.h
> > > +++ b/include/media/v4l2-async.h
> > > @@ -8,6 +8,7 @@
> > >  #ifndef V4L2_ASYNC_H
> > >  #define V4L2_ASYNC_H
> > >
> > > +#include <linux/kref.h>
> > >  #include <linux/list.h>
> > >  #include <linux/mutex.h>
> > >
> > > @@ -63,24 +64,47 @@ struct v4l2_async_match {
> > >  };
> > >
> > >  /**
> > > - * struct v4l2_async_connection - sub-device descriptor, as known to a bridge
> > > + * struct v4l2_async_subdev - sub-device descriptor
> > >   *
> > > + * @kref:	kref for refcounting the subdev
> > > + * @asd_list:	Entry in the list of async sub-devices
> > > + * @subdev_list: used to link struct v4l2_async_subdev objects, waiting to be
> > > + *		probed, to a notifier->waiting_head list
> > > + * @asc_head:	head for struct v4l2_async_connection.asd_list list
> > > + * @registered:	whether the sub-device has been registered
> > > + */
> > > +struct v4l2_async_subdev {
> > > +	struct kref kref;
> > > +	struct list_head asd_list;
> > > +	struct list_head subdev_list;
> > 
> > subdev_list is not used
> 
> Thanks, I think I just forgot this here when splitting the two.
> 
> > > +	struct list_head asc_head;
> > > +	bool registered;
> > > +};
> > > +
> > > +/**
> > > + * struct v4l2_async_connection - sub-device connection descriptor, as known to
> > > + *				  a bridge
> > > + *
> > > + * @asd:	the async sub-device related to this connection
> > >   * @match:	struct of match type and per-bus type matching data sets
> > >   * @asc_list:	used to add struct v4l2_async_connection objects to the
> > >   *		master notifier @asc_list
> > >   * @waiting_list: used to link struct v4l2_async_connection objects, waiting to
> > >   *		be probed, to a notifier->waiting list
> > > + * @asc_subdev_list:	entry in struct v4l2_async_subdev.asc_head list
> > >   *
> > > - * When this struct is used as a member in a driver specific struct,
> > > - * the driver specific struct shall contain the &struct
> > > - * v4l2_async_connection as its first member.
> > > + * When this struct is used as a member in a driver specific struct, the driver
> > > + * specific struct shall contain the &struct v4l2_async_connection as its first
> > > + * member.
> > >   */
> > >  struct v4l2_async_connection {
> > > +	struct v4l2_async_subdev *asd;
> > >  	struct v4l2_async_match match;
> > >
> > >  	/* v4l2-async core private: not to be used by drivers */
> > >  	struct list_head asc_list;
> > >  	struct list_head waiting_list;
> > > +	struct list_head asc_subdev_list;
> > >  };
> > >
> > >  /**
> > > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > > index a2cce11dda5c..d510fe6ea243 100644
> > > --- a/include/media/v4l2-subdev.h
> > > +++ b/include/media/v4l2-subdev.h
> > > @@ -1063,7 +1063,7 @@ struct v4l2_subdev {
> > >  	struct device *dev;
> > >  	struct fwnode_handle *fwnode;
> > >  	struct list_head async_list;
> > > -	struct v4l2_async_connection *asd;
> > > +	struct v4l2_async_subdev *asd;
> > >  	struct v4l2_async_notifier *notifier;
> > >  	struct v4l2_async_notifier *subdev_notifier;
> > >  	struct v4l2_subdev_platform_data *pdata;

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 01/18] media: v4l: async: Return async sub-devices to subnotifier list
  2023-04-25  1:28   ` Laurent Pinchart
@ 2023-04-25  8:32     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-25  8:32 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 04:28:57AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Thu, Mar 30, 2023 at 02:58:36PM +0300, Sakari Ailus wrote:
> > When an async notifier is unregistered, the async sub-devices in the
> > notifier's done list will disappear with the notifier. However this is
> > currently also done to the sub-notifiers that remain registered. Their
> > sub-devices only need to be unbound while the async sub-devices themselves
> > need to be returned to the sub-notifier's waiting list. Do this now.
> > 
> > Fixes: 2cab00bb076b ("media: v4l: async: Allow binding notifiers to sub-devices")
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/v4l2-core/v4l2-async.c | 13 ++++++++-----
> >  1 file changed, 8 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index 2f1b718a9189..008a2a3e312e 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -414,7 +414,8 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
> >  
> >  /* Unbind all sub-devices in the notifier tree. */
> >  static void
> > -v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
> > +v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> > +				 bool readd)
> 
> I've read this as "read d" and was wondering what it meant. Maybe
> "re_add" would be a better variable name ?
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

Thank you.

The patch has been already merged and the argument will soon disappear with
the async rework patchset.

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 02/18] media: v4l: async: Add some debug prints
  2023-04-21  8:18       ` Laurent Pinchart
@ 2023-04-27  9:18         ` Sakari Ailus
  2023-04-27 17:27           ` Laurent Pinchart
  0 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-04-27  9:18 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Laurent,

On Fri, Apr 21, 2023 at 11:18:42AM +0300, Laurent Pinchart wrote:
> Hello,
> 
> On Fri, Apr 14, 2023 at 01:46:54PM +0300, Sakari Ailus wrote:
> > On Thu, Apr 13, 2023 at 06:49:52PM +0200, Jacopo Mondi wrote:
> > > On Thu, Mar 30, 2023 at 02:58:37PM +0300, Sakari Ailus wrote:
> > > > Just add some debug prints for V4L2 async sub-device matching process.
> > > > These might come useful in figuring out why things don't work as expected.
> > > >
> > > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > > ---
> > > >  drivers/media/v4l2-core/v4l2-async.c | 59 ++++++++++++++++++++++++----
> > > >  1 file changed, 52 insertions(+), 7 deletions(-)
> > > >
> > > > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > > > index 008a2a3e312e..6dd426c2ca68 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-async.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > > > @@ -75,6 +75,12 @@ static bool match_i2c(struct v4l2_async_notifier *notifier,
> > > >  #endif
> > > >  }
> > > >
> > > > +static struct device *notifier_dev(struct v4l2_async_notifier *notifier)
> > > > +{
> > > > +	return notifier->sd ? notifier->sd->dev : notifier->v4l2_dev ?
> > > > +		notifier->v4l2_dev->dev : NULL;
> 
> Nested ?: operators can be confusing, I'd write
> 
> 	if (notifier->sd)
> 		return notifier->sd->dev
> 	if (notifier->v4l2_dev)
> 		return notifier->v4l2_dev->dev;
> 	return NULL;

I don't mind. I can use that, I'll add some newlines, too.

> 
> > > > +}
> > > > +
> > > >  static bool
> > > >  match_fwnode_one(struct v4l2_async_notifier *notifier,
> > > >  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
> > > > @@ -86,13 +92,18 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > > >  	bool sd_fwnode_is_ep;
> > > >  	struct device *dev;
> > > >
> > > > +	dev_dbg(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
> 
> "async:" is a bit too generic as a prefix. Maybe "v4l2_async:" or
> "async_nf:" instead ?

"v4l2-async"?

> 
> > > > +		sd_fwnode, asd->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 == asd->match.fwnode)
> > > > +	if (sd_fwnode == asd->match.fwnode) {
> > > > +		dev_dbg(sd->dev, "async: direct match found\n");
> > > >  		return true;
> > > > +	}
> > > >
> > > >  	/*
> > > >  	 * Otherwise, check if the sd fwnode and the asd fwnode refer to an
> > > > @@ -105,8 +116,10 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > > >  	sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd_fwnode);
> > > >  	asd_fwnode_is_ep = fwnode_graph_is_endpoint(asd->match.fwnode);
> > > >
> > > > -	if (sd_fwnode_is_ep == asd_fwnode_is_ep)
> > > > +	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
> > > > +		dev_dbg(sd->dev, "async: matching node types\n");
> > > 
> > > "matching node type" is misleading as it suggests a match has been
> > > found. As both sd and asd are of the same type, I would use a
> > > message similar to the above
> > > 
> > > 		dev_dbg(sd->dev, "async: direct match failed\n");
> > 
> > As it seems further matching attempts will always produce more debug
> > prints, I'll just drop this altogether.
> 
> I'm not sure what you mean here. Isn't it useful to have an explicit
> message on failure ? I like Jacopo's proposal.

I'm fine with that.

> 
> > > >  		return false;
> > > > +	}
> > > >
> > > >  	/*
> > > >  	 * The sd and asd fwnodes are of different types. Get the device fwnode
> > > > @@ -120,10 +133,15 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > > >  		other_fwnode = sd_fwnode;
> > > >  	}
> > > >
> > > > +	dev_dbg(sd->dev, "async: fwnode compat match, need %pfw, trying %pfw\n",
> > > > +		dev_fwnode, other_fwnode);
> > > > +
> > > >  	fwnode_handle_put(dev_fwnode);
> > > >
> > > > -	if (dev_fwnode != other_fwnode)
> > > > +	if (dev_fwnode != other_fwnode) {
> > > > +		dev_dbg(sd->dev, "async: compat match not found\n");
> > > 
> > > and to be more consistent: "compat match failed"
> > 
> > I think it's in all cases either "found" or "not found" in this patch.
> > 
> > > >  		return false;
> > > > +	}
> > > >
> > > >  	/*
> > > >  	 * We have a heterogeneous match. Retrieve the struct device of the side
> > > > @@ -143,12 +161,17 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > > >  			   dev->driver->name);
> > > >  	}
> > > >
> > > > +	dev_dbg(sd->dev, "async: compat match found\n");
> > > > +
> > > >  	return true;
> > > >  }
> > > >
> > > >  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > > >  			 struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> > > >  {
> > > > +	dev_dbg(sd->dev, "async: matching for notifier %pfw, sd %pfw\n",
> 
> Maybe mentioning "fwnode" here ?

Yes. I'll remove "for", too.

> 
> > > > +		dev_fwnode(notifier_dev(notifier)), sd->fwnode);
> 
> Is there a reason to print the notifier dev as a fwnode instead of using
> dev_name() ?

Yes. These strings are comparable to sub-device node names, so this should
help figuring out what is the async sub-device being matched to. This is
the case on both DT and ACPI.

But see below.

> 
> I'm also wondering, wouldn't it be better to use notifier_dev(notifier)
> as the dev argument to dev_dbg(), and print dev_name(sd->dev) in the
> format string ? That's what you're doing below.

Once there is a match, yes. But if that fails to happen, fwnodes are the
most relevant...

> 
> Also, sd->fwnode is printed in match_fwnode_one(), so you could possibly
> drop it from here.

but yes, that's a good point. I'll drop printing fwnodes here.

> 
> > > > +
> > > >  	if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
> > > >  		return true;
> > > >
> > > > @@ -156,6 +179,8 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > > >  	if (IS_ERR_OR_NULL(sd->fwnode->secondary))
> > > >  		return false;
> > > >
> > > > +	dev_dbg(sd->dev, "async: trying secondary fwnode match\n");
> > > > +
> > > >  	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
> > > >  }
> > > >
> > > > @@ -247,16 +272,21 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
> > > >  {
> > > >  	struct v4l2_subdev *sd;
> > > >
> > > > -	if (!list_empty(&notifier->waiting))
> > > > +	if (!list_empty(&notifier->waiting)) {
> > > > +		dev_dbg(notifier_dev(notifier), "async: waiting for subdevs\n");
> > > >  		return false;
> > > > +	}
> > > >
> > > >  	list_for_each_entry(sd, &notifier->done, async_list) {
> > > >  		struct v4l2_async_notifier *subdev_notifier =
> > > >  			v4l2_async_find_subdev_notifier(sd);
> > > >
> > > >  		if (subdev_notifier &&
> > > > -		    !v4l2_async_nf_can_complete(subdev_notifier))
> > > > +		    !v4l2_async_nf_can_complete(subdev_notifier)) {
> > > > +			dev_dbg(notifier_dev(notifier),
> > > > +				"async: cannot complete\n");
> > > 
> > > These two will be printed out a lot of times, don't they ?
> > 
> > That may be, if you have many async sub-devices. Perhaps these could be
> > dropped --- the user will be able to find what is still pending via sysfs.
> 
> I'm fine with that. If you want to keep the message, can you print the
> subdev_notifier dev in the message here ?

I'll drop it for now.

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching
  2023-04-25  1:37           ` Laurent Pinchart
@ 2023-04-27  9:23             ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-27  9:23 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Niklas Söderlund, Jacopo Mondi, linux-media, Philipp Zabel,
	hverkuil, Francesco Dolcini, aishwarya.kothari, Robert Foss,
	Todor Tomov, Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 04:37:42AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> On Mon, Apr 24, 2023 at 10:33:06PM +0300, Sakari Ailus wrote:
> > On Mon, Apr 24, 2023 at 09:20:22PM +0200, Niklas Söderlund wrote:
> > > On 2023-04-14 14:07:40 +0300, Sakari Ailus wrote:
> > > > On Thu, Apr 13, 2023 at 06:50:04PM +0200, Jacopo Mondi wrote:
> > > > > On Thu, Mar 30, 2023 at 02:58:38PM +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.
> > > > > 
> > > > > As you know I'm a bit debated.
> > > > > 
> > > > > Strict endpoint-matching requires one subdev to be registed per each
> > > > > endpoint, and this is tedious for drivers that have to register a
> > > > > subdev for each of its endpoints
> > > > > 
> > > > > Allowing a subdev to be matched multiple times on different endpoints
> > > > > gives a way for lazy drivers to take a shortcut and simplify their
> > > > > topologies to a single subdev, when they would actually need more.
> > > > 
> > > > I'd say this is really about interface design, not being "lazy". It depends
> > > > on the sub-device. Ideally the framework should be also as easy for drivers
> > > > drivers to use as possible.
> > > > 
> > > > What is not supported, though, is multiple sub-devices with a single device
> > > > node. Do we need that? At least I don't think I came across a driver that
> > > > would.
> > > 
> > > If I understand you correctly about multiple sub-device from a single 
> > > device node, this exists today. The ADV748x driver have a single device 
> > > node in DT and register multiple sub-devices, one for each source 
> > > endpoint.
> > > 
> > > The ADV748x have two CSI-2 transmitters, one 4-lane and one 1-lane as 
> > > well as two different video capture "ports" one HDMI and one CVBS. Both 
> > > capture ports can be active at the same time and routed internally 
> > > inside the ADV748x to the two different CSI-2 transmitters.
> > > 
> > > In order todo this the ADV748x register multiple subdevices and modifies 
> > > the fwnode to be the endpoint instead of the device node. So the change 
> > > in this patch for ADV748x driver would break that driver.
> > 
> > Ah, indeed. I guess I'll need to support that case as well then. It doesn't
> > seem to be troublesome to implement, but I'm tempted making it a special
> > case: every other driver would apparently be fine matching with device
> > fwnode whereas doing endpoint-to-endpoint matching adds complexity to the
> > drivers. This patch removes about 100 lines of rather ugly code largely
> > from v4l2-async.
> 
> It's only 50 lines from v4l2-async, and I don't think the code is uglier
> than the rest of the file :-) In general, I prefer implementing tricky
> code in the framework and simplifying drivers. I think our goals align
> there, the framework should do the right thing by default for the
> majority of cases. However, as Niklas pointed out, endpoint matching is
> needed for drivers that register multiple subdevs with external
> connections (such as the adv742x), and that's exactly why endpoint
> matching was added in the first place. I think this needs to be kept.

I'm certainly fine with keeping functionality that driver needs and indeed
did not intend to break it. However I'd like to simplify this for majority
of drivers, this one can use additional APIs to get the job done.

I'll address this in v2.

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 04/18] media: v4l: async: Make V4L2 async match information a struct
  2023-04-25  1:10   ` Laurent Pinchart
@ 2023-04-27 10:36     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-27 10:36 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 04:10:57AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Thu, Mar 30, 2023 at 02:58:39PM +0300, Sakari Ailus wrote:
> > Make V4L2 async match information a struct, making it easier to use it
> > elsewhere outside the scope of struct v4l2_async_subdev.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/v4l2-core/v4l2-async.c  | 18 ++++++-------
> >  drivers/media/v4l2-core/v4l2-fwnode.c |  2 +-
> >  include/media/v4l2-async.h            | 39 ++++++++++++++++-----------
> >  3 files changed, 33 insertions(+), 26 deletions(-)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index 13fe0bdc70b6..bb78e3618ab5 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -147,7 +147,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
> >  
> >  	list_for_each_entry(asd, &notifier->waiting, list) {
> >  		/* bus_type has been verified valid before */
> > -		switch (asd->match_type) {
> > +		switch (asd->match.type) {
> >  		case V4L2_ASYNC_MATCH_I2C:
> 
> Renaming V4L2_ASYNC_MATCH_* to V4L2_ASYNC_MATCH_TYPE_* would be nice in
> a separate patch.

I'll add one on top.

> 
> >  			match = match_i2c;
> >  			break;
> > @@ -172,10 +172,10 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
> >  static bool asd_equal(struct v4l2_async_subdev *asd_x,
> >  		      struct v4l2_async_subdev *asd_y)
> >  {
> > -	if (asd_x->match_type != asd_y->match_type)
> > +	if (asd_x->match.type != asd_y->match.type)
> >  		return false;
> >  
> > -	switch (asd_x->match_type) {
> > +	switch (asd_x->match.type) {
> >  	case V4L2_ASYNC_MATCH_I2C:
> >  		return asd_x->match.i2c.adapter_id ==
> >  			asd_y->match.i2c.adapter_id &&
> > @@ -494,7 +494,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
> >  	if (!asd)
> >  		return -EINVAL;
> >  
> > -	switch (asd->match_type) {
> > +	switch (asd->match.type) {
> >  	case V4L2_ASYNC_MATCH_I2C:
> >  	case V4L2_ASYNC_MATCH_FWNODE:
> >  		if (v4l2_async_nf_has_async_subdev(notifier, asd, this_index)) {
> > @@ -504,7 +504,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
> >  		break;
> >  	default:
> >  		dev_err(dev, "Invalid match type %u on %p\n",
> > -			asd->match_type, asd);
> > +			asd->match.type, asd);
> >  		return -EINVAL;
> >  	}
> >  
> > @@ -630,7 +630,7 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> >  		return;
> >  
> >  	list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
> > -		switch (asd->match_type) {
> > +		switch (asd->match.type) {
> >  		case V4L2_ASYNC_MATCH_FWNODE:
> >  			fwnode_handle_put(asd->match.fwnode);
> >  			break;
> > @@ -685,7 +685,7 @@ __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
> >  	if (!asd)
> >  		return ERR_PTR(-ENOMEM);
> >  
> > -	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> > +	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
> >  	asd->match.fwnode = fwnode_handle_get(fwnode);
> >  
> >  	ret = __v4l2_async_nf_add_subdev(notifier, asd);
> > @@ -732,7 +732,7 @@ __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier, int adapter_id,
> >  	if (!asd)
> >  		return ERR_PTR(-ENOMEM);
> >  
> > -	asd->match_type = V4L2_ASYNC_MATCH_I2C;
> > +	asd->match.type = V4L2_ASYNC_MATCH_I2C;
> >  	asd->match.i2c.adapter_id = adapter_id;
> >  	asd->match.i2c.address = address;
> >  
> > @@ -850,7 +850,7 @@ EXPORT_SYMBOL(v4l2_async_unregister_subdev);
> >  static void print_waiting_subdev(struct seq_file *s,
> >  				 struct v4l2_async_subdev *asd)
> >  {
> > -	switch (asd->match_type) {
> > +	switch (asd->match.type) {
> >  	case V4L2_ASYNC_MATCH_I2C:
> >  		seq_printf(s, " [i2c] dev=%d-%04x\n", asd->match.i2c.adapter_id,
> >  			   asd->match.i2c.address);
> > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > index 3d9533c1b202..e6bd63364bed 100644
> > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > @@ -811,7 +811,7 @@ v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
> >  	if (!asd)
> >  		return -ENOMEM;
> >  
> > -	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> > +	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
> >  	asd->match.fwnode =
> >  		fwnode_graph_get_remote_port_parent(endpoint);
> >  	if (!asd->match.fwnode) {
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index 25eb1d138c06..0c4cffd081c9 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -34,23 +34,38 @@ enum v4l2_async_match_type {
> >  };
> >  
> >  /**
> > - * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> > + * struct v4l2_async_match - async sub-device match information
> 
> The new structure name sounds like it stores data about an actual match,
> while in reality it stores information for matching subdevs with
> notifier entries. How about naming the structure v4l2_async_match_info,
> or v4l2_async_match_descriptor or v4l2_async_match_desc ?

v4l2_async_match_desc is shorter, I'll use that.

> 
> >   *
> > - * @match_type:	type of match that will be used
> > - * @match:	union of per-bus type matching data sets
> > - * @match.fwnode:
> > + * @type:	type of match that will be used
> > + * @fwnode:
> >   *		pointer to &struct fwnode_handle to be matched.
> >   *		Used if @match_type is %V4L2_ASYNC_MATCH_FWNODE.
> > - * @match.i2c:	embedded struct with I2C parameters to be matched.
> > + * @i2c:	embedded struct with I2C parameters to be matched.
> >   *		Both @match.i2c.adapter_id and @match.i2c.address
> >   *		should be matched.
> >   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> > - * @match.i2c.adapter_id:
> > + * @i2c.adapter_id:
> >   *		I2C adapter ID to be matched.
> >   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> > - * @match.i2c.address:
> > + * @i2c.address:
> >   *		I2C address to be matched.
> >   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> > + */
> > +struct v4l2_async_match {
> > +	enum v4l2_async_match_type type;
> > +	union {
> > +		struct fwnode_handle *fwnode;
> > +		struct {
> > +			int adapter_id;
> > +			unsigned short address;
> > +		} i2c;
> > +	};
> > +};
> > +
> > +/**
> > + * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> > + *
> > + * @match:	struct of match type and per-bus type matching data sets
> >   * @asd_list:	used to add struct v4l2_async_subdev objects to the
> >   *		master notifier @asd_list
> >   * @list:	used to link struct v4l2_async_subdev objects, waiting to be
> > @@ -61,15 +76,7 @@ enum v4l2_async_match_type {
> >   * v4l2_async_subdev as its first member.
> >   */
> >  struct v4l2_async_subdev {
> > -	enum v4l2_async_match_type match_type;
> > -	union {
> > -		struct fwnode_handle *fwnode;
> > -		struct {
> > -			int adapter_id;
> > -			unsigned short address;
> > -		} i2c;
> > -	} match;
> > -
> > +	struct v4l2_async_match match;
> >  	/* v4l2-async core private: not to be used by drivers */
> >  	struct list_head list;
> >  	struct list_head asd_list;
> 

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 04/18] media: v4l: async: Make V4L2 async match information a struct
  2023-04-13 16:51   ` Jacopo Mondi
@ 2023-04-27 10:47     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-27 10:47 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linux-media, Philipp Zabel, Laurent Pinchart, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Jacopo,

On Thu, Apr 13, 2023 at 06:51:29PM +0200, Jacopo Mondi wrote:
> Hi Sakari
> 
> On Thu, Mar 30, 2023 at 02:58:39PM +0300, Sakari Ailus wrote:
> > Make V4L2 async match information a struct, making it easier to use it
> > elsewhere outside the scope of struct v4l2_async_subdev.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/v4l2-core/v4l2-async.c  | 18 ++++++-------
> >  drivers/media/v4l2-core/v4l2-fwnode.c |  2 +-
> >  include/media/v4l2-async.h            | 39 ++++++++++++++++-----------
> >  3 files changed, 33 insertions(+), 26 deletions(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index 13fe0bdc70b6..bb78e3618ab5 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -147,7 +147,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
> >
> >  	list_for_each_entry(asd, &notifier->waiting, list) {
> >  		/* bus_type has been verified valid before */
> > -		switch (asd->match_type) {
> > +		switch (asd->match.type) {
> >  		case V4L2_ASYNC_MATCH_I2C:
> >  			match = match_i2c;
> >  			break;
> > @@ -172,10 +172,10 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
> >  static bool asd_equal(struct v4l2_async_subdev *asd_x,
> >  		      struct v4l2_async_subdev *asd_y)
> >  {
> > -	if (asd_x->match_type != asd_y->match_type)
> > +	if (asd_x->match.type != asd_y->match.type)
> >  		return false;
> >
> > -	switch (asd_x->match_type) {
> > +	switch (asd_x->match.type) {
> >  	case V4L2_ASYNC_MATCH_I2C:
> >  		return asd_x->match.i2c.adapter_id ==
> >  			asd_y->match.i2c.adapter_id &&
> > @@ -494,7 +494,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
> >  	if (!asd)
> >  		return -EINVAL;
> >
> > -	switch (asd->match_type) {
> > +	switch (asd->match.type) {
> >  	case V4L2_ASYNC_MATCH_I2C:
> >  	case V4L2_ASYNC_MATCH_FWNODE:
> >  		if (v4l2_async_nf_has_async_subdev(notifier, asd, this_index)) {
> > @@ -504,7 +504,7 @@ static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
> >  		break;
> >  	default:
> >  		dev_err(dev, "Invalid match type %u on %p\n",
> > -			asd->match_type, asd);
> > +			asd->match.type, asd);
> >  		return -EINVAL;
> >  	}
> >
> > @@ -630,7 +630,7 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> >  		return;
> >
> >  	list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
> > -		switch (asd->match_type) {
> > +		switch (asd->match.type) {
> >  		case V4L2_ASYNC_MATCH_FWNODE:
> >  			fwnode_handle_put(asd->match.fwnode);
> >  			break;
> > @@ -685,7 +685,7 @@ __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
> >  	if (!asd)
> >  		return ERR_PTR(-ENOMEM);
> >
> > -	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> > +	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
> >  	asd->match.fwnode = fwnode_handle_get(fwnode);
> >
> >  	ret = __v4l2_async_nf_add_subdev(notifier, asd);
> > @@ -732,7 +732,7 @@ __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier, int adapter_id,
> >  	if (!asd)
> >  		return ERR_PTR(-ENOMEM);
> >
> > -	asd->match_type = V4L2_ASYNC_MATCH_I2C;
> > +	asd->match.type = V4L2_ASYNC_MATCH_I2C;
> >  	asd->match.i2c.adapter_id = adapter_id;
> >  	asd->match.i2c.address = address;
> >
> > @@ -850,7 +850,7 @@ EXPORT_SYMBOL(v4l2_async_unregister_subdev);
> >  static void print_waiting_subdev(struct seq_file *s,
> >  				 struct v4l2_async_subdev *asd)
> >  {
> > -	switch (asd->match_type) {
> > +	switch (asd->match.type) {
> >  	case V4L2_ASYNC_MATCH_I2C:
> >  		seq_printf(s, " [i2c] dev=%d-%04x\n", asd->match.i2c.adapter_id,
> >  			   asd->match.i2c.address);
> > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > index 3d9533c1b202..e6bd63364bed 100644
> > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > @@ -811,7 +811,7 @@ v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
> >  	if (!asd)
> >  		return -ENOMEM;
> >
> > -	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> > +	asd->match.type = V4L2_ASYNC_MATCH_FWNODE;
> >  	asd->match.fwnode =
> >  		fwnode_graph_get_remote_port_parent(endpoint);
> >  	if (!asd->match.fwnode) {
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index 25eb1d138c06..0c4cffd081c9 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -34,23 +34,38 @@ enum v4l2_async_match_type {
> >  };
> >
> >  /**
> > - * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> > + * struct v4l2_async_match - async sub-device match information
> >   *
> > - * @match_type:	type of match that will be used
> > - * @match:	union of per-bus type matching data sets
> > - * @match.fwnode:
> > + * @type:	type of match that will be used
> > + * @fwnode:
> >   *		pointer to &struct fwnode_handle to be matched.
> 
> These two could be on a single line

Will fix for v2.

> 
> >   *		Used if @match_type is %V4L2_ASYNC_MATCH_FWNODE.
> > - * @match.i2c:	embedded struct with I2C parameters to be matched.
> > + * @i2c:	embedded struct with I2C parameters to be matched.
> >   *		Both @match.i2c.adapter_id and @match.i2c.address
> >   *		should be matched.
> >   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> > - * @match.i2c.adapter_id:
> > + * @i2c.adapter_id:
> >   *		I2C adapter ID to be matched.
> >   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> > - * @match.i2c.address:
> > + * @i2c.address:
> >   *		I2C address to be matched.
> >   *		Used if @match_type is %V4L2_ASYNC_MATCH_I2C.
> > + */
> > +struct v4l2_async_match {
> > +	enum v4l2_async_match_type type;
> > +	union {
> > +		struct fwnode_handle *fwnode;
> > +		struct {
> > +			int adapter_id;
> > +			unsigned short address;
> > +		} i2c;
> > +	};
> > +};
> > +
> > +/**
> > + * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> > + *
> > + * @match:	struct of match type and per-bus type matching data sets
> >   * @asd_list:	used to add struct v4l2_async_subdev objects to the
> >   *		master notifier @asd_list
> >   * @list:	used to link struct v4l2_async_subdev objects, waiting to be
> > @@ -61,15 +76,7 @@ enum v4l2_async_match_type {
> >   * v4l2_async_subdev as its first member.
> >   */
> >  struct v4l2_async_subdev {
> > -	enum v4l2_async_match_type match_type;
> > -	union {
> > -		struct fwnode_handle *fwnode;
> > -		struct {
> > -			int adapter_id;
> > -			unsigned short address;
> > -		} i2c;
> > -	} match;
> > -
> > +	struct v4l2_async_match match;
> 
> nit: I would maintain a blank line

I'll rework some of this still, the comment is actually wrong as none of
these fields are expected to be accessed by drivers.

> 
> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

Thanks!

> 
> Thanks
>    j
> 
> >  	/* v4l2-async core private: not to be used by drivers */
> >  	struct list_head list;
> >  	struct list_head asd_list;

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 05/18] media: v4l: async: Clean testing for duplicated async subdevs
  2023-04-25  1:15   ` Laurent Pinchart
@ 2023-04-27 11:06     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-27 11:06 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 04:15:41AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Thu, Mar 30, 2023 at 02:58:40PM +0300, Sakari Ailus wrote:
> > There's a need to verify that a single async sub-device isn't being added
> > multiple times, this would be an error. This takes place at the time of
> > adding the async sub-device to the notifier's list as well as when the
> > notifier is added to the global notifier's list.
> > 
> > Use the pointer to the sub-device for testing this instead of an index to
> > an array that is long gone.
> 
> Reading the patch, I have no idea what the "long gone array" is. Could
> you please expand the commit message to make this easier to review ?

Yes... the async sub-devices were placed in an array earlier, that's what
the index was referring to. Although this could be an entry in a linked
list. Not how they are usually referred to though. This will go away
permanently later on in the set.

I'll add this to the commit message.

> v4l2-async is very difficult to follow in general, reviewing this series
> is painful :-S Let's try to improve it with better commit messages.

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 06/18] media: v4l: async: Only pass match information for async subdev validation
  2023-04-25  1:24   ` Laurent Pinchart
@ 2023-04-27 11:45     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-27 11:45 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 04:24:26AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.

Thank you for the review.

> 
> On Thu, Mar 30, 2023 at 02:58:41PM +0300, Sakari Ailus wrote:
> > Pass only information required for sub-device matching to functions
> > checking whether the async sub-device already exists. Do the same for
> > debug message printing. This makes further changes to other aspects of
> > async sub-devices easier.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/v4l2-core/v4l2-async.c | 93 ++++++++++++++--------------
> >  1 file changed, 46 insertions(+), 47 deletions(-)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index fc9ae22e2b47..224ebf50f2d0 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -62,14 +62,14 @@ static void v4l2_async_nf_call_destroy(struct v4l2_async_notifier *n,
> >  }
> >  
> >  static bool match_i2c(struct v4l2_async_notifier *notifier,
> > -		      struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> > +		      struct v4l2_subdev *sd, struct v4l2_async_match *match)
> >  {
> >  #if IS_ENABLED(CONFIG_I2C)
> >  	struct i2c_client *client = i2c_verify_client(sd->dev);
> >  
> >  	return client &&
> > -		asd->match.i2c.adapter_id == client->adapter->nr &&
> > -		asd->match.i2c.address == client->addr;
> > +		match->i2c.adapter_id == client->adapter->nr &&
> > +		match->i2c.address == client->addr;
> >  #else
> >  	return false;
> >  #endif
> > @@ -84,26 +84,26 @@ static struct device *notifier_dev(struct v4l2_async_notifier *notifier)
> >  static bool
> >  match_fwnode_one(struct v4l2_async_notifier *notifier,
> >  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
> > -		 struct v4l2_async_subdev *asd)
> > +		 struct v4l2_async_match *match)
> >  {
> >  	struct fwnode_handle *asd_dev_fwnode;
> 
> match_dev_node, to remove references to asd ?

Sounds good.

> 
> >  	bool ret;
> >  
> >  	dev_dbg(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
> > -		sd_fwnode, asd->match.fwnode);
> > +		sd_fwnode, match->fwnode);
> >  
> > -	if (sd_fwnode == asd->match.fwnode) {
> > +	if (sd_fwnode == match->fwnode) {
> >  		dev_dbg(sd->dev, "async: direct match found\n");
> >  		return true;
> >  	}
> >  
> > -	if (!fwnode_graph_is_endpoint(asd->match.fwnode)) {
> > +	if (!fwnode_graph_is_endpoint(match->fwnode)) {
> >  		dev_dbg(sd->dev,
> >  			"async: async subdev fwnode not endpoint, no match\n");
> 
> The reference to "subdev" could be dropped here too.

This will get changed in an earlier patch to "v4l2-async: direct match
failed".

> 
> >  		return false;
> >  	}
> >  
> > -	asd_dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
> > +	asd_dev_fwnode = fwnode_graph_get_port_parent(match->fwnode);
> >  
> >  	ret = sd_fwnode == asd_dev_fwnode;
> >  
> > @@ -116,12 +116,12 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> >  }
> >  
> >  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > -			 struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> > +			 struct v4l2_subdev *sd, struct v4l2_async_match *match)
> >  {
> >  	dev_dbg(sd->dev, "async: matching for notifier %pfw, sd %pfw\n",
> >  		dev_fwnode(notifier_dev(notifier)), sd->fwnode);
> >  
> > -	if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
> > +	if (match_fwnode_one(notifier, sd, sd->fwnode, match))
> >  		return true;
> >  
> >  	/* Also check the secondary fwnode. */
> > @@ -130,7 +130,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
> >  
> >  	dev_dbg(sd->dev, "async: trying secondary fwnode match\n");
> >  
> > -	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
> > +	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, match);
> >  }
> >  
> >  static LIST_HEAD(subdev_list);
> > @@ -142,7 +142,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
> >  		      struct v4l2_subdev *sd)
> >  {
> >  	bool (*match)(struct v4l2_async_notifier *notifier,
> > -		      struct v4l2_subdev *sd, struct v4l2_async_subdev *asd);
> > +		      struct v4l2_subdev *sd, struct v4l2_async_match *match);
> >  	struct v4l2_async_subdev *asd;
> >  
> >  	list_for_each_entry(asd, &notifier->waiting, list) {
> > @@ -161,7 +161,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
> >  		}
> >  
> >  		/* match cannot be NULL here */
> > -		if (match(notifier, sd, asd))
> > +		if (match(notifier, sd, &asd->match))
> >  			return asd;
> >  	}
> >  
> > @@ -169,20 +169,18 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier,
> >  }
> >  
> >  /* Compare two async sub-device descriptors for equivalence */
> > -static bool asd_equal(struct v4l2_async_subdev *asd_x,
> > -		      struct v4l2_async_subdev *asd_y)
> > +static bool asd_equal(struct v4l2_async_match *match1,
> > +		      struct v4l2_async_match *match2)
> 
> The function doesn't deal with asds anymore, let's rename it.
> v4l2_async_match_equal() could be a good name. Please also update the
> comment above the function.

Seems fine.

> 
> >  {
> > -	if (asd_x->match.type != asd_y->match.type)
> > +	if (match1->type != match2->type)
> >  		return false;
> >  
> > -	switch (asd_x->match.type) {
> > +	switch (match1->type) {
> >  	case V4L2_ASYNC_MATCH_I2C:
> > -		return asd_x->match.i2c.adapter_id ==
> > -			asd_y->match.i2c.adapter_id &&
> > -			asd_x->match.i2c.address ==
> > -			asd_y->match.i2c.address;
> > +		return match1->i2c.adapter_id == match2->i2c.adapter_id &&
> > +			match1->i2c.address == match2->i2c.address;
> >  	case V4L2_ASYNC_MATCH_FWNODE:
> > -		return asd_x->match.fwnode == asd_y->match.fwnode;
> > +		return match1->fwnode == match2->fwnode;
> >  	default:
> >  		break;
> >  	}
> > @@ -434,20 +432,20 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> >  /* See if an async sub-device can be found in a notifier's lists. */
> >  static bool
> >  __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> > -				 struct v4l2_async_subdev *asd)
> > +				 struct v4l2_async_match *match)
> 
> This function should be renamed to drop "subdev" as well.
> __v4l2_async_nf_has_match() is a candidate,
> __v4l2_async_nf_has_match_entry() is also an option to avoid implying
> that the function tests for a match between a subdev and a match entry.

Seems fine to me.

> 
> >  {
> > -	struct v4l2_async_subdev *asd_y;
> > +	struct v4l2_async_subdev *asd;
> >  	struct v4l2_subdev *sd;
> >  
> > -	list_for_each_entry(asd_y, &notifier->waiting, list)
> > -		if (asd_equal(asd, asd_y))
> > +	list_for_each_entry(asd, &notifier->waiting, list)
> > +		if (asd_equal(&asd->match, match))
> >  			return true;
> >  
> >  	list_for_each_entry(sd, &notifier->done, async_list) {
> >  		if (WARN_ON(!sd->asd))
> >  			continue;
> >  
> > -		if (asd_equal(asd, sd->asd))
> > +		if (asd_equal(&sd->asd->match, match))
> >  			return true;
> >  	}
> >  
> > @@ -460,49 +458,50 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> >   */
> >  static bool
> >  v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> > -			       struct v4l2_async_subdev *asd, bool skip_self)
> > +			       struct v4l2_async_match *match, bool skip_self)
> 
> Same here.
> 
> >  {
> > -	struct v4l2_async_subdev *asd_y;
> > +	struct v4l2_async_subdev *asd;
> >  
> >  	lockdep_assert_held(&list_lock);
> >  
> >  	/* Check that an asd is not being added more than once. */
> > -	list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
> > -		if (asd == asd_y)
> > +	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
> > +		if (&asd->match == match)
> >  			break;
> > -		if (asd_equal(asd, asd_y))
> > +		if (asd_equal(&asd->match, match))
> >  			return true;
> >  	}
> >  
> >  	/* Check that an asd does not exist in other notifiers. */
> >  	list_for_each_entry(notifier, &notifier_list, list)
> > -		if (__v4l2_async_nf_has_async_subdev(notifier, asd))
> > +		if (__v4l2_async_nf_has_async_subdev(notifier, match))
> >  			return true;
> >  
> >  	return false;
> >  }
> >  
> >  static int v4l2_async_nf_asd_valid(struct v4l2_async_notifier *notifier,
> > -				   struct v4l2_async_subdev *asd,
> > +				   struct v4l2_async_match *match,
> >  				   bool skip_self)
> 
> And here.
> 
> >  {
> >  	struct device *dev =
> >  		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
> >  
> > -	if (!asd)
> > +	if (!match)
> >  		return -EINVAL;
> >  
> > -	switch (asd->match.type) {
> > +	switch (match->type) {
> >  	case V4L2_ASYNC_MATCH_I2C:
> >  	case V4L2_ASYNC_MATCH_FWNODE:
> > -		if (v4l2_async_nf_has_async_subdev(notifier, asd, skip_self)) {
> > +		if (v4l2_async_nf_has_async_subdev(notifier, match,
> > +						   skip_self)) {
> >  			dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
> 
> "match descriptor" ?


Yes!

> 
> >  			return -EEXIST;
> >  		}
> >  		break;
> >  	default:
> > -		dev_err(dev, "Invalid match type %u on %p\n",
> > -			asd->match.type, asd);
> > +		dev_err(dev, "Invalid match type %u on %p\n", match->type,
> > +			match);
> >  		return -EINVAL;
> >  	}
> >  
> > @@ -526,7 +525,7 @@ static int __v4l2_async_nf_register(struct v4l2_async_notifier *notifier)
> >  	mutex_lock(&list_lock);
> >  
> >  	list_for_each_entry(asd, &notifier->asd_list, asd_list) {
> > -		ret = v4l2_async_nf_asd_valid(notifier, asd, true);
> > +		ret = v4l2_async_nf_asd_valid(notifier, &asd->match, true);
> >  		if (ret)
> >  			goto err_unlock;
> >  
> > @@ -659,7 +658,7 @@ int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
> >  
> >  	mutex_lock(&list_lock);
> >  
> > -	ret = v4l2_async_nf_asd_valid(notifier, asd, false);
> > +	ret = v4l2_async_nf_asd_valid(notifier, &asd->match, false);
> >  	if (ret)
> >  		goto unlock;
> >  
> > @@ -846,15 +845,15 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
> >  EXPORT_SYMBOL(v4l2_async_unregister_subdev);
> >  
> >  static void print_waiting_subdev(struct seq_file *s,
> 
> Same here. v4l2_async_print_match() or v4l2_async_print_match_entry()
> could be good names.

v4l2_async_print_waiting_matches()?

> 
> In general, it would be useful to have a glossary of terms used in
> v4l2-async, and make sure they're used consistently.

I think this should be already outside this set. I'm all for consolidated
terms though. I'll go through the set in this respect as well.

> 
> > -				 struct v4l2_async_subdev *asd)
> > +				 struct v4l2_async_match *match)
> >  {
> > -	switch (asd->match.type) {
> > +	switch (match->type) {
> >  	case V4L2_ASYNC_MATCH_I2C:
> > -		seq_printf(s, " [i2c] dev=%d-%04x\n", asd->match.i2c.adapter_id,
> > -			   asd->match.i2c.address);
> > +		seq_printf(s, " [i2c] dev=%d-%04x\n", match->i2c.adapter_id,
> > +			   match->i2c.address);
> >  		break;
> >  	case V4L2_ASYNC_MATCH_FWNODE: {
> > -		struct fwnode_handle *devnode, *fwnode = asd->match.fwnode;
> > +		struct fwnode_handle *devnode, *fwnode = match->fwnode;
> >  
> >  		devnode = fwnode_graph_is_endpoint(fwnode) ?
> >  			  fwnode_graph_get_port_parent(fwnode) :
> > @@ -891,7 +890,7 @@ static int pending_subdevs_show(struct seq_file *s, void *data)
> >  	list_for_each_entry(notif, &notifier_list, list) {
> >  		seq_printf(s, "%s:\n", v4l2_async_nf_name(notif));
> >  		list_for_each_entry(asd, &notif->waiting, list)
> > -			print_waiting_subdev(s, asd);
> > +			print_waiting_subdev(s, &asd->match);
> >  	}
> >  
> >  	mutex_unlock(&list_lock);
> 

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 07/18] media: v4l: async: Clean up list heads and entries
  2023-04-25  0:49   ` Laurent Pinchart
@ 2023-04-27 11:52     ` Sakari Ailus
  2023-04-27 17:36       ` Laurent Pinchart
  0 siblings, 1 reply; 73+ messages in thread
From: Sakari Ailus @ 2023-04-27 11:52 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 03:49:36AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Thu, Mar 30, 2023 at 02:58:42PM +0300, Sakari Ailus wrote:
> > The naming of list heads and list entries is confusing as they're named
> > similarly. Use _head for list head and _list for list entries.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  2 +-
> >  .../platform/renesas/rcar-vin/rcar-core.c     |  2 +-
> >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  2 +-
> >  drivers/media/platform/xilinx/xilinx-vipp.c   | 10 +--
> >  drivers/media/v4l2-core/v4l2-async.c          | 66 +++++++++----------
> >  .../staging/media/imx/imx-media-dev-common.c  |  2 +-
> >  drivers/staging/media/tegra-video/vi.c        |  6 +-
> >  include/media/v4l2-async.h                    | 21 +++---
> >  8 files changed, 56 insertions(+), 55 deletions(-)
> 
> [snip]
> 
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index 0c4cffd081c9..425280b4d387 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -68,7 +68,7 @@ struct v4l2_async_match {
> >   * @match:	struct of match type and per-bus type matching data sets
> >   * @asd_list:	used to add struct v4l2_async_subdev objects to the
> >   *		master notifier @asd_list
> 
> It's now called @asd_head.
> 
> > - * @list:	used to link struct v4l2_async_subdev objects, waiting to be
> > + * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
> >   *		probed, to a notifier->waiting list
> 
> It's now called notifier->waiting_head.
> 
> Please double-check comments and documentation to catch other
> occurrences.

Sure.

> 
> >   *
> >   * When this struct is used as a member in a driver specific struct,
> > @@ -77,9 +77,10 @@ struct v4l2_async_match {
> >   */
> >  struct v4l2_async_subdev {
> >  	struct v4l2_async_match match;
> > +
> >  	/* v4l2-async core private: not to be used by drivers */
> > -	struct list_head list;
> >  	struct list_head asd_list;
> > +	struct list_head waiting_list;
> >  };
> >  
> >  /**
> > @@ -108,20 +109,20 @@ struct v4l2_async_notifier_operations {
> >   * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
> >   * @sd:		sub-device that registered the notifier, NULL otherwise
> >   * @parent:	parent notifier
> > - * @asd_list:	master list of struct v4l2_async_subdev
> > - * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
> > - * @done:	list of struct v4l2_subdev, already probed
> > - * @list:	member in a global list of notifiers
> > + * @asd_head:	master list of struct v4l2_async_subdev
> > + * @waiting_list: list of struct v4l2_async_subdev, waiting for their drivers
> > + * @done_head:	list of struct v4l2_subdev, already probed
> > + * @notifier_list: member in a global list of notifiers
> >   */
> >  struct v4l2_async_notifier {
> >  	const struct v4l2_async_notifier_operations *ops;
> >  	struct v4l2_device *v4l2_dev;
> >  	struct v4l2_subdev *sd;
> >  	struct v4l2_async_notifier *parent;
> > -	struct list_head asd_list;
> > -	struct list_head waiting;
> > -	struct list_head done;
> > -	struct list_head list;
> > +	struct list_head asd_head;
> > +	struct list_head waiting_head;
> > +	struct list_head done_head;
> > +	struct list_head notifier_list;
> 
> I find the _head suffix to still be confusing. How about the following ?
> 
> 	struct {
> 		struct list_head all;
> 		struct list_head waiting;
> 		struct list_head done;
> 	} asds;

There are many list heads and entries in v4l2-async related structs and
before this patch. _head is used for all list heads, _list for list
entries. I prefer having _head as this way it is trivial to look for all
instances of that list head, removing the _head part makes this much
harder.

How about using _entry for list entries instead?

There doesn't seem to be much consistency in the kernel but in the majority
of cases it is self-evident I guess.

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 02/18] media: v4l: async: Add some debug prints
  2023-04-27  9:18         ` Sakari Ailus
@ 2023-04-27 17:27           ` Laurent Pinchart
  2023-04-28  7:29             ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-27 17:27 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

On Thu, Apr 27, 2023 at 12:18:43PM +0300, Sakari Ailus wrote:
> On Fri, Apr 21, 2023 at 11:18:42AM +0300, Laurent Pinchart wrote:
> > On Fri, Apr 14, 2023 at 01:46:54PM +0300, Sakari Ailus wrote:
> > > On Thu, Apr 13, 2023 at 06:49:52PM +0200, Jacopo Mondi wrote:
> > > > On Thu, Mar 30, 2023 at 02:58:37PM +0300, Sakari Ailus wrote:
> > > > > Just add some debug prints for V4L2 async sub-device matching process.
> > > > > These might come useful in figuring out why things don't work as expected.
> > > > >
> > > > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > > > ---
> > > > >  drivers/media/v4l2-core/v4l2-async.c | 59 ++++++++++++++++++++++++----
> > > > >  1 file changed, 52 insertions(+), 7 deletions(-)
> > > > >
> > > > > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > > > > index 008a2a3e312e..6dd426c2ca68 100644
> > > > > --- a/drivers/media/v4l2-core/v4l2-async.c
> > > > > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > > > > @@ -75,6 +75,12 @@ static bool match_i2c(struct v4l2_async_notifier *notifier,
> > > > >  #endif
> > > > >  }
> > > > >
> > > > > +static struct device *notifier_dev(struct v4l2_async_notifier *notifier)
> > > > > +{
> > > > > +	return notifier->sd ? notifier->sd->dev : notifier->v4l2_dev ?
> > > > > +		notifier->v4l2_dev->dev : NULL;
> > 
> > Nested ?: operators can be confusing, I'd write
> > 
> > 	if (notifier->sd)
> > 		return notifier->sd->dev
> > 	if (notifier->v4l2_dev)
> > 		return notifier->v4l2_dev->dev;
> > 	return NULL;
> 
> I don't mind. I can use that, I'll add some newlines, too.
> 
> > > > > +}
> > > > > +
> > > > >  static bool
> > > > >  match_fwnode_one(struct v4l2_async_notifier *notifier,
> > > > >  		 struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
> > > > > @@ -86,13 +92,18 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > > > >  	bool sd_fwnode_is_ep;
> > > > >  	struct device *dev;
> > > > >
> > > > > +	dev_dbg(sd->dev, "async: fwnode match: need %pfw, trying %pfw\n",
> > 
> > "async:" is a bit too generic as a prefix. Maybe "v4l2_async:" or
> > "async_nf:" instead ?
> 
> "v4l2-async"?

Works for me.

> > > > > +		sd_fwnode, asd->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 == asd->match.fwnode)
> > > > > +	if (sd_fwnode == asd->match.fwnode) {
> > > > > +		dev_dbg(sd->dev, "async: direct match found\n");
> > > > >  		return true;
> > > > > +	}
> > > > >
> > > > >  	/*
> > > > >  	 * Otherwise, check if the sd fwnode and the asd fwnode refer to an
> > > > > @@ -105,8 +116,10 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > > > >  	sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd_fwnode);
> > > > >  	asd_fwnode_is_ep = fwnode_graph_is_endpoint(asd->match.fwnode);
> > > > >
> > > > > -	if (sd_fwnode_is_ep == asd_fwnode_is_ep)
> > > > > +	if (sd_fwnode_is_ep == asd_fwnode_is_ep) {
> > > > > +		dev_dbg(sd->dev, "async: matching node types\n");
> > > > 
> > > > "matching node type" is misleading as it suggests a match has been
> > > > found. As both sd and asd are of the same type, I would use a
> > > > message similar to the above
> > > > 
> > > > 		dev_dbg(sd->dev, "async: direct match failed\n");
> > > 
> > > As it seems further matching attempts will always produce more debug
> > > prints, I'll just drop this altogether.
> > 
> > I'm not sure what you mean here. Isn't it useful to have an explicit
> > message on failure ? I like Jacopo's proposal.
> 
> I'm fine with that.
> 
> > > > >  		return false;
> > > > > +	}
> > > > >
> > > > >  	/*
> > > > >  	 * The sd and asd fwnodes are of different types. Get the device fwnode
> > > > > @@ -120,10 +133,15 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > > > >  		other_fwnode = sd_fwnode;
> > > > >  	}
> > > > >
> > > > > +	dev_dbg(sd->dev, "async: fwnode compat match, need %pfw, trying %pfw\n",
> > > > > +		dev_fwnode, other_fwnode);
> > > > > +
> > > > >  	fwnode_handle_put(dev_fwnode);
> > > > >
> > > > > -	if (dev_fwnode != other_fwnode)
> > > > > +	if (dev_fwnode != other_fwnode) {
> > > > > +		dev_dbg(sd->dev, "async: compat match not found\n");
> > > > 
> > > > and to be more consistent: "compat match failed"
> > > 
> > > I think it's in all cases either "found" or "not found" in this patch.
> > > 
> > > > >  		return false;
> > > > > +	}
> > > > >
> > > > >  	/*
> > > > >  	 * We have a heterogeneous match. Retrieve the struct device of the side
> > > > > @@ -143,12 +161,17 @@ match_fwnode_one(struct v4l2_async_notifier *notifier,
> > > > >  			   dev->driver->name);
> > > > >  	}
> > > > >
> > > > > +	dev_dbg(sd->dev, "async: compat match found\n");
> > > > > +
> > > > >  	return true;
> > > > >  }
> > > > >
> > > > >  static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > > > >  			 struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> > > > >  {
> > > > > +	dev_dbg(sd->dev, "async: matching for notifier %pfw, sd %pfw\n",
> > 
> > Maybe mentioning "fwnode" here ?
> 
> Yes. I'll remove "for", too.
> 
> > > > > +		dev_fwnode(notifier_dev(notifier)), sd->fwnode);
> > 
> > Is there a reason to print the notifier dev as a fwnode instead of using
> > dev_name() ?
> 
> Yes. These strings are comparable to sub-device node names, so this should
> help figuring out what is the async sub-device being matched to. This is
> the case on both DT and ACPI.
> 
> But see below.
> 
> > I'm also wondering, wouldn't it be better to use notifier_dev(notifier)
> > as the dev argument to dev_dbg(), and print dev_name(sd->dev) in the
> > format string ? That's what you're doing below.
> 
> Once there is a match, yes. But if that fails to happen, fwnodes are the
> most relevant...

My main point was about using notifier_dev(notifier) as the dev argument
to dev_dbg(), and printing sd in the message. The notifier seems to be
the core object to me here, I think that's what we should use as context
for dev_dbg().

> > Also, sd->fwnode is printed in match_fwnode_one(), so you could possibly
> > drop it from here.
> 
> but yes, that's a good point. I'll drop printing fwnodes here.
> 
> > > > > +
> > > > >  	if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
> > > > >  		return true;
> > > > >
> > > > > @@ -156,6 +179,8 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > > > >  	if (IS_ERR_OR_NULL(sd->fwnode->secondary))
> > > > >  		return false;
> > > > >
> > > > > +	dev_dbg(sd->dev, "async: trying secondary fwnode match\n");
> > > > > +
> > > > >  	return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
> > > > >  }
> > > > >
> > > > > @@ -247,16 +272,21 @@ v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
> > > > >  {
> > > > >  	struct v4l2_subdev *sd;
> > > > >
> > > > > -	if (!list_empty(&notifier->waiting))
> > > > > +	if (!list_empty(&notifier->waiting)) {
> > > > > +		dev_dbg(notifier_dev(notifier), "async: waiting for subdevs\n");
> > > > >  		return false;
> > > > > +	}
> > > > >
> > > > >  	list_for_each_entry(sd, &notifier->done, async_list) {
> > > > >  		struct v4l2_async_notifier *subdev_notifier =
> > > > >  			v4l2_async_find_subdev_notifier(sd);
> > > > >
> > > > >  		if (subdev_notifier &&
> > > > > -		    !v4l2_async_nf_can_complete(subdev_notifier))
> > > > > +		    !v4l2_async_nf_can_complete(subdev_notifier)) {
> > > > > +			dev_dbg(notifier_dev(notifier),
> > > > > +				"async: cannot complete\n");
> > > > 
> > > > These two will be printed out a lot of times, don't they ?
> > > 
> > > That may be, if you have many async sub-devices. Perhaps these could be
> > > dropped --- the user will be able to find what is still pending via sysfs.
> > 
> > I'm fine with that. If you want to keep the message, can you print the
> > subdev_notifier dev in the message here ?
> 
> I'll drop it for now.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 07/18] media: v4l: async: Clean up list heads and entries
  2023-04-27 11:52     ` Sakari Ailus
@ 2023-04-27 17:36       ` Laurent Pinchart
  2023-04-28  7:37         ` Sakari Ailus
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent Pinchart @ 2023-04-27 17:36 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Sakari,

On Thu, Apr 27, 2023 at 02:52:37PM +0300, Sakari Ailus wrote:
> On Tue, Apr 25, 2023 at 03:49:36AM +0300, Laurent Pinchart wrote:
> > On Thu, Mar 30, 2023 at 02:58:42PM +0300, Sakari Ailus wrote:
> > > The naming of list heads and list entries is confusing as they're named
> > > similarly. Use _head for list head and _list for list entries.
> > > 
> > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > ---
> > >  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  2 +-
> > >  .../platform/renesas/rcar-vin/rcar-core.c     |  2 +-
> > >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  2 +-
> > >  drivers/media/platform/xilinx/xilinx-vipp.c   | 10 +--
> > >  drivers/media/v4l2-core/v4l2-async.c          | 66 +++++++++----------
> > >  .../staging/media/imx/imx-media-dev-common.c  |  2 +-
> > >  drivers/staging/media/tegra-video/vi.c        |  6 +-
> > >  include/media/v4l2-async.h                    | 21 +++---
> > >  8 files changed, 56 insertions(+), 55 deletions(-)
> > 
> > [snip]
> > 
> > > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > > index 0c4cffd081c9..425280b4d387 100644
> > > --- a/include/media/v4l2-async.h
> > > +++ b/include/media/v4l2-async.h
> > > @@ -68,7 +68,7 @@ struct v4l2_async_match {
> > >   * @match:	struct of match type and per-bus type matching data sets
> > >   * @asd_list:	used to add struct v4l2_async_subdev objects to the
> > >   *		master notifier @asd_list
> > 
> > It's now called @asd_head.
> > 
> > > - * @list:	used to link struct v4l2_async_subdev objects, waiting to be
> > > + * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
> > >   *		probed, to a notifier->waiting list
> > 
> > It's now called notifier->waiting_head.
> > 
> > Please double-check comments and documentation to catch other
> > occurrences.
> 
> Sure.
> 
> > 
> > >   *
> > >   * When this struct is used as a member in a driver specific struct,
> > > @@ -77,9 +77,10 @@ struct v4l2_async_match {
> > >   */
> > >  struct v4l2_async_subdev {
> > >  	struct v4l2_async_match match;
> > > +
> > >  	/* v4l2-async core private: not to be used by drivers */
> > > -	struct list_head list;
> > >  	struct list_head asd_list;
> > > +	struct list_head waiting_list;
> > >  };
> > >  
> > >  /**
> > > @@ -108,20 +109,20 @@ struct v4l2_async_notifier_operations {
> > >   * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
> > >   * @sd:		sub-device that registered the notifier, NULL otherwise
> > >   * @parent:	parent notifier
> > > - * @asd_list:	master list of struct v4l2_async_subdev
> > > - * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
> > > - * @done:	list of struct v4l2_subdev, already probed
> > > - * @list:	member in a global list of notifiers
> > > + * @asd_head:	master list of struct v4l2_async_subdev
> > > + * @waiting_list: list of struct v4l2_async_subdev, waiting for their drivers
> > > + * @done_head:	list of struct v4l2_subdev, already probed
> > > + * @notifier_list: member in a global list of notifiers
> > >   */
> > >  struct v4l2_async_notifier {
> > >  	const struct v4l2_async_notifier_operations *ops;
> > >  	struct v4l2_device *v4l2_dev;
> > >  	struct v4l2_subdev *sd;
> > >  	struct v4l2_async_notifier *parent;
> > > -	struct list_head asd_list;
> > > -	struct list_head waiting;
> > > -	struct list_head done;
> > > -	struct list_head list;
> > > +	struct list_head asd_head;
> > > +	struct list_head waiting_head;
> > > +	struct list_head done_head;
> > > +	struct list_head notifier_list;
> > 
> > I find the _head suffix to still be confusing. How about the following ?
> > 
> > 	struct {
> > 		struct list_head all;
> > 		struct list_head waiting;
> > 		struct list_head done;
> > 	} asds;
> 
> There are many list heads and entries in v4l2-async related structs and
> before this patch. _head is used for all list heads, _list for list
> entries. I prefer having _head as this way it is trivial to look for all
> instances of that list head, removing the _head part makes this much
> harder.
> 
> How about using _entry for list entries instead?

I like that. I would have used _entry for the list entries, and _list
for the list "heads". I don't like the _head suffix very much, as all of
them are struct list_head instances. I won't nack the series for this
though :-)

> There doesn't seem to be much consistency in the kernel but in the majority
> of cases it is self-evident I guess.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 02/18] media: v4l: async: Add some debug prints
  2023-04-27 17:27           ` Laurent Pinchart
@ 2023-04-28  7:29             ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-28  7:29 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Laurent,

On Thu, Apr 27, 2023 at 08:27:52PM +0300, Laurent Pinchart wrote:
> > > I'm also wondering, wouldn't it be better to use notifier_dev(notifier)
> > > as the dev argument to dev_dbg(), and print dev_name(sd->dev) in the
> > > format string ? That's what you're doing below.
> > 
> > Once there is a match, yes. But if that fails to happen, fwnodes are the
> > most relevant...
> 
> My main point was about using notifier_dev(notifier) as the dev argument
> to dev_dbg(), and printing sd in the message. The notifier seems to be
> the core object to me here, I think that's what we should use as context
> for dev_dbg().

Ah, yes, this makes sense, I've actually already made that change.

-- 
Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 07/18] media: v4l: async: Clean up list heads and entries
  2023-04-27 17:36       ` Laurent Pinchart
@ 2023-04-28  7:37         ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-28  7:37 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Laurent,

On Thu, Apr 27, 2023 at 08:36:21PM +0300, Laurent Pinchart wrote:
> > > > -	struct list_head asd_list;
> > > > -	struct list_head waiting;
> > > > -	struct list_head done;
> > > > -	struct list_head list;
> > > > +	struct list_head asd_head;
> > > > +	struct list_head waiting_head;
> > > > +	struct list_head done_head;
> > > > +	struct list_head notifier_list;
> > > 
> > > I find the _head suffix to still be confusing. How about the following ?
> > > 
> > > 	struct {
> > > 		struct list_head all;
> > > 		struct list_head waiting;
> > > 		struct list_head done;
> > > 	} asds;
> > 
> > There are many list heads and entries in v4l2-async related structs and
> > before this patch. _head is used for all list heads, _list for list
> > entries. I prefer having _head as this way it is trivial to look for all
> > instances of that list head, removing the _head part makes this much
> > harder.
> > 
> > How about using _entry for list entries instead?
> 
> I like that. I would have used _entry for the list entries, and _list
> for the list "heads". I don't like the _head suffix very much, as all of
> them are struct list_head instances. I won't nack the series for this
> though :-)

I'm fine with "_list" suffix for list heads, I happened to choose "_head"
when writing the set. It's trivial to change that.

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 08/18] media: v4l: async: Rename v4l2_async_subdev as v4l2_async_connection
  2023-04-25  0:59       ` Laurent Pinchart
@ 2023-04-28  9:33         ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-28  9:33 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 03:59:50AM +0300, Laurent Pinchart wrote:
> Hi Sakari
> 
> On Fri, Apr 14, 2023 at 03:17:56PM +0300, Sakari Ailus wrote:
> > On Fri, Apr 14, 2023 at 10:22:41AM +0200, Jacopo Mondi wrote:
> > > On Thu, Mar 30, 2023 at 02:58:43PM +0300, Sakari Ailus wrote:
> > > > This patch has been generated by:
> > > >
> > > > 	git grep -l v4l2_async_subdev | \
> > > > 		while read i; do \
> > > > 			spatch --sp-file async.spatch --in-place $i; done \
> > > > 			perl -i -pe 's/v4l2_async_\Ksubdev/connection/g' $i \
> > > > 		done
> > > >
> > > > While async.spatch looks like:
> > > >
> > > > @ name @
> > > > @@
> > > > - struct v4l2_async_subdev
> > > > + struct v4l2_async_connection
> > > >
> > > > Additionally, __v4l2_async_nf_add_subdev() has been renamed as
> > > > __v4l2_async_nf_add_connection(). Some manual editing has been performed
> > > > as well.
> 
> The commit message fails to explain why.

I'll add this for v2.

> 
> > > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > > ---
> > > >  .../driver-api/media/v4l2-subdev.rst          |  10 +-
> > > >  drivers/media/i2c/max9286.c                   |   9 +-
> > > >  drivers/media/i2c/st-mipid02.c                |   8 +-
> > > >  drivers/media/i2c/tc358746.c                  |   6 +-
> > > >  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  10 +-
> > > >  drivers/media/platform/atmel/atmel-isi.c      |   8 +-
> > > >  drivers/media/platform/atmel/atmel-isi.h      |   2 +-
> > > >  drivers/media/platform/cadence/cdns-csi2rx.c  |   6 +-
> > > >  drivers/media/platform/intel/pxa_camera.c     |  12 +-
> > > >  drivers/media/platform/marvell/cafe-driver.c  |   5 +-
> > > >  drivers/media/platform/marvell/mcam-core.c    |   4 +-
> > > >  drivers/media/platform/marvell/mmp-driver.c   |   4 +-
> > > >  .../platform/microchip/microchip-csi2dc.c     |   6 +-
> > > >  .../platform/microchip/microchip-isc-base.c   |   4 +-
> > > >  .../media/platform/microchip/microchip-isc.h  |   2 +-
> > > >  .../microchip/microchip-sama5d2-isc.c         |   4 +-
> > > >  .../microchip/microchip-sama7g5-isc.c         |   4 +-
> > > >  drivers/media/platform/nxp/imx-mipi-csis.c    |   6 +-
> > > >  drivers/media/platform/nxp/imx7-media-csi.c   |   6 +-
> > > >  drivers/media/platform/qcom/camss/camss.c     |   2 +-
> > > >  drivers/media/platform/qcom/camss/camss.h     |   2 +-
> > > >  drivers/media/platform/renesas/rcar-isp.c     |   8 +-
> > > >  .../platform/renesas/rcar-vin/rcar-core.c     |  18 +-
> > > >  .../platform/renesas/rcar-vin/rcar-csi2.c     |   8 +-
> > > >  .../platform/renesas/rcar-vin/rcar-vin.h      |   4 +-
> > > >  drivers/media/platform/renesas/rcar_drif.c    |   8 +-
> > > >  drivers/media/platform/renesas/renesas-ceu.c  |   6 +-
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  10 +-
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |   2 +-
> > > >  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   |   8 +-
> > > >  .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
> > > >  .../platform/rockchip/rkisp1/rkisp1-dev.c     |   4 +-
> > > >  .../platform/samsung/exynos4-is/media-dev.c   |   6 +-
> > > >  .../platform/samsung/exynos4-is/media-dev.h   |   2 +-
> > > >  drivers/media/platform/st/stm32/stm32-dcmi.c  |   8 +-
> > > >  .../platform/sunxi/sun4i-csi/sun4i_csi.c      |   6 +-
> > > >  .../sunxi/sun6i-csi/sun6i_csi_bridge.c        |   2 +-
> > > >  .../sunxi/sun6i-csi/sun6i_csi_bridge.h        |   2 +-
> > > >  .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c   |   6 +-
> > > >  .../sun8i_a83t_mipi_csi2.c                    |   6 +-
> > > >  .../media/platform/ti/am437x/am437x-vpfe.c    |   5 +-
> > > >  .../media/platform/ti/am437x/am437x-vpfe.h    |   2 +-
> > > >  drivers/media/platform/ti/cal/cal.c           |   6 +-
> > > >  .../media/platform/ti/davinci/vpif_capture.c  |   7 +-
> > > >  drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
> > > >  drivers/media/platform/video-mux.c            |   6 +-
> > > >  drivers/media/platform/xilinx/xilinx-vipp.c   |  24 +--
> > > >  drivers/media/v4l2-core/v4l2-async.c          | 166 +++++++++---------
> > > >  drivers/media/v4l2-core/v4l2-fwnode.c         |  14 +-
> > > >  .../media/deprecated/atmel/atmel-isc-base.c   |   4 +-
> > > >  .../media/deprecated/atmel/atmel-isc.h        |   2 +-
> > > >  .../deprecated/atmel/atmel-sama5d2-isc.c      |   4 +-
> > > >  .../deprecated/atmel/atmel-sama7g5-isc.c      |   4 +-
> > > >  drivers/staging/media/imx/imx-media-csi.c     |   6 +-
> > > >  .../staging/media/imx/imx-media-dev-common.c  |   4 +-
> > > >  drivers/staging/media/imx/imx-media-dev.c     |   2 +-
> > > >  drivers/staging/media/imx/imx-media-of.c      |   4 +-
> > > >  drivers/staging/media/imx/imx6-mipi-csi2.c    |   8 +-
> > > >  drivers/staging/media/imx/imx8mq-mipi-csi2.c  |   6 +-
> > > >  .../media/sunxi/sun6i-isp/sun6i_isp_proc.c    |   2 +-
> > > >  .../media/sunxi/sun6i-isp/sun6i_isp_proc.h    |   2 +-
> > > >  drivers/staging/media/tegra-video/vi.c        |  14 +-
> > > >  drivers/staging/media/tegra-video/vi.h        |   2 +-
> > > >  include/media/davinci/vpif_types.h            |   2 +-
> > > >  include/media/v4l2-async.h                    |  78 ++++----
> > > >  include/media/v4l2-fwnode.h                   |  10 +-
> > > >  include/media/v4l2-subdev.h                   |   4 +-
> > > >  67 files changed, 313 insertions(+), 313 deletions(-)
> > > >
> > > > diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst
> > > > index 260cfa8c3f3d..1c5cb1a637ab 100644
> > > > --- a/Documentation/driver-api/media/v4l2-subdev.rst
> > > > +++ b/Documentation/driver-api/media/v4l2-subdev.rst
> > > > @@ -215,13 +215,13 @@ found in firmware. The notifier for the sub-device is unregistered with the
> > > >  async sub-device.
> > > >
> > > >  These functions allocate an async sub-device descriptor which is of type struct
> > > > -:c:type:`v4l2_async_subdev` embedded in a driver-specific struct. The &struct
> > > > -:c:type:`v4l2_async_subdev` shall be the first member of this struct:
> > > > +:c:type:`v4l2_async_connection` embedded in a driver-specific struct. The &struct
> > > > +:c:type:`v4l2_async_connection` shall be the first member of this struct:
> > > >
> > > >  .. code-block:: c
> > > >
> > > >  	struct my_async_subdev {
> > > > -		struct v4l2_async_subdev asd;
> > > > +		struct v4l2_async_connection asd;
> 
> s/asd/asc/

Yes.

> 
> > > >  		...
> > > >  	};
> > > >
> > > > @@ -244,10 +244,10 @@ notifier callback is called. After all subdevices have been located the
> > > >  system the .unbind() method is called. All three callbacks are optional.
> > > >
> > > >  Drivers can store any type of custom data in their driver-specific
> > > > -:c:type:`v4l2_async_subdev` wrapper. If any of that data requires special
> > > > +:c:type:`v4l2_async_connection` wrapper. If any of that data requires special
> > > >  handling when the structure is freed, drivers must implement the ``.destroy()``
> > > >  notifier callback. The framework will call it right before freeing the
> > > > -:c:type:`v4l2_async_subdev`.
> > > > +:c:type:`v4l2_async_connection`.
> > > >
> > > >  Calling subdev operations
> > > >  ~~~~~~~~~~~~~~~~~~~~~~~~~
> > > > diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
> > > > index 2d0f43e3fb9f..13cb2537a06d 100644
> > > 
> > > [snip: I'll only comment framework changes as I presume if driver
> > > changes compile, they're good]
> > > 
> > > > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > > > index 425280b4d387..9cf383e81a16 100644
> > > > --- a/include/media/v4l2-async.h
> > > > +++ b/include/media/v4l2-async.h
> > > > @@ -63,23 +63,23 @@ struct v4l2_async_match {
> > > >  };
> > > >
> > > >  /**
> > > > - * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
> > > > + * struct v4l2_async_connection - sub-device descriptor, as known to a bridge
> > > >   *
> > > >   * @match:	struct of match type and per-bus type matching data sets
> > > > - * @asd_list:	used to add struct v4l2_async_subdev objects to the
> > > > - *		master notifier @asd_list
> > > > - * @waiting_list: used to link struct v4l2_async_subdev objects, waiting to be
> > > > - *		probed, to a notifier->waiting list
> > > > + * @asc_list:	used to add struct v4l2_async_connection objects to the
> > > > + *		master notifier @asc_list
> > > 
> > > notifier asc_head
> > 
> > Thanks!
> > 
> > > > + * @waiting_list: used to link struct v4l2_async_connection objects, waiting to
> > > > + *		be probed, to a notifier->waiting list
> > > >   *
> > > >   * When this struct is used as a member in a driver specific struct,
> > > >   * the driver specific struct shall contain the &struct
> > > > - * v4l2_async_subdev as its first member.
> > > > + * v4l2_async_connection as its first member.
> > > >   */
> > > > -struct v4l2_async_subdev {
> > > > +struct v4l2_async_connection {
> > > >  	struct v4l2_async_match match;
> > > >
> > > >  	/* v4l2-async core private: not to be used by drivers */
> > > > -	struct list_head asd_list;
> > > > +	struct list_head asc_list;
> > > >  	struct list_head waiting_list;
> > > >  };
> > > >
> > > > @@ -89,17 +89,17 @@ struct v4l2_async_subdev {
> > > 
> > > For more context:
> > > 
> > >     * @bound:	        a subdevice driver has successfully probed one of the subdevices
> > > >   * @complete:	All subdevices have been probed successfully. The complete
> > > 
> > > the usage of the term "subdevice" when referring to connection is
> > > spread everywhere in documentation :/
> 
> I don't think I really like the name "connection" :-S Maybe that's
> because it's not explained properly here, neither in the commit message
> nor in the documentation. I may have better ideas when reviewing the

Connection covers data links and ancillary links that in practice are
created in bound callbacks. Feel free to propose something else. I'll add
more description for this.

> next patch, but I wonder if v4l2_async_nf_entry or v4l2_async_entry
> would be a better name. It would also allow renaming the "asd" variables
> to something more explicit.

Nf entry is rather abstract, isn't it? Although that is not necessarily an
issue: some of the current async sub-devices continue to be matched the
same way, for association rather than for actual physical bus between them.

> 
> > > But I mostly wonder, and I guess this is a comment on the next patch:
> > > do we now get multiple 'bound' calls for the same subdevice when
> > > matched on multiple connections ?
> > 
> > Correct. That isn't an issue for current drivers as the API before this set
> > only allowed a single downstream link per async sub-device. Some more of
> > the documentation probably needs to be reworked due to this.
> > 
> > > >   *		callback is only executed for the root notifier.
> > > >   * @unbind:	a subdevice is leaving
> > > > - * @destroy:	the asd is about to be freed
> > > > + * @destroy:	the asc is about to be freed
> > > >   */
> > > >  struct v4l2_async_notifier_operations {
> > > >  	int (*bound)(struct v4l2_async_notifier *notifier,
> > > >  		     struct v4l2_subdev *subdev,
> > > > -		     struct v4l2_async_subdev *asd);
> > > > +		     struct v4l2_async_connection *asc);
> > > >  	int (*complete)(struct v4l2_async_notifier *notifier);
> > > >  	void (*unbind)(struct v4l2_async_notifier *notifier,
> > > >  		       struct v4l2_subdev *subdev,
> > > > -		       struct v4l2_async_subdev *asd);
> > > > -	void (*destroy)(struct v4l2_async_subdev *asd);
> > > > +		       struct v4l2_async_connection *asc);
> > > > +	void (*destroy)(struct v4l2_async_connection *asc);
> > > >  };
> > > >
> > > >  /**
> > > > @@ -109,7 +109,7 @@ struct v4l2_async_notifier_operations {
> > > >   * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
> > > >   * @sd:		sub-device that registered the notifier, NULL otherwise
> > > >   * @parent:	parent notifier
> > > > - * @asd_head:	master list of struct v4l2_async_subdev
> > > > + * @asc_head:	master list of struct v4l2_async_subdev
> > > >   * @waiting_list: list of struct v4l2_async_subdev, waiting for their drivers
> > > >   * @done_head:	list of struct v4l2_subdev, already probed
> > > >   * @notifier_list: member in a global list of notifiers
> > > > @@ -119,7 +119,7 @@ struct v4l2_async_notifier {
> > > >  	struct v4l2_device *v4l2_dev;
> > > >  	struct v4l2_subdev *sd;
> > > >  	struct v4l2_async_notifier *parent;
> > > > -	struct list_head asd_head;
> > > > +	struct list_head asc_head;
> > > >  	struct list_head waiting_head;
> > > >  	struct list_head done_head;
> > > >  	struct list_head notifier_list;
> > > > @@ -137,75 +137,75 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
> > > >   *
> > > >   * @notifier: pointer to &struct v4l2_async_notifier
> > > >   *
> > > > - * This function initializes the notifier @asd_list. It must be called
> > > > + * This function initializes the notifier @asc_list. It must be called
> > > >   * before adding a subdevice to a notifier, using one of:
> > > >   * v4l2_async_nf_add_fwnode_remote(),
> > > >   * v4l2_async_nf_add_fwnode(),
> > > >   * v4l2_async_nf_add_i2c(),
> > > > - * __v4l2_async_nf_add_subdev() or
> > > > + * __v4l2_async_nf_add_connection() or
> > > >   * v4l2_async_nf_parse_fwnode_endpoints().
> > > >   */
> > > >  void v4l2_async_nf_init(struct v4l2_async_notifier *notifier);
> > > >
> > > >  /**
> > > > - * __v4l2_async_nf_add_subdev - Add an async subdev to the
> > > > - *				notifier's master asd list.
> > > > + * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
> > > > + *				      master asc list.
> > > >   *
> > > >   * @notifier: pointer to &struct v4l2_async_notifier
> > > > - * @asd: pointer to &struct v4l2_async_subdev
> > > > + * @asc: pointer to &struct v4l2_async_connection
> > > >   *
> > > >   * \warning: Drivers should avoid using this function and instead use one of:
> > > >   * v4l2_async_nf_add_fwnode(),
> > > >   * v4l2_async_nf_add_fwnode_remote() or
> > > >   * v4l2_async_nf_add_i2c().
> > > >   *
> > > > - * Call this function before registering a notifier to link the provided @asd to
> > > > - * the notifiers master @asd_list. The @asd must be allocated with k*alloc() as
> > > > + * Call this function before registering a notifier to link the provided @asc to
> > > > + * the notifiers master @asc_list. The @asc must be allocated with k*alloc() as
> > > >   * it will be freed by the framework when the notifier is destroyed.
> > > >   */
> > > > -int __v4l2_async_nf_add_subdev(struct v4l2_async_notifier *notifier,
> > > > -			       struct v4l2_async_subdev *asd);
> > > > +int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> > > > +				   struct v4l2_async_connection *asc);
> > > >
> > > > -struct v4l2_async_subdev *
> > > > +struct v4l2_async_connection *
> > > >  __v4l2_async_nf_add_fwnode(struct v4l2_async_notifier *notifier,
> > > >  			   struct fwnode_handle *fwnode,
> > > > -			   unsigned int asd_struct_size);
> > > > +			   unsigned int asc_struct_size);
> > > >  /**
> > > >   * v4l2_async_nf_add_fwnode - Allocate and add a fwnode async
> > > > - *				subdev to the notifier's master asd_list.
> > > > + *				subdev to the notifier's master asc_list.
> > > >   *
> > > >   * @notifier: pointer to &struct v4l2_async_notifier
> > > >   * @fwnode: fwnode handle of the sub-device to be matched, pointer to
> > > >   *	    &struct fwnode_handle
> > > >   * @type: Type of the driver's async sub-device struct. The &struct
> > > > - *	  v4l2_async_subdev shall be the first member of the driver's async
> > > > + *	  v4l2_async_connection shall be the first member of the driver's async
> > > >   *	  sub-device struct, i.e. both begin at the same memory address.
> > > >   *
> > > > - * Allocate a fwnode-matched asd of size asd_struct_size, and add it to the
> > > > - * notifiers @asd_list. The function also gets a reference of the fwnode which
> > > > + * Allocate a fwnode-matched asc of size asc_struct_size, and add it to the
> > > > + * notifiers @asc_list. The function also gets a reference of the fwnode which
> > > >   * is released later at notifier cleanup time.
> > > >   */
> > > >  #define v4l2_async_nf_add_fwnode(notifier, fwnode, type)		\
> > > >  	((type *)__v4l2_async_nf_add_fwnode(notifier, fwnode, sizeof(type)))
> > > >
> > > > -struct v4l2_async_subdev *
> > > > +struct v4l2_async_connection *
> > > >  __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
> > > >  				  struct fwnode_handle *endpoint,
> > > > -				  unsigned int asd_struct_size);
> > > > +				  unsigned int asc_struct_size);
> > > >  /**
> > > >   * v4l2_async_nf_add_fwnode_remote - Allocate and add a fwnode
> > > >   *						  remote async subdev to the
> > > > - *						  notifier's master asd_list.
> > > > + *						  notifier's master asc_list.
> > > >   *
> > > >   * @notifier: pointer to &struct v4l2_async_notifier
> > > >   * @ep: local endpoint pointing to the remote sub-device to be matched,
> > > >   *	pointer to &struct fwnode_handle
> > > >   * @type: Type of the driver's async sub-device struct. The &struct
> > > > - *	  v4l2_async_subdev shall be the first member of the driver's async
> > > > + *	  v4l2_async_connection shall be the first member of the driver's async
> > > >   *	  sub-device struct, i.e. both begin at the same memory address.
> > > >   *
> > > >   * Gets the remote endpoint of a given local endpoint, set it up for fwnode
> > > > - * matching and adds the async sub-device to the notifier's @asd_list. The
> > > > + * matching and adds the async sub-device to the notifier's @asc_list. The
> > > >   * function also gets a reference of the fwnode which is released later at
> > > >   * notifier cleanup time.
> > > >   *
> > > > @@ -215,19 +215,19 @@ __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif,
> > > >  #define v4l2_async_nf_add_fwnode_remote(notifier, ep, type) \
> > > >  	((type *)__v4l2_async_nf_add_fwnode_remote(notifier, ep, sizeof(type)))
> > > >
> > > > -struct v4l2_async_subdev *
> > > > +struct v4l2_async_connection *
> > > >  __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier,
> > > >  			int adapter_id, unsigned short address,
> > > > -			unsigned int asd_struct_size);
> > > > +			unsigned int asc_struct_size);
> > > >  /**
> > > >   * v4l2_async_nf_add_i2c - Allocate and add an i2c async
> > > > - *				subdev to the notifier's master asd_list.
> > > > + *				subdev to the notifier's master asc_list.
> > > >   *
> > > >   * @notifier: pointer to &struct v4l2_async_notifier
> > > >   * @adapter: I2C adapter ID to be matched
> > > >   * @address: I2C address of sub-device to be matched
> > > >   * @type: Type of the driver's async sub-device struct. The &struct
> > > > - *	  v4l2_async_subdev shall be the first member of the driver's async
> > > > + *	  v4l2_async_connection shall be the first member of the driver's async
> > > >   *	  sub-device struct, i.e. both begin at the same memory address.
> > > >   *
> > > >   * Same as v4l2_async_nf_add_fwnode() but for I2C matched
> > > > @@ -275,7 +275,7 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier);
> > > >   * v4l2_async_nf_add_fwnode_remote(),
> > > >   * v4l2_async_nf_add_fwnode(),
> > > >   * v4l2_async_nf_add_i2c(),
> > > > - * __v4l2_async_nf_add_subdev() or
> > > > + * __v4l2_async_nf_add_connection() or
> > > >   * v4l2_async_nf_parse_fwnode_endpoints().
> > > >   *
> > > >   * There is no harm from calling v4l2_async_nf_cleanup() in other
> > > > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > > > index 394d798f3dfa..ebb83154abd5 100644
> > > > --- a/include/media/v4l2-fwnode.h
> > > > +++ b/include/media/v4l2-fwnode.h
> > > > @@ -23,7 +23,7 @@
> > > >
> > > >  struct fwnode_handle;
> > > >  struct v4l2_async_notifier;
> > > > -struct v4l2_async_subdev;
> > > > +struct v4l2_async_connection;
> > > >
> > > >  /**
> > > >   * struct v4l2_fwnode_endpoint - the endpoint data structure
> > > > @@ -399,7 +399,7 @@ int v4l2_fwnode_device_parse(struct device *dev,
> > > >   *
> > > >   * @dev: pointer to &struct device
> > > >   * @vep: pointer to &struct v4l2_fwnode_endpoint
> > > > - * @asd: pointer to &struct v4l2_async_subdev
> > > > + * @asd: pointer to &struct v4l2_async_connection
> 
> s/asd/asc/
> 

I'm rebasing Jacopo's patch early in the set so these changes will be
eliminated.

> > > >   *
> > > >   * Return:
> > > >   * * %0 on success
> > > > @@ -409,7 +409,7 @@ int v4l2_fwnode_device_parse(struct device *dev,
> > > >   */
> > > >  typedef int (*parse_endpoint_func)(struct device *dev,
> > > >  				  struct v4l2_fwnode_endpoint *vep,
> > > > -				  struct v4l2_async_subdev *asd);
> > > > +				  struct v4l2_async_connection *asd);
> 
> s/asd/asc/
> 
> > > >
> > > >  /**
> > > >   * v4l2_async_nf_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
> > > 
> > > Ah nice this function is DEPRECATED and not used anywhere anymore.
> > > I'll send a patch on top of this series to drop it
> > 
> > Thanks! I'll toss it in.
> > 
> > > > @@ -417,8 +417,8 @@ typedef int (*parse_endpoint_func)(struct device *dev,
> > > >   * @dev: the device the endpoints of which are to be parsed
> > > >   * @notifier: notifier for @dev
> > > >   * @asd_struct_size: size of the driver's async sub-device struct, including
> > > > - *		     sizeof(struct v4l2_async_subdev). The &struct
> > > > - *		     v4l2_async_subdev shall be the first member of
> > > > + *		     sizeof(struct v4l2_async_connection). The &struct
> > > > + *		     v4l2_async_connection shall be the first member of
> > > >   *		     the driver's async sub-device struct, i.e. both
> > > >   *		     begin at the same memory address.
> > > >   * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> > > > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > > > index 17773be4a4ee..a2cce11dda5c 100644
> > > > --- a/include/media/v4l2-subdev.h
> > > > +++ b/include/media/v4l2-subdev.h
> > > > @@ -1021,7 +1021,7 @@ struct v4l2_subdev_platform_data {
> > > >   *	    either dev->of_node->fwnode or dev->fwnode (whichever is non-NULL).
> > > >   * @async_list: Links this subdev to a global subdev_list or @notifier->done
> > > >   *	list.
> > > > - * @asd: Pointer to respective &struct v4l2_async_subdev.
> > > > + * @asc: Pointer to respective &struct v4l2_async_connection.
> > > 
> > > this is still named 'asd' in code
> > 
> > Fixed.
> 
> "asd" used to stand for "Async SubDev". "asc" could be argued to stand
> for "ASync Connection", but that's a weird acronym. Would "connection"
> or "conn" be a better variable name ?

I thought "asc" would be better distinguished by folks who already know
v4l2-async and async sub-devices. I actually did use "conn" in early
version of this set.

> 
> I'm also sure you'll dislike this, but I'd like driver code to be
> changed to rename the variables too.

I have no objections, however this can be done driver-by-driver once this
set is merged. The set is already touching a large number of drivers, in
various ways.

In practice, an async connection is functionally equivalent to an async
sub-device for existing drivers after all.

> 
> > > >   * @notifier: Pointer to the managing notifier.
> > > >   * @subdev_notifier: A sub-device notifier implicitly registered for the sub-
> > > >   *		     device using v4l2_async_register_subdev_sensor().
> > > > @@ -1063,7 +1063,7 @@ struct v4l2_subdev {
> > > >  	struct device *dev;
> > > >  	struct fwnode_handle *fwnode;
> > > >  	struct list_head async_list;
> > > > -	struct v4l2_async_subdev *asd;
> > > > +	struct v4l2_async_connection *asd;
> > > >  	struct v4l2_async_notifier *notifier;
> > > >  	struct v4l2_async_notifier *subdev_notifier;
> > > >  	struct v4l2_subdev_platform_data *pdata;
> 

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 09/18] media: v4l: async: Differentiate connecting and creating sub-devices
  2023-04-25  2:14       ` Laurent Pinchart
@ 2023-04-28  9:46         ` Sakari Ailus
  2023-04-28 10:29         ` Sakari Ailus
  1 sibling, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-28  9:46 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 05:14:42AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Fri, Apr 14, 2023 at 04:35:00PM +0300, Sakari Ailus wrote:
> > On Fri, Apr 14, 2023 at 10:52:25AM +0200, Jacopo Mondi wrote:
> > > On Thu, Mar 30, 2023 at 02:58:44PM +0300, Sakari Ailus wrote:
> > > > When the v4l2-async framework was introduced, the use case for it was to
> > > > connect a camera sensor with a parallel receiver. Both tended to be rather
> > > > simple devices with a single connection between them.
> > > >
> > > > The framework has been since improved in multiple ways but there are
> > > > limitations that have remained, for instance the assumption an async
> > > > sub-device is connected towards a single notifier and via a single link
> > > > only.
> > > >
> > > > This patch adds an object that represents the device while an earlier
> > > > patch in the series re-purposed the old struct v4l2_async_subdev as the
> > > > connection.
> > > >
> > > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > > ---
> > > >  .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
> > > >  .../platform/rockchip/rkisp1/rkisp1-dev.c     |   8 +-
> > > >  drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
> > > >  drivers/media/v4l2-core/v4l2-async.c          | 163 ++++++++++++++++--
> > > >  include/media/v4l2-async.h                    |  32 +++-
> > > >  include/media/v4l2-subdev.h                   |   2 +-
> 
> We the introduction of such a new core concept, Documentation/ should
> also be updated.

This can already be done when renaming the async sub-devices earlier in the
patch. From driver point of view the semantic change takes place then.

> 
> > > >  6 files changed, 179 insertions(+), 30 deletions(-)
> > > >
> > > > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > > index d30f0ecb1bfd..a1293c45aae1 100644
> > > > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > > @@ -148,7 +148,7 @@ struct rkisp1_info {
> > > >   * @port:		port number (0: MIPI, 1: Parallel)
> > > >   */
> > > >  struct rkisp1_sensor_async {
> > > > -	struct v4l2_async_connection asd;
> > > > +	struct v4l2_async_subdev asd;
> 
> Ah, we're back to "asd" naming... There's no point in going back and
> forth in drivers, so you can ignore my comment about renaming the
> variables in drivers. Please however record the reason why variables are
> not renamed in the commit message of patch 08/18.
> 
> On second thought, why does patch 08/18 switch to v4l2_async_connection
> in a very large number of drivers, and this patch only moves back to
> v4l2_async_subdev in rkisp1 and omap3isp ? What's special about these
> two drivers ?



> 
> And on third thought this seems completely wrong,
> v4l2_async_nf_add_fwnode() will return a pointer to a struct
> v4l2_async_connection that is expected to be the first member of the
> driver-specific async structure.
> 
> > > >  	unsigned int index;
> > > >  	struct fwnode_handle *source_ep;
> > > >  	unsigned int lanes;
> > > > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > > > index 39fa98e6dbbc..5bdb1ecedf6a 100644
> > > > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > > > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
> > > > @@ -122,12 +122,12 @@ struct rkisp1_isr_data {
> > > >
> > > >  static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
> > > >  					struct v4l2_subdev *sd,
> > > > -					struct v4l2_async_connection *asd)
> > > > +					struct v4l2_async_connection *asc)
> 
> This belongs to a previous patch. Same for other changes below.
> 
> > > >  {
> > > >  	struct rkisp1_device *rkisp1 =
> > > >  		container_of(notifier, struct rkisp1_device, notifier);
> > > >  	struct rkisp1_sensor_async *s_asd =
> > > > -		container_of(asd, struct rkisp1_sensor_async, asd);
> > > > +		container_of(asc->asd, struct rkisp1_sensor_async, asd);
> > > >  	int source_pad;
> > > >  	int ret;
> > > >
> > > > @@ -165,10 +165,10 @@ static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
> > > >  	return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
> > > >  }
> > > >
> > > > -static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asd)
> > > > +static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asc)
> > > >  {
> > > >  	struct rkisp1_sensor_async *rk_asd =
> > > > -		container_of(asd, struct rkisp1_sensor_async, asd);
> > > > +		container_of(asc->asd, struct rkisp1_sensor_async, asd);
> > > >
> > > >  	fwnode_handle_put(rk_asd->source_ep);
> > > >  }
> > > > diff --git a/drivers/media/platform/ti/omap3isp/isp.h b/drivers/media/platform/ti/omap3isp/isp.h
> > > > index 32ea70c8d2f9..a9d760fbf349 100644
> > > > --- a/drivers/media/platform/ti/omap3isp/isp.h
> > > > +++ b/drivers/media/platform/ti/omap3isp/isp.h
> > > > @@ -220,7 +220,7 @@ struct isp_device {
> > > >  };
> > > >
> > > >  struct isp_async_subdev {
> > > > -	struct v4l2_async_connection asd;
> > > > +	struct v4l2_async_subdev asd;
> > > >  	struct isp_bus_cfg bus;
> > > >  };
> > > >
> > > > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > > > index 56ce40481ec4..4c3bd64d6a00 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-async.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > > > @@ -134,6 +134,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
> > > >  }
> > > >
> > > >  static LIST_HEAD(subdev_head);
> > > > +static LIST_HEAD(asd_head);
> > > >  static LIST_HEAD(notifier_head);
> > > >  static DEFINE_MUTEX(list_lock);
> > > >
> > > > @@ -304,13 +305,20 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> > > >  	struct v4l2_async_notifier *subdev_notifier;
> > > >  	int ret;
> > > >
> > > > -	ret = v4l2_device_register_subdev(v4l2_dev, sd);
> > > > -	if (ret < 0)
> > > > -		return ret;
> > > > +	if (!asc->asd->registered) {
> > > > +		ret = v4l2_device_register_subdev(v4l2_dev, sd);
> > > > +		if (ret < 0)
> > > > +			return ret;
> > > > +	}
> > > >
> > > >  	ret = v4l2_async_nf_call_bound(notifier, sd, asc);
> > > 
> > > This is the part that puzzles me the most: are we going to receive
> > > multiple bound() calls for the same subdevice when matched on multiple
> > > connections ? If that's the case, is this desirable ?
> > 
> > Yes, that is the intent: we're dealing with connections, not to much
> > sub-devices as such. That is what the current bound callbacks generally do.
> > Some also deal with sub-devices but that's fine: driver changes may be
> > needed to add support for new functionality.
> 
> Do I understand correctly that this change is meant to support the needs
> of the i.MX6 media drivers ? If so, I'd like to see them using this new
> capability of v4l2-async, to make sure it works as expected.

This set helps as it allows creating multiple links from an async
sub-device to one or more notifiers. But I'm not sure it'll be enough: you
can only have a single root notifier at the moment (as you can have a
single media device).

> 
> > > >  	if (ret < 0) {
> > > > -		v4l2_device_unregister_subdev(sd);
> > > > +		if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> > > > +			dev_dbg(notifier_dev(notifier),
> > > > +				"failed binding %pfw (%d)\n",
> > > > +				asc->match.fwnode, ret);
> > > > +		if (!asc->asd->registered)
> > > 
> > > This should probably be
> > > 		if (asc->asd->registered)
> > 
> > Oops! Well, almost. The sub-device should only be unregistered here if it
> > was just registered. But I'll fix it for v2.
> > 
> > > > +			v4l2_device_unregister_subdev(sd);
> > > >  		return ret;
> > > >  	}
> > > >
> > > > @@ -322,14 +330,26 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> > > >  	 */
> > > >  	ret = v4l2_async_create_ancillary_links(notifier, sd);
> > > 
> > > Also this part seems suspicious if called multiple times for the same
> > > subdevice when matched on multiple connections
> > > 
> > > Do we need to refcount the connections for each async sub-dev,
> > > decrement at each match, and only when all of them are matched
> > > operated on the subdevice ?
> > > :
> > 
> > The ancillary link can be created when the sub-device is registered so I
> > don't think we'll need to refcount it. I'll address this in v2.
> > 
> > > >  	if (ret) {
> > > > +		if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> > > > +			dev_dbg(notifier_dev(notifier),
> > > > +				"failed creating links for %pfw (%d)\n",
> > > > +				asc->match.fwnode, ret);
> > > >  		v4l2_async_nf_call_unbind(notifier, sd, asc);
> > > > -		v4l2_device_unregister_subdev(sd);
> > > > +		list_del(&asc->asc_subdev_list);
> > > > +		if (!asc->asd->registered)
> > > > +			v4l2_device_unregister_subdev(sd);
> > > >  		return ret;
> > > >  	}
> > > >
> > > >  	list_del(&asc->waiting_list);
> > > > -	sd->asd = asc;
> > > > -	sd->notifier = notifier;
> > > > +	if (!sd->asd) {
> > > > +		WARN_ON(asc->asd->registered);
> > > > +		sd->asd = asc->asd;
> > > > +		sd->notifier = notifier;
> > > > +		asc->asd->registered = true;
> > > > +	} else {
> > > > +		WARN_ON(sd->asd != asc->asd);
> > > > +	}
> > > >
> > > >  	/* Move from the global subdevice list to notifier's done */
> > > >  	list_move(&sd->async_list, &notifier->done_head);
> > > > @@ -403,6 +423,21 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
> > > >  	sd->asd = NULL;
> > > >  }
> > > >
> > > > +static void v4l2_async_unbind_subdev_one(struct v4l2_async_notifier *notifier,
> > > > +					 struct v4l2_subdev *sd, bool readd)
> > > > +{
> > > > +	struct v4l2_async_connection *asc, *tmp;
> > > > +
> > > > +	list_for_each_entry_safe(asc, tmp, &sd->asd->asc_head,
> > > > +				 asc_subdev_list) {
> > > > +		v4l2_async_nf_call_unbind(notifier, sd, asc);
> > > > +		list_del(&asc->asc_subdev_list);
> > > > +		if (readd)
> > > > +			list_add_tail(&asc->waiting_list,
> > > > +				      &notifier->waiting_head);
> > > > +	}
> > > > +}
> > > > +
> > > >  /* Unbind all sub-devices in the notifier tree. */
> > > >  static void
> > > >  v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> > > > @@ -417,10 +452,8 @@ v4l2_async_nf_unbind_all_subdevs(struct v4l2_async_notifier *notifier,
> > > >  		if (subdev_notifier)
> > > >  			v4l2_async_nf_unbind_all_subdevs(subdev_notifier, true);
> > > >
> > > > -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> > > > -		if (readd)
> > > > -			list_add_tail(&sd->asd->waiting_list,
> > > > -				      &notifier->waiting_head);
> > > > +		v4l2_async_unbind_subdev_one(notifier, sd, readd);
> > > > +
> > > >  		v4l2_async_cleanup(sd);
> > > >
> > > >  		list_move(&sd->async_list, &subdev_head);
> > > > @@ -445,8 +478,9 @@ __v4l2_async_nf_has_async_subdev(struct v4l2_async_notifier *notifier,
> > > >  		if (WARN_ON(!sd->asd))
> > > >  			continue;
> > > >
> > > > -		if (asc_equal(&sd->asd->match, match))
> > > > -			return true;
> > > > +		list_for_each_entry(asc, &sd->asd->asc_head, asc_list)
> > > > +			if (asc_equal(&asc->match, match))
> > > > +				return true;
> > > >  	}
> > > >
> > > >  	return false;
> > > > @@ -619,6 +653,18 @@ void v4l2_async_nf_unregister(struct v4l2_async_notifier *notifier)
> > > >  }
> > > >  EXPORT_SYMBOL(v4l2_async_nf_unregister);
> > > >
> > > > +static void release_async_subdev(struct kref *kref)
> > > > +{
> > > > +	struct v4l2_async_subdev *asd =
> > > > +		container_of_const(kref, struct v4l2_async_subdev, kref);
> > > > +
> > > > +	list_del(&asd->asd_list);
> > > > +
> > > > +	WARN_ON(!list_empty(&asd->asc_head));
> > > > +
> > > > +	kfree(asd);
> > > > +}
> > > > +
> > > >  static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> > > >  {
> > > >  	struct v4l2_async_connection *asc, *tmp;
> > > > @@ -627,16 +673,24 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> > > >  		return;
> > > >
> > > >  	list_for_each_entry_safe(asc, tmp, &notifier->asc_head, asc_list) {
> > > > +		list_del(&asc->asc_list);
> > > > +		v4l2_async_nf_call_destroy(notifier, asc);
> > > > +
> > > >  		switch (asc->match.type) {
> > > >  		case V4L2_ASYNC_MATCH_FWNODE:
> > > > +			pr_debug("release async connection for fwnode %pfw\n",
> > > > +				 asc->match.fwnode);
> > > 
> > > Why pr_debug ? Can't you use notifier_dev() ?
> > 
> > The notifier is being cleaned up. We should have dev still around though,
> > so I'll change this.
> > 
> > > >  			fwnode_handle_put(asc->match.fwnode);
> > > >  			break;
> > > > -		default:
> > > > +		case V4L2_ASYNC_MATCH_I2C:
> > > > +			pr_debug("release I²C async connection\n");
> > > >  			break;
> > > > +		default:
> > > > +			pr_debug("release invalid async connection type %u\n",
> > > > +				 asc->match.type);
> > > >  		}
> > > >
> > > > -		list_del(&asc->asc_list);
> > > > -		v4l2_async_nf_call_destroy(notifier, asc);
> > > > +		kref_put(&asc->asd->kref, release_async_subdev);
> > > >  		kfree(asc);
> > > >  	}
> > > >  }
> > > > @@ -651,6 +705,71 @@ void v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
> > > >  }
> > > >  EXPORT_SYMBOL_GPL(v4l2_async_nf_cleanup);
> > > >
> > > > +static bool async_subdev_has_connection(struct v4l2_async_notifier *notifier,
> > > > +					struct v4l2_async_subdev *asd,
> > > > +					struct v4l2_async_connection *asc)
> > > > +{
> > > > +	struct v4l2_async_connection *__asc;
> > > > +
> > > > +	list_for_each_entry(__asc, &asd->asc_head, asc_subdev_list) {
> > > > +		if (__asc->match.type != V4L2_ASYNC_MATCH_FWNODE)
> > > > +			continue;
> > > > +
> > > > +		if (__asc->match.fwnode != asc->match.fwnode)
> > > > +			continue;
> > > > +
> > > > +		dev_dbg(notifier_dev(notifier), "found!\n");
> > > 
> > > Such message without much context can quickly become noise
> > 
> > I think I'll just drop it.
> > 
> > > > +
> > > > +		return true;
> > > > +	}
> > > > +
> > > > +	return false;
> > > > +}
> > > > +
> > > > +/* Find an async sub-device for the async connection. */
> > > > +static int v4l2_async_find_async_subdev(struct v4l2_async_notifier *notifier,
> > > > +					struct v4l2_async_connection *asc)
> > > > +{
> > > > +	struct v4l2_async_subdev *asd;
> > > > +
> > > > +	lockdep_assert_held(&list_lock);
> > > > +
> > > > +	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE)
> > > > +		dev_dbg(notifier_dev(notifier),
> > > > +			"async: looking up subdev for %pfw\n",
> > > > +			asc->match.fwnode);
> > > > +
> > > > +	/*
> > > > +	 * Matching by endpoint nodes may mean there are multiple connections to
> > > > +	 * a single device. This is only possible with fwnode matching.
> > > > +	 */
> > > > +	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE &&
> > > > +	    fwnode_graph_is_endpoint(asc->match.fwnode)) {
> 
> Maybe
> 
> 	if (asc->match.type == V4L2_ASYNC_MATCH_FWNODE) {
> 		dev_dbg(notifier_dev(notifier),
> 			"async: looking up subdev for %pfw\n",
> 			asc->match.fwnode);
> 
> 		if (fwnode_graph_is_endpoint(asc->match.fwnode)) {
> 			list_for_each_entry(asd, &asd_head, asd_list) {
> 				if (async_subdev_has_connection(notifier, asd, asc)) {
> 					kref_get(&asd->kref);
> 					goto found;
> 				}
> 			}
> 		}
> 	}

Hmm. Seems fine to me.

> 
> > > > +		list_for_each_entry(asd, &asd_head, asd_list) {
> > > > +			if (async_subdev_has_connection(notifier, asd, asc)) {
> > > > +				kref_get(&asd->kref);
> > > > +				goto found;
> > > > +			}
> > > > +		}
> > > > +	}
> > > > +
> > > > +	dev_dbg(notifier_dev(notifier), "not found, allocating new one\n");
> > > > +
> > > > +	asd = kzalloc(sizeof(*asd), GFP_KERNEL);
> > > > +	if (!asd)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	kref_init(&asd->kref);
> > > > +	INIT_LIST_HEAD(&asd->asc_head);
> > > > +	list_add(&asd->asd_list, &asd_head);
> 
> There may be something I'm missing, but it seems that this function will
> allocate a v4l2_async_subdev

Yes, that's the intention. As a single async sub-device may have multiple
connections to it, one needs to determine when that async sub-device is
allocated. And that happens when the first connection is created to it.

> 
> > > > +
> > > > +found:
> > > > +	list_add(&asc->asc_subdev_list, &asd->asc_head);
> > > > +	asc->asd = asd;
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > >  int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> > > >  				   struct v4l2_async_connection *asc)
> > > >  {
> > > > @@ -662,6 +781,10 @@ int __v4l2_async_nf_add_connection(struct v4l2_async_notifier *notifier,
> > > >  	if (ret)
> > > >  		goto unlock;
> > > >
> > > > +	ret = v4l2_async_find_async_subdev(notifier, asc);
> > > > +	if (ret)
> > > > +		goto unlock;
> > > > +
> > > >  	list_add_tail(&asc->asc_list, &notifier->asc_head);
> > > >
> > > >  unlock:
> > > > @@ -809,7 +932,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
> > > >  		v4l2_async_nf_unbind_all_subdevs(subdev_notifier, false);
> > > >
> > > >  	if (sd->asd)
> > > > -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> > > > +		v4l2_async_unbind_subdev_one(notifier, sd, true);
> > > >  	v4l2_async_cleanup(sd);
> > > >
> > > >  	mutex_unlock(&list_lock);
> > > > @@ -832,10 +955,12 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
> > > >
> > > >  	if (sd->asd) {
> > > >  		struct v4l2_async_notifier *notifier = sd->notifier;
> > > > +		struct v4l2_async_connection *asc;
> > > >
> > > > -		list_add(&sd->asd->waiting_list, &notifier->waiting_head);
> > > > +		list_for_each_entry(asc, &sd->asd->asc_head, asc_subdev_list)
> > > > +			list_add(&asc->waiting_list, &notifier->waiting_head);
> > > >
> > > > -		v4l2_async_nf_call_unbind(notifier, sd, sd->asd);
> > > > +		v4l2_async_unbind_subdev_one(notifier, sd, true);
> > > >  	}
> > > >
> > > >  	v4l2_async_cleanup(sd);
> > > > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > > > index 9cf383e81a16..750bf4ddb267 100644
> > > > --- a/include/media/v4l2-async.h
> > > > +++ b/include/media/v4l2-async.h
> > > > @@ -8,6 +8,7 @@
> > > >  #ifndef V4L2_ASYNC_H
> > > >  #define V4L2_ASYNC_H
> > > >
> > > > +#include <linux/kref.h>
> > > >  #include <linux/list.h>
> > > >  #include <linux/mutex.h>
> > > >
> > > > @@ -63,24 +64,47 @@ struct v4l2_async_match {
> > > >  };
> > > >
> > > >  /**
> > > > - * struct v4l2_async_connection - sub-device descriptor, as known to a bridge
> > > > + * struct v4l2_async_subdev - sub-device descriptor
> > > >   *
> > > > + * @kref:	kref for refcounting the subdev
> > > > + * @asd_list:	Entry in the list of async sub-devices
> > > > + * @subdev_list: used to link struct v4l2_async_subdev objects, waiting to be
> > > > + *		probed, to a notifier->waiting_head list
> > > > + * @asc_head:	head for struct v4l2_async_connection.asd_list list
> > > > + * @registered:	whether the sub-device has been registered
> > > > + */
> > > > +struct v4l2_async_subdev {
> > > > +	struct kref kref;
> > > > +	struct list_head asd_list;
> > > > +	struct list_head subdev_list;
> > > 
> > > subdev_list is not used
> > 
> > Thanks, I think I just forgot this here when splitting the two.
> > 
> > > > +	struct list_head asc_head;
> > > > +	bool registered;
> > > > +};
> > > > +
> > > > +/**
> > > > + * struct v4l2_async_connection - sub-device connection descriptor, as known to
> > > > + *				  a bridge
> > > > + *
> > > > + * @asd:	the async sub-device related to this connection
> > > >   * @match:	struct of match type and per-bus type matching data sets
> > > >   * @asc_list:	used to add struct v4l2_async_connection objects to the
> > > >   *		master notifier @asc_list
> > > >   * @waiting_list: used to link struct v4l2_async_connection objects, waiting to
> > > >   *		be probed, to a notifier->waiting list
> > > > + * @asc_subdev_list:	entry in struct v4l2_async_subdev.asc_head list
> > > >   *
> > > > - * When this struct is used as a member in a driver specific struct,
> > > > - * the driver specific struct shall contain the &struct
> > > > - * v4l2_async_connection as its first member.
> > > > + * When this struct is used as a member in a driver specific struct, the driver
> > > > + * specific struct shall contain the &struct v4l2_async_connection as its first
> > > > + * member.
> > > >   */
> > > >  struct v4l2_async_connection {
> > > > +	struct v4l2_async_subdev *asd;
> > > >  	struct v4l2_async_match match;
> > > >
> > > >  	/* v4l2-async core private: not to be used by drivers */
> > > >  	struct list_head asc_list;
> > > >  	struct list_head waiting_list;
> > > > +	struct list_head asc_subdev_list;
> > > >  };
> > > >
> > > >  /**
> > > > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > > > index a2cce11dda5c..d510fe6ea243 100644
> > > > --- a/include/media/v4l2-subdev.h
> > > > +++ b/include/media/v4l2-subdev.h
> > > > @@ -1063,7 +1063,7 @@ struct v4l2_subdev {
> > > >  	struct device *dev;
> > > >  	struct fwnode_handle *fwnode;
> > > >  	struct list_head async_list;
> > > > -	struct v4l2_async_connection *asd;
> > > > +	struct v4l2_async_subdev *asd;
> > > >  	struct v4l2_async_notifier *notifier;
> > > >  	struct v4l2_async_notifier *subdev_notifier;
> > > >  	struct v4l2_subdev_platform_data *pdata;

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 09/18] media: v4l: async: Differentiate connecting and creating sub-devices
  2023-04-25  2:14       ` Laurent Pinchart
  2023-04-28  9:46         ` Sakari Ailus
@ 2023-04-28 10:29         ` Sakari Ailus
  1 sibling, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-28 10:29 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 05:14:42AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Fri, Apr 14, 2023 at 04:35:00PM +0300, Sakari Ailus wrote:
> > On Fri, Apr 14, 2023 at 10:52:25AM +0200, Jacopo Mondi wrote:
> > > On Thu, Mar 30, 2023 at 02:58:44PM +0300, Sakari Ailus wrote:
> > > > When the v4l2-async framework was introduced, the use case for it was to
> > > > connect a camera sensor with a parallel receiver. Both tended to be rather
> > > > simple devices with a single connection between them.
> > > >
> > > > The framework has been since improved in multiple ways but there are
> > > > limitations that have remained, for instance the assumption an async
> > > > sub-device is connected towards a single notifier and via a single link
> > > > only.
> > > >
> > > > This patch adds an object that represents the device while an earlier
> > > > patch in the series re-purposed the old struct v4l2_async_subdev as the
> > > > connection.
> > > >
> > > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > > ---
> > > >  .../platform/rockchip/rkisp1/rkisp1-common.h  |   2 +-
> > > >  .../platform/rockchip/rkisp1/rkisp1-dev.c     |   8 +-
> > > >  drivers/media/platform/ti/omap3isp/isp.h      |   2 +-
> > > >  drivers/media/v4l2-core/v4l2-async.c          | 163 ++++++++++++++++--
> > > >  include/media/v4l2-async.h                    |  32 +++-
> > > >  include/media/v4l2-subdev.h                   |   2 +-
> 
> We the introduction of such a new core concept, Documentation/ should
> also be updated.
> 
> > > >  6 files changed, 179 insertions(+), 30 deletions(-)
> > > >
> > > > diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > > index d30f0ecb1bfd..a1293c45aae1 100644
> > > > --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > > +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
> > > > @@ -148,7 +148,7 @@ struct rkisp1_info {
> > > >   * @port:		port number (0: MIPI, 1: Parallel)
> > > >   */
> > > >  struct rkisp1_sensor_async {
> > > > -	struct v4l2_async_connection asd;
> > > > +	struct v4l2_async_subdev asd;
> 
> Ah, we're back to "asd" naming... There's no point in going back and
> forth in drivers, so you can ignore my comment about renaming the
> variables in drivers. Please however record the reason why variables are
> not renamed in the commit message of patch 08/18.
> 
> On second thought, why does patch 08/18 switch to v4l2_async_connection
> in a very large number of drivers, and this patch only moves back to
> v4l2_async_subdev in rkisp1 and omap3isp ? What's special about these
> two drivers ?

These changes actually appear unintended currently. The relation between
the driver struct remains related to the async connection. I'll drop them.

-- 
Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 17/18] media: v4l: async: Set v4l2_device in async notifier init
  2023-04-25  0:35   ` Laurent Pinchart
  2023-04-25  2:00     ` Laurent Pinchart
@ 2023-04-28 10:33     ` Sakari Ailus
  1 sibling, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-28 10:33 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 03:35:26AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Thu, Mar 30, 2023 at 02:58:52PM +0300, Sakari Ailus wrote:
> > Set the v4l2_device already in async notifier init, so struct device
> > related to it will be available before the notifier is registered.
> > 
> > This patch has been mostly generated using the following command:
> > 
> > git grep -l v4l2_async_nf_init -- drivers/media/ drivers/staging/media/ |
> > 	while read i; do perl -e '
> > 	@a=<>; unlink("'$i'"); open(F, "> '$i'");
> > 	for $f ({i=>"v4l2_async_nf_init", r=>"v4l2_async_nf_register"},
> > 		{i=>"v4l2_async_subdev_nf_init",
> > 		 r=>"v4l2_async_subdev_nf_register"} ) {
> > 	my $b; @a = map { $b = "$1, $2" if
> > 	s/$f->{r}\(([^,]*),\s*([^\)]*)\)/v4l2_async_nf_register\($2\)/;
> > 	$_; } @a; @a = map { if (defined $b) {
> > 	s/v4l2_async_nf_init\([^\)]*\)/$f->{i}\($b\)/;
> > 	s/$f->{r}\(\K[^,]*,\s*//; }; $_; } @a; }; print F @a; close F;'
> > 	< $i; done
> 
> You should learn coccinelle at some point :-)

Sometimes Perl is just easier. :-)

> 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/i2c/max9286.c                   |  4 +-
> >  drivers/media/i2c/st-mipid02.c                |  4 +-
> >  drivers/media/i2c/tc358746.c                  |  4 +-
> >  drivers/media/pci/intel/ipu3/ipu3-cio2-main.c |  4 +-
> >  drivers/media/platform/atmel/atmel-isi.c      |  4 +-
> >  drivers/media/platform/cadence/cdns-csi2rx.c  |  4 +-
> >  drivers/media/platform/intel/pxa_camera.c     |  4 +-
> >  drivers/media/platform/marvell/cafe-driver.c  |  2 +-
> >  drivers/media/platform/marvell/mcam-core.c    |  2 +-
> >  drivers/media/platform/marvell/mmp-driver.c   |  2 +-
> >  .../platform/microchip/microchip-csi2dc.c     |  5 +--
> >  .../microchip/microchip-sama5d2-isc.c         |  5 +--
> >  .../microchip/microchip-sama7g5-isc.c         |  5 +--
> >  drivers/media/platform/nxp/imx-mipi-csis.c    |  4 +-
> >  drivers/media/platform/nxp/imx7-media-csi.c   |  4 +-
> >  drivers/media/platform/qcom/camss/camss.c     |  5 +--
> >  drivers/media/platform/renesas/rcar-isp.c     |  4 +-
> >  .../platform/renesas/rcar-vin/rcar-core.c     |  8 ++--
> >  .../platform/renesas/rcar-vin/rcar-csi2.c     |  4 +-
> >  drivers/media/platform/renesas/rcar_drif.c    |  4 +-
> >  drivers/media/platform/renesas/renesas-ceu.c  |  4 +-
> >  .../platform/renesas/rzg2l-cru/rzg2l-core.c   |  4 +-
> >  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   |  4 +-
> >  .../platform/rockchip/rkisp1/rkisp1-dev.c     |  4 +-
> >  .../platform/samsung/exynos4-is/media-dev.c   |  5 +--
> >  drivers/media/platform/st/stm32/stm32-dcmi.c  |  4 +-
> >  .../platform/sunxi/sun4i-csi/sun4i_csi.c      |  4 +-
> >  .../sunxi/sun6i-csi/sun6i_csi_bridge.c        |  6 +--
> >  .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c   |  4 +-
> >  .../sun8i_a83t_mipi_csi2.c                    |  4 +-
> >  .../media/platform/ti/am437x/am437x-vpfe.c    |  4 +-
> >  drivers/media/platform/ti/cal/cal.c           |  4 +-
> >  .../media/platform/ti/davinci/vpif_capture.c  | 11 ++---
> >  drivers/media/platform/ti/omap3isp/isp.c      |  4 +-
> >  drivers/media/platform/video-mux.c            |  4 +-
> >  drivers/media/platform/xilinx/xilinx-vipp.c   |  4 +-
> >  drivers/media/v4l2-core/v4l2-async.c          | 43 +++++++------------
> >  drivers/media/v4l2-core/v4l2-fwnode.c         |  4 +-
> >  .../deprecated/atmel/atmel-sama5d2-isc.c      |  5 +--
> >  drivers/staging/media/imx/imx-media-csi.c     |  4 +-
> >  .../staging/media/imx/imx-media-dev-common.c  |  4 +-
> >  drivers/staging/media/imx/imx6-mipi-csi2.c    |  4 +-
> >  drivers/staging/media/imx/imx8mq-mipi-csi2.c  |  4 +-
> >  .../media/sunxi/sun6i-isp/sun6i_isp_proc.c    |  4 +-
> >  drivers/staging/media/tegra-video/vi.c        |  4 +-
> >  include/media/v4l2-async.h                    | 35 +++++++++------
> >  46 files changed, 129 insertions(+), 138 deletions(-)
> 
> [snip]
> 
> > diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> > index 750bf4ddb267..cf2082e17fc4 100644
> > --- a/include/media/v4l2-async.h
> > +++ b/include/media/v4l2-async.h
> > @@ -159,6 +159,24 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir);
> >  /**
> >   * v4l2_async_nf_init - Initialize a notifier.
> >   *
> > + * @v4l2_dev: pointer to &struct v4l2_device
> > + * @notifier: pointer to &struct v4l2_async_notifier
> > + *
> > + * This function initializes the notifier @asc_list. It must be called
> > + * before adding a subdevice to a notifier, using one of:
> > + * v4l2_async_nf_add_fwnode_remote(),
> > + * v4l2_async_nf_add_fwnode(),
> > + * v4l2_async_nf_add_i2c(),
> > + * __v4l2_async_nf_add_connection() or
> > + * v4l2_async_nf_parse_fwnode_endpoints().
> > + */
> > +void v4l2_async_nf_init(struct v4l2_device *v4l2_dev,
> > +			struct v4l2_async_notifier *notifier);
> 
> The function operates on a notifier, could we make it the first argument
> ? Same for v4l2_async_subdev_nf_init().

Works for me.

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 17/18] media: v4l: async: Set v4l2_device in async notifier init
  2023-04-25  2:00     ` Laurent Pinchart
@ 2023-04-28 10:35       ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-28 10:35 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

On Tue, Apr 25, 2023 at 05:00:52AM +0300, Laurent Pinchart wrote:
> On Tue, Apr 25, 2023 at 03:35:26AM +0300, Laurent Pinchart wrote:
> > Hi Sakari,
> > 
> > Thank you for the patch.
> > 
> > On Thu, Mar 30, 2023 at 02:58:52PM +0300, Sakari Ailus wrote:
> > > Set the v4l2_device already in async notifier init, so struct device
> > > related to it will be available before the notifier is registered.
> 
> Also, please explain why this is needed.

I'll add this for v2. Basically the debug messages have NULL device before
notifier registration before this patch.

-- 
Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 10/18] media: pxa_camera: Register V4L2 device early, fix probe error handling
  2023-04-25  0:25   ` Laurent Pinchart
@ 2023-04-28 11:21     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-28 11:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 03:25:06AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Thu, Mar 30, 2023 at 02:58:45PM +0300, Sakari Ailus wrote:
> > Register V4L2 device before initialising the notifier. This way the device
> > is available to the notifier from the beginning.
> 
> Could you please explain in the commit message why this is needed ? Same
> comment for subsequent patches in this series.

Yes.

> 
> > Also fix error handling in probe.
> 
> Splitting this in two patches, with the fix first, would make it easier
> to review.

I'll address these in v2.

-- 
Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 11/18] media: marvell: cafe: Register V4L2 device earlier
  2023-04-25  0:27   ` Laurent Pinchart
@ 2023-04-28 11:22     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-28 11:22 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-media, Philipp Zabel, hverkuil, Francesco Dolcini,
	aishwarya.kothari, Robert Foss, Todor Tomov, Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 03:27:11AM +0300, Laurent Pinchart wrote:
> Hi Sakari,
> 
> Thank you for the patch.
> 
> On Thu, Mar 30, 2023 at 02:58:46PM +0300, Sakari Ailus wrote:
> > Register V4L2 device before the async notifier so the struct device will
> > be available for the notifier.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > ---
> >  drivers/media/platform/marvell/cafe-driver.c | 12 ++++++++++--
> >  drivers/media/platform/marvell/mcam-core.c   |  6 ------
> >  2 files changed, 10 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/media/platform/marvell/cafe-driver.c b/drivers/media/platform/marvell/cafe-driver.c
> > index dd1bba70bd79..4d8843623255 100644
> > --- a/drivers/media/platform/marvell/cafe-driver.c
> > +++ b/drivers/media/platform/marvell/cafe-driver.c
> > @@ -536,6 +536,11 @@ static int cafe_pci_probe(struct pci_dev *pdev,
> >  	if (ret)
> >  		goto out_pdown;
> >  
> > +	ret = v4l2_device_register(mcam->dev, &mcam->v4l2_dev);
> > +	if (ret)
> > +		goto out_smbus_shutdown;
> > +
> > +
> >  	v4l2_async_nf_init(&mcam->notifier);
> >  
> >  	asd = v4l2_async_nf_add_i2c(&mcam->notifier,
> > @@ -544,12 +549,12 @@ static int cafe_pci_probe(struct pci_dev *pdev,
> >  				    struct v4l2_async_connection);
> >  	if (IS_ERR(asd)) {
> >  		ret = PTR_ERR(asd);
> > -		goto out_smbus_shutdown;
> > +		goto out_v4l2_device_unregister;
> >  	}
> >  
> >  	ret = mccic_register(mcam);
> >  	if (ret)
> > -		goto out_smbus_shutdown;
> > +		goto out_v4l2_device_unregister;
> >  
> >  	clkdev_create(mcam->mclk, "xclk", "%d-%04x",
> >  		i2c_adapter_id(cam->i2c_adapter), ov7670_info.addr);
> > @@ -565,6 +570,8 @@ static int cafe_pci_probe(struct pci_dev *pdev,
> >  
> >  out_mccic_shutdown:
> >  	mccic_shutdown(mcam);
> > +out_v4l2_device_unregister:
> > +	v4l2_device_unregister(&mcam->v4l2_dev);
> >  out_smbus_shutdown:
> >  	cafe_smbus_shutdown(cam);
> >  out_pdown:
> > @@ -587,6 +594,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
> >  static void cafe_shutdown(struct cafe_camera *cam)
> >  {
> >  	mccic_shutdown(&cam->mcam);
> > +	v4l2_device_unregister(&cam->mcam.v4l2_dev);
> >  	cafe_smbus_shutdown(cam);
> >  	free_irq(cam->pdev->irq, cam);
> >  	pci_iounmap(cam->pdev, cam->mcam.regs);
> > diff --git a/drivers/media/platform/marvell/mcam-core.c b/drivers/media/platform/marvell/mcam-core.c
> > index b74a362ec075..2ecdcbcb37fd 100644
> > --- a/drivers/media/platform/marvell/mcam-core.c
> > +++ b/drivers/media/platform/marvell/mcam-core.c
> > @@ -1866,10 +1866,6 @@ int mccic_register(struct mcam_camera *cam)
> >  	/*
> >  	 * Register with V4L
> >  	 */
> > -	ret = v4l2_device_register(cam->dev, &cam->v4l2_dev);
> > -	if (ret)
> > -		goto out;
> > -
> >  	mutex_init(&cam->s_mutex);
> >  	cam->state = S_NOTREADY;
> >  	mcam_set_config_needed(cam, 1);
> > @@ -1915,7 +1911,6 @@ int mccic_register(struct mcam_camera *cam)
> >  
> >  out:
> >  	v4l2_async_nf_unregister(&cam->notifier);
> > -	v4l2_device_unregister(&cam->v4l2_dev);
> >  	v4l2_async_nf_cleanup(&cam->notifier);
> 
> Wouldn't the v4l2_async_nf_* calls be better placed in cafe-driver.c,
> given that v4l2_async_nf_init() is called there too ? Same below.

Probably yes, but I'd like to avoid making unnecessary changes to drivers I
can't test.

> 
> >  	return ret;
> >  }
> > @@ -1937,7 +1932,6 @@ void mccic_shutdown(struct mcam_camera *cam)
> >  		mcam_free_dma_bufs(cam);
> >  	v4l2_ctrl_handler_free(&cam->ctrl_handler);
> >  	v4l2_async_nf_unregister(&cam->notifier);
> > -	v4l2_device_unregister(&cam->v4l2_dev);
> >  	v4l2_async_nf_cleanup(&cam->notifier);
> >  }
> >  EXPORT_SYMBOL_GPL(mccic_shutdown);
> 

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

* Re: [PATCH 19/18] media: v4l: Drop v4l2_async_nf_parse_fwnode_endpoints()
  2023-04-25  1:06   ` Laurent Pinchart
@ 2023-04-28 11:30     ` Sakari Ailus
  0 siblings, 0 replies; 73+ messages in thread
From: Sakari Ailus @ 2023-04-28 11:30 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jacopo Mondi, linux-media, Philipp Zabel, hverkuil,
	Francesco Dolcini, aishwarya.kothari, Robert Foss, Todor Tomov,
	Hyun Kwon

Hi Laurent,

On Tue, Apr 25, 2023 at 04:06:54AM +0300, Laurent Pinchart wrote:
> > -/**
> > - * __v4l2_async_nf_add_connection() - Add an async subdev to the notifier's
> > - *				      master asc list.
> > - *
> > - * @notifier: pointer to &struct v4l2_async_notifier
> > - * @asc: pointer to &struct v4l2_async_connection
> > - *
> > - * \warning: Drivers should avoid using this function and instead use one of:
> > - * v4l2_async_nf_add_fwnode(),
> > - * v4l2_async_nf_add_fwnode_remote() or
> > - * v4l2_async_nf_add_i2c().
> > - *
> > - * Call this function before registering a notifier to link the provided @asc to
> > - * the notifiers master @asc_list. The @asc must be allocated with k*alloc() as
> > - * it will be freed by the framework when the notifier is destroyed.
> > - */
> 
> You could move this documentation to the .c file (dropping the warning).
> There's little documentation of internal function for v4l2-async, which
> makes the code hard to understand. Let's not make it worse by dropping
> existing documentation :-)

As this is no longer usable by drivers, I'm not sure how relevant keeping
this around for just v4l2-async internal use is.

For instance, did I read any of these comments when writing this patchset?
I can say I did not read a single one of them. They are not specific enough
for understanding the implementation anyway, this is written for driver
authors in mind. Instead what can and probably should be added are object
relations and why certain non-obvious things are done the way they are.
I'll add this for the patches when the code as such seems fine.

I'll address the rest of the comments in v2.

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 73+ messages in thread

end of thread, other threads:[~2023-04-28 11:30 UTC | newest]

Thread overview: 73+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-30 11:58 [PATCH 00/18] Separate links and async sub-devices Sakari Ailus
2023-03-30 11:58 ` [PATCH 01/18] media: v4l: async: Return async sub-devices to subnotifier list Sakari Ailus
2023-04-13 16:49   ` Jacopo Mondi
2023-04-25  1:28   ` Laurent Pinchart
2023-04-25  8:32     ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 02/18] media: v4l: async: Add some debug prints Sakari Ailus
2023-04-13 16:49   ` Jacopo Mondi
2023-04-14 10:46     ` Sakari Ailus
2023-04-21  8:18       ` Laurent Pinchart
2023-04-27  9:18         ` Sakari Ailus
2023-04-27 17:27           ` Laurent Pinchart
2023-04-28  7:29             ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 03/18] media: v4l: async: Simplify async sub-device fwnode matching Sakari Ailus
2023-04-13 16:50   ` Jacopo Mondi
2023-04-14 11:07     ` Sakari Ailus
2023-04-24 19:20       ` Niklas Söderlund
2023-04-24 19:33         ` Sakari Ailus
2023-04-25  1:37           ` Laurent Pinchart
2023-04-27  9:23             ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 04/18] media: v4l: async: Make V4L2 async match information a struct Sakari Ailus
2023-04-13 16:51   ` Jacopo Mondi
2023-04-27 10:47     ` Sakari Ailus
2023-04-25  1:10   ` Laurent Pinchart
2023-04-27 10:36     ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 05/18] media: v4l: async: Clean testing for duplicated async subdevs Sakari Ailus
2023-04-13 16:58   ` Jacopo Mondi
2023-04-14 11:16     ` Sakari Ailus
2023-04-25  1:15   ` Laurent Pinchart
2023-04-27 11:06     ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 06/18] media: v4l: async: Only pass match information for async subdev validation Sakari Ailus
2023-04-14  7:15   ` Jacopo Mondi
2023-04-14 11:39     ` Sakari Ailus
2023-04-25  1:24   ` Laurent Pinchart
2023-04-27 11:45     ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 07/18] media: v4l: async: Clean up list heads and entries Sakari Ailus
2023-04-14  7:26   ` Jacopo Mondi
2023-04-14 11:54     ` Sakari Ailus
2023-04-25  0:49   ` Laurent Pinchart
2023-04-27 11:52     ` Sakari Ailus
2023-04-27 17:36       ` Laurent Pinchart
2023-04-28  7:37         ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 08/18] media: v4l: async: Rename v4l2_async_subdev as v4l2_async_connection Sakari Ailus
2023-04-14  8:22   ` Jacopo Mondi
2023-04-14 12:17     ` Sakari Ailus
2023-04-25  0:59       ` Laurent Pinchart
2023-04-28  9:33         ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 09/18] media: v4l: async: Differentiate connecting and creating sub-devices Sakari Ailus
2023-04-14  8:52   ` Jacopo Mondi
2023-04-14 13:35     ` Sakari Ailus
2023-04-25  2:14       ` Laurent Pinchart
2023-04-28  9:46         ` Sakari Ailus
2023-04-28 10:29         ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 10/18] media: pxa_camera: Register V4L2 device early, fix probe error handling Sakari Ailus
2023-04-25  0:25   ` Laurent Pinchart
2023-04-28 11:21     ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 11/18] media: marvell: cafe: Register V4L2 device earlier Sakari Ailus
2023-04-25  0:27   ` Laurent Pinchart
2023-04-28 11:22     ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 12/18] media: am437x-vpfe: Register V4L2 device early Sakari Ailus
2023-03-30 11:58 ` [PATCH 13/18] media: omap3isp: Initialise V4L2 async notifier later Sakari Ailus
2023-03-30 11:58 ` [PATCH 14/18] media: xilinx-vipp: Init async notifier after registering V4L2 device Sakari Ailus
2023-04-25  0:31   ` Laurent Pinchart
2023-03-30 11:58 ` [PATCH 15/18] media: davinci: " Sakari Ailus
2023-03-30 11:58 ` [PATCH 16/18] media: qcom: Initialise V4L2 async notifier later Sakari Ailus
2023-03-30 11:58 ` [PATCH 17/18] media: v4l: async: Set v4l2_device in async notifier init Sakari Ailus
2023-04-25  0:35   ` Laurent Pinchart
2023-04-25  2:00     ` Laurent Pinchart
2023-04-28 10:35       ` Sakari Ailus
2023-04-28 10:33     ` Sakari Ailus
2023-03-30 11:58 ` [PATCH 18/18] Documentation: media: Document sub-device notifiers Sakari Ailus
2023-04-14  9:14 ` [PATCH 19/18] media: v4l: Drop v4l2_async_nf_parse_fwnode_endpoints() Jacopo Mondi
2023-04-25  1:06   ` Laurent Pinchart
2023-04-28 11:30     ` Sakari Ailus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).