aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2012-07-04 02:22:38 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2012-07-11 07:06:46 -0400
commit9cf65991dd93ac3d5f97f536171c388918b7c1a9 (patch)
tree06d01607f5667fe43cca031bbeef94bd2cfec5ec /drivers/usb/core
parent6d1d051330ee096f575523647fbd8ffe703600b5 (diff)
USB: Disable LPM while the device is unconfigured.
The USB 3.0 Set/Clear Feature U1/U2 Enable cannot be sent to a device in the Default or Addressed state. It can only be sent to a configured device. Change the USB core to initialize the LPM disable count to 1 (disabled), which reflects this limitation. Change usb_set_configuration() to ensure that if the device is unconfigured on entry, usb_lpm_disable() is not called. This avoids sending the Clear Feature U1/U2 when the device is in the Addressed state. When usb_set_configuration() exits with a successfully installed configuration, usb_lpm_enable() will be called. Once the new configuration is installed, make sure usb_set_configuration() only calls usb_enable_lpm() if the device moved to the Configured state. If we have unconfigured the device by sending it a Set Configuration for config 0, don't enable LPM. This commit should be backported to kernels as old as 3.5, that contain the commit 8306095fd2c1100e8244c09bf560f97aca5a311d "USB: Disable USB 3.0 LPM in critical sections." Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/message.c7
-rw-r--r--drivers/usb/core/usb.c1
2 files changed, 5 insertions, 3 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 8b9d669e3784..37239048be14 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1792,14 +1792,15 @@ free_interfaces:
1792 * installed, so that the xHCI driver can recalculate the U1/U2 1792 * installed, so that the xHCI driver can recalculate the U1/U2
1793 * timeouts. 1793 * timeouts.
1794 */ 1794 */
1795 if (usb_disable_lpm(dev)) { 1795 if (dev->actconfig && usb_disable_lpm(dev)) {
1796 dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__); 1796 dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
1797 mutex_unlock(hcd->bandwidth_mutex); 1797 mutex_unlock(hcd->bandwidth_mutex);
1798 return -ENOMEM; 1798 return -ENOMEM;
1799 } 1799 }
1800 ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL); 1800 ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
1801 if (ret < 0) { 1801 if (ret < 0) {
1802 usb_enable_lpm(dev); 1802 if (dev->actconfig)
1803 usb_enable_lpm(dev);
1803 mutex_unlock(hcd->bandwidth_mutex); 1804 mutex_unlock(hcd->bandwidth_mutex);
1804 usb_autosuspend_device(dev); 1805 usb_autosuspend_device(dev);
1805 goto free_interfaces; 1806 goto free_interfaces;
@@ -1819,7 +1820,7 @@ free_interfaces:
1819 if (!cp) { 1820 if (!cp) {
1820 usb_set_device_state(dev, USB_STATE_ADDRESS); 1821 usb_set_device_state(dev, USB_STATE_ADDRESS);
1821 usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); 1822 usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
1822 usb_enable_lpm(dev); 1823 /* Leave LPM disabled while the device is unconfigured. */
1823 mutex_unlock(hcd->bandwidth_mutex); 1824 mutex_unlock(hcd->bandwidth_mutex);
1824 usb_autosuspend_device(dev); 1825 usb_autosuspend_device(dev);
1825 goto free_interfaces; 1826 goto free_interfaces;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 25d0c61c3f8a..cd8fb44a3e16 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -396,6 +396,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
396 dev->dev.dma_mask = bus->controller->dma_mask; 396 dev->dev.dma_mask = bus->controller->dma_mask;
397 set_dev_node(&dev->dev, dev_to_node(bus->controller)); 397 set_dev_node(&dev->dev, dev_to_node(bus->controller));
398 dev->state = USB_STATE_ATTACHED; 398 dev->state = USB_STATE_ATTACHED;
399 dev->lpm_disable_count = 1;
399 atomic_set(&dev->urbnum, 0); 400 atomic_set(&dev->urbnum, 0);
400 401
401 INIT_LIST_HEAD(&dev->ep0.urb_list); 402 INIT_LIST_HEAD(&dev->ep0.urb_list);