From: "Wang, Yu" <yu.y.wang@xxxxxxxxx> The system suspend flow as following: 1, Freeze all user processes and kenrel threads. 2, Trying to suspend all devices. 2.1, If pci device under RPM suspended state, then pci driver will try to resume it to RPM active state in prepare stage. 2.2, xhci_resume function will call usb_hcd_resume_root_hub to queue two workqueue items to resume usb2&usb3 roothub devices. 2.3, Call suspend callbacks of devices. 2.3.1, All suspend callbacks be called of all hcd's children included roothub devices. 2.3.2, Fianlly, hcd_pci_suspend callback be called. Due to workqueue threads were already frozen in step 1. So the workqueue items can't be scheduled which will cause roothub devices can't be resumed in this flow. Then HCD_FLAG_WAKEUP_PENDING flags will not be clear which set in usb_hcd_resume_root_hub function. Finally, hcd_pci_suspend will return -EBUSY, and system suspend is failed. The reason why this issue doesn't show up very often, it is due to choose_wakeup will be called in step step 2.3.1. In step 2.3.1 udev->do_remote_wakeup is not equal device_may_wakeup(&udev->dev), then udev will be resume to RPM active for change the wakeup settings. This is one be resumed to RPM active to change lucky hit which hides this issue. For some special xHCI controllers which have no USB2 port, then roothub will not match hub driver due to probe failed. Then its do_remote_wakeup will be set to zero, then will not hit above lucky. Actually, xhci driver needn't to resume roothub devices everytime like above case. It's only needed when there are pending event TRBs. Signed-off-by: Wang, Yu <yu.y.wang@xxxxxxxxx> --- drivers/usb/host/xhci.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 3008369..4285e94 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -932,7 +932,7 @@ int xhci_suspend(struct xhci_hcd *xhci) */ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) { - u32 command, temp = 0; + u32 command, temp = 0, status; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; int retval = 0; @@ -1050,8 +1050,12 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) done: if (retval == 0) { - usb_hcd_resume_root_hub(hcd); - usb_hcd_resume_root_hub(xhci->shared_hcd); + /* Resume root hubs only when have pending events. */ + status = xhci_readl(xhci, &xhci->op_regs->status); + if (status & STS_EINT) { + usb_hcd_resume_root_hub(hcd); + usb_hcd_resume_root_hub(xhci->shared_hcd); + } } /* -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html