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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Don,

Please test this patch on top of the other patch.

Sarah Sharp

>8-------------------------------------------------------------------8<
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.

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
Reported-by: Don Zickus <dzickus@xxxxxxxxxx>
---
 drivers/usb/core/hub.c |   14 ++++++++++----
 1 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 55bef91..2568441 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3484,8 +3484,16 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
 		enum usb3_link_state state)
 {
 	int timeout;
-	__u8 u1_mel;
-	__le16 u2_mel;
+	__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
 	 * first, so that it can change its schedule to account for the
@@ -3512,8 +3520,6 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
 	 * link commands.  This can cause transfer errors, so only enable
 	 * device-initiated LPM.
 	 */
-	u1_mel = udev->bos->ss_cap->bU1devExitLat;
-	u2_mel = udev->bos->ss_cap->bU2DevExitLat;
 	if ((state == USB3_LPM_U1 && u1_mel == USB_U1_MAX_VALID_MEL) ||
 			(state == USB3_LPM_U2 &&
 			 le16_to_cpu(u2_mel) == USB_U2_MAX_VALID_MEL)) {
-- 
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux