Commit b001b297 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'for-usb-linus-2012-10-11' of...

Merge tag 'for-usb-linus-2012-10-11' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-linus

USB 3.0 Link PM fixes.

Hi Greg,

Here's four fixes for the USB 3.0 Link Power Management code.  They
work around some USB 3.0 devices that don't support LPM, like the
Western Digital My Passport hard drive.  They also fix an LPM disable
ref count bug that would cause LPM to remain disabled for a device
after a failed probe.

Please queue for 3.7 after the merge window closes.  Several patches are
marked for stable.

Sarah Sharp
parents 0b381a28 1510a1a2
......@@ -367,6 +367,10 @@ static int usb_probe_interface(struct device *dev)
intf->condition = USB_INTERFACE_UNBOUND;
usb_cancel_queued_reset(intf);
/* If the LPM disable succeeded, balance the ref counts. */
if (!lpm_disable_error)
usb_unlocked_enable_lpm(udev);
/* Unbound interfaces are always runtime-PM-disabled and -suspended */
if (driver->supports_autosuspend)
pm_runtime_disable(dev);
......
......@@ -3241,8 +3241,7 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
(state == USB3_LPM_U2 &&
(u2_sel > USB3_LPM_MAX_U2_SEL_PEL ||
u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) {
dev_dbg(&udev->dev, "Device-initiated %s disabled due "
"to long SEL %llu ms or PEL %llu ms\n",
dev_dbg(&udev->dev, "Device-initiated %s disabled due to long SEL %llu us or PEL %llu us\n",
usb3_lpm_names[state], u1_sel, u1_pel);
return -EINVAL;
}
......@@ -3319,16 +3318,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.
......@@ -3414,7 +3403,28 @@ 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;
/* 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;
/*
* 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
......
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