aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-11-26 09:23:57 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-11-26 09:23:57 +1100
commit2a859ab07b6ab66f4134c4fffc341398bd3d328c (patch)
treec5e7eaf3bffbc18feb326940e39794328d98dc07 /drivers/usb/core
parentcedddd812a79a4fda3885a15711aee3de78c4a24 (diff)
parente716e014384688d1a50d1aa5213ee74748c6d4e0 (diff)
downloadkernel_replicant_linux-2a859ab07b6ab66f4134c4fffc341398bd3d328c.tar.gz
kernel_replicant_linux-2a859ab07b6ab66f4134c4fffc341398bd3d328c.tar.bz2
kernel_replicant_linux-2a859ab07b6ab66f4134c4fffc341398bd3d328c.zip
Merge branch 'merge' into next
Merge my own merge branch to get various fixes from there and upstream, especially the hvc console tty refcouting fixes which which testing is quite a bit harder...
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/devio.c1
-rw-r--r--drivers/usb/core/driver.c4
-rw-r--r--drivers/usb/core/hub.c43
3 files changed, 33 insertions, 15 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index e0356cb859b5..b78fbe222b72 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1348,6 +1348,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
ret = -EFAULT;
goto error;
}
+ uurb->buffer += u;
}
totlen -= u;
}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index ddd820d25288..6056db7af410 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -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);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 673ee4696262..1af04bdeaf0c 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -739,13 +739,16 @@ static void hub_tt_work(struct work_struct *work)
int limit = 100;
spin_lock_irqsave (&hub->tt.lock, flags);
- while (--limit && !list_empty (&hub->tt.clear_list)) {
+ while (!list_empty(&hub->tt.clear_list)) {
struct list_head *next;
struct usb_tt_clear *clear;
struct usb_device *hdev = hub->hdev;
const struct hc_driver *drv;
int status;
+ if (!hub->quiescing && --limit < 0)
+ break;
+
next = hub->tt.clear_list.next;
clear = list_entry (next, struct usb_tt_clear, clear_list);
list_del (&clear->clear_list);
@@ -1210,7 +1213,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
if (hub->has_indicators)
cancel_delayed_work_sync(&hub->leds);
if (hub->tt.hub)
- cancel_work_sync(&hub->tt.clear_work);
+ flush_work(&hub->tt.clear_work);
}
/* caller has locked the hub device */
@@ -3241,8 +3244,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;
}
@@ -3320,16 +3322,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 +3406,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