diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 45 |
1 files changed, 38 insertions, 7 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 92dde941fdbe..06cec635e703 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1112,16 +1112,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) | |||
1112 | /* | 1112 | /* |
1113 | * USB3 protocol ports will automatically transition | 1113 | * USB3 protocol ports will automatically transition |
1114 | * to Enabled state when detect an USB3.0 device attach. | 1114 | * to Enabled state when detect an USB3.0 device attach. |
1115 | * Do not disable USB3 protocol ports. | 1115 | * Do not disable USB3 protocol ports, just pretend |
1116 | * power was lost | ||
1116 | */ | 1117 | */ |
1117 | if (!hub_is_superspeed(hdev)) { | 1118 | portstatus &= ~USB_PORT_STAT_ENABLE; |
1119 | if (!hub_is_superspeed(hdev)) | ||
1118 | usb_clear_port_feature(hdev, port1, | 1120 | usb_clear_port_feature(hdev, port1, |
1119 | USB_PORT_FEAT_ENABLE); | 1121 | USB_PORT_FEAT_ENABLE); |
1120 | portstatus &= ~USB_PORT_STAT_ENABLE; | ||
1121 | } else { | ||
1122 | /* Pretend that power was lost for USB3 devs */ | ||
1123 | portstatus &= ~USB_PORT_STAT_ENABLE; | ||
1124 | } | ||
1125 | } | 1122 | } |
1126 | 1123 | ||
1127 | /* Clear status-change flags; we'll debounce later */ | 1124 | /* Clear status-change flags; we'll debounce later */ |
@@ -3958,6 +3955,32 @@ static int hub_set_address(struct usb_device *udev, int devnum) | |||
3958 | return retval; | 3955 | return retval; |
3959 | } | 3956 | } |
3960 | 3957 | ||
3958 | /* | ||
3959 | * There are reports of USB 3.0 devices that say they support USB 2.0 Link PM | ||
3960 | * when they're plugged into a USB 2.0 port, but they don't work when LPM is | ||
3961 | * enabled. | ||
3962 | * | ||
3963 | * Only enable USB 2.0 Link PM if the port is internal (hardwired), or the | ||
3964 | * device says it supports the new USB 2.0 Link PM errata by setting the BESL | ||
3965 | * support bit in the BOS descriptor. | ||
3966 | */ | ||
3967 | static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) | ||
3968 | { | ||
3969 | int connect_type; | ||
3970 | |||
3971 | if (!udev->usb2_hw_lpm_capable) | ||
3972 | return; | ||
3973 | |||
3974 | connect_type = usb_get_hub_port_connect_type(udev->parent, | ||
3975 | udev->portnum); | ||
3976 | |||
3977 | if ((udev->bos->ext_cap->bmAttributes & USB_BESL_SUPPORT) || | ||
3978 | connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { | ||
3979 | udev->usb2_hw_lpm_allowed = 1; | ||
3980 | usb_set_usb2_hardware_lpm(udev, 1); | ||
3981 | } | ||
3982 | } | ||
3983 | |||
3961 | /* Reset device, (re)assign address, get device descriptor. | 3984 | /* Reset device, (re)assign address, get device descriptor. |
3962 | * Device connection must be stable, no more debouncing needed. | 3985 | * Device connection must be stable, no more debouncing needed. |
3963 | * Returns device in USB_STATE_ADDRESS, except on error. | 3986 | * Returns device in USB_STATE_ADDRESS, except on error. |
@@ -4251,6 +4274,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, | |||
4251 | /* notify HCD that we have a device connected and addressed */ | 4274 | /* notify HCD that we have a device connected and addressed */ |
4252 | if (hcd->driver->update_device) | 4275 | if (hcd->driver->update_device) |
4253 | hcd->driver->update_device(hcd, udev); | 4276 | hcd->driver->update_device(hcd, udev); |
4277 | hub_set_initial_usb2_lpm_policy(udev); | ||
4254 | fail: | 4278 | fail: |
4255 | if (retval) { | 4279 | if (retval) { |
4256 | hub_port_disable(hub, port1, 0); | 4280 | hub_port_disable(hub, port1, 0); |
@@ -5095,6 +5119,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev) | |||
5095 | } | 5119 | } |
5096 | parent_hub = usb_hub_to_struct_hub(parent_hdev); | 5120 | parent_hub = usb_hub_to_struct_hub(parent_hdev); |
5097 | 5121 | ||
5122 | /* Disable USB2 hardware LPM. | ||
5123 | * It will be re-enabled by the enumeration process. | ||
5124 | */ | ||
5125 | if (udev->usb2_hw_lpm_enabled == 1) | ||
5126 | usb_set_usb2_hardware_lpm(udev, 0); | ||
5127 | |||
5098 | bos = udev->bos; | 5128 | bos = udev->bos; |
5099 | udev->bos = NULL; | 5129 | udev->bos = NULL; |
5100 | 5130 | ||
@@ -5202,6 +5232,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) | |||
5202 | 5232 | ||
5203 | done: | 5233 | done: |
5204 | /* Now that the alt settings are re-installed, enable LTM and LPM. */ | 5234 | /* Now that the alt settings are re-installed, enable LTM and LPM. */ |
5235 | usb_set_usb2_hardware_lpm(udev, 1); | ||
5205 | usb_unlocked_enable_lpm(udev); | 5236 | usb_unlocked_enable_lpm(udev); |
5206 | usb_enable_ltm(udev); | 5237 | usb_enable_ltm(udev); |
5207 | usb_release_bos_descriptor(udev); | 5238 | usb_release_bos_descriptor(udev); |