Commit ae8963ad authored by Sarah Sharp's avatar Sarah Sharp

usb: Don't enable LPM if the exit latency is zero.

Some USB 3.0 devices signal that they don't implement Link PM by having
all zeroes in the U1/U2 exit latencies in their SuperSpeed BOS
descriptor.  Don found that a Western Digital device he has experiences
transfer errors when LPM is enabled.  The lsusb shows the U1/U2 exit
latencies are set to zero:

Binary Object Store Descriptor:
  bLength                 5
  bDescriptorType        15
  wTotalLength           22
  bNumDeviceCaps          2
  SuperSpeed USB Device Capability:
    bLength                10
    bDescriptorType        16
    bDevCapabilityType      3
    bmAttributes         0x00
      Latency Tolerance Messages (LTM) Supported
    wSpeedsSupported   0x000e
      Device can operate at Full Speed (12Mbps)
      Device can operate at High Speed (480Mbps)
      Device can operate at SuperSpeed (5Gbps)
    bFunctionalitySupport   1
      Lowest fully-functional device speed is Full Speed (12Mbps)
    bU1DevExitLat           0 micro seconds
    bU2DevExitLat           0 micro seconds

The fix is to not enable LPM for a particular link state if we find its
corresponding exit latency is zero.

This patch should be backported to kernels as old as 3.5, that contain
the commit 1ea7e0e8 "USB: Add support to
enable/disable USB3 link states."
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Reported-by: default avatarDon Zickus <dzickus@redhat.com>
Tested-by: default avatarDon Zickus <dzickus@redhat.com>
Cc: stable@vger.kernel.org
parent d01f87c0
...@@ -3415,6 +3415,16 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, ...@@ -3415,6 +3415,16 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
enum usb3_link_state state) enum usb3_link_state state)
{ {
int timeout; int timeout;
__u8 u1_mel = udev->bos->ss_cap->bU1devExitLat;
__le16 u2_mel = udev->bos->ss_cap->bU2DevExitLat;
/* If the device says it doesn't have *any* exit latency to come out of
* U1 or U2, it's probably lying. Assume it doesn't implement that link
* state.
*/
if ((state == USB3_LPM_U1 && u1_mel == 0) ||
(state == USB3_LPM_U2 && u2_mel == 0))
return;
/* We allow the host controller to set the U1/U2 timeout internally /* We allow the host controller to set the U1/U2 timeout internally
* first, so that it can change its schedule to account for the * first, so that it can change its schedule to account for the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment