]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 24 Jul 2025 07:12:47 +0000 (09:12 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 24 Jul 2025 07:12:47 +0000 (09:12 +0200)
added patches:
usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch

queue-5.4/series
queue-5.4/usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch [new file with mode: 0644]

index f83ae43b7a509850a77f3f2e26e2e40bb71fc2ba..05a8f9e202adb74b251577ff13fafec4781e6f32 100644 (file)
@@ -51,3 +51,4 @@ net_sched-sch_sfq-don-t-allow-1-packet-limit.patch
 net_sched-sch_sfq-use-a-temporary-work-area-for-validating-configuration.patch
 net_sched-sch_sfq-move-the-limit-validation.patch
 net_sched-sch_sfq-reject-invalid-perturb-period.patch
+usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch
diff --git a/queue-5.4/usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch b/queue-5.4/usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch
new file mode 100644 (file)
index 0000000..b2f9cbd
--- /dev/null
@@ -0,0 +1,126 @@
+From 8f5b7e2bec1c36578fdaa74a6951833541103e27 Mon Sep 17 00:00:00 2001
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+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 <mathias.nyman@linux.intel.com>
+
+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 <stable@kernel.org>
+Fixes: 2839f5bcfcfc ("USB: Turn on auto-suspend for USB 3.0 hubs.")
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20250611112441.2267883-1-mathias.nyman@linux.intel.com
+[ replaced hub_get/hub_put wrapper functions with direct kref_get/kref_put calls ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -51,6 +51,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. */
+@@ -1024,11 +1030,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)
+ {
+@@ -1051,6 +1058,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));
++              kref_put(&hub->kref, hub_release);
++              return;
++      }
++
+       kref_get(&hub->kref);
+       /* The superspeed hub except for root hub has to use Hub Depth
+@@ -1299,6 +1313,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;
++      }
++
+       kref_put(&hub->kref, hub_release);
+ }
+@@ -1317,6 +1341,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
+ };