diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 47 |
1 files changed, 37 insertions, 10 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index cf7bbcb9a63c..c5c1f6cf3228 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -38,6 +38,9 @@ #define USB_VENDOR_GENESYS_LOGIC 0x05e3 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 +#define USB_TP_TRANSMISSION_DELAY 40 /* ns */ +#define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */ + /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -1049,12 +1052,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) ret = hcd->driver->update_hub_device(hcd, hdev, &hub->tt, GFP_NOIO); if (ret < 0) { - dev_err(hub->intfdev, "Host not " - "accepting hub info " - "update.\n"); - dev_err(hub->intfdev, "LS/FS devices " - "and hubs may not work " - "under this hub\n."); + dev_err(hub->intfdev, + "Host not accepting hub info update\n"); + dev_err(hub->intfdev, + "LS/FS devices and hubs may not work under this hub\n"); } } hub_power_on(hub, true); @@ -1352,6 +1353,20 @@ static int hub_configure(struct usb_hub *hub, goto fail; } + /* + * Accumulate wHubDelay + 40ns for every hub in the tree of devices. + * The resulting value will be used for SetIsochDelay() request. + */ + if (hub_is_superspeed(hdev) || hub_is_superspeedplus(hdev)) { + u32 delay = __le16_to_cpu(hub->descriptor->u.ss.wHubDelay); + + if (hdev->parent) + delay += hdev->parent->hub_delay; + + delay += USB_TP_TRANSMISSION_DELAY; + hdev->hub_delay = min_t(u32, delay, USB_TP_TRANSMISSION_DELAY_MAX); + } + maxchild = hub->descriptor->bNbrPorts; dev_info(hub_dev, "%d port%s detected\n", maxchild, (maxchild == 1) ? "" : "s"); @@ -3157,7 +3172,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_set_usb2_hardware_lpm(udev, 0); if (usb_disable_ltm(udev)) { - dev_err(&udev->dev, "Failed to disable LTM before suspend\n."); + dev_err(&udev->dev, "Failed to disable LTM before suspend\n"); status = -ENOMEM; if (PMSG_IS_AUTO(msg)) goto err_ltm; @@ -4599,7 +4614,20 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, if (retval >= 0) retval = -EMSGSIZE; } else { + u32 delay; + retval = 0; + + delay = udev->parent->hub_delay; + udev->hub_delay = min_t(u32, delay, + USB_TP_TRANSMISSION_DELAY_MAX); + retval = usb_set_isoch_delay(udev); + if (retval) { + dev_dbg(&udev->dev, + "Failed set isoch delay, error %d\n", + retval); + retval = 0; + } break; } } @@ -5484,13 +5512,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev) */ ret = usb_unlocked_disable_lpm(udev); if (ret) { - dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); + dev_err(&udev->dev, "%s Failed to disable LPM\n", __func__); goto re_enumerate_no_bos; } ret = usb_disable_ltm(udev); if (ret) { - dev_err(&udev->dev, "%s Failed to disable LTM\n.", - __func__); + dev_err(&udev->dev, "%s Failed to disable LTM\n", __func__); goto re_enumerate_no_bos; } |