From patchwork Wed Aug 10 06:00:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Saravana Kannan X-Patchwork-Id: 12940251 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 71BB8C25B0E for ; Wed, 10 Aug 2022 06:01:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231153AbiHJGB1 (ORCPT ); Wed, 10 Aug 2022 02:01:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59814 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231134AbiHJGAx (ORCPT ); Wed, 10 Aug 2022 02:00:53 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4B3CE1160 for ; Tue, 9 Aug 2022 23:00:51 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-31f58599ad3so119778167b3.20 for ; Tue, 09 Aug 2022 23:00:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc; bh=yrSVoQ6qAYfctoHLwpmXbxKbM2DM2+R0yDzKfNT+j3U=; b=izJdAflNpJVWEHox4ERNJay3x/S/To+x9+9KV2R1NX8mVvLkWbAu6pJiC9H/0M2NLn ocfw4JmzrHQavKYT18YDK+gRqRMLcmdMUlfVbEdUf1j5kocdA8ySJfeFlofn11B2cfFz L++awHGTPcRZ7ppPUyPRLd9hJzIs+EpLqWOSJazPVt5H2lMeAtFzeElMKf++YUZJHiLb isRQVJNIFzGeSCHAvXXWt4EwTkNgXEVtj5u56DjinNjAVlJDGrYeypA2UodBtn4uxhAR g5j/JPv9wvCk1M9zcUEHPTHcUKe5W/ChBf53weBSEyaV0ZknXYDa9svnM+XwA9IPjEhH CkhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:x-gm-message-state:from:to:cc; bh=yrSVoQ6qAYfctoHLwpmXbxKbM2DM2+R0yDzKfNT+j3U=; b=rvZq5Uk9cn4lsVUAF7jsS7ZNp/T3Ln8+3YGeJ8gOrLg0um99+p/Y0qSmeAUtA6e6wf 8wjNVneE+Oag6ui/IA3k4sh/z5JYfUXDorNWN8dz60WdW8QlQRfHi9xVVq87Vq5Nredh KByfYaZwpNsUTagVcoNAa4VRVrfQAasKqQ2j4Rk0jtyT/TstgOLmGtNfI0oa1a3Xq4Rd Qvn1inWsSigMvX8LAkUuT4PRWY40SoZIxC5cJ5oWHDFnBSDMyFKCollp16SV3w4jA11f y7HhehJq9qXYkn285CVSFxEfHtHiAsUiC0a+2dIF1ytSlkfYVH+GuTfiUF4bOEgq5N7d 2TZQ== X-Gm-Message-State: ACgBeo3NDp5f6v/exuJzJkK4seiAxA1xPOE6AbYJW42w7Ju37ZHl2UJi cn7tIcAn2gd7L2NXtuaNa9SUsUqnr0qklwA= X-Google-Smtp-Source: AA6agR6oBnWJI1pwT9B0nAdocGFOqlZelz8ZvTX+uF4itGLdhkdgHLvMyL5bD42EBVo8bfxVt++iHuhLW/lxloY= X-Received: from saravanak.san.corp.google.com ([2620:15c:2d:3:f21:76ca:766f:e0ab]) (user=saravanak job=sendgmr) by 2002:a25:8101:0:b0:676:c7fd:2143 with SMTP id o1-20020a258101000000b00676c7fd2143mr22340191ybk.364.1660111250277; Tue, 09 Aug 2022 23:00:50 -0700 (PDT) Date: Tue, 9 Aug 2022 23:00:30 -0700 In-Reply-To: <20220810060040.321697-1-saravanak@google.com> Message-Id: <20220810060040.321697-2-saravanak@google.com> Mime-Version: 1.0 References: <20220810060040.321697-1-saravanak@google.com> X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v1 1/9] driver core: fw_devlink: Don't purge child fwnode's consumer links From: Saravana Kannan To: Greg Kroah-Hartman , "Rafael J. Wysocki" , Linus Walleij , Bartosz Golaszewski , Rob Herring , Frank Rowand , Geert Uytterhoeven , Magnus Damm , Andy Shevchenko , Daniel Scally , Heikki Krogerus , Sakari Ailus , Len Brown Cc: Saravana Kannan , Abel Vesa , Alexander Stein , Tony Lindgren , Sudeep Holla , Geert Uytterhoeven , John Stultz , Doug Anderson , Guenter Roeck , kernel-team@android.com, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-acpi@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org When a device X is bound successfully to a driver, if it has a child firmware node Y that doesn't have a struct device created by then, we delete fwnode links where the child firmware node Y is the supplier. We did this to avoid blocking the consumers of the child firmware node Y from deferring probe indefinitely. While that a step in the right direction, it's better to make the consumers of the child firmware node Y to be consumers of the device X because device X is probably implementing whatever functionality is represented by child firmware node Y. By doing this, we capture the device dependencies more accurately and ensure better probe/suspend/resume ordering. Signed-off-by: Saravana Kannan --- drivers/base/core.c | 91 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 17 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 753e7cca0f40..6f575c2a24ad 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -53,11 +53,12 @@ static LIST_HEAD(deferred_sync); static unsigned int defer_sync_state_count = 1; static DEFINE_MUTEX(fwnode_link_lock); static bool fw_devlink_is_permissive(void); +static void __fw_devlink_link_to_consumers(struct device *dev); static bool fw_devlink_drv_reg_done; static bool fw_devlink_best_effort; /** - * fwnode_link_add - Create a link between two fwnode_handles. + * __fwnode_link_add - Create a link between two fwnode_handles. * @con: Consumer end of the link. * @sup: Supplier end of the link. * @@ -73,22 +74,18 @@ static bool fw_devlink_best_effort; * Attempts to create duplicate links between the same pair of fwnode handles * are ignored and there is no reference counting. */ -int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup) +static int __fwnode_link_add(struct fwnode_handle *con, + struct fwnode_handle *sup) { struct fwnode_link *link; - int ret = 0; - - mutex_lock(&fwnode_link_lock); list_for_each_entry(link, &sup->consumers, s_hook) if (link->consumer == con) - goto out; + return 0; link = kzalloc(sizeof(*link), GFP_KERNEL); - if (!link) { - ret = -ENOMEM; - goto out; - } + if (!link) + return -ENOMEM; link->supplier = sup; INIT_LIST_HEAD(&link->s_hook); @@ -99,9 +96,17 @@ int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup) list_add(&link->c_hook, &con->suppliers); pr_debug("%pfwP Linked as a fwnode consumer to %pfwP\n", con, sup); -out: - mutex_unlock(&fwnode_link_lock); + return 0; +} + +int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup) +{ + int ret = 0; + + mutex_lock(&fwnode_link_lock); + ret = __fwnode_link_add(con, sup); + mutex_unlock(&fwnode_link_lock); return ret; } @@ -180,6 +185,51 @@ void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode) } EXPORT_SYMBOL_GPL(fw_devlink_purge_absent_suppliers); +/** + * __fwnode_links_move_consumers - Move consumer from @from to @to fwnode_handle + * @from: move consumers away from this fwnode + * @to: move consumers to this fwnode + * + * Move all consumer links from @from fwnode to @to fwnode. + */ +static void __fwnode_links_move_consumers(struct fwnode_handle *from, + struct fwnode_handle *to) +{ + struct fwnode_link *link, *tmp; + + list_for_each_entry_safe(link, tmp, &from->consumers, s_hook) { + __fwnode_link_add(link->consumer, to); + __fwnode_link_del(link); + } +} + +/** + * __fw_devlink_pickup_dangling_consumers - Pick up dangling consumers + * @fwnode: fwnode from which to pick up dangling consumers + * @new_sup: fwnode of new supplier + * + * If the @fwnode has a corresponding struct device and the device supports + * probing (that is, added to a bus), then we want to let fw_devlink create + * MANAGED device links to this device, so leave @fwnode and its descendant's + * fwnode links alone. + * + * Otherwise, move its consumers to the new supplier @new_sup. + */ +static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode, + struct fwnode_handle *new_sup) +{ + struct fwnode_handle *child; + + if (fwnode->dev && fwnode->dev->bus) + return; + + fwnode->flags |= FWNODE_FLAG_NOT_DEVICE; + __fwnode_links_move_consumers(fwnode, new_sup); + + fwnode_for_each_available_child_node(fwnode, child) + __fw_devlink_pickup_dangling_consumers(child, new_sup); +} + #ifdef CONFIG_SRCU static DEFINE_MUTEX(device_links_lock); DEFINE_STATIC_SRCU(device_links_srcu); @@ -1266,16 +1316,23 @@ void device_links_driver_bound(struct device *dev) * them. So, fw_devlink no longer needs to create device links to any * of the device's suppliers. * - * Also, if a child firmware node of this bound device is not added as - * a device by now, assume it is never going to be added and make sure - * other devices don't defer probe indefinitely by waiting for such a - * child device. + * Also, if a child firmware node of this bound device is not added as a + * device by now, assume it is never going to be added. Make this bound + * device the fallback supplier to the dangling consumers of the child + * firmware node because this bound device is probably implementing the + * child firmware node functionality and we don't want the dangling + * consumers to defer probe indefinitely waiting for a device for the + * child firmware node. */ if (dev->fwnode && dev->fwnode->dev == dev) { struct fwnode_handle *child; fwnode_links_purge_suppliers(dev->fwnode); + mutex_lock(&fwnode_link_lock); fwnode_for_each_available_child_node(dev->fwnode, child) - fw_devlink_purge_absent_suppliers(child); + __fw_devlink_pickup_dangling_consumers(child, + dev->fwnode); + __fw_devlink_link_to_consumers(dev); + mutex_unlock(&fwnode_link_lock); } device_remove_file(dev, &dev_attr_waiting_for_supplier);