From: Chris Chiu <chris.chiu@xxxxxxxxxxxxx> On the Realtek high-speed Hub(0bda:5487), the port which has wakeup enabled_descendants will sometimes timeout when setting PORT_SUSPEND feature. After checking the PORT_SUSPEND bit in wPortStatus, it is already set. However, the hub will fail to activate because the PORT_SUSPEND feature of that port is not cleared during resume. All connected devices are lost after resume. Check the port status to verify whether it's really suspended when timeout happpens. If yes, mark it as suspended so the device can be resumed correctly. Signed-off-by: Chris Chiu <chris.chiu@xxxxxxxxxxxxx> --- Changelog: v3: - create a new goto target for the timeout case instead of reset_resume - Revise the commit title/message because reset_resume is not required. v2: - create a new variable to keep the result of hub_port_status when suspend timeout. drivers/usb/core/hub.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b2bc4b7c4289..c5d64175eaa9 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3385,6 +3385,21 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) status = 0; } if (status) { + if (status == -ETIMEDOUT) { + u16 portstatus, portchange; + + int ret = hub_port_status(hub, port1, &portstatus, + &portchange); + + dev_dbg(&port_dev->dev, + "suspend timeout, status %04x\n", portstatus); + + if (ret == 0 && port_is_suspended(hub, portstatus)) { + status = 0; + goto suspend_done; + } + } + dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status); /* Try to enable USB3 LTM again */ @@ -3401,6 +3416,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) if (!PMSG_IS_AUTO(msg)) status = 0; } else { + suspend_done: dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n", (PMSG_IS_AUTO(msg) ? "auto-" : ""), udev->do_remote_wakeup); -- 2.20.1