diff options
author | Kai-Heng Feng <kai.heng.feng@canonical.com> | 2019-01-12 03:54:25 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-01-18 10:02:56 +0100 |
commit | d7a6c0ce8d26412903c7981503bad9e1cc7c45d2 (patch) | |
tree | 7290ea96ae2ae03f491117ef10d90491ba3d05a8 /drivers/usb/core/driver.c | |
parent | 7529b2574a7aaf902f1f8159fbc2a7caa74be559 (diff) | |
download | linux-stable-d7a6c0ce8d26412903c7981503bad9e1cc7c45d2.tar.gz linux-stable-d7a6c0ce8d26412903c7981503bad9e1cc7c45d2.tar.bz2 linux-stable-d7a6c0ce8d26412903c7981503bad9e1cc7c45d2.zip |
USB: Consolidate LPM checks to avoid enabling LPM twice
USB Bluetooth controller QCA ROME (0cf3:e007) sometimes stops working
after S3:
[ 165.110742] Bluetooth: hci0: using NVM file: qca/nvm_usb_00000302.bin
[ 168.432065] Bluetooth: hci0: Failed to send body at 4 of 1953 (-110)
After some experiments, I found that disabling LPM can workaround the
issue.
On some platforms, the USB power is cut during S3, so the driver uses
reset-resume to resume the device. During port resume, LPM gets enabled
twice, by usb_reset_and_verify_device() and usb_port_resume().
Consolidate all checks into new LPM helpers to make sure LPM only gets
enabled once.
Fixes: de68bab4fa96 ("usb: Don't enable USB 2.0 Link PM by default.”)
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Cc: stable <stable@vger.kernel.org> # after much soaking
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r-- | drivers/usb/core/driver.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index c276ffc5561f..8987cec9549d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1901,9 +1901,6 @@ static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) struct usb_hcd *hcd = bus_to_hcd(udev->bus); int ret = -EPERM; - if (enable && !udev->usb2_hw_lpm_allowed) - return 0; - if (hcd->driver->set_usb2_hw_lpm) { ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); if (!ret) @@ -1915,11 +1912,19 @@ static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) int usb_enable_usb2_hardware_lpm(struct usb_device *udev) { + if (!udev->usb2_hw_lpm_capable || + !udev->usb2_hw_lpm_allowed || + udev->usb2_hw_lpm_enabled) + return 0; + return usb_set_usb2_hardware_lpm(udev, 1); } int usb_disable_usb2_hardware_lpm(struct usb_device *udev) { + if (!udev->usb2_hw_lpm_enabled) + return 0; + return usb_set_usb2_hardware_lpm(udev, 0); } |