aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/message.c
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2012-05-02 17:25:52 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2012-05-18 18:41:59 -0400
commit8306095fd2c1100e8244c09bf560f97aca5a311d (patch)
tree1096f11806046e60f32496f1bac843a6f17b4c26 /drivers/usb/core/message.c
parent1ea7e0e8e3d0f50901d335ea4178ab2aa8c88201 (diff)
USB: Disable USB 3.0 LPM in critical sections.
There are several places where the USB core needs to disable USB 3.0 Link PM: - usb_bind_interface - usb_unbind_interface - usb_driver_claim_interface - usb_port_suspend/usb_port_resume - usb_reset_and_verify_device - usb_set_interface - usb_reset_configuration - usb_set_configuration Use the new LPM disable/enable functions to temporarily disable LPM around these critical sections. We need to protect the critical section around binding and unbinding USB interface drivers. USB drivers may want to disable hub-initiated USB 3.0 LPM, which will change the value of the U1/U2 timeouts that the xHCI driver will install. We need to disable LPM completely until the driver is bound to the interface, and the driver has a chance to enable whatever alternate interface setting it needs in its probe routine. Then re-enable USB3 LPM, and recalculate the U1/U2 timeout values. We also need to disable LPM in usb_driver_claim_interface, because drivers like usbfs can bind to an interface through that function. Note, there is no way currently for userspace drivers to disable hub-initiated USB 3.0 LPM. Revisit this later. When a driver is unbound, the U1/U2 timeouts may change because we are unbinding the last driver that needed hub-initiated USB 3.0 LPM to be disabled. USB LPM must be disabled when a USB device is going to be suspended. The USB 3.0 spec does not define a state transition from U1 or U2 into U3, so we need to bring the device into U0 by disabling LPM before we can place it into U3. Therefore, call usb_unlocked_disable_lpm() in usb_port_suspend(), and call usb_unlocked_enable_lpm() in usb_port_resume(). If the port suspend fails, make sure to re-enable LPM by calling usb_unlocked_enable_lpm(), since usb_port_resume() will not be called on a failed port suspend. USB 3.0 devices lose their USB 3.0 LPM settings (including whether USB device-initiated LPM is enabled) across device suspend. Therefore, disable LPM before the device will be reset in usb_reset_and_verify_device(), and re-enable LPM after the reset is complete and the configuration/alt settings are re-installed. The calculated U1/U2 timeout values are heavily dependent on what USB device endpoints are currently enabled. When any of the enabled endpoints on the device might change, due to a new configuration, or new alternate interface setting, we need to first disable USB 3.0 LPM, add or delete endpoints from the xHCI schedule, install the new interfaces and alt settings, and then re-enable LPM. Do this in usb_set_interface, usb_reset_configuration, and usb_set_configuration. Basically, there is a call to disable and then enable LPM in all functions that lock the bandwidth_mutex. One exception is usb_disable_device, because the device is disconnecting or otherwise going away, and we should not care about whether USB 3.0 LPM is enabled. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/core/message.c')
-rw-r--r--drivers/usb/core/message.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index ca717da3be95..b548cf1dbc62 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1308,10 +1308,19 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
1308 * Remove the current alt setting and add the new alt setting. 1308 * Remove the current alt setting and add the new alt setting.
1309 */ 1309 */
1310 mutex_lock(hcd->bandwidth_mutex); 1310 mutex_lock(hcd->bandwidth_mutex);
1311 /* Disable LPM, and re-enable it once the new alt setting is installed,
1312 * so that the xHCI driver can recalculate the U1/U2 timeouts.
1313 */
1314 if (usb_disable_lpm(dev)) {
1315 dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__);
1316 mutex_unlock(hcd->bandwidth_mutex);
1317 return -ENOMEM;
1318 }
1311 ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt); 1319 ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);
1312 if (ret < 0) { 1320 if (ret < 0) {
1313 dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n", 1321 dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n",
1314 alternate); 1322 alternate);
1323 usb_enable_lpm(dev);
1315 mutex_unlock(hcd->bandwidth_mutex); 1324 mutex_unlock(hcd->bandwidth_mutex);
1316 return ret; 1325 return ret;
1317 } 1326 }
@@ -1334,6 +1343,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
1334 } else if (ret < 0) { 1343 } else if (ret < 0) {
1335 /* Re-instate the old alt setting */ 1344 /* Re-instate the old alt setting */
1336 usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting); 1345 usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting);
1346 usb_enable_lpm(dev);
1337 mutex_unlock(hcd->bandwidth_mutex); 1347 mutex_unlock(hcd->bandwidth_mutex);
1338 return ret; 1348 return ret;
1339 } 1349 }
@@ -1354,6 +1364,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
1354 1364
1355 iface->cur_altsetting = alt; 1365 iface->cur_altsetting = alt;
1356 1366
1367 /* Now that the interface is installed, re-enable LPM. */
1368 usb_unlocked_enable_lpm(dev);
1369
1357 /* If the interface only has one altsetting and the device didn't 1370 /* If the interface only has one altsetting and the device didn't
1358 * accept the request, we attempt to carry out the equivalent action 1371 * accept the request, we attempt to carry out the equivalent action
1359 * by manually clearing the HALT feature for each endpoint in the 1372 * by manually clearing the HALT feature for each endpoint in the
@@ -1437,6 +1450,14 @@ int usb_reset_configuration(struct usb_device *dev)
1437 config = dev->actconfig; 1450 config = dev->actconfig;
1438 retval = 0; 1451 retval = 0;
1439 mutex_lock(hcd->bandwidth_mutex); 1452 mutex_lock(hcd->bandwidth_mutex);
1453 /* Disable LPM, and re-enable it once the configuration is reset, so
1454 * that the xHCI driver can recalculate the U1/U2 timeouts.
1455 */
1456 if (usb_disable_lpm(dev)) {
1457 dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
1458 mutex_unlock(hcd->bandwidth_mutex);
1459 return -ENOMEM;
1460 }
1440 /* Make sure we have enough bandwidth for each alternate setting 0 */ 1461 /* Make sure we have enough bandwidth for each alternate setting 0 */
1441 for (i = 0; i < config->desc.bNumInterfaces; i++) { 1462 for (i = 0; i < config->desc.bNumInterfaces; i++) {
1442 struct usb_interface *intf = config->interface[i]; 1463 struct usb_interface *intf = config->interface[i];
@@ -1465,6 +1486,7 @@ reset_old_alts:
1465 usb_hcd_alloc_bandwidth(dev, NULL, 1486 usb_hcd_alloc_bandwidth(dev, NULL,
1466 alt, intf->cur_altsetting); 1487 alt, intf->cur_altsetting);
1467 } 1488 }
1489 usb_enable_lpm(dev);
1468 mutex_unlock(hcd->bandwidth_mutex); 1490 mutex_unlock(hcd->bandwidth_mutex);
1469 return retval; 1491 return retval;
1470 } 1492 }
@@ -1502,6 +1524,8 @@ reset_old_alts:
1502 create_intf_ep_devs(intf); 1524 create_intf_ep_devs(intf);
1503 } 1525 }
1504 } 1526 }
1527 /* Now that the interfaces are installed, re-enable LPM. */
1528 usb_unlocked_enable_lpm(dev);
1505 return 0; 1529 return 0;
1506} 1530}
1507EXPORT_SYMBOL_GPL(usb_reset_configuration); 1531EXPORT_SYMBOL_GPL(usb_reset_configuration);
@@ -1763,8 +1787,18 @@ free_interfaces:
1763 * this call fails, the device state is unchanged. 1787 * this call fails, the device state is unchanged.
1764 */ 1788 */
1765 mutex_lock(hcd->bandwidth_mutex); 1789 mutex_lock(hcd->bandwidth_mutex);
1790 /* Disable LPM, and re-enable it once the new configuration is
1791 * installed, so that the xHCI driver can recalculate the U1/U2
1792 * timeouts.
1793 */
1794 if (usb_disable_lpm(dev)) {
1795 dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
1796 mutex_unlock(hcd->bandwidth_mutex);
1797 return -ENOMEM;
1798 }
1766 ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL); 1799 ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
1767 if (ret < 0) { 1800 if (ret < 0) {
1801 usb_enable_lpm(dev);
1768 mutex_unlock(hcd->bandwidth_mutex); 1802 mutex_unlock(hcd->bandwidth_mutex);
1769 usb_autosuspend_device(dev); 1803 usb_autosuspend_device(dev);
1770 goto free_interfaces; 1804 goto free_interfaces;
@@ -1784,6 +1818,7 @@ free_interfaces:
1784 if (!cp) { 1818 if (!cp) {
1785 usb_set_device_state(dev, USB_STATE_ADDRESS); 1819 usb_set_device_state(dev, USB_STATE_ADDRESS);
1786 usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); 1820 usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
1821 usb_enable_lpm(dev);
1787 mutex_unlock(hcd->bandwidth_mutex); 1822 mutex_unlock(hcd->bandwidth_mutex);
1788 usb_autosuspend_device(dev); 1823 usb_autosuspend_device(dev);
1789 goto free_interfaces; 1824 goto free_interfaces;
@@ -1838,6 +1873,9 @@ free_interfaces:
1838 !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) 1873 !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
1839 cp->string = usb_cache_string(dev, cp->desc.iConfiguration); 1874 cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
1840 1875
1876 /* Now that the interfaces are installed, re-enable LPM. */
1877 usb_unlocked_enable_lpm(dev);
1878
1841 /* Now that all the interfaces are set up, register them 1879 /* Now that all the interfaces are set up, register them
1842 * to trigger binding of drivers to interfaces. probe() 1880 * to trigger binding of drivers to interfaces. probe()
1843 * routines may install different altsettings and may 1881 * routines may install different altsettings and may