From: Pin-yen Lin <treapking@chromium.org> mainline inclusion from mainline-v6.18-rc1 commit 632d31067be2f414c57955efcf29c79290cc749b category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IDARBZ Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... ---------------------------------------------------------------------- Device links with DL_FLAG_SYNC_STATE_ONLY should not affect system suspend and resume, and functions like device_reorder_to_tail() and device_link_add() don't try to reorder the consumers with that flag. However, dpm_wait_for_consumers() and dpm_wait_for_suppliers() don't check thas flag before triggering dpm_wait(), leading to potential hang during suspend/resume. This can be reproduced on MT8186 Corsola Chromebook with devicetree like: usb-a-connector { compatible = "usb-a-connector"; port { usb_a_con: endpoint { remote-endpoint = <&usb_hs>; }; }; }; usb_host { compatible = "mediatek,mt8186-xhci", "mediatek,mtk-xhci"; port { usb_hs: endpoint { remote-endpoint = <&usb_a_con>; }; }; }; In this case, the two nodes form a cycle and a SYNC_STATE_ONLY devlink between usb_host (supplier) and usb-a-connector (consumer) is created. Address this by exporting device_link_flag_is_sync_state_only() and making dpm_wait_for_consumers() and dpm_wait_for_suppliers() use it when deciding if dpm_wait() should be called. Fixes: 05ef983e0d65 ("driver core: Add device link support for SYNC_STATE_ONLY flag") Signed-off-by: Pin-yen Lin <treapking@chromium.org> Link: https://patch.msgid.link/20250926102320.4053167-1-treapking@chromium.org [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Conflicts: drivers/base/power/main.c drivers/base/base.h [context conflict] Signed-off-by: Xinyu Zheng <zhengxinyu6@huawei.com> --- drivers/base/base.h | 1 + drivers/base/core.c | 2 +- drivers/base/power/main.c | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index 7ac16589af3c..f1cb4fd978a6 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -236,6 +236,7 @@ void device_links_driver_cleanup(struct device *dev); void device_links_no_driver(struct device *dev); bool device_links_busy(struct device *dev); void device_links_unbind_consumers(struct device *dev); +bool device_link_flag_is_sync_state_only(u32 flags); void fw_devlink_drivers_done(void); void fw_devlink_probing_done(void); diff --git a/drivers/base/core.c b/drivers/base/core.c index 34e89dd39dd6..d94195829f6e 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -294,7 +294,7 @@ static bool device_is_ancestor(struct device *dev, struct device *target) #define DL_MARKER_FLAGS (DL_FLAG_INFERRED | \ DL_FLAG_CYCLE | \ DL_FLAG_MANAGED) -static inline bool device_link_flag_is_sync_state_only(u32 flags) +bool device_link_flag_is_sync_state_only(u32 flags) { return (flags & ~DL_MARKER_FLAGS) == DL_FLAG_SYNC_STATE_ONLY; } diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index ef5157fc8dcc..521a90e260e6 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -268,7 +268,8 @@ static void dpm_wait_for_suppliers(struct device *dev, bool async) * walking. */ list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) - if (READ_ONCE(link->status) != DL_STATE_DORMANT) + if (READ_ONCE(link->status) != DL_STATE_DORMANT && + !device_link_flag_is_sync_state_only(link->flags)) dpm_wait(link->supplier, async); device_links_read_unlock(idx); @@ -325,7 +326,8 @@ static void dpm_wait_for_consumers(struct device *dev, bool async) * unregistration). */ list_for_each_entry_rcu_locked(link, &dev->links.consumers, s_node) - if (READ_ONCE(link->status) != DL_STATE_DORMANT) + if (READ_ONCE(link->status) != DL_STATE_DORMANT && + !device_link_flag_is_sync_state_only(link->flags)) dpm_wait(link->consumer, async); device_links_read_unlock(idx); -- 2.34.1