Re: [RFC PATCH] usb: core: defer leaf-device resume off the S3 critical path
From: Oliver Neukum
Date: Wed Aug 05 2026 - 09:29:11 EST
On 05.08.26 11:36, Hongyu Xie wrote:
Problem:
System resume (dpm_resume) invokes each device's resume callback
synchronously on the wake-up critical path. For a USB leaf device
this means port resume and, when reset_resume is needed, a port
reset that, for persistent devices, waits up to 2000 ms for the
device connection (CCS; on SuperSpeed this includes link training)
to be re-established (wait_for_connected()). Slow link training of
some U-disks and webcams after S3 power-on therefore stalls the
entire system wake-up: on an
arm64 test machine with four leaf devices (bluetooth, UVC camera,
two U-disks) dpm_resume took 2508 ms, about 2.1 s of it caused by a
single SanDisk U-disk whose link training stayed in Rx.Detect for
2000 ms (worst case: -ENODEV fallback to disconnect +
re-enumeration). A device compatibility issue should not lengthen
the system-wide wake-up.
Fix:
The patch addresses this on four levels:
1. Defer leaf-device recovery off the critical path. Leaf devices
(udev->parent && !udev->maxchild) that are port-suspended on
system resume have their real port resume moved to a per-device
work item queued from usb_resume_complete(), after all hubs have
finished resume. The work reuses the same udev (in-place reset,
devnum preserved); drivers without reset_resume get unbind+rebind.
If you do this, you may have drivers which do not runtime PM
face devices that are effectively runtime suspended. This will
not work.
2. Safe abandonment. If a new suspend or a disconnect arrives before
the work item runs, the reset is abandoned, not flushed: the
device is still port-suspended, which is exactly what the new
suspend needs, and the work item then only releases the runtime
reference it took. The abandon decision is serialized with the
work item by the device lock, so no cancel_work_sync() (which
would deadlock against the work item's device_lock()) is needed
on the suspend path.
You cannot do this without checking whether remote_wakeup is correctly
set.
Furthermore you cannot just use the system work queue for this.
You must not have any memory allocations with GFP_KERNEL on that
queue.
Regards
Oliver