Skip to content

Commit

Permalink
usb: Send Set SEL before enabling parent U1/U2 timeout.
Browse files Browse the repository at this point in the history
The Set SEL control transfer tells a device the exit latencies
associated with a device-initated U1 or U2 exit.  Since a parent hub may
initiate a transition to U1 soon after a downstream port's U1 timeout is
set, we need to make sure the device receives the Set SEL transfer
before the parent hub timeout is set.

This patch should be backported to kernels as old as 3.5, that contain
the commit 1ea7e0e "USB: Add support to
enable/disable USB3 link states."

Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: stable@vger.kernel.org
  • Loading branch information
Sarah Sharp committed Oct 8, 2012
1 parent ae8963a commit 65a95b7
Showing 1 changed file with 12 additions and 11 deletions.
23 changes: 12 additions & 11 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -3319,16 +3319,6 @@ static int usb_set_device_initiated_lpm(struct usb_device *udev,
}

if (enable) {
/*
* First, let the device know about the exit latencies
* associated with the link state we're about to enable.
*/
ret = usb_req_set_sel(udev, state);
if (ret < 0) {
dev_warn(&udev->dev, "Set SEL for device-initiated "
"%s failed.\n", usb3_lpm_names[state]);
return -EBUSY;
}
/*
* Now send the control transfer to enable device-initiated LPM
* for either U1 or U2.
Expand Down Expand Up @@ -3414,7 +3404,7 @@ static int usb_set_lpm_timeout(struct usb_device *udev,
static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
enum usb3_link_state state)
{
int timeout;
int timeout, ret;
__u8 u1_mel = udev->bos->ss_cap->bU1devExitLat;
__le16 u2_mel = udev->bos->ss_cap->bU2DevExitLat;

Expand All @@ -3426,6 +3416,17 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
(state == USB3_LPM_U2 && u2_mel == 0))
return;

/*
* First, let the device know about the exit latencies
* associated with the link state we're about to enable.
*/
ret = usb_req_set_sel(udev, state);
if (ret < 0) {
dev_warn(&udev->dev, "Set SEL for device-initiated %s failed.\n",
usb3_lpm_names[state]);
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
* additional latency to send data to a device in a lower power
Expand Down

0 comments on commit 65a95b7

Please sign in to comment.