[RFC] xhci: Fix xhci block system enter system suspend state.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux