Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9cf65991 authored by Sarah Sharp's avatar Sarah Sharp
Browse files

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 8306095f "USB: Disable USB
3.0 LPM in critical sections."

Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: stable@vger.kernel.org
parent 6d1d0513
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -1792,13 +1792,14 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
	 * installed, so that the xHCI driver can recalculate the U1/U2
	 * timeouts.
	 */
	if (usb_disable_lpm(dev)) {
	if (dev->actconfig && 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);
	if (ret < 0) {
		if (dev->actconfig)
			usb_enable_lpm(dev);
		mutex_unlock(hcd->bandwidth_mutex);
		usb_autosuspend_device(dev);
@@ -1819,7 +1820,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
	if (!cp) {
		usb_set_device_state(dev, USB_STATE_ADDRESS);
		usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
		usb_enable_lpm(dev);
		/* Leave LPM disabled while the device is unconfigured. */
		mutex_unlock(hcd->bandwidth_mutex);
		usb_autosuspend_device(dev);
		goto free_interfaces;
+1 −0
Original line number Diff line number Diff line
@@ -396,6 +396,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
	dev->dev.dma_mask = bus->controller->dma_mask;
	set_dev_node(&dev->dev, dev_to_node(bus->controller));
	dev->state = USB_STATE_ATTACHED;
	dev->lpm_disable_count = 1;
	atomic_set(&dev->urbnum, 0);

	INIT_LIST_HEAD(&dev->ep0.urb_list);