From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5B7BD314A78 for ; Wed, 15 Oct 2025 07:16:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760512605; cv=none; b=g+8ZCQ7CkcQuk3uLUBwgWdxzDWH1xT8+HeiTfcb7Y9UGnT5UkN4bH5nY0WP7Rllw3N3DqxHUibGvMRNxXcMsWzoA15ib33t08wvM4L+8jHAcAvo5U01jV7UyL8p7A3OpFb6ZPnxv6CQMhnIzdTJyIvP/V0Nda+vPyIDId7c9M6w= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760512605; c=relaxed/simple; bh=pAhFf6r1gPhsc9yn1e5QfKKvXJEOaHwdYqkgkjJ0eDc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=J0PxtxyUDXmAr3q5Y3yDP+67Fd0QnSsG/8M+O93QLO5yB1mXbCCYm4JRyVfskOoD/4yAOqG42LSI13MOxycMuPKogIlWagoSnsQtN/ivJb+7QpdouwhnT9Jppszr0axMzwsVRyE61xeD5hxCQbhwtO64vPVLEK9MWqMT8hqy0PM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=eib2whJK; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="eib2whJK" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id BFFE3C09FA9; Wed, 15 Oct 2025 07:16:22 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id D32B0606F9; Wed, 15 Oct 2025 07:16:41 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id D1F1E102F22AF; Wed, 15 Oct 2025 09:16:25 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1760512598; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=BgVh1h4ZRFv4qD84MwSaZbkiILKraX25PCS5EVzcZVw=; b=eib2whJKSfA18SSheaRE5Lo+mWL4rtZSgW7JKPf+RWwucJ6MmEbYMRYV58YwnRio2u+Uda k2TouQmGNm6j1U9ggz5jDSIoQ75DyyR/sW6qxbECjn+ZszETau9vk7fa5xF/svLTwBVYNY FfeMB2Vn25Zy9U+OldAW/rC5aettNPLe2OrwpZiN3AG9owWM5ZtXON7xQT/IOFcqnRkf8T 5IZU5EHvpkTlbEhEK+jzoeu9NogjE+9k7j9UgIqDz8qBh/h1D8bXjN/QzlXz5C9X9yrCK4 dG4BNjRq9i0bmYQgvUc7wYq0t0nERr8KAfDxOKbey1IZDIm0MaF19A6ZvtEtSA== From: Herve Codina To: Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Shawn Guo , Sascha Hauer , Pengutronix Kernel Team , Fabio Estevam , Michael Turquette , Stephen Boyd , Andi Shyti , Wolfram Sang , Peter Rosin , Arnd Bergmann , Herve Codina , Saravana Kannan , Bjorn Helgaas , Charles Keepax , Richard Fitzgerald , David Rhodes , Linus Walleij , Ulf Hansson , Mark Brown , Andy Shevchenko , Daniel Scally , Heikki Krogerus , Sakari Ailus , Len Brown , Davidlohr Bueso , Jonathan Cameron , Dave Jiang , Alison Schofield , Vishal Verma , Ira Weiny , Dan Williams , Geert Uytterhoeven Cc: Wolfram Sang , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org, linux-i2c@vger.kernel.org, linux-pci@vger.kernel.org, linux-sound@vger.kernel.org, patches@opensource.cirrus.com, linux-gpio@vger.kernel.org, linux-pm@vger.kernel.org, linux-spi@vger.kernel.org, linux-acpi@vger.kernel.org, linux-cxl@vger.kernel.org, Allan Nielsen , Horatiu Vultur , Steen Hegelund , Luca Ceresoli , Thomas Petazzoni Subject: [PATCH v4 03/29] of: dynamic: Fix overlayed devices not probing because of fw_devlink Date: Wed, 15 Oct 2025 09:13:50 +0200 Message-ID: <20251015071420.1173068-4-herve.codina@bootlin.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251015071420.1173068-1-herve.codina@bootlin.com> References: <20251015071420.1173068-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Last-TLS-Session-Version: TLSv1.3 From: Saravana Kannan When an overlay is applied, if the target device has already probed successfully and bound to a device, then some of the fw_devlink logic that ran when the device was probed needs to be rerun. This allows newly created dangling consumers of the overlayed device tree nodes to be moved to become consumers of the target device. Fixes: 1a50d9403fb9 ("treewide: Fix probing of devices in DT overlays") Reported-by: Herve Codina Closes: https://lore.kernel.org/lkml/CAMuHMdXEnSD4rRJ-o90x4OprUacN_rJgyo8x6=9F9rZ+-KzjOg@mail.gmail.com/ Closes: https://lore.kernel.org/all/20240221095137.616d2aaa@bootlin.com/ Closes: https://lore.kernel.org/lkml/20240312151835.29ef62a0@bootlin.com/ Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/lkml/20240411235623.1260061-3-saravanak@google.com/ [Herve: Rebase on top of recent kernel and use get_device_from_fwnode()] Signed-off-by: Herve Codina --- drivers/base/core.c | 74 +++++++++++++++++++++++++++++++++++++----- drivers/of/overlay.c | 15 +++++++++ include/linux/fwnode.h | 1 + 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 334f5a4fbb9e..cf157066499b 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -235,6 +235,70 @@ static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode, __fw_devlink_pickup_dangling_consumers(child, new_sup); } +static void fw_devlink_pickup_dangling_consumers(struct device *dev) +{ + struct fwnode_handle *child; + + guard(mutex)(&fwnode_link_lock); + + fwnode_for_each_available_child_node(dev->fwnode, child) + __fw_devlink_pickup_dangling_consumers(child, dev->fwnode); + __fw_devlink_link_to_consumers(dev); +} + +/** + * fw_devlink_refresh_fwnode - Recheck the tree under this firmware node + * @fwnode: The fwnode under which the fwnode tree has changed + * + * This function is mainly meant to adjust the supplier/consumer dependencies + * after a fwnode tree overlay has occurred. + */ +void fw_devlink_refresh_fwnode(struct fwnode_handle *fwnode) +{ + struct device *dev; + + /* + * Find the closest ancestor fwnode that has been converted to a device + * that can bind to a driver (bus device). + */ + fwnode_handle_get(fwnode); + do { + if (fwnode->flags & FWNODE_FLAG_NOT_DEVICE) + continue; + + dev = get_device_from_fwnode(fwnode); + if (!dev) + continue; + + if (dev->bus) + break; + + put_device(dev); + } while ((fwnode = fwnode_get_next_parent(fwnode))); + + /* + * If none of the ancestor fwnodes have (yet) been converted to a device + * that can bind to a driver, there's nothing to fix up. + */ + if (!fwnode) + return; + + WARN(device_is_bound(dev) && dev->links.status != DL_DEV_DRIVER_BOUND, + "Don't multithread overlaying and probing the same device!\n"); + + /* + * If the device has already bound to a driver, then we need to redo + * some of the work that was done after the device was bound to a + * driver. If the device hasn't bound to a driver, running thing too + * soon would incorrectly pick up consumers that it shouldn't. + */ + if (dev->links.status == DL_DEV_DRIVER_BOUND) + fw_devlink_pickup_dangling_consumers(dev); + + put_device(dev); + fwnode_handle_put(fwnode); +} + static DEFINE_MUTEX(device_links_lock); DEFINE_STATIC_SRCU(device_links_srcu); @@ -1312,16 +1376,8 @@ void device_links_driver_bound(struct device *dev) * child firmware node. */ if (dev->fwnode && dev->fwnode->dev == dev) { - struct fwnode_handle *child; - fwnode_links_purge_suppliers(dev->fwnode); - - guard(mutex)(&fwnode_link_lock); - - fwnode_for_each_available_child_node(dev->fwnode, child) - __fw_devlink_pickup_dangling_consumers(child, - dev->fwnode); - __fw_devlink_link_to_consumers(dev); + fw_devlink_pickup_dangling_consumers(dev); } device_remove_file(dev, &dev_attr_waiting_for_supplier); diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 255e8362f600..1528d8ad9f26 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -185,6 +185,15 @@ static int overlay_notify(struct overlay_changeset *ovcs, return 0; } +static void overlay_fw_devlink_refresh(struct overlay_changeset *ovcs) +{ + for (int i = 0; i < ovcs->count; i++) { + struct device_node *np = ovcs->fragments[i].target; + + fw_devlink_refresh_fwnode(of_fwnode_handle(np)); + } +} + /* * The values of properties in the "/__symbols__" node are paths in * the ovcs->overlay_root. When duplicating the properties, the paths @@ -951,6 +960,12 @@ static int of_overlay_apply(struct overlay_changeset *ovcs, pr_err("overlay apply changeset entry notify error %d\n", ret); /* notify failure is not fatal, continue */ + /* + * Needs to happen after changeset notify to give the listeners a chance + * to finish creating all the devices they need to create. + */ + overlay_fw_devlink_refresh(ovcs); + ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_APPLY); if (ret_tmp) if (!ret) diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index 097be89487bf..a921ca2fe940 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -228,6 +228,7 @@ int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup, u8 flags); void fwnode_links_purge(struct fwnode_handle *fwnode); void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode); +void fw_devlink_refresh_fwnode(struct fwnode_handle *fwnode); bool fw_devlink_is_strict(void); #endif -- 2.51.0