| From 65a95b75bc5afa7bbb844e222481044c1c4767eb Mon Sep 17 00:00:00 2001 |
| From: Sarah Sharp <sarah.a.sharp@linux.intel.com> |
| Date: Fri, 5 Oct 2012 10:32:07 -0700 |
| Subject: usb: Send Set SEL before enabling parent U1/U2 timeout. |
| |
| From: Sarah Sharp <sarah.a.sharp@linux.intel.com> |
| |
| commit 65a95b75bc5afa7bbb844e222481044c1c4767eb upstream. |
| |
| 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 1ea7e0e8e3d0f50901d335ea4178ab2aa8c88201 "USB: Add support to |
| enable/disable USB3 link states." |
| |
| Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/core/hub.c | 23 ++++++++++++----------- |
| 1 file changed, 12 insertions(+), 11 deletions(-) |
| |
| --- a/drivers/usb/core/hub.c |
| +++ b/drivers/usb/core/hub.c |
| @@ -3258,16 +3258,6 @@ static int usb_set_device_initiated_lpm( |
| |
| 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. |
| */ |
| @@ -3352,7 +3342,7 @@ static int usb_set_lpm_timeout(struct us |
| 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; |
| |
| @@ -3364,6 +3354,17 @@ static void usb_enable_link_state(struct |
| (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 |