|
@@ -1308,10 +1308,19 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
|
|
* Remove the current alt setting and add the new alt setting.
|
|
* Remove the current alt setting and add the new alt setting.
|
|
*/
|
|
*/
|
|
mutex_lock(hcd->bandwidth_mutex);
|
|
mutex_lock(hcd->bandwidth_mutex);
|
|
|
|
+ /* Disable LPM, and re-enable it once the new alt setting is installed,
|
|
|
|
+ * so that the xHCI driver can recalculate the U1/U2 timeouts.
|
|
|
|
+ */
|
|
|
|
+ if (usb_disable_lpm(dev)) {
|
|
|
|
+ dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__);
|
|
|
|
+ mutex_unlock(hcd->bandwidth_mutex);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);
|
|
ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n",
|
|
dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n",
|
|
alternate);
|
|
alternate);
|
|
|
|
+ usb_enable_lpm(dev);
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -1334,6 +1343,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
|
|
} else if (ret < 0) {
|
|
} else if (ret < 0) {
|
|
/* Re-instate the old alt setting */
|
|
/* Re-instate the old alt setting */
|
|
usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting);
|
|
usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting);
|
|
|
|
+ usb_enable_lpm(dev);
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -1354,6 +1364,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
|
|
|
|
|
|
iface->cur_altsetting = alt;
|
|
iface->cur_altsetting = alt;
|
|
|
|
|
|
|
|
+ /* Now that the interface is installed, re-enable LPM. */
|
|
|
|
+ usb_unlocked_enable_lpm(dev);
|
|
|
|
+
|
|
/* If the interface only has one altsetting and the device didn't
|
|
/* If the interface only has one altsetting and the device didn't
|
|
* accept the request, we attempt to carry out the equivalent action
|
|
* accept the request, we attempt to carry out the equivalent action
|
|
* by manually clearing the HALT feature for each endpoint in the
|
|
* by manually clearing the HALT feature for each endpoint in the
|
|
@@ -1437,6 +1450,14 @@ int usb_reset_configuration(struct usb_device *dev)
|
|
config = dev->actconfig;
|
|
config = dev->actconfig;
|
|
retval = 0;
|
|
retval = 0;
|
|
mutex_lock(hcd->bandwidth_mutex);
|
|
mutex_lock(hcd->bandwidth_mutex);
|
|
|
|
+ /* Disable LPM, and re-enable it once the configuration is reset, so
|
|
|
|
+ * that the xHCI driver can recalculate the U1/U2 timeouts.
|
|
|
|
+ */
|
|
|
|
+ if (usb_disable_lpm(dev)) {
|
|
|
|
+ dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
|
|
|
|
+ mutex_unlock(hcd->bandwidth_mutex);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
/* Make sure we have enough bandwidth for each alternate setting 0 */
|
|
/* Make sure we have enough bandwidth for each alternate setting 0 */
|
|
for (i = 0; i < config->desc.bNumInterfaces; i++) {
|
|
for (i = 0; i < config->desc.bNumInterfaces; i++) {
|
|
struct usb_interface *intf = config->interface[i];
|
|
struct usb_interface *intf = config->interface[i];
|
|
@@ -1465,6 +1486,7 @@ reset_old_alts:
|
|
usb_hcd_alloc_bandwidth(dev, NULL,
|
|
usb_hcd_alloc_bandwidth(dev, NULL,
|
|
alt, intf->cur_altsetting);
|
|
alt, intf->cur_altsetting);
|
|
}
|
|
}
|
|
|
|
+ usb_enable_lpm(dev);
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
@@ -1502,6 +1524,8 @@ reset_old_alts:
|
|
create_intf_ep_devs(intf);
|
|
create_intf_ep_devs(intf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ /* Now that the interfaces are installed, re-enable LPM. */
|
|
|
|
+ usb_unlocked_enable_lpm(dev);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(usb_reset_configuration);
|
|
EXPORT_SYMBOL_GPL(usb_reset_configuration);
|
|
@@ -1763,8 +1787,18 @@ free_interfaces:
|
|
* this call fails, the device state is unchanged.
|
|
* this call fails, the device state is unchanged.
|
|
*/
|
|
*/
|
|
mutex_lock(hcd->bandwidth_mutex);
|
|
mutex_lock(hcd->bandwidth_mutex);
|
|
|
|
+ /* Disable LPM, and re-enable it once the new configuration is
|
|
|
|
+ * installed, so that the xHCI driver can recalculate the U1/U2
|
|
|
|
+ * timeouts.
|
|
|
|
+ */
|
|
|
|
+ if (usb_disable_lpm(dev)) {
|
|
|
|
+ dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
|
|
|
|
+ mutex_unlock(hcd->bandwidth_mutex);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
|
|
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
|
|
+ usb_enable_lpm(dev);
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
usb_autosuspend_device(dev);
|
|
usb_autosuspend_device(dev);
|
|
goto free_interfaces;
|
|
goto free_interfaces;
|
|
@@ -1784,6 +1818,7 @@ free_interfaces:
|
|
if (!cp) {
|
|
if (!cp) {
|
|
usb_set_device_state(dev, USB_STATE_ADDRESS);
|
|
usb_set_device_state(dev, USB_STATE_ADDRESS);
|
|
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
|
|
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
|
|
|
|
+ usb_enable_lpm(dev);
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
mutex_unlock(hcd->bandwidth_mutex);
|
|
usb_autosuspend_device(dev);
|
|
usb_autosuspend_device(dev);
|
|
goto free_interfaces;
|
|
goto free_interfaces;
|
|
@@ -1838,6 +1873,9 @@ free_interfaces:
|
|
!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
|
|
!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
|
|
cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
|
|
cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
|
|
|
|
|
|
|
|
+ /* Now that the interfaces are installed, re-enable LPM. */
|
|
|
|
+ usb_unlocked_enable_lpm(dev);
|
|
|
|
+
|
|
/* Now that all the interfaces are set up, register them
|
|
/* Now that all the interfaces are set up, register them
|
|
* to trigger binding of drivers to interfaces. probe()
|
|
* to trigger binding of drivers to interfaces. probe()
|
|
* routines may install different altsettings and may
|
|
* routines may install different altsettings and may
|