Re: parallel suspend/resume

David Brownell
2007-12-07T18:01:12Z

> What about ordering constraints? A lot of them aren't explicit. We
> just depend on the fact that devices get suspended in reverse order of
> registration. You can't do that in parallel.

Those constraints should *become* explicit ... not stay implicit!

FWIW the appended patch removes that rude "order of registration"
policy, so that the suspend/resume list matches the device tree.
It's behaved OK on PCs and, in light duty, a few development boards;
I've carried it around most of this year.

I'd expect this to eventually turn up some cases where Linux is
right now doing a bad job of exposing devices with multiple such
ordering constraint ... power management via I2C seems likely to
turn up a few of them. We'd need some automatic way to detect
and report such problems so that they could be fixed.

- Dave

============= SNIP!
Change how the PM list is constructed, so that devices are added right
after their parents (when they have one) rather than at the end of the
list. This preserves sequencing guarantees, but enables sequencing of
suspend/resume operations by more important characteristics than "when
device happened to enumerate" ... e.g. clocksources and clockevents
at a clearly defined point during suspend and resume, power management
chips nearer their I2C parent.

This patch has a potential downside for devices that have multiple
power dependencies and which "just happened to work" before. Or
looking at it the other way around: a potential upside for devices
that didn't work before.

---
drivers/base/power/main.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)

--- g26.orig/drivers/base/power/main.c 2007-11-29 20:06:04.000000000 -0800
+++ g26/drivers/base/power/main.c 2007-11-29 20:11:38.000000000 -0800
@@ -40,11 +40,17 @@ int (*platform_enable_wakeup)(struct dev

void device_pm_add(struct device *dev)
{
- pr_debug("PM: Adding info for %s:%s\n",
+ struct device *parent = dev->parent;
+
+ pr_debug("PM: Adding info for %s:%s after %s\n",
dev->bus ? dev->bus->name : "No Bus",
- kobject_name(&dev->kobj));
+ kobject_name(&dev->kobj),
+ parent ? parent->bus_id : "(no parent)");
mutex_lock(&dpm_list_mtx);
- list_add_tail(&dev->power.entry, &dpm_active);
+ if (parent)
+ list_add(&dev->power.entry, &parent->power.entry);
+ else
+ list_add_tail(&dev->power.entry, &dpm_active);
mutex_unlock(&dpm_list_mtx);
}