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:
parent
0c590e2361
commit
9bbdf1e0af
|
@ -2,7 +2,7 @@
|
|||
|
||||
Alan Stern <stern@rowland.harvard.edu>
|
||||
|
||||
November 10, 2009
|
||||
December 11, 2009
|
||||
|
||||
|
||||
|
||||
|
@ -29,9 +29,9 @@ covered to some extent (see Documentation/power/*.txt for more
|
|||
information about system PM).
|
||||
|
||||
Note: Dynamic PM support for USB is present only if the kernel was
|
||||
built with CONFIG_USB_SUSPEND enabled. System PM support is present
|
||||
only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION
|
||||
enabled.
|
||||
built with CONFIG_USB_SUSPEND enabled (which depends on
|
||||
CONFIG_PM_RUNTIME). System PM support is present only if the kernel
|
||||
was built with CONFIG_SUSPEND or CONFIG_HIBERNATION enabled.
|
||||
|
||||
|
||||
What is Remote Wakeup?
|
||||
|
@ -326,64 +326,63 @@ driver does so by calling these six functions:
|
|||
void usb_autopm_get_interface_no_resume(struct usb_interface *intf);
|
||||
void usb_autopm_put_interface_no_suspend(struct usb_interface *intf);
|
||||
|
||||
The functions work by maintaining a counter in the usb_interface
|
||||
structure. When intf->pm_usage_count is > 0 then the interface is
|
||||
deemed to be busy, and the kernel will not autosuspend the interface's
|
||||
device. When intf->pm_usage_count is <= 0 then the interface is
|
||||
considered to be idle, and the kernel may autosuspend the device.
|
||||
The functions work by maintaining a usage counter in the
|
||||
usb_interface's embedded device structure. When the counter is > 0
|
||||
then the interface is deemed to be busy, and the kernel will not
|
||||
autosuspend the interface's device. When the usage counter is = 0
|
||||
then the interface is considered to be idle, and the kernel may
|
||||
autosuspend the device.
|
||||
|
||||
(There is a similar pm_usage_count field in struct usb_device,
|
||||
(There is a similar usage counter field in struct usb_device,
|
||||
associated with the device itself rather than any of its interfaces.
|
||||
This field is used only by the USB core.)
|
||||
This counter is used only by the USB core.)
|
||||
|
||||
Drivers must not modify intf->pm_usage_count directly; its value
|
||||
should be changed only be using the functions listed above. Drivers
|
||||
are responsible for insuring that the overall change to pm_usage_count
|
||||
during their lifetime balances out to 0 (it may be necessary for the
|
||||
disconnect method to call usb_autopm_put_interface() one or more times
|
||||
to fulfill this requirement). The first two routines use the PM mutex
|
||||
in struct usb_device for mutual exclusion; drivers using the async
|
||||
routines are responsible for their own synchronization and mutual
|
||||
exclusion.
|
||||
Drivers need not be concerned about balancing changes to the usage
|
||||
counter; the USB core will undo any remaining "get"s when a driver
|
||||
is unbound from its interface. As a corollary, drivers must not call
|
||||
any of the usb_autopm_* functions after their diconnect() routine has
|
||||
returned.
|
||||
|
||||
usb_autopm_get_interface() increments pm_usage_count and
|
||||
attempts an autoresume if the new value is > 0 and the
|
||||
device is suspended.
|
||||
Drivers using the async routines are responsible for their own
|
||||
synchronization and mutual exclusion.
|
||||
|
||||
usb_autopm_put_interface() decrements pm_usage_count and
|
||||
attempts an autosuspend if the new value is <= 0 and the
|
||||
device isn't suspended.
|
||||
usb_autopm_get_interface() increments the usage counter and
|
||||
does an autoresume if the device is suspended. If the
|
||||
autoresume fails, the counter is decremented back.
|
||||
|
||||
usb_autopm_put_interface() decrements the usage counter and
|
||||
attempts an autosuspend if the new value is = 0.
|
||||
|
||||
usb_autopm_get_interface_async() and
|
||||
usb_autopm_put_interface_async() do almost the same things as
|
||||
their non-async counterparts. The differences are: they do
|
||||
not acquire the PM mutex, and they use a workqueue to do their
|
||||
their non-async counterparts. The big difference is that they
|
||||
use a workqueue to do the resume or suspend part of their
|
||||
jobs. As a result they can be called in an atomic context,
|
||||
such as an URB's completion handler, but when they return the
|
||||
device will not generally not yet be in the desired state.
|
||||
device will generally not yet be in the desired state.
|
||||
|
||||
usb_autopm_get_interface_no_resume() and
|
||||
usb_autopm_put_interface_no_suspend() merely increment or
|
||||
decrement the pm_usage_count value; they do not attempt to
|
||||
carry out an autoresume or an autosuspend. Hence they can be
|
||||
called in an atomic context.
|
||||
decrement the usage counter; they do not attempt to carry out
|
||||
an autoresume or an autosuspend. Hence they can be called in
|
||||
an atomic context.
|
||||
|
||||
The conventional usage pattern is that a driver calls
|
||||
The simplest usage pattern is that a driver calls
|
||||
usb_autopm_get_interface() in its open routine and
|
||||
usb_autopm_put_interface() in its close or release routine. But
|
||||
other patterns are possible.
|
||||
usb_autopm_put_interface() in its close or release routine. But other
|
||||
patterns are possible.
|
||||
|
||||
The autosuspend attempts mentioned above will often fail for one
|
||||
reason or another. For example, the power/level attribute might be
|
||||
set to "on", or another interface in the same device might not be
|
||||
idle. This is perfectly normal. If the reason for failure was that
|
||||
the device hasn't been idle for long enough, a delayed workqueue
|
||||
routine is automatically set up to carry out the operation when the
|
||||
autosuspend idle-delay has expired.
|
||||
the device hasn't been idle for long enough, a timer is scheduled to
|
||||
carry out the operation automatically when the autosuspend idle-delay
|
||||
has expired.
|
||||
|
||||
Autoresume attempts also can fail, although failure would mean that
|
||||
the device is no longer present or operating properly. Unlike
|
||||
autosuspend, there's no delay for an autoresume.
|
||||
autosuspend, there's no idle-delay for an autoresume.
|
||||
|
||||
|
||||
Other parts of the driver interface
|
||||
|
@ -413,26 +412,27 @@ though, setting this flag won't cause the kernel to autoresume it.
|
|||
Normally a driver would set this flag in its probe method, at which
|
||||
time the device is guaranteed not to be autosuspended.)
|
||||
|
||||
The synchronous usb_autopm_* routines have to run in a sleepable
|
||||
process context; they must not be called from an interrupt handler or
|
||||
while holding a spinlock. In fact, the entire autosuspend mechanism
|
||||
is not well geared toward interrupt-driven operation. However there
|
||||
is one thing a driver can do in an interrupt handler:
|
||||
If a driver does its I/O asynchronously in interrupt context, it
|
||||
should call usb_autopm_get_interface_async() before starting output and
|
||||
usb_autopm_put_interface_async() when the output queue drains. When
|
||||
it receives an input event, it should call
|
||||
|
||||
usb_mark_last_busy(struct usb_device *udev);
|
||||
|
||||
This sets udev->last_busy to the current time. udev->last_busy is the
|
||||
field used for idle-delay calculations; updating it will cause any
|
||||
pending autosuspend to be moved back. The usb_autopm_* routines will
|
||||
also set the last_busy field to the current time.
|
||||
in the event handler. This sets udev->last_busy to the current time.
|
||||
udev->last_busy is the field used for idle-delay calculations;
|
||||
updating it will cause any pending autosuspend to be moved back. Most
|
||||
of the usb_autopm_* routines will also set the last_busy field to the
|
||||
current time.
|
||||
|
||||
Calling urb_mark_last_busy() from within an URB completion handler is
|
||||
subject to races: The kernel may have just finished deciding the
|
||||
device has been idle for long enough but not yet gotten around to
|
||||
calling the driver's suspend method. The driver would have to be
|
||||
responsible for synchronizing its suspend method with its URB
|
||||
completion handler and causing the autosuspend to fail with -EBUSY if
|
||||
an URB had completed too recently.
|
||||
Asynchronous operation is always subject to races. For example, a
|
||||
driver may call one of the usb_autopm_*_interface_async() routines at
|
||||
a time when the core has just finished deciding the device has been
|
||||
idle for long enough but not yet gotten around to calling the driver's
|
||||
suspend method. The suspend method must be responsible for
|
||||
synchronizing with the output request routine and the URB completion
|
||||
handler; it should cause autosuspends to fail with -EBUSY if the
|
||||
driver needs to use the device.
|
||||
|
||||
External suspend calls should never be allowed to fail in this way,
|
||||
only autosuspend calls. The driver can tell them apart by checking
|
||||
|
@ -440,75 +440,23 @@ the PM_EVENT_AUTO bit in the message.event argument to the suspend
|
|||
method; this bit will be set for internal PM events (autosuspend) and
|
||||
clear for external PM events.
|
||||
|
||||
Many of the ingredients in the autosuspend framework are oriented
|
||||
towards interfaces: The usb_interface structure contains the
|
||||
pm_usage_cnt field, and the usb_autopm_* routines take an interface
|
||||
pointer as their argument. But somewhat confusingly, a few of the
|
||||
pieces (i.e., usb_mark_last_busy()) use the usb_device structure
|
||||
instead. Drivers need to keep this straight; they can call
|
||||
interface_to_usbdev() to find the device structure for a given
|
||||
interface.
|
||||
|
||||
Mutual exclusion
|
||||
----------------
|
||||
|
||||
Locking requirements
|
||||
--------------------
|
||||
|
||||
All three suspend/resume methods are always called while holding the
|
||||
usb_device's PM mutex. For external events -- but not necessarily for
|
||||
autosuspend or autoresume -- the device semaphore (udev->dev.sem) will
|
||||
also be held. This implies that external suspend/resume events are
|
||||
mutually exclusive with calls to probe, disconnect, pre_reset, and
|
||||
post_reset; the USB core guarantees that this is true of internal
|
||||
suspend/resume events as well.
|
||||
For external events -- but not necessarily for autosuspend or
|
||||
autoresume -- the device semaphore (udev->dev.sem) will be held when a
|
||||
suspend or resume method is called. This implies that external
|
||||
suspend/resume events are mutually exclusive with calls to probe,
|
||||
disconnect, pre_reset, and post_reset; the USB core guarantees that
|
||||
this is true of autosuspend/autoresume events as well.
|
||||
|
||||
If a driver wants to block all suspend/resume calls during some
|
||||
critical section, it can simply acquire udev->pm_mutex. Note that
|
||||
calls to resume may be triggered indirectly. Block IO due to memory
|
||||
allocations can make the vm subsystem resume a device. Thus while
|
||||
holding this lock you must not allocate memory with GFP_KERNEL or
|
||||
GFP_NOFS.
|
||||
|
||||
Alternatively, if the critical section might call some of the
|
||||
usb_autopm_* routines, the driver can avoid deadlock by doing:
|
||||
|
||||
down(&udev->dev.sem);
|
||||
rc = usb_autopm_get_interface(intf);
|
||||
|
||||
and at the end of the critical section:
|
||||
|
||||
if (!rc)
|
||||
usb_autopm_put_interface(intf);
|
||||
up(&udev->dev.sem);
|
||||
|
||||
Holding the device semaphore will block all external PM calls, and the
|
||||
usb_autopm_get_interface() will prevent any internal PM calls, even if
|
||||
it fails. (Exercise: Why?)
|
||||
|
||||
The rules for locking order are:
|
||||
|
||||
Never acquire any device semaphore while holding any PM mutex.
|
||||
|
||||
Never acquire udev->pm_mutex while holding the PM mutex for
|
||||
a device that isn't a descendant of udev.
|
||||
|
||||
In other words, PM mutexes should only be acquired going up the device
|
||||
tree, and they should be acquired only after locking all the device
|
||||
semaphores you need to hold. These rules don't matter to drivers very
|
||||
much; they usually affect just the USB core.
|
||||
|
||||
Still, drivers do need to be careful. For example, many drivers use a
|
||||
private mutex to synchronize their normal I/O activities with their
|
||||
disconnect method. Now if the driver supports autosuspend then it
|
||||
must call usb_autopm_put_interface() from somewhere -- maybe from its
|
||||
close method. It should make the call while holding the private mutex,
|
||||
since a driver shouldn't call any of the usb_autopm_* functions for an
|
||||
interface from which it has been unbound.
|
||||
|
||||
But the usb_autpm_* routines always acquire the device's PM mutex, and
|
||||
consequently the locking order has to be: private mutex first, PM
|
||||
mutex second. Since the suspend method is always called with the PM
|
||||
mutex held, it mustn't try to acquire the private mutex. It has to
|
||||
synchronize with the driver's I/O activities in some other way.
|
||||
critical section, the best way is to lock the device and call
|
||||
usb_autopm_get_interface() (and do the reverse at the end of the
|
||||
critical section). Holding the device semaphore will block all
|
||||
external PM calls, and the usb_autopm_get_interface() will prevent any
|
||||
internal PM calls, even if it fails. (Exercise: Why?)
|
||||
|
||||
|
||||
Interaction between dynamic PM and system PM
|
||||
|
@ -517,22 +465,11 @@ synchronize with the driver's I/O activities in some other way.
|
|||
Dynamic power management and system power management can interact in
|
||||
a couple of ways.
|
||||
|
||||
Firstly, a device may already be manually suspended or autosuspended
|
||||
when a system suspend occurs. Since system suspends are supposed to
|
||||
be as transparent as possible, the device should remain suspended
|
||||
following the system resume. The 2.6.23 kernel obeys this principle
|
||||
for manually suspended devices but not for autosuspended devices; they
|
||||
do get resumed when the system wakes up. (Presumably they will be
|
||||
autosuspended again after their idle-delay time expires.) In later
|
||||
kernels this behavior will be fixed.
|
||||
|
||||
(There is an exception. If a device would undergo a reset-resume
|
||||
instead of a normal resume, and the device is enabled for remote
|
||||
wakeup, then the reset-resume takes place even if the device was
|
||||
already suspended when the system suspend began. The justification is
|
||||
that a reset-resume is a kind of remote-wakeup event. Or to put it
|
||||
another way, a device which needs a reset won't be able to generate
|
||||
normal remote-wakeup signals, so it ought to be resumed immediately.)
|
||||
Firstly, a device may already be autosuspended when a system suspend
|
||||
occurs. Since system suspends are supposed to be as transparent as
|
||||
possible, the device should remain suspended following the system
|
||||
resume. But this theory may not work out well in practice; over time
|
||||
the kernel's behavior in this regard has changed.
|
||||
|
||||
Secondly, a dynamic power-management event may occur as a system
|
||||
suspend is underway. The window for this is short, since system
|
||||
|
|
|
@ -91,8 +91,8 @@ config USB_DYNAMIC_MINORS
|
|||
If you are unsure about this, say N here.
|
||||
|
||||
config USB_SUSPEND
|
||||
bool "USB selective suspend/resume and wakeup"
|
||||
depends on USB && PM
|
||||
bool "USB runtime power management (suspend/resume and wakeup)"
|
||||
depends on USB && PM_RUNTIME
|
||||
help
|
||||
If you say Y here, you can use driver calls or the sysfs
|
||||
"power/level" file to suspend or resume individual USB
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -39,6 +39,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
|
@ -1858,6 +1859,10 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
|
|||
return status;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
|
||||
/* Workqueue routine for root-hub remote wakeup */
|
||||
static void hcd_resume_work(struct work_struct *work)
|
||||
{
|
||||
|
@ -1884,12 +1889,12 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
|
|||
|
||||
spin_lock_irqsave (&hcd_root_hub_lock, flags);
|
||||
if (hcd->rh_registered)
|
||||
queue_work(ksuspend_usb_wq, &hcd->wakeup_work);
|
||||
queue_work(pm_wq, &hcd->wakeup_work);
|
||||
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
|
||||
|
||||
#endif
|
||||
#endif /* CONFIG_USB_SUSPEND */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -2034,7 +2039,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
|
|||
init_timer(&hcd->rh_timer);
|
||||
hcd->rh_timer.function = rh_timer_func;
|
||||
hcd->rh_timer.data = (unsigned long) hcd;
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
|
||||
#endif
|
||||
mutex_init(&hcd->bandwidth_mutex);
|
||||
|
@ -2234,7 +2239,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
|
|||
hcd->rh_registered = 0;
|
||||
spin_unlock_irq (&hcd_root_hub_lock);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
cancel_work_sync(&hcd->wakeup_work);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ struct usb_hcd {
|
|||
|
||||
struct timer_list rh_timer; /* drives root-hub polling */
|
||||
struct urb *status_urb; /* the current status urb */
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
struct work_struct wakeup_work; /* for remote wakeup */
|
||||
#endif
|
||||
|
||||
|
@ -464,16 +464,20 @@ extern int usb_find_interface_driver(struct usb_device *dev,
|
|||
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
|
||||
extern void usb_root_hub_lost_power(struct usb_device *rhdev);
|
||||
extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
|
||||
extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
|
||||
#else
|
||||
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
#endif /* CONFIG_USB_SUSPEND */
|
||||
|
||||
|
||||
/*
|
||||
* USB device fs stuff
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1843,7 +1843,6 @@ free_interfaces:
|
|||
intf->dev.dma_mask = dev->dev.dma_mask;
|
||||
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
|
||||
device_initialize(&intf->dev);
|
||||
mark_quiesced(intf);
|
||||
dev_set_name(&intf->dev, "%d-%s:%d.%d",
|
||||
dev->bus->busnum, dev->devpath,
|
||||
configuration, alt->desc.bInterfaceNumber);
|
||||
|
|
|
@ -49,9 +49,6 @@ const char *usbcore_name = "usbcore";
|
|||
|
||||
static int nousb; /* Disable USB when built into kernel image */
|
||||
|
||||
/* Workqueue for autosuspend and for remote wakeup of root hubs */
|
||||
struct workqueue_struct *ksuspend_usb_wq;
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
static int usb_autosuspend_delay = 2; /* Default delay value,
|
||||
* in seconds */
|
||||
|
@ -264,23 +261,6 @@ static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int ksuspend_usb_init(void)
|
||||
{
|
||||
/* This workqueue is supposed to be both freezable and
|
||||
* singlethreaded. Its job doesn't justify running on more
|
||||
* than one CPU.
|
||||
*/
|
||||
ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd");
|
||||
if (!ksuspend_usb_wq)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ksuspend_usb_cleanup(void)
|
||||
{
|
||||
destroy_workqueue(ksuspend_usb_wq);
|
||||
}
|
||||
|
||||
/* USB device Power-Management thunks.
|
||||
* There's no need to distinguish here between quiescing a USB device
|
||||
* and powering it down; the generic_suspend() routine takes care of
|
||||
|
@ -296,7 +276,7 @@ static int usb_dev_prepare(struct device *dev)
|
|||
static void usb_dev_complete(struct device *dev)
|
||||
{
|
||||
/* Currently used only for rebinding interfaces */
|
||||
usb_resume(dev, PMSG_RESUME); /* Message event is meaningless */
|
||||
usb_resume(dev, PMSG_ON); /* FIXME: change to PMSG_COMPLETE */
|
||||
}
|
||||
|
||||
static int usb_dev_suspend(struct device *dev)
|
||||
|
@ -342,9 +322,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {
|
|||
|
||||
#else
|
||||
|
||||
#define ksuspend_usb_init() 0
|
||||
#define ksuspend_usb_cleanup() do {} while (0)
|
||||
#define usb_device_pm_ops (*(struct dev_pm_ops *)0)
|
||||
#define usb_device_pm_ops (*(struct dev_pm_ops *) NULL)
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
|
@ -472,9 +450,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
|||
INIT_LIST_HEAD(&dev->filelist);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
mutex_init(&dev->pm_mutex);
|
||||
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
|
||||
INIT_WORK(&dev->autoresume, usb_autoresume_work);
|
||||
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
|
||||
dev->connect_time = jiffies;
|
||||
dev->active_duration = -jiffies;
|
||||
|
@ -1117,9 +1092,6 @@ static int __init usb_init(void)
|
|||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = ksuspend_usb_init();
|
||||
if (retval)
|
||||
goto out;
|
||||
retval = bus_register(&usb_bus_type);
|
||||
if (retval)
|
||||
goto bus_register_failed;
|
||||
|
@ -1159,7 +1131,7 @@ major_init_failed:
|
|||
bus_notifier_failed:
|
||||
bus_unregister(&usb_bus_type);
|
||||
bus_register_failed:
|
||||
ksuspend_usb_cleanup();
|
||||
usb_debugfs_cleanup();
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
@ -1181,7 +1153,6 @@ static void __exit usb_exit(void)
|
|||
usb_hub_cleanup();
|
||||
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
|
||||
bus_unregister(&usb_bus_type);
|
||||
ksuspend_usb_cleanup();
|
||||
usb_debugfs_cleanup();
|
||||
}
|
||||
|
||||
|
|
|
@ -55,25 +55,8 @@ extern void usb_major_cleanup(void);
|
|||
extern int usb_suspend(struct device *dev, pm_message_t msg);
|
||||
extern int usb_resume(struct device *dev, pm_message_t msg);
|
||||
|
||||
extern void usb_autosuspend_work(struct work_struct *work);
|
||||
extern void usb_autoresume_work(struct work_struct *work);
|
||||
extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
|
||||
extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
|
||||
extern int usb_external_suspend_device(struct usb_device *udev,
|
||||
pm_message_t msg);
|
||||
extern int usb_external_resume_device(struct usb_device *udev,
|
||||
pm_message_t msg);
|
||||
extern int usb_remote_wakeup(struct usb_device *dev);
|
||||
|
||||
static inline void usb_pm_lock(struct usb_device *udev)
|
||||
{
|
||||
mutex_lock_nested(&udev->pm_mutex, udev->level);
|
||||
}
|
||||
|
||||
static inline void usb_pm_unlock(struct usb_device *udev)
|
||||
{
|
||||
mutex_unlock(&udev->pm_mutex);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
@ -87,14 +70,6 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int usb_remote_wakeup(struct usb_device *udev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void usb_pm_lock(struct usb_device *udev) {}
|
||||
static inline void usb_pm_unlock(struct usb_device *udev) {}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
|
@ -102,6 +77,7 @@ static inline void usb_pm_unlock(struct usb_device *udev) {}
|
|||
extern void usb_autosuspend_device(struct usb_device *udev);
|
||||
extern void usb_try_autosuspend_device(struct usb_device *udev);
|
||||
extern int usb_autoresume_device(struct usb_device *udev);
|
||||
extern int usb_remote_wakeup(struct usb_device *dev);
|
||||
|
||||
#else
|
||||
|
||||
|
@ -112,9 +88,13 @@ static inline int usb_autoresume_device(struct usb_device *udev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int usb_remote_wakeup(struct usb_device *udev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extern struct workqueue_struct *ksuspend_usb_wq;
|
||||
extern struct bus_type usb_bus_type;
|
||||
extern struct device_type usb_device_type;
|
||||
extern struct device_type usb_if_device_type;
|
||||
|
@ -144,23 +124,6 @@ static inline int is_usb_device_driver(struct device_driver *drv)
|
|||
for_devices;
|
||||
}
|
||||
|
||||
/* Interfaces and their "power state" are owned by usbcore */
|
||||
|
||||
static inline void mark_active(struct usb_interface *f)
|
||||
{
|
||||
f->is_active = 1;
|
||||
}
|
||||
|
||||
static inline void mark_quiesced(struct usb_interface *f)
|
||||
{
|
||||
f->is_active = 0;
|
||||
}
|
||||
|
||||
static inline int is_active(const struct usb_interface *f)
|
||||
{
|
||||
return f->is_active;
|
||||
}
|
||||
|
||||
|
||||
/* for labeling diagnostics */
|
||||
extern const char *usbcore_name;
|
||||
|
|
|
@ -1580,10 +1580,6 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
|||
return -ERESTARTSYS;
|
||||
|
||||
/* FIXME: What if a system sleep starts while a test is running? */
|
||||
if (!intf->is_active) {
|
||||
mutex_unlock(&dev->lock);
|
||||
return -EHOSTUNREACH;
|
||||
}
|
||||
|
||||
/* some devices, like ez-usb default devices, need a non-default
|
||||
* altsetting to have any active endpoints. some tests change
|
||||
|
|
|
@ -122,7 +122,6 @@ enum usb_interface_condition {
|
|||
* number from the USB core by calling usb_register_dev().
|
||||
* @condition: binding state of the interface: not bound, binding
|
||||
* (in probe()), bound to a driver, or unbinding (in disconnect())
|
||||
* @is_active: flag set when the interface is bound and not suspended.
|
||||
* @sysfs_files_created: sysfs attributes exist
|
||||
* @ep_devs_created: endpoint child pseudo-devices exist
|
||||
* @unregistering: flag set when the interface is being unregistered
|
||||
|
@ -135,8 +134,7 @@ enum usb_interface_condition {
|
|||
* @dev: driver model's view of this device
|
||||
* @usb_dev: if an interface is bound to the USB major, this will point
|
||||
* to the sysfs representation for that device.
|
||||
* @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
|
||||
* allowed unless the counter is 0.
|
||||
* @pm_usage_cnt: PM usage counter for this interface
|
||||
* @reset_ws: Used for scheduling resets from atomic context.
|
||||
* @reset_running: set to 1 if the interface is currently running a
|
||||
* queued reset so that usb_cancel_queued_reset() doesn't try to
|
||||
|
@ -184,7 +182,6 @@ struct usb_interface {
|
|||
int minor; /* minor number this interface is
|
||||
* bound to */
|
||||
enum usb_interface_condition condition; /* state of binding */
|
||||
unsigned is_active:1; /* the interface is not suspended */
|
||||
unsigned sysfs_files_created:1; /* the sysfs attributes exist */
|
||||
unsigned ep_devs_created:1; /* endpoint "devices" exist */
|
||||
unsigned unregistering:1; /* unregistration is in progress */
|
||||
|
@ -401,7 +398,6 @@ struct usb_tt;
|
|||
* @portnum: parent port number (origin 1)
|
||||
* @level: number of USB hub ancestors
|
||||
* @can_submit: URBs may be submitted
|
||||
* @discon_suspended: disconnected while suspended
|
||||
* @persist_enabled: USB_PERSIST enabled for this device
|
||||
* @have_langid: whether string_langid is valid
|
||||
* @authorized: policy has said we can use it;
|
||||
|
@ -421,20 +417,15 @@ struct usb_tt;
|
|||
* @usbfs_dentry: usbfs dentry entry for the device
|
||||
* @maxchild: number of ports if hub
|
||||
* @children: child devices - USB devices that are attached to this hub
|
||||
* @pm_usage_cnt: usage counter for autosuspend
|
||||
* @quirks: quirks of the whole device
|
||||
* @urbnum: number of URBs submitted for the whole device
|
||||
* @active_duration: total time device is not suspended
|
||||
* @autosuspend: for delayed autosuspends
|
||||
* @autoresume: for autoresumes requested while in_interrupt
|
||||
* @pm_mutex: protects PM operations
|
||||
* @last_busy: time of last use
|
||||
* @autosuspend_delay: in jiffies
|
||||
* @connect_time: time device was first connected
|
||||
* @do_remote_wakeup: remote wakeup should be enabled
|
||||
* @reset_resume: needs reset instead of resume
|
||||
* @autosuspend_disabled: autosuspend disabled by the user
|
||||
* @skip_sys_resume: skip the next system resume
|
||||
* @wusb_dev: if this is a Wireless USB device, link to the WUSB
|
||||
* specific data for the device.
|
||||
* @slot_id: Slot ID assigned by xHCI
|
||||
|
@ -475,7 +466,6 @@ struct usb_device {
|
|||
u8 level;
|
||||
|
||||
unsigned can_submit:1;
|
||||
unsigned discon_suspended:1;
|
||||
unsigned persist_enabled:1;
|
||||
unsigned have_langid:1;
|
||||
unsigned authorized:1;
|
||||
|
@ -499,17 +489,12 @@ struct usb_device {
|
|||
int maxchild;
|
||||
struct usb_device *children[USB_MAXCHILDREN];
|
||||
|
||||
int pm_usage_cnt;
|
||||
u32 quirks;
|
||||
atomic_t urbnum;
|
||||
|
||||
unsigned long active_duration;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct delayed_work autosuspend;
|
||||
struct work_struct autoresume;
|
||||
struct mutex pm_mutex;
|
||||
|
||||
unsigned long last_busy;
|
||||
int autosuspend_delay;
|
||||
unsigned long connect_time;
|
||||
|
@ -517,7 +502,6 @@ struct usb_device {
|
|||
unsigned do_remote_wakeup:1;
|
||||
unsigned reset_resume:1;
|
||||
unsigned autosuspend_disabled:1;
|
||||
unsigned skip_sys_resume:1;
|
||||
#endif
|
||||
struct wusb_dev *wusb_dev;
|
||||
int slot_id;
|
||||
|
@ -549,17 +533,8 @@ extern int usb_autopm_get_interface(struct usb_interface *intf);
|
|||
extern void usb_autopm_put_interface(struct usb_interface *intf);
|
||||
extern int usb_autopm_get_interface_async(struct usb_interface *intf);
|
||||
extern void usb_autopm_put_interface_async(struct usb_interface *intf);
|
||||
|
||||
static inline void usb_autopm_get_interface_no_resume(
|
||||
struct usb_interface *intf)
|
||||
{
|
||||
atomic_inc(&intf->pm_usage_cnt);
|
||||
}
|
||||
static inline void usb_autopm_put_interface_no_suspend(
|
||||
struct usb_interface *intf)
|
||||
{
|
||||
atomic_dec(&intf->pm_usage_cnt);
|
||||
}
|
||||
extern void usb_autopm_get_interface_no_resume(struct usb_interface *intf);
|
||||
extern void usb_autopm_put_interface_no_suspend(struct usb_interface *intf);
|
||||
|
||||
static inline void usb_mark_last_busy(struct usb_device *udev)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue