Features Download
From: Alan Stern <stern <at> rowland.harvard.edu>
Subject: [RFC 0/4] USB autosuspend/autoresume
Newsgroups: gmane.linux.usb.devel
Date: Monday 17th July 2006 18:34:20 UTC (over 12 years ago)

I wanted to get this onto the public lists before heading out to OLS,
so here it is.

Following is a series of four patches implementing autosuspend and
autoresume for USB.  The only interface drivers altered are the hub
driver and usb-skeleton, so most of the features will be visible only
with hubs.  Here are the ideas behind the design.

The first idea is that each suspend or resume event is propagated up
the device tree: Whenever a device suspends or resumes, its parent hub
is notified.  When a device suspends it may turn out the parent hub
has no more unsuspended children; in that case the parent hub will in
turn be autosuspended, and so on up the tree.  Or it may turn out that
we want to resume a device but the parent hub is also suspended; in
that case the parent hub will be resumed first, and its parent if
needed, and so on.

The autoresumes occur immediately, but there is a short delay between
the time an autosuspend is requested and when it is carried out.  This
delay is necessary to prevent "bouncing" of devices between awake and
asleep states.  (Imagine what would happen otherwise if you had a
complicated tree of devices, all suspended, and ran lsusb -- every hub
would have to go through a resume/suspend cycle once for each device
behind it.)  To implement the delay, a work_struct has been added to
struct usb_device.  This was the simplest approach, although not the
most space-efficient.  I set the delay length to 2 seconds.  Perhaps
shorter would be better and perhaps it will need to vary by device;
we won't know until we have more experience.

The second idea is that suspend() and resume() method calls can no
longer protected by a usb_device's device lock, since the locking
rules forbid acquiring these locks going up the device tree.  Instead
a new lock, pm_mutex, has been added to the usb_device struct.  The
core is careful to avoid letting PM calls occur during probe() or
disconnect(), but drivers will still need to be wary of the
possibility that their suspend() or resume() methods might be called
at awkward times.  (For now this mostly matters only for hubs; other
devices don't have USB children and so don't have to worry about PM
requests bubbling up from below.)

The third idea is that devices should not be autosuspended at times
when they are in use.  There is a new "pm_usage" field added to both
the usb_device and usb_interface structures; the device will not be
autosuspended if any of these fields is larger than 0.  The field in
the usb_device structure follows a strict "increment/decrement"
regimen, just like a reference counter.  For example, when a usbfs
device file is opened, the device is autoresumed (if it was suspended)
and the device's pm_usage field in incremented.  When the device file
is closed, the pm_usage field is decremented and the device is
autosuspended if the field is now <= 0.  As a different kind of
example, when a suspended device sends a remote wakeup request, it and
its interfaces will be resumed but the pm_usage field will remain
unchanged.  Unless one of the interface drivers does something, in all
likelihood the device will be autosuspended again shortly afterward.

The pm_usage field in the usb_interface structure is entirely under
the control of the interface's driver.  The driver may follow the
"increment/decrement" reference-counter model if it wants.  This is
appropriate for drivers which, like usb-skeleton, expose a
character-device node to userspace (pm_usage is incremented when the
device node is opened and is decremented when the node is released).
There are new function calls exported for interface drivers:

	usb_autopm_get_interface() will resume the interface's device
	if it is suspended and will increment the pm_usage value.

	usb_autopm_put_interface() will decrement the pm_usage value
	and submit an autosuspend request if the value is now <= 0.

However a driver may make its own changes to pm_usage, thereby
obtaining a more flexible model for the interface's "busy-ness".  The
hub driver does this.

The fourth idea is that usbcore will do its own autosuspending and
autoresuming at appropriate times.  Devices are autoresumed whenever
one of their interfaces is probed or unbound and also whenever
usb_set_configuration() or usb_reset_composite_device() is called.
When the probe, unbind, set-config, or reset call is over, the device
is autosuspended unless one of the pm_usage counters is still > 0.

The fifth idea is that not all drivers will support autosuspend.  (In
these patches, only usb-skeleton and the hub driver, together with the
usb_generic device driver, do.)  A new flag has been added to the
usb_driver and usb_device_driver structures, indicating whether the
driver supports autosuspend.  If the flag isn't set, then whenever the
driver is bound to an interface (or device) that interface's pm_usage
counter is set to 1.  The non-autosuspend-aware driver will never
change the counter, and hence the device will never be autosuspended.

The sixth idea is that host controller drivers no longer need to worry
about autosuspending their root hubs.  This functionality is now
centralized in the hub driver, which will take care of autosuspending
every hub, not just root hubs.  Consequently the existing code in
ohci-hcd and its supporting code in usbcore has been removed.
(ehci-hcd does not do autosuspend, and uhci-hcd has a rather different
sort of mechanism.)

The seventh idea is that some interface drivers, like the hub driver,
will rely on remote-wakeup requests to make autosuspend/autoresume
work properly.  If the remote-wakeup feature can't be set for a device
bound to one of these drivers, then autosuspend must fail.
Implementing this required adding some new flags.  The most important
of them are:

	One in usb_interface, indicating that the interface's driver
	requires remote-wakeup capability.  The driver should set this
	flag during probe().

	One in usb_device, indicating that the current suspend or
	resume request is in fact an autosuspend or autoresume.  Only
	autosuspend requests may fail for lack of remote wakeup; other
	suspend requests must succeed regardless.  Also, various error
	messages are suppressed if this flag is set, since autosuspend
	is expected to fail fairly often.

Okay, this is a lot of material.  That's why it's broken up into four
patches (although the majority of the work is in the first one).

Alan Stern

Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share
opinions on IT & business topics through brief surveys -- and earn cash
[email protected]
To unsubscribe, use the last form field at:
CD: 3ms