Re: [PATCH] usb: port: add delay after usb_hub_set_port_power()

From: Alan Stern

Date: Wed Feb 11 2026 - 10:04:48 EST


On Wed, Feb 11, 2026 at 06:36:28PM +0800, Xu Yang wrote:
> When disable the root hub port, somehow the device is disconnected and
> re-connected again. This happens because usb_clear_port_feature() does not
> clear a truly happened port change. That says, in fact, port change event
> may happen after usb_clear_port_feature() is called. Then the subsequent
> port change event will have impact on usb device suspend routine.

This is not a very good description of the problem. Here's a better
one:

When a port is disabled, an attached device will be disconnected. This
causes a port-status-change event, which will race with hub autosuspend
(if the disabled port was the only connected port on its hub), causing
an immediate resume and a second autosuspend. Both of these can be
avoided by adding a short delay after the call to
usb_hub_set_port_power().

Alan Stern

> Below log shows what is happening:
>
> $ echo 1 > usb1-port1/disable
> [ 37.958239] usb 1-1: USB disconnect, device number 2
> [ 37.964101] usb 1-1: unregistering device
> [ 37.970070] hub 1-0:1.0: hub_suspend
> [ 37.971305] hub 1-0:1.0: state 7 ports 1 chg 0000 evt 0002
> [ 37.974412] usb usb1: bus auto-suspend, wakeup 1
> [ 37.988175] usb usb1: suspend raced with wakeup event <---
> [ 37.993947] usb usb1: usb auto-resume
> [ 37.998401] hub 1-0:1.0: hub_resume
> [ 38.105688] usb usb1-port1: status 0000, change 0000, 12 Mb/s
> [ 38.112399] hub 1-0:1.0: state 7 ports 1 chg 0000 evt 0000
> [ 38.118645] hub 1-0:1.0: hub_suspend
> [ 38.122963] usb usb1: bus auto-suspend, wakeup 1
> [ 38.200368] usb usb1: usb wakeup-resume
> [ 38.204982] usb usb1: usb auto-resume
> [ 38.209376] hub 1-0:1.0: hub_resume
> [ 38.213676] usb usb1-port1: status 0101 change 0001
> [ 38.321552] hub 1-0:1.0: state 7 ports 1 chg 0002 evt 0000
> [ 38.327978] usb usb1-port1: status 0101, change 0000, 12 Mb/s
> [ 38.457429] usb 1-1: new high-speed USB device number 3 using ci_hdrc
>
> To fix the issue, add delay after usb_hub_set_port_power(). So port change
> bit will be fixed to the final state and usb_clear_port_feature() can
> correctly clear it after this period. This will also avoid usb runtime
> suspend routine to run because usb_autopm_put_interface() not run yet.
>
> Fixes: f061f43d7418 ("usb: hub: port: add sysfs entry to switch port power")
> Cc: stable@xxxxxxxxxx
> Signed-off-by: Xu Yang <xu.yang_2@xxxxxxx>
> ---
> drivers/usb/core/port.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
> index f54198171b6a..a47df5d32f7c 100644
> --- a/drivers/usb/core/port.c
> +++ b/drivers/usb/core/port.c
> @@ -141,6 +141,7 @@ static ssize_t disable_store(struct device *dev, struct device_attribute *attr,
> usb_disconnect(&port_dev->child);
>
> rc = usb_hub_set_port_power(hdev, hub, port1, !disabled);
> + msleep(2 * hub_power_on_good_delay(hub));
>
> if (disabled) {
> usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
> --
> 2.34.1
>