From f48db17d81699c4ac315208d769db61732baebfe Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 22 Jul 2025 10:32:21 +0200 Subject: [PATCH] 5.15-stable patches added patches: usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch usb-hub-fix-flushing-and-scheduling-of-delayed-work-that-tunes-runtime-pm.patch usb-hub-fix-flushing-of-delayed-work-used-for-post-resume-purposes.patch --- queue-5.15/series | 3 + ...r-usb3-devices-behind-suspended-hubs.patch | 124 ++++++++++++++++++ ...f-delayed-work-that-tunes-runtime-pm.patch | 63 +++++++++ ...d-work-used-for-post-resume-purposes.patch | 117 +++++++++++++++++ 4 files changed, 307 insertions(+) create mode 100644 queue-5.15/usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch create mode 100644 queue-5.15/usb-hub-fix-flushing-and-scheduling-of-delayed-work-that-tunes-runtime-pm.patch create mode 100644 queue-5.15/usb-hub-fix-flushing-of-delayed-work-used-for-post-resume-purposes.patch diff --git a/queue-5.15/series b/queue-5.15/series index 3da93b398f..0dc689c556 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -58,3 +58,6 @@ net-bridge-do-not-offload-igmp-mld-messages.patch net-sched-return-null-when-htb_lookup_leaf-encounter.patch sched-change-nr_uninterruptible-type-to-unsigned-long.patch clone_private_mnt-make-sure-that-caller-has-cap_sys_admin-in-the-right-userns.patch +usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch +usb-hub-fix-flushing-and-scheduling-of-delayed-work-that-tunes-runtime-pm.patch +usb-hub-fix-flushing-of-delayed-work-used-for-post-resume-purposes.patch diff --git a/queue-5.15/usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch b/queue-5.15/usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch new file mode 100644 index 0000000000..03f3cf9f5e --- /dev/null +++ b/queue-5.15/usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch @@ -0,0 +1,124 @@ +From 8f5b7e2bec1c36578fdaa74a6951833541103e27 Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Wed, 11 Jun 2025 14:24:41 +0300 +Subject: usb: hub: fix detection of high tier USB3 devices behind suspended hubs + +From: Mathias Nyman + +commit 8f5b7e2bec1c36578fdaa74a6951833541103e27 upstream. + +USB3 devices connected behind several external suspended hubs may not +be detected when plugged in due to aggressive hub runtime pm suspend. + +The hub driver immediately runtime-suspends hubs if there are no +active children or port activity. + +There is a delay between the wake signal causing hub resume, and driver +visible port activity on the hub downstream facing ports. +Most of the LFPS handshake, resume signaling and link training done +on the downstream ports is not visible to the hub driver until completed, +when device then will appear fully enabled and running on the port. + +This delay between wake signal and detectable port change is even more +significant with chained suspended hubs where the wake signal will +propagate upstream first. Suspended hubs will only start resuming +downstream ports after upstream facing port resumes. + +The hub driver may resume a USB3 hub, read status of all ports, not +yet see any activity, and runtime suspend back the hub before any +port activity is visible. + +This exact case was seen when conncting USB3 devices to a suspended +Thunderbolt dock. + +USB3 specification defines a 100ms tU3WakeupRetryDelay, indicating +USB3 devices expect to be resumed within 100ms after signaling wake. +if not then device will resend the wake signal. + +Give the USB3 hubs twice this time (200ms) to detect any port +changes after resume, before allowing hub to runtime suspend again. + +Cc: stable +Fixes: 2839f5bcfcfc ("USB: Turn on auto-suspend for USB 3.0 hubs.") +Acked-by: Alan Stern +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20250611112441.2267883-1-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/hub.c | 33 ++++++++++++++++++++++++++++++++- + 1 file changed, 32 insertions(+), 1 deletion(-) + +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -53,6 +53,12 @@ + #define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */ + #define USB_PING_RESPONSE_TIME 400 /* ns */ + ++/* ++ * Give SS hubs 200ms time after wake to train downstream links before ++ * assuming no port activity and allowing hub to runtime suspend back. ++ */ ++#define USB_SS_PORT_U0_WAKE_TIME 200 /* ms */ ++ + /* Protect struct usb_device->state and ->children members + * Note: Both are also protected by ->dev.sem, except that ->state can + * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ +@@ -1025,11 +1031,12 @@ int usb_remove_device(struct usb_device + + enum hub_activation_type { + HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */ +- HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, ++ HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, HUB_POST_RESUME, + }; + + static void hub_init_func2(struct work_struct *ws); + static void hub_init_func3(struct work_struct *ws); ++static void hub_post_resume(struct work_struct *ws); + + static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) + { +@@ -1052,6 +1059,13 @@ static void hub_activate(struct usb_hub + goto init2; + goto init3; + } ++ ++ if (type == HUB_POST_RESUME) { ++ usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); ++ hub_put(hub); ++ return; ++ } ++ + hub_get(hub); + + /* The superspeed hub except for root hub has to use Hub Depth +@@ -1300,6 +1314,16 @@ static void hub_activate(struct usb_hub + device_unlock(&hdev->dev); + } + ++ if (type == HUB_RESUME && hub_is_superspeed(hub->hdev)) { ++ /* give usb3 downstream links training time after hub resume */ ++ INIT_DELAYED_WORK(&hub->init_work, hub_post_resume); ++ queue_delayed_work(system_power_efficient_wq, &hub->init_work, ++ msecs_to_jiffies(USB_SS_PORT_U0_WAKE_TIME)); ++ usb_autopm_get_interface_no_resume( ++ to_usb_interface(hub->intfdev)); ++ return; ++ } ++ + hub_put(hub); + } + +@@ -1318,6 +1342,13 @@ static void hub_init_func3(struct work_s + hub_activate(hub, HUB_INIT3); + } + ++static void hub_post_resume(struct work_struct *ws) ++{ ++ struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work); ++ ++ hub_activate(hub, HUB_POST_RESUME); ++} ++ + enum hub_quiescing_type { + HUB_DISCONNECT, HUB_PRE_RESET, HUB_SUSPEND + }; diff --git a/queue-5.15/usb-hub-fix-flushing-and-scheduling-of-delayed-work-that-tunes-runtime-pm.patch b/queue-5.15/usb-hub-fix-flushing-and-scheduling-of-delayed-work-that-tunes-runtime-pm.patch new file mode 100644 index 0000000000..08beaf80dc --- /dev/null +++ b/queue-5.15/usb-hub-fix-flushing-and-scheduling-of-delayed-work-that-tunes-runtime-pm.patch @@ -0,0 +1,63 @@ +From a49e1e2e785fb3621f2d748581881b23a364998a Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Thu, 26 Jun 2025 16:01:02 +0300 +Subject: usb: hub: Fix flushing and scheduling of delayed work that tunes runtime pm + +From: Mathias Nyman + +commit a49e1e2e785fb3621f2d748581881b23a364998a upstream. + +Delayed work to prevent USB3 hubs from runtime-suspending immediately +after resume was added in commit 8f5b7e2bec1c ("usb: hub: fix detection +of high tier USB3 devices behind suspended hubs"). + +This delayed work needs be flushed if system suspends, or hub needs to +be quiesced for other reasons right after resume. Not flushing it +triggered issues on QC SC8280XP CRD board during suspend/resume testing. + +Fix it by flushing the delayed resume work in hub_quiesce() + +The delayed work item that allow hub runtime suspend is also scheduled +just before calling autopm get. Alan pointed out there is a small risk +that work is run before autopm get, which would call autopm put before +get, and mess up the runtime pm usage order. +Swap the order of work sheduling and calling autopm get to solve this. + +Cc: stable +Fixes: 8f5b7e2bec1c ("usb: hub: fix detection of high tier USB3 devices behind suspended hubs") +Reported-by: Konrad Dybcio +Closes: https://lore.kernel.org/linux-usb/acaaa928-832c-48ca-b0ea-d202d5cd3d6c@oss.qualcomm.com +Reported-by: Alan Stern +Closes: https://lore.kernel.org/linux-usb/c73fbead-66d7-497a-8fa1-75ea4761090a@rowland.harvard.edu +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20250626130102.3639861-2-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/hub.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -1316,11 +1316,12 @@ static void hub_activate(struct usb_hub + + if (type == HUB_RESUME && hub_is_superspeed(hub->hdev)) { + /* give usb3 downstream links training time after hub resume */ ++ usb_autopm_get_interface_no_resume( ++ to_usb_interface(hub->intfdev)); ++ + INIT_DELAYED_WORK(&hub->init_work, hub_post_resume); + queue_delayed_work(system_power_efficient_wq, &hub->init_work, + msecs_to_jiffies(USB_SS_PORT_U0_WAKE_TIME)); +- usb_autopm_get_interface_no_resume( +- to_usb_interface(hub->intfdev)); + return; + } + +@@ -1374,6 +1375,7 @@ static void hub_quiesce(struct usb_hub * + + /* Stop hub_wq and related activity */ + del_timer_sync(&hub->irq_urb_retry); ++ flush_delayed_work(&hub->init_work); + usb_kill_urb(hub->urb); + if (hub->has_indicators) + cancel_delayed_work_sync(&hub->leds); diff --git a/queue-5.15/usb-hub-fix-flushing-of-delayed-work-used-for-post-resume-purposes.patch b/queue-5.15/usb-hub-fix-flushing-of-delayed-work-used-for-post-resume-purposes.patch new file mode 100644 index 0000000000..6fab51fee9 --- /dev/null +++ b/queue-5.15/usb-hub-fix-flushing-of-delayed-work-used-for-post-resume-purposes.patch @@ -0,0 +1,117 @@ +From 9bd9c8026341f75f25c53104eb7e656e357ca1a2 Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Fri, 27 Jun 2025 19:43:48 +0300 +Subject: usb: hub: Fix flushing of delayed work used for post resume purposes + +From: Mathias Nyman + +commit 9bd9c8026341f75f25c53104eb7e656e357ca1a2 upstream. + +Delayed work that prevents USB3 hubs from runtime-suspending too early +needed to be flushed in hub_quiesce() to resolve issues detected on +QC SC8280XP CRD board during suspend resume testing. + +This flushing did however trigger new issues on Raspberry Pi 3B+, which +doesn't have USB3 ports, and doesn't queue any post resume delayed work. + +The flushed 'hub->init_work' item is used for several purposes, and +is originally initialized with a 'NULL' work function. The work function +is also changed on the fly, which may contribute to the issue. + +Solve this by creating a dedicated delayed work item for post resume work, +and flush that delayed work in hub_quiesce() + +Cc: stable +Fixes: a49e1e2e785f ("usb: hub: Fix flushing and scheduling of delayed work that tunes runtime pm") +Reported-by: Mark Brown +Closes: https://lore.kernel.org/linux-usb/aF5rNp1l0LWITnEB@finisterre.sirena.org.uk +Signed-off-by: Mathias Nyman +Tested-by: Konrad Dybcio # SC8280XP CRD +Tested-by: Mark Brown +Link: https://lore.kernel.org/r/20250627164348.3982628-2-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/hub.c | 21 ++++++++------------- + drivers/usb/core/hub.h | 1 + + 2 files changed, 9 insertions(+), 13 deletions(-) + +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -1031,12 +1031,11 @@ int usb_remove_device(struct usb_device + + enum hub_activation_type { + HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */ +- HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, HUB_POST_RESUME, ++ HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, + }; + + static void hub_init_func2(struct work_struct *ws); + static void hub_init_func3(struct work_struct *ws); +-static void hub_post_resume(struct work_struct *ws); + + static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) + { +@@ -1060,12 +1059,6 @@ static void hub_activate(struct usb_hub + goto init3; + } + +- if (type == HUB_POST_RESUME) { +- usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); +- hub_put(hub); +- return; +- } +- + hub_get(hub); + + /* The superspeed hub except for root hub has to use Hub Depth +@@ -1319,8 +1312,8 @@ static void hub_activate(struct usb_hub + usb_autopm_get_interface_no_resume( + to_usb_interface(hub->intfdev)); + +- INIT_DELAYED_WORK(&hub->init_work, hub_post_resume); +- queue_delayed_work(system_power_efficient_wq, &hub->init_work, ++ queue_delayed_work(system_power_efficient_wq, ++ &hub->post_resume_work, + msecs_to_jiffies(USB_SS_PORT_U0_WAKE_TIME)); + return; + } +@@ -1345,9 +1338,10 @@ static void hub_init_func3(struct work_s + + static void hub_post_resume(struct work_struct *ws) + { +- struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work); ++ struct usb_hub *hub = container_of(ws, struct usb_hub, post_resume_work.work); + +- hub_activate(hub, HUB_POST_RESUME); ++ usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); ++ hub_put(hub); + } + + enum hub_quiescing_type { +@@ -1375,7 +1369,7 @@ static void hub_quiesce(struct usb_hub * + + /* Stop hub_wq and related activity */ + del_timer_sync(&hub->irq_urb_retry); +- flush_delayed_work(&hub->init_work); ++ flush_delayed_work(&hub->post_resume_work); + usb_kill_urb(hub->urb); + if (hub->has_indicators) + cancel_delayed_work_sync(&hub->leds); +@@ -1932,6 +1926,7 @@ static int hub_probe(struct usb_interfac + hub->hdev = hdev; + INIT_DELAYED_WORK(&hub->leds, led_work); + INIT_DELAYED_WORK(&hub->init_work, NULL); ++ INIT_DELAYED_WORK(&hub->post_resume_work, hub_post_resume); + INIT_WORK(&hub->events, hub_event); + spin_lock_init(&hub->irq_urb_lock); + timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0); +--- a/drivers/usb/core/hub.h ++++ b/drivers/usb/core/hub.h +@@ -69,6 +69,7 @@ struct usb_hub { + u8 indicator[USB_MAXCHILDREN]; + struct delayed_work leds; + struct delayed_work init_work; ++ struct delayed_work post_resume_work; + struct work_struct events; + spinlock_t irq_urb_lock; + struct timer_list irq_urb_retry; -- 2.47.2