[Acked] [PATCH SRU V/W/X/Y] USB: leave LPM alone if possible when binding/unbinding interface drivers
Andy Whitcroft
apw at canonical.com
Fri May 27 12:24:54 UTC 2016
On Wed, May 25, 2016 at 11:58:49AM -0600, Tim Gardner wrote:
> From: Alan Stern <stern at rowland.harvard.edu>
>
> BugLink: http://bugs.launchpad.net/bugs/1577024
>
> When a USB driver is bound to an interface (either through probing or
> by claiming it) or is unbound from an interface, the USB core always
> disables Link Power Management during the transition and then
> re-enables it afterward. The reason is because the driver might want
> to prevent hub-initiated link power transitions, in which case the HCD
> would have to recalculate the various LPM parameters. This
> recalculation takes place when LPM is re-enabled and the new
> parameters are sent to the device and its parent hub.
>
> However, if the driver does not want to prevent hub-initiated link
> power transitions then none of this work is necessary. The parameters
> don't need to be recalculated, and LPM doesn't need to be disabled and
> re-enabled.
>
> It turns out that disabling and enabling LPM can be time-consuming,
> enough so that it interferes with user programs that want to claim and
> release interfaces rapidly via usbfs. Since the usbfs kernel driver
> doesn't set the disable_hub_initiated_lpm flag, we can speed things up
> and get the user programs to work by leaving LPM alone whenever the
> flag isn't set.
>
> And while we're improving the way disable_hub_initiated_lpm gets used,
> let's also fix its kerneldoc.
>
> Signed-off-by: Alan Stern <stern at rowland.harvard.edu>
> Tested-by: Matthew Giassa <matthew at giassa.net>
> CC: Mathias Nyman <mathias.nyman at intel.com>
> CC: <stable at vger.kernel.org>
> Signed-off-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> (cherry picked from commit 6fb650d43da3e7054984dc548eaa88765a94d49f)
> Signed-off-by: Tim Gardner <tim.gardner at canonical.com>
> ---
> drivers/usb/core/driver.c | 40 +++++++++++++++++++++++-----------------
> include/linux/usb.h | 2 +-
> 2 files changed, 24 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
> index 2057d91..dadd1e8d 100644
> --- a/drivers/usb/core/driver.c
> +++ b/drivers/usb/core/driver.c
> @@ -284,7 +284,7 @@ static int usb_probe_interface(struct device *dev)
> struct usb_device *udev = interface_to_usbdev(intf);
> const struct usb_device_id *id;
> int error = -ENODEV;
> - int lpm_disable_error;
> + int lpm_disable_error = -ENODEV;
>
> dev_dbg(dev, "%s\n", __func__);
>
> @@ -336,12 +336,14 @@ static int usb_probe_interface(struct device *dev)
> * setting during probe, that should also be fine. usb_set_interface()
> * will attempt to disable LPM, and fail if it can't disable it.
> */
> - lpm_disable_error = usb_unlocked_disable_lpm(udev);
> - if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
> - dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
> - __func__, driver->name);
> - error = lpm_disable_error;
> - goto err;
> + if (driver->disable_hub_initiated_lpm) {
> + lpm_disable_error = usb_unlocked_disable_lpm(udev);
> + if (lpm_disable_error) {
> + dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
> + __func__, driver->name);
> + error = lpm_disable_error;
> + goto err;
> + }
> }
>
> /* Carry out a deferred switch to altsetting 0 */
> @@ -391,7 +393,8 @@ static int usb_unbind_interface(struct device *dev)
> struct usb_interface *intf = to_usb_interface(dev);
> struct usb_host_endpoint *ep, **eps = NULL;
> struct usb_device *udev;
> - int i, j, error, r, lpm_disable_error;
> + int i, j, error, r;
> + int lpm_disable_error = -ENODEV;
>
> intf->condition = USB_INTERFACE_UNBINDING;
>
> @@ -399,12 +402,13 @@ static int usb_unbind_interface(struct device *dev)
> udev = interface_to_usbdev(intf);
> error = usb_autoresume_device(udev);
>
> - /* Hub-initiated LPM policy may change, so attempt to disable LPM until
> + /* If hub-initiated LPM policy may change, attempt to disable LPM until
> * the driver is unbound. If LPM isn't disabled, that's fine because it
> * wouldn't be enabled unless all the bound interfaces supported
> * hub-initiated LPM.
> */
> - lpm_disable_error = usb_unlocked_disable_lpm(udev);
> + if (driver->disable_hub_initiated_lpm)
> + lpm_disable_error = usb_unlocked_disable_lpm(udev);
>
> /*
> * Terminate all URBs for this interface unless the driver
> @@ -505,7 +509,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
> struct device *dev;
> struct usb_device *udev;
> int retval = 0;
> - int lpm_disable_error;
> + int lpm_disable_error = -ENODEV;
>
> if (!iface)
> return -ENODEV;
> @@ -526,12 +530,14 @@ int usb_driver_claim_interface(struct usb_driver *driver,
>
> iface->condition = USB_INTERFACE_BOUND;
>
> - /* Disable LPM until this driver is bound. */
> - lpm_disable_error = usb_unlocked_disable_lpm(udev);
> - if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
> - dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
> - __func__, driver->name);
> - return -ENOMEM;
> + /* See the comment about disabling LPM in usb_probe_interface(). */
> + if (driver->disable_hub_initiated_lpm) {
> + lpm_disable_error = usb_unlocked_disable_lpm(udev);
> + if (lpm_disable_error) {
> + dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
> + __func__, driver->name);
> + return -ENOMEM;
> + }
> }
>
> /* Claimed interfaces are initially inactive (suspended) and
> diff --git a/include/linux/usb.h b/include/linux/usb.h
> index 22b226d..1b1692a 100644
> --- a/include/linux/usb.h
> +++ b/include/linux/usb.h
> @@ -1070,7 +1070,7 @@ struct usbdrv_wrap {
> * for interfaces bound to this driver.
> * @soft_unbind: if set to 1, the USB core will not kill URBs and disable
> * endpoints before calling the driver's disconnect method.
> - * @disable_hub_initiated_lpm: if set to 0, the USB core will not allow hubs
> + * @disable_hub_initiated_lpm: if set to 1, the USB core will not allow hubs
> * to initiate lower power link state transitions when an idle timeout
> * occurs. Device-initiated USB 3.0 link PM will still be allowed.
> *
Looks to do what is claimed. Is a clean cherry-pick.
Acked-by: Andy Whitcroft <apw at canonical.com>
-apw
More information about the kernel-team
mailing list