|
@@ -1501,20 +1501,25 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|
|
port_index = max_ports;
|
|
port_index = max_ports;
|
|
|
while (port_index--) {
|
|
while (port_index--) {
|
|
|
u32 t1, t2;
|
|
u32 t1, t2;
|
|
|
-
|
|
|
|
|
|
|
+ int retries = 10;
|
|
|
|
|
+retry:
|
|
|
t1 = readl(ports[port_index]->addr);
|
|
t1 = readl(ports[port_index]->addr);
|
|
|
t2 = xhci_port_state_to_neutral(t1);
|
|
t2 = xhci_port_state_to_neutral(t1);
|
|
|
portsc_buf[port_index] = 0;
|
|
portsc_buf[port_index] = 0;
|
|
|
|
|
|
|
|
- /* Bail out if a USB3 port has a new device in link training */
|
|
|
|
|
- if ((hcd->speed >= HCD_USB3) &&
|
|
|
|
|
|
|
+ /*
|
|
|
|
|
+ * Give a USB3 port in link training time to finish, but don't
|
|
|
|
|
+ * prevent suspend as port might be stuck
|
|
|
|
|
+ */
|
|
|
|
|
+ if ((hcd->speed >= HCD_USB3) && retries-- &&
|
|
|
(t1 & PORT_PLS_MASK) == XDEV_POLLING) {
|
|
(t1 & PORT_PLS_MASK) == XDEV_POLLING) {
|
|
|
- bus_state->bus_suspended = 0;
|
|
|
|
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
|
|
- xhci_dbg(xhci, "Bus suspend bailout, port in polling\n");
|
|
|
|
|
- return -EBUSY;
|
|
|
|
|
|
|
+ msleep(XHCI_PORT_POLLING_LFPS_TIME);
|
|
|
|
|
+ spin_lock_irqsave(&xhci->lock, flags);
|
|
|
|
|
+ xhci_dbg(xhci, "port %d polling in bus suspend, waiting\n",
|
|
|
|
|
+ port_index);
|
|
|
|
|
+ goto retry;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
/* suspend ports in U0, or bail out for new connect changes */
|
|
/* suspend ports in U0, or bail out for new connect changes */
|
|
|
if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) {
|
|
if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) {
|
|
|
if ((t1 & PORT_CSC) && wake_enabled) {
|
|
if ((t1 & PORT_CSC) && wake_enabled) {
|