aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorWang, Yu <yu.y.wang@intel.com>2014-06-24 10:14:44 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-06-24 12:29:35 -0400
commitd6236f6d1d885aa19d1cd7317346fe795227a3cc (patch)
treeba48ad5a147015c596efb6fcfdba124b4bce9e47 /drivers/usb
parentff8cbf250b448aac35589f6075082c3fcad8a8fe (diff)
xhci: Fix runtime suspended xhci from blocking system suspend.
The system suspend flow as following: 1, Freeze all user processes and kenrel threads. 2, Try to suspend all devices. 2.1, If pci device is in RPM suspended state, then pci driver will try to resume it to RPM active state in the prepare stage. 2.2, xhci_resume function calls 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 of all hcd's children, including roothub devices are called. 2.3.2, Finally, hcd_pci_suspend callback is called. Due to workqueue threads were already frozen in step 1, the workqueue items can't be scheduled, and the roothub devices can't be resumed in this flow. The HCD_FLAG_WAKEUP_PENDING flag which is set in usb_hcd_resume_root_hub won't be cleared. Finally, hcd_pci_suspend will return -EBUSY, and system suspend fails. The reason why this issue doesn't show up very often is due to that choose_wakeup will be called in step 2.3.1. In step 2.3.1, if udev->do_remote_wakeup is not equal to device_may_wakeup(&udev->dev), then udev will resume to RPM active for changing the wakeup settings. This has been a 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, and we won't be as lucky. xhci driver doesn't need to resume roothub devices everytime like in the above case. It's only needed when there are pending event TRBs. This patch should be back-ported to kernels as old as 3.2, that contains the commit f69e3120df82391a0ee8118e0a156239a06b2afb "USB: XHCI: resume root hubs when the controller resumes" Cc: stable@vger.kernel.org # 3.2 Signed-off-by: Wang, Yu <yu.y.wang@intel.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> [use readl() instead of removed xhci_readl(), reword commit message -Mathias] Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/xhci.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 2b8d9a24af09..7436d5f5e67a 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -936,7 +936,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
936 */ 936 */
937int xhci_resume(struct xhci_hcd *xhci, bool hibernated) 937int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
938{ 938{
939 u32 command, temp = 0; 939 u32 command, temp = 0, status;
940 struct usb_hcd *hcd = xhci_to_hcd(xhci); 940 struct usb_hcd *hcd = xhci_to_hcd(xhci);
941 struct usb_hcd *secondary_hcd; 941 struct usb_hcd *secondary_hcd;
942 int retval = 0; 942 int retval = 0;
@@ -1054,8 +1054,12 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
1054 1054
1055 done: 1055 done:
1056 if (retval == 0) { 1056 if (retval == 0) {
1057 usb_hcd_resume_root_hub(hcd); 1057 /* Resume root hubs only when have pending events. */
1058 usb_hcd_resume_root_hub(xhci->shared_hcd); 1058 status = readl(&xhci->op_regs->status);
1059 if (status & STS_EINT) {
1060 usb_hcd_resume_root_hub(hcd);
1061 usb_hcd_resume_root_hub(xhci->shared_hcd);
1062 }
1059 } 1063 }
1060 1064
1061 /* 1065 /*