aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c43
1 files changed, 28 insertions, 15 deletions
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)
739 int limit = 100; 739 int limit = 100;
740 740
741 spin_lock_irqsave (&hub->tt.lock, flags); 741 spin_lock_irqsave (&hub->tt.lock, flags);
742 while (--limit && !list_empty (&hub->tt.clear_list)) { 742 while (!list_empty(&hub->tt.clear_list)) {
743 struct list_head *next; 743 struct list_head *next;
744 struct usb_tt_clear *clear; 744 struct usb_tt_clear *clear;
745 struct usb_device *hdev = hub->hdev; 745 struct usb_device *hdev = hub->hdev;
746 const struct hc_driver *drv; 746 const struct hc_driver *drv;
747 int status; 747 int status;
748 748
749 if (!hub->quiescing && --limit < 0)
750 break;
751
749 next = hub->tt.clear_list.next; 752 next = hub->tt.clear_list.next;
750 clear = list_entry (next, struct usb_tt_clear, clear_list); 753 clear = list_entry (next, struct usb_tt_clear, clear_list);
751 list_del (&clear->clear_list); 754 list_del (&clear->clear_list);
@@ -1210,7 +1213,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
1210 if (hub->has_indicators) 1213 if (hub->has_indicators)
1211 cancel_delayed_work_sync(&hub->leds); 1214 cancel_delayed_work_sync(&hub->leds);
1212 if (hub->tt.hub) 1215 if (hub->tt.hub)
1213 cancel_work_sync(&hub->tt.clear_work); 1216 flush_work(&hub->tt.clear_work);
1214} 1217}
1215 1218
1216/* caller has locked the hub device */ 1219/* 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)
3241 (state == USB3_LPM_U2 && 3244 (state == USB3_LPM_U2 &&
3242 (u2_sel > USB3_LPM_MAX_U2_SEL_PEL || 3245 (u2_sel > USB3_LPM_MAX_U2_SEL_PEL ||
3243 u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) { 3246 u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) {
3244 dev_dbg(&udev->dev, "Device-initiated %s disabled due " 3247 dev_dbg(&udev->dev, "Device-initiated %s disabled due to long SEL %llu us or PEL %llu us\n",
3245 "to long SEL %llu ms or PEL %llu ms\n",
3246 usb3_lpm_names[state], u1_sel, u1_pel); 3248 usb3_lpm_names[state], u1_sel, u1_pel);
3247 return -EINVAL; 3249 return -EINVAL;
3248 } 3250 }
@@ -3320,16 +3322,6 @@ static int usb_set_device_initiated_lpm(struct usb_device *udev,
3320 3322
3321 if (enable) { 3323 if (enable) {
3322 /* 3324 /*
3323 * First, let the device know about the exit latencies
3324 * associated with the link state we're about to enable.
3325 */
3326 ret = usb_req_set_sel(udev, state);
3327 if (ret < 0) {
3328 dev_warn(&udev->dev, "Set SEL for device-initiated "
3329 "%s failed.\n", usb3_lpm_names[state]);
3330 return -EBUSY;
3331 }
3332 /*
3333 * Now send the control transfer to enable device-initiated LPM 3325 * Now send the control transfer to enable device-initiated LPM
3334 * for either U1 or U2. 3326 * for either U1 or U2.
3335 */ 3327 */
@@ -3414,7 +3406,28 @@ static int usb_set_lpm_timeout(struct usb_device *udev,
3414static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, 3406static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
3415 enum usb3_link_state state) 3407 enum usb3_link_state state)
3416{ 3408{
3417 int timeout; 3409 int timeout, ret;
3410 __u8 u1_mel = udev->bos->ss_cap->bU1devExitLat;
3411 __le16 u2_mel = udev->bos->ss_cap->bU2DevExitLat;
3412
3413 /* If the device says it doesn't have *any* exit latency to come out of
3414 * U1 or U2, it's probably lying. Assume it doesn't implement that link
3415 * state.
3416 */
3417 if ((state == USB3_LPM_U1 && u1_mel == 0) ||
3418 (state == USB3_LPM_U2 && u2_mel == 0))
3419 return;
3420
3421 /*
3422 * First, let the device know about the exit latencies
3423 * associated with the link state we're about to enable.
3424 */
3425 ret = usb_req_set_sel(udev, state);
3426 if (ret < 0) {
3427 dev_warn(&udev->dev, "Set SEL for device-initiated %s failed.\n",
3428 usb3_lpm_names[state]);
3429 return;
3430 }
3418 3431
3419 /* We allow the host controller to set the U1/U2 timeout internally 3432 /* We allow the host controller to set the U1/U2 timeout internally
3420 * first, so that it can change its schedule to account for the 3433 * first, so that it can change its schedule to account for the