From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 2D7C846C4D8; Tue, 21 Jul 2026 17:45:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784655936; cv=none; b=ijxwOGKRsefXnkt33M2VGl1mI5Q54fkOpntgheDnMFPhwAPWUSmzUrftCJGkACYklyNzJ1v/a8JASNSxmmYiHWXt0pskWykqSCUN+RDM77sk6tkbAbWowOL3l1dcy+GrBDXy/hIHtE/ZEBmocslOpltiKUyIUb7dw6xa/9G8v8I= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784655936; c=relaxed/simple; bh=Q9P2MToyngg9R9dy3DmqopWFgVoixpeQShruJDEblfE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kdVcMFavlkAuYad7FqTCpW420i/SEJwIjQidmr/crbuM9TslfE3Qxb9kHkg0UPq6gx4ZskxGz3C2eLFZWTBM3M/gHfdRUPz8qoMzpSFJV6qvjXd8xUwYPE2uBqIRTdlZwLrp3YJYXKTNV0T3XX28AfCxFOjYcwFnnxQ4CAM7Ka8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=iVjTnDeM; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="iVjTnDeM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9A0031F000E9; Tue, 21 Jul 2026 17:45:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1784655935; bh=yjLGqzY3JcxfHkMfuu0nOZBD0XAOEqTotoYAD3TrTa8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=iVjTnDeMjizT4bXxsLPQ5sXq/CPCnZ5JCW85XyGjn8JFkS9MI96Tw17n7B+2GfTCP eNNDccyCS6Dq94AXZ8vM8ndlLcnEotJo5aMEQtEEQqaV8acqCPDAPaUyOY5n0qkNTR yrDlcYLwd+apfwb41zYP7Pz2Mwow3enHBORD6eMo= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Herve Codina , Saravana Kannan , Kalle Niemi , Geert Uytterhoeven , "Rob Herring (Arm)" , Sasha Levin Subject: [PATCH 6.18 0198/1611] of: dynamic: Fix overlayed devices not probing because of fw_devlink Date: Tue, 21 Jul 2026 17:05:14 +0200 Message-ID: <20260721152519.405361977@linuxfoundation.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260721152514.750365251@linuxfoundation.org> References: <20260721152514.750365251@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Saravana Kannan [ Upstream commit 81e7c6befa36cecdcbf7244393bd67e8f8c59bf5 ] 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. [Herve: Add the call to driver_deferred_probe_trigger()] [Herve: Use fwnode_test_flag() to test fwnode flags value] 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] Signed-off-by: Herve Codina Tested-by: Kalle Niemi Tested-by: Geert Uytterhoeven Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260511155755.34428-3-herve.codina@bootlin.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/base/core.c | 83 +++++++++++++++++++++++++++++++++++++----- drivers/of/overlay.c | 15 ++++++++ include/linux/fwnode.h | 1 + 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 01e14f787916a2..5034d9b103642f 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -235,6 +235,79 @@ 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_test_flag(fwnode, FWNODE_FLAG_NOT_DEVICE)) + continue; + + dev = get_dev_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 things 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); + /* + * Some of dangling consumers could have been put previously in + * the deferred probe list due to the unavailability of their + * suppliers. Those consumers have been picked up and some of + * their suppliers links have been updated. Time to re-try their + * probe sequence. + */ + driver_deferred_probe_trigger(); + } + + put_device(dev); + fwnode_handle_put(fwnode); +} + static DEFINE_MUTEX(device_links_lock); DEFINE_STATIC_SRCU(device_links_srcu); @@ -1312,16 +1385,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 255e8362f600a9..1528d8ad9f2682 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 c30a9baafc0d99..4e86e6990d284a 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -253,6 +253,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.53.0