diff options
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 19 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 8 |
2 files changed, 20 insertions, 7 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index e2eece693655..96a740543183 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -1545,20 +1545,25 @@ int xhci_bus_suspend(struct usb_hcd *hcd) | |||
1545 | port_index = max_ports; | 1545 | port_index = max_ports; |
1546 | while (port_index--) { | 1546 | while (port_index--) { |
1547 | u32 t1, t2; | 1547 | u32 t1, t2; |
1548 | 1548 | int retries = 10; | |
1549 | retry: | ||
1549 | t1 = readl(ports[port_index]->addr); | 1550 | t1 = readl(ports[port_index]->addr); |
1550 | t2 = xhci_port_state_to_neutral(t1); | 1551 | t2 = xhci_port_state_to_neutral(t1); |
1551 | portsc_buf[port_index] = 0; | 1552 | portsc_buf[port_index] = 0; |
1552 | 1553 | ||
1553 | /* Bail out if a USB3 port has a new device in link training */ | 1554 | /* |
1554 | if ((hcd->speed >= HCD_USB3) && | 1555 | * Give a USB3 port in link training time to finish, but don't |
1556 | * prevent suspend as port might be stuck | ||
1557 | */ | ||
1558 | if ((hcd->speed >= HCD_USB3) && retries-- && | ||
1555 | (t1 & PORT_PLS_MASK) == XDEV_POLLING) { | 1559 | (t1 & PORT_PLS_MASK) == XDEV_POLLING) { |
1556 | bus_state->bus_suspended = 0; | ||
1557 | spin_unlock_irqrestore(&xhci->lock, flags); | 1560 | spin_unlock_irqrestore(&xhci->lock, flags); |
1558 | xhci_dbg(xhci, "Bus suspend bailout, port in polling\n"); | 1561 | msleep(XHCI_PORT_POLLING_LFPS_TIME); |
1559 | return -EBUSY; | 1562 | spin_lock_irqsave(&xhci->lock, flags); |
1563 | xhci_dbg(xhci, "port %d polling in bus suspend, waiting\n", | ||
1564 | port_index); | ||
1565 | goto retry; | ||
1560 | } | 1566 | } |
1561 | |||
1562 | /* suspend ports in U0, or bail out for new connect changes */ | 1567 | /* suspend ports in U0, or bail out for new connect changes */ |
1563 | if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) { | 1568 | if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) { |
1564 | if ((t1 & PORT_CSC) && wake_enabled) { | 1569 | if ((t1 & PORT_CSC) && wake_enabled) { |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 652dc36e3012..9334cdee382a 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -452,6 +452,14 @@ struct xhci_op_regs { | |||
452 | */ | 452 | */ |
453 | #define XHCI_DEFAULT_BESL 4 | 453 | #define XHCI_DEFAULT_BESL 4 |
454 | 454 | ||
455 | /* | ||
456 | * USB3 specification define a 360ms tPollingLFPSTiemout for USB3 ports | ||
457 | * to complete link training. usually link trainig completes much faster | ||
458 | * so check status 10 times with 36ms sleep in places we need to wait for | ||
459 | * polling to complete. | ||
460 | */ | ||
461 | #define XHCI_PORT_POLLING_LFPS_TIME 36 | ||
462 | |||
455 | /** | 463 | /** |
456 | * struct xhci_intr_reg - Interrupt Register Set | 464 | * struct xhci_intr_reg - Interrupt Register Set |
457 | * @irq_pending: IMAN - Interrupt Management Register. Used to enable | 465 | * @irq_pending: IMAN - Interrupt Management Register. Used to enable |