USB: convert to the runtime PM framework

This patch (as1329) converts the USB stack over to the PM core's
runtime PM framework.  This involves numerous changes throughout
usbcore, especially to hub.c and driver.c.  Perhaps the most notable
change is that CONFIG_USB_SUSPEND now depends on CONFIG_PM_RUNTIME
instead of CONFIG_PM.

Several fields in the usb_device and usb_interface structures are no
longer needed.  Some code which used to depend on CONFIG_USB_PM now
depends on CONFIG_USB_SUSPEND (requiring some rearrangement of header
files).

The only visible change in behavior should be that following a system
sleep (resume from RAM or resume from hibernation), autosuspended USB
devices will be resumed just like everything else.  They won't remain
suspended.  But if they aren't in use then they will naturally
autosuspend again in a few seconds.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Alan Stern
2010-01-08 12:57:28 -05:00
committed by Greg Kroah-Hartman
parent 0c590e2361
commit 9bbdf1e0af
11 changed files with 486 additions and 780 deletions

View File

@@ -22,6 +22,7 @@
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
#include <linux/pm_runtime.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -71,7 +72,6 @@ struct usb_hub {
unsigned mA_per_port; /* current for each child */
unsigned init_done:1;
unsigned limited_power:1;
unsigned quiescing:1;
unsigned disconnected:1;
@@ -820,7 +820,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
}
init3:
hub->quiescing = 0;
hub->init_done = 1;
status = usb_submit_urb(hub->urb, GFP_NOIO);
if (status < 0)
@@ -861,11 +860,6 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
int i;
cancel_delayed_work_sync(&hub->init_work);
if (!hub->init_done) {
hub->init_done = 1;
usb_autopm_put_interface_no_suspend(
to_usb_interface(hub->intfdev));
}
/* khubd and related activity won't re-trigger */
hub->quiescing = 1;
@@ -1405,10 +1399,8 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev)
if (udev->children[i])
recursively_mark_NOTATTACHED(udev->children[i]);
}
if (udev->state == USB_STATE_SUSPENDED) {
udev->discon_suspended = 1;
if (udev->state == USB_STATE_SUSPENDED)
udev->active_duration -= jiffies;
}
udev->state = USB_STATE_NOTATTACHED;
}
@@ -1532,31 +1524,6 @@ static void update_address(struct usb_device *udev, int devnum)
udev->devnum = devnum;
}
#ifdef CONFIG_USB_SUSPEND
static void usb_stop_pm(struct usb_device *udev)
{
/* Synchronize with the ksuspend thread to prevent any more
* autosuspend requests from being submitted, and decrement
* the parent's count of unsuspended children.
*/
usb_pm_lock(udev);
if (udev->parent && !udev->discon_suspended)
usb_autosuspend_device(udev->parent);
usb_pm_unlock(udev);
/* Stop any autosuspend or autoresume requests already submitted */
cancel_delayed_work_sync(&udev->autosuspend);
cancel_work_sync(&udev->autoresume);
}
#else
static inline void usb_stop_pm(struct usb_device *udev)
{ }
#endif
/**
* usb_disconnect - disconnect a device (usbcore-internal)
* @pdev: pointer to device being disconnected
@@ -1625,8 +1592,6 @@ void usb_disconnect(struct usb_device **pdev)
*pdev = NULL;
spin_unlock_irq(&device_state_lock);
usb_stop_pm(udev);
put_device(&udev->dev);
}
@@ -1803,9 +1768,6 @@ int usb_new_device(struct usb_device *udev)
int err;
if (udev->parent) {
/* Increment the parent's count of unsuspended children */
usb_autoresume_device(udev->parent);
/* Initialize non-root-hub device wakeup to disabled;
* device (un)configuration controls wakeup capable
* sysfs power/wakeup controls wakeup enabled/disabled
@@ -1814,6 +1776,10 @@ int usb_new_device(struct usb_device *udev)
device_set_wakeup_enable(&udev->dev, 1);
}
/* Tell the runtime-PM framework the device is active */
pm_runtime_set_active(&udev->dev);
pm_runtime_enable(&udev->dev);
usb_detect_quirks(udev);
err = usb_enumerate_device(udev); /* Read descriptors */
if (err < 0)
@@ -1844,7 +1810,8 @@ int usb_new_device(struct usb_device *udev)
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
usb_stop_pm(udev);
pm_runtime_disable(&udev->dev);
pm_runtime_set_suspended(&udev->dev);
return err;
}
@@ -2408,8 +2375,11 @@ int usb_remote_wakeup(struct usb_device *udev)
if (udev->state == USB_STATE_SUSPENDED) {
dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
usb_mark_last_busy(udev);
status = usb_external_resume_device(udev, PMSG_REMOTE_RESUME);
status = usb_autoresume_device(udev);
if (status == 0) {
/* Let the drivers do their thing, then... */
usb_autosuspend_device(udev);
}
}
return status;
}
@@ -2446,11 +2416,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return status;
}
int usb_remote_wakeup(struct usb_device *udev)
{
return 0;
}
#endif
static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
@@ -3268,7 +3233,7 @@ static void hub_events(void)
* disconnected while waiting for the lock to succeed. */
usb_lock_device(hdev);
if (unlikely(hub->disconnected))
goto loop2;
goto loop_disconnected;
/* If the hub has died, clean up after it */
if (hdev->state == USB_STATE_NOTATTACHED) {
@@ -3428,7 +3393,7 @@ static void hub_events(void)
* kick_khubd() and allow autosuspend.
*/
usb_autopm_put_interface(intf);
loop2:
loop_disconnected:
usb_unlock_device(hdev);
kref_put(&hub->kref, hub_release);