Skip to content

Commit 2f31a67

Browse files
matnymangregkh
authored andcommitted
usb: xhci: Prevent bus suspend if a port connect change or polling state is detected
USB3 roothub might autosuspend before a plugged USB3 device is detected, causing USB3 device enumeration failure. USB3 devices don't show up as connected and enabled until USB3 link trainig completes. On a fast booting platform with a slow USB3 link training the link might reach the connected enabled state just as the bus is suspending. If this device is discovered first time by the xhci_bus_suspend() routine it will be put to U3 suspended state like the other ports which failed to suspend earlier. The hub thread will notice the connect change and resume the bus, moving the port back to U0 This U0 -> U3 -> U0 transition right after being connected seems to be too much for some devices, causing them to first go to SS.Inactive state, and finally end up stuck in a polling state with reset asserted Fix this by failing the bus suspend if a port has a connect change or is in a polling state in xhci_bus_suspend(). Don't do any port changes until all ports are checked, buffer all port changes and only write them in the end if suspend can proceed Cc: stable@vger.kernel.org Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 22454b7 commit 2f31a67

File tree

1 file changed

+46
-14
lines changed

1 file changed

+46
-14
lines changed

drivers/usb/host/xhci-hub.c

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,42 +1474,55 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
14741474
unsigned long flags;
14751475
struct xhci_hub *rhub;
14761476
struct xhci_port **ports;
1477+
u32 portsc_buf[USB_MAXCHILDREN];
1478+
bool wake_enabled;
14771479

14781480
rhub = xhci_get_rhub(hcd);
14791481
ports = rhub->ports;
14801482
max_ports = rhub->num_ports;
14811483
bus_state = &xhci->bus_state[hcd_index(hcd)];
1484+
wake_enabled = hcd->self.root_hub->do_remote_wakeup;
14821485

14831486
spin_lock_irqsave(&xhci->lock, flags);
14841487

1485-
if (hcd->self.root_hub->do_remote_wakeup) {
1488+
if (wake_enabled) {
14861489
if (bus_state->resuming_ports || /* USB2 */
14871490
bus_state->port_remote_wakeup) { /* USB3 */
14881491
spin_unlock_irqrestore(&xhci->lock, flags);
14891492
xhci_dbg(xhci, "suspend failed because a port is resuming\n");
14901493
return -EBUSY;
14911494
}
14921495
}
1493-
1494-
port_index = max_ports;
1496+
/*
1497+
* Prepare ports for suspend, but don't write anything before all ports
1498+
* are checked and we know bus suspend can proceed
1499+
*/
14951500
bus_state->bus_suspended = 0;
1501+
port_index = max_ports;
14961502
while (port_index--) {
1497-
/* suspend the port if the port is not suspended */
14981503
u32 t1, t2;
1499-
int slot_id;
15001504

15011505
t1 = readl(ports[port_index]->addr);
15021506
t2 = xhci_port_state_to_neutral(t1);
1507+
portsc_buf[port_index] = 0;
15031508

1504-
if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) {
1505-
xhci_dbg(xhci, "port %d not suspended\n", port_index);
1506-
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
1507-
port_index + 1);
1508-
if (slot_id) {
1509+
/* Bail out if a USB3 port has a new device in link training */
1510+
if ((t1 & PORT_PLS_MASK) == XDEV_POLLING) {
1511+
bus_state->bus_suspended = 0;
1512+
spin_unlock_irqrestore(&xhci->lock, flags);
1513+
xhci_dbg(xhci, "Bus suspend bailout, port in polling\n");
1514+
return -EBUSY;
1515+
}
1516+
1517+
/* suspend ports in U0, or bail out for new connect changes */
1518+
if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) {
1519+
if ((t1 & PORT_CSC) && wake_enabled) {
1520+
bus_state->bus_suspended = 0;
15091521
spin_unlock_irqrestore(&xhci->lock, flags);
1510-
xhci_stop_device(xhci, slot_id, 1);
1511-
spin_lock_irqsave(&xhci->lock, flags);
1522+
xhci_dbg(xhci, "Bus suspend bailout, port connect change\n");
1523+
return -EBUSY;
15121524
}
1525+
xhci_dbg(xhci, "port %d not suspended\n", port_index);
15131526
t2 &= ~PORT_PLS_MASK;
15141527
t2 |= PORT_LINK_STROBE | XDEV_U3;
15151528
set_bit(port_index, &bus_state->bus_suspended);
@@ -1518,7 +1531,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
15181531
* including the USB 3.0 roothub, but only if CONFIG_PM
15191532
* is enabled, so also enable remote wake here.
15201533
*/
1521-
if (hcd->self.root_hub->do_remote_wakeup) {
1534+
if (wake_enabled) {
15221535
if (t1 & PORT_CONNECT) {
15231536
t2 |= PORT_WKOC_E | PORT_WKDISC_E;
15241537
t2 &= ~PORT_WKCONN_E;
@@ -1538,7 +1551,26 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
15381551

15391552
t1 = xhci_port_state_to_neutral(t1);
15401553
if (t1 != t2)
1541-
writel(t2, ports[port_index]->addr);
1554+
portsc_buf[port_index] = t2;
1555+
}
1556+
1557+
/* write port settings, stopping and suspending ports if needed */
1558+
port_index = max_ports;
1559+
while (port_index--) {
1560+
if (!portsc_buf[port_index])
1561+
continue;
1562+
if (test_bit(port_index, &bus_state->bus_suspended)) {
1563+
int slot_id;
1564+
1565+
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
1566+
port_index + 1);
1567+
if (slot_id) {
1568+
spin_unlock_irqrestore(&xhci->lock, flags);
1569+
xhci_stop_device(xhci, slot_id, 1);
1570+
spin_lock_irqsave(&xhci->lock, flags);
1571+
}
1572+
}
1573+
writel(portsc_buf[port_index], ports[port_index]->addr);
15421574
}
15431575
hcd->state = HC_STATE_SUSPENDED;
15441576
bus_state->next_statechange = jiffies + msecs_to_jiffies(10);

0 commit comments

Comments
 (0)