usb: Reset USB-3 devices on USB-3 link bounce
authorHans de Goede <hdegoede@redhat.com>
Fri, 8 Nov 2013 12:41:05 +0000 (13:41 +0100)
committerSimon Horman <horms+renesas@verge.net.au>
Fri, 5 Dec 2014 04:13:28 +0000 (13:13 +0900)
commitec9b9398b427f9c7b5d285d382d501a3b15998cc
tree2a365e66d3b27cb37efc669e94513ac04ed0575e
parent9f572bde40019efc24fe77a2794cc5f8d68780b3
usb: Reset USB-3 devices on USB-3 link bounce

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: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
(cherry picked from commit a82b76f7fa6154e8ab2d8071842a3e38b9c0d0ff)
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
drivers/usb/core/hub.c