• Hans de Goede's avatar
    usb: Reset USB-3 devices on USB-3 link bounce · a82b76f7
    Hans de Goede authored
    On disconnect USB3 protocol ports transit from U0 to SS.Inactive to Rx.Detect,
    on a recoverable error, the port stays in SS.Inactive and we recover from it by
    doing a warm-reset (through usb_device_reset if we have a udev for the port).
    
    If this really is a disconnect we may end up trying the warm-reset anyways,
    since khubd may run before the SS.Inactive to Rx.Detect transition, or it
    may get skipped if the transition to Rx.Detect happens before khubd gets run.
    
    With a loose connector, or in the case which actually led me to debugging this
    bad ACPI firmware toggling Vbus off and on in quick succession, the port
    may transition from Rx.Detect to U0 again before khubd gets run. In this case
    the device state is unknown really, but khubd happily goes into the resuscitate
    an existing device path, and the device driver never gets notified about the
    device state being messed up.
    
    If the above scenario happens with a streams using device, as soon as an urb
    is submitted to an endpoint with streams, the following appears in dmesg:
    
    ERROR Transfer event for disabled endpoint or incorrect stream ring
    @0000000036807420 00000000 00000000 04000000 04078000
    
    Notice how the TRB address is all zeros. I've seen this both on Intel
    Pantherpoint and Nec xhci hosts.
    
    Luckily we can detect the U0 to SS.Inactive to Rx.Detect to U0 all having
    happened before khubd runs case since the C_LINK_STATE bit gets set in the
    portchange bits on the U0 -> SS.Inactive change. This bit will also be set on
    suspend / resume, but then it gets cleared by port_hub_init before khubd runs.
    
    So if the C_LINK_STATE bit is set and a warm-reset is not needed, iow the port
    is not still in SS.Inactive, and the port still has a connection, then the
    device needs to be reset to put it back in a known state.
    
    I've verified that doing the device reset also fixes the transfer event with
    all zeros address issue.
    Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
    Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
    a82b76f7
hub.c 157 KB