| From: Zhengjun Xing <zhengjun.xing@linux.intel.com> |
| Date: Wed, 21 Mar 2018 13:29:42 +0800 |
| Subject: USB:fix USB3 devices behind USB3 hubs not resuming at hibernate thaw |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| commit 64627388b50158fd24d6ad88132525b95a5ef573 upstream. |
| |
| USB3 hubs don't support global suspend. |
| |
| USB3 specification 10.10, Enhanced SuperSpeed hubs only support selective |
| suspend and resume, they do not support global suspend/resume where the |
| hub downstream facing ports states are not affected. |
| |
| When system enters hibernation it first enters freeze process where only |
| the root hub enters suspend, usb_port_suspend() is not called for other |
| devices, and suspend status flags are not set for them. Other devices are |
| expected to suspend globally. Some external USB3 hubs will suspend the |
| downstream facing port at global suspend. These devices won't be resumed |
| at thaw as the suspend status flag is not set. |
| |
| A USB3 removable hard disk connected through a USB3 hub that won't resume |
| at thaw will fail to synchronize SCSI cache, return “cmd cmplt err -71” |
| error, and needs a 60 seconds timeout which causing system hang for 60s |
| before the USB host reset the port for the USB3 removable hard disk to |
| recover. |
| |
| Fix this by always calling usb_port_suspend() during freeze for USB3 |
| devices. |
| |
| Signed-off-by: Zhengjun Xing <zhengjun.xing@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/usb/core/generic.c | 9 +++++++-- |
| 1 file changed, 7 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/usb/core/generic.c |
| +++ b/drivers/usb/core/generic.c |
| @@ -208,8 +208,13 @@ static int generic_suspend(struct usb_de |
| if (!udev->parent) |
| rc = hcd_bus_suspend(udev, msg); |
| |
| - /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ |
| - else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) |
| + /* |
| + * Non-root USB2 devices don't need to do anything for FREEZE |
| + * or PRETHAW. USB3 devices don't support global suspend and |
| + * needs to be selectively suspended. |
| + */ |
| + else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) |
| + && (udev->speed < USB_SPEED_SUPER)) |
| rc = 0; |
| else |
| rc = usb_port_suspend(udev, msg); |