mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 01:53:29 +02:00
PM: sleep: Do not wait on SYNC_STATE_ONLY device links
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: 05ef983e0d ("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>
This commit is contained in:
parent
3ce3f56999
commit
632d31067b
|
|
@ -248,6 +248,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -287,7 +287,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -278,7 +278,8 @@ static void dpm_wait_for_suppliers(struct device *dev, bool async)
|
|||
* walking.
|
||||
*/
|
||||
dev_for_each_link_to_supplier(link, dev)
|
||||
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);
|
||||
|
|
@ -335,7 +336,8 @@ static void dpm_wait_for_consumers(struct device *dev, bool async)
|
|||
* unregistration).
|
||||
*/
|
||||
dev_for_each_link_to_consumer(link, dev)
|
||||
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user