• Sarah Sharp's avatar
    usb: Fix xHCI host issues on remote wakeup. · 8b3d4570
    Sarah Sharp authored
    When a device signals remote wakeup on a roothub, and the suspend change
    bit is set, the host controller driver must not give control back to the
    USB core until the port goes back into the active state.
    
    EHCI accomplishes this by waiting in the get port status function until
    the PORT_RESUME bit is cleared:
    
                            /* stop resume signaling */
                            temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME);
                            ehci_writel(ehci, temp, status_reg);
                            clear_bit(wIndex, &ehci->resuming_ports);
                            retval = ehci_handshake(ehci, status_reg,
                                            PORT_RESUME, 0, 2000 /* 2msec */);
    
    Similarly, the xHCI host should wait until the port goes into U0, before
    passing control up to the USB core.  When the port transitions from the
    RExit state to U0, the xHCI driver will get a port status change event.
    We need to wait for that event before passing control up to the USB
    core.
    
    After the port transitions to the active state, the USB core should time
    a recovery interval before it talks to the device.  The length of that
    recovery interval is TRSMRCY, 10 ms, mentioned in the USB 2.0 spec,
    section 7.1.7.7.  The previous xHCI code (which did not wait for the
    port to go into U0) would cause the USB core to violate that recovery
    interval.
    
    This bug caused numerous USB device disconnects on remote wakeup under
    ChromeOS and a Lynx Point LP xHCI host that takes up to 20 ms to move
    from RExit to U0.  ChromeOS is very aggressive about power savings, and
    sets the autosuspend_delay to 100 ms, and disables USB persist.
    
    I attempted to replicate this bug with Ubuntu 12.04, but could not.  I
    used Ubuntu 12.04 on the same platform, with the same BIOS that the bug
    was triggered on ChromeOS with.  I also changed the USB sysfs settings
    as described above, but still could not reproduce the bug under Ubuntu.
    It may be that ChromeOS userspace triggers this bug through additional
    settings.
    Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
    8b3d4570
xhci.h 64.6 KB