From mboxrd@z Thu Jan 1 00:00:00 1970 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 0E782C678D5 for ; Tue, 7 Mar 2023 17:38:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231761AbjCGRiy (ORCPT ); Tue, 7 Mar 2023 12:38:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42464 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231738AbjCGRi3 (ORCPT ); Tue, 7 Mar 2023 12:38:29 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9A5239AA18 for ; Tue, 7 Mar 2023 09:34:28 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 362C86150D for ; Tue, 7 Mar 2023 17:34:28 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2C680C433EF; Tue, 7 Mar 2023 17:34:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1678210467; bh=C8Rv+P01xgWKOI0r79vc2rx+4roCz6LOsJh/keIkZak=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vEFVW98cUhU4h0Pb/cyhVFJ9bzohPFHJ2yK7Ei4Hm1wQN6m02CRHqzr8LjyyZebFw yBUEg6Z+v/xmHHFbGcyrsxkBJ0oCMliJOyHyOLkLNBYU/knUHTkYIPry/8OX+QkDAV OD7FuNEQHzOpgUvJcB5F8jdODb7FT9htP738ds28= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Saravana Kannan , Colin Foster , Sudeep Holla , Douglas Anderson , Geert Uytterhoeven , Sasha Levin , Luca Weiss Subject: [PATCH 6.2 0550/1001] driver core: fw_devlink: Add DL_FLAG_CYCLE support to device links Date: Tue, 7 Mar 2023 17:55:22 +0100 Message-Id: <20230307170045.335749825@linuxfoundation.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230307170022.094103862@linuxfoundation.org> References: <20230307170022.094103862@linuxfoundation.org> User-Agent: quilt/0.67 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: Saravana Kannan [ Upstream commit 67cad5c67019c38126b749621665b6723d3ae7e6 ] fw_devlink uses DL_FLAG_SYNC_STATE_ONLY device link flag for two purposes: 1. To allow a parent device to proxy its child device's dependency on a supplier so that the supplier doesn't get its sync_state() callback before the child device/consumer can be added and probed. In this usage scenario, we need to ignore cycles for ensure correctness of sync_state() callbacks. 2. When there are dependency cycles in firmware, we don't know which of those dependencies are valid. So, we have to ignore them all wrt probe ordering while still making sure the sync_state() callbacks come correctly. However, when detecting dependency cycles, there can be multiple dependency cycles between two devices that we need to detect. For example: A -> B -> A and A -> C -> B -> A. To detect multiple cycles correct, we need to be able to differentiate DL_FLAG_SYNC_STATE_ONLY device links used for (1) vs (2) above. To allow this differentiation, add a DL_FLAG_CYCLE that can be use to mark use case (2). We can then use the DL_FLAG_CYCLE to decide which DL_FLAG_SYNC_STATE_ONLY device links to follow when looking for dependency cycles. Fixes: 2de9d8e0d2fe ("driver core: fw_devlink: Improve handling of cyclic dependencies") Signed-off-by: Saravana Kannan Tested-by: Colin Foster Tested-by: Sudeep Holla Tested-by: Douglas Anderson Tested-by: Geert Uytterhoeven Tested-by: Luca Weiss # qcom/sm7225-fairphone-fp4 Link: https://lore.kernel.org/r/20230207014207.1678715-6-saravanak@google.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/base/core.c | 28 ++++++++++++++++++---------- include/linux/device.h | 1 + 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 9fccf7b4e7ea3..609d1b04ee75a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -272,6 +272,12 @@ static bool device_is_ancestor(struct device *dev, struct device *target) return false; } +static inline bool device_link_flag_is_sync_state_only(u32 flags) +{ + return (flags & ~(DL_FLAG_INFERRED | DL_FLAG_CYCLE)) == + (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED); +} + /** * device_is_dependent - Check if one device depends on another one * @dev: Device to check dependencies for. @@ -298,8 +304,7 @@ int device_is_dependent(struct device *dev, void *target) return ret; list_for_each_entry(link, &dev->links.consumers, s_node) { - if ((link->flags & ~DL_FLAG_INFERRED) == - (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED)) + if (device_link_flag_is_sync_state_only(link->flags)) continue; if (link->consumer == target) @@ -372,8 +377,7 @@ static int device_reorder_to_tail(struct device *dev, void *not_used) device_for_each_child(dev, NULL, device_reorder_to_tail); list_for_each_entry(link, &dev->links.consumers, s_node) { - if ((link->flags & ~DL_FLAG_INFERRED) == - (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED)) + if (device_link_flag_is_sync_state_only(link->flags)) continue; device_reorder_to_tail(link->consumer, NULL); } @@ -634,7 +638,8 @@ postcore_initcall(devlink_class_init); DL_FLAG_AUTOREMOVE_SUPPLIER | \ DL_FLAG_AUTOPROBE_CONSUMER | \ DL_FLAG_SYNC_STATE_ONLY | \ - DL_FLAG_INFERRED) + DL_FLAG_INFERRED | \ + DL_FLAG_CYCLE) #define DL_ADD_VALID_FLAGS (DL_MANAGED_LINK_FLAGS | DL_FLAG_STATELESS | \ DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE) @@ -703,8 +708,6 @@ struct device_link *device_link_add(struct device *consumer, if (!consumer || !supplier || consumer == supplier || flags & ~DL_ADD_VALID_FLAGS || (flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) || - (flags & DL_FLAG_SYNC_STATE_ONLY && - (flags & ~DL_FLAG_INFERRED) != DL_FLAG_SYNC_STATE_ONLY) || (flags & DL_FLAG_AUTOPROBE_CONSUMER && flags & (DL_FLAG_AUTOREMOVE_CONSUMER | DL_FLAG_AUTOREMOVE_SUPPLIER))) @@ -720,6 +723,10 @@ struct device_link *device_link_add(struct device *consumer, if (!(flags & DL_FLAG_STATELESS)) flags |= DL_FLAG_MANAGED; + if (flags & DL_FLAG_SYNC_STATE_ONLY && + !device_link_flag_is_sync_state_only(flags)) + return NULL; + device_links_write_lock(); device_pm_lock(); @@ -1672,7 +1679,7 @@ static void fw_devlink_relax_link(struct device_link *link) if (!(link->flags & DL_FLAG_INFERRED)) return; - if (link->flags == (DL_FLAG_MANAGED | FW_DEVLINK_FLAGS_PERMISSIVE)) + if (device_link_flag_is_sync_state_only(link->flags)) return; pm_runtime_drop_link(link); @@ -1796,8 +1803,8 @@ static int fw_devlink_relax_cycle(struct device *con, void *sup) return ret; list_for_each_entry(link, &con->links.consumers, s_node) { - if ((link->flags & ~DL_FLAG_INFERRED) == - (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED)) + if (!(link->flags & DL_FLAG_CYCLE) && + device_link_flag_is_sync_state_only(link->flags)) continue; if (!fw_devlink_relax_cycle(link->consumer, sup)) @@ -1806,6 +1813,7 @@ static int fw_devlink_relax_cycle(struct device *con, void *sup) ret = 1; fw_devlink_relax_link(link); + link->flags |= DL_FLAG_CYCLE; } return ret; } diff --git a/include/linux/device.h b/include/linux/device.h index 44e3acae7b36e..f4d20655d2d7e 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -328,6 +328,7 @@ enum device_link_state { #define DL_FLAG_MANAGED BIT(6) #define DL_FLAG_SYNC_STATE_ONLY BIT(7) #define DL_FLAG_INFERRED BIT(8) +#define DL_FLAG_CYCLE BIT(9) /** * enum dl_dev_state - Device driver presence tracking information. -- 2.39.2