USB: fix interface runtime-PM settings
authorAlan Stern <stern@rowland.harvard.edu>
Tue, 11 May 2010 15:44:06 +0000 (11:44 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 20 May 2010 20:21:45 +0000 (13:21 -0700)
This patch (as1379) reworks the logic for handling USB interface
runtime-PM settings -- hopefully it's right this time!  The problem is
that when a driver is unbound or binding fails, runtime PM for the
interface always gets disabled.  But pm_runtime_disable() nests, so it
shouldn't be called unless the interface was previously enabled for
runtime PM.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reported-by: Rob Duncan <Robert.Duncan@exar.com>
Tested-by: Rob Duncan <Robert.Duncan@exar.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/driver.c

index 2071467..ded550e 100644 (file)
@@ -334,7 +334,8 @@ static int usb_probe_interface(struct device *dev)
        usb_cancel_queued_reset(intf);
 
        /* Unbound interfaces are always runtime-PM-disabled and -suspended */
-       pm_runtime_disable(dev);
+       if (driver->supports_autosuspend)
+               pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
 
        usb_autosuspend_device(udev);
@@ -389,7 +390,8 @@ static int usb_unbind_interface(struct device *dev)
        intf->needs_remote_wakeup = 0;
 
        /* Unbound interfaces are always runtime-PM-disabled and -suspended */
-       pm_runtime_disable(dev);
+       if (driver->supports_autosuspend)
+               pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
 
        /* Undo any residual pm_autopm_get_interface_* calls */
@@ -438,14 +440,17 @@ int usb_driver_claim_interface(struct usb_driver *driver,
 
        iface->condition = USB_INTERFACE_BOUND;
 
-       /* Claimed interfaces are initially inactive (suspended).  They are
-        * runtime-PM-enabled only if the driver has autosuspend support.
-        * They are sensitive to their children's power states.
+       /* Claimed interfaces are initially inactive (suspended) and
+        * runtime-PM-enabled, but only if the driver has autosuspend
+        * support.  Otherwise they are marked active, to prevent the
+        * device from being autosuspended, but left disabled.  In either
+        * case they are sensitive to their children's power states.
         */
-       pm_runtime_set_suspended(dev);
        pm_suspend_ignore_children(dev, false);
        if (driver->supports_autosuspend)
                pm_runtime_enable(dev);
+       else
+               pm_runtime_set_active(dev);
 
        /* if interface was already added, bind now; else let
         * the future device_add() bind it, bypassing probe()