From: Marcelo Tosatti <marcelo@kvack.org>
To: linux-pm@lists.linux-foundation.org
Subject: parallel suspend/resume
Date: Mon, 8 Oct 2007 15:46:39 -0400 [thread overview]
Message-ID: <20071008194639.GA5301@dmt> (raw)
Hi,
I spent some time working with the parallel suspend/resume idea, even
wrote a simple patch (attached), but that obviously does not scale to
large number of devices.
What would be a better approach?
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 05dc876..45f5851 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -62,6 +62,8 @@ int device_pm_add(struct device * dev)
down(&dpm_list_sem);
list_add_tail(&dev->power.entry, &dpm_active);
device_pm_set_parent(dev, dev->parent);
+ init_waitqueue_head(&dev->power.powered_on);
+ INIT_LIST_HEAD(&dev->power.entry_sus);
if ((error = dpm_sysfs_add(dev)))
list_del(&dev->power.entry);
up(&dpm_list_sem);
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
index a2c6418..a3de7d6 100644
--- a/drivers/base/power/resume.c
+++ b/drivers/base/power/resume.c
@@ -9,10 +9,13 @@
*/
#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
#include <linux/resume-trace.h>
#include "../base.h"
#include "power.h"
+LIST_HEAD(suspend_threads);
/**
* resume_device - Restore state for one device.
@@ -40,24 +43,61 @@ int resume_device(struct device * dev)
if (dev->bus && dev->bus->resume) {
dev_dbg(dev,"resuming\n");
error = dev->bus->resume(dev);
+ dev_dbg(dev,"finish\n");
}
if (!error && dev->type && dev->type->resume) {
dev_dbg(dev,"resuming\n");
error = dev->type->resume(dev);
+ dev_dbg(dev,"finish\n");
}
if (!error && dev->class && dev->class->resume) {
dev_dbg(dev,"class resume\n");
error = dev->class->resume(dev);
+ dev_dbg(dev,"finish\n");
}
+ dev->power.power_state = PMSG_ON;
+
up(&dev->sem);
TRACE_RESUME(error);
+
return error;
}
+static int resume_device_work(void *data)
+{
+ int error;
+ struct device *dev = (struct device *)data;
+
+ if (dev->power.pm_parent
+ && dev->power.pm_parent->power.power_state.event) {
+ dev_err(dev, "PM: resume from %d, parent %s still %d\n",
+ dev->power.power_state.event,
+ dev->power.pm_parent->bus_id,
+ dev->power.pm_parent->power.power_state.event);
+ wait_event_interruptible(dev->power.pm_parent->power.powered_on,
+ !dev->power.pm_parent->power.power_state.event);
+ }
+
+ error = resume_device(dev);
+ if (!error)
+ wake_up_all(&dev->power.powered_on);
+
+ put_device(dev);
+ return error;
+}
+
+int span_resume_thread(struct device *dev)
+{
+ dev->power.resume_thread = kthread_run(resume_device_work, dev,
+ "resume-%s", dev_driver_string(dev));
+ list_add(&dev->power.entry_sus, &suspend_threads);
+ return 0;
+}
+
static int resume_device_early(struct device * dev)
{
@@ -80,6 +120,8 @@ static int resume_device_early(struct de
*/
void dpm_resume(void)
{
+ struct dev_pm_info *dev;
+
down(&dpm_list_sem);
while(!list_empty(&dpm_off)) {
struct list_head * entry = dpm_off.next;
@@ -90,11 +132,15 @@ void dpm_resume(void)
up(&dpm_list_sem);
if (!dev->power.prev_state.event)
- resume_device(dev);
+ span_resume_thread(dev);
down(&dpm_list_sem);
- put_device(dev);
}
up(&dpm_list_sem);
+
+ list_for_each_entry(dev, &suspend_threads, entry_sus)
+ wait_event_interruptible(dev->powered_on,
+ !dev->power_state.event);
+ INIT_LIST_HEAD(&suspend_threads);
}
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
index 42d2b86..3f6e9b0 100644
--- a/drivers/base/power/suspend.c
+++ b/drivers/base/power/suspend.c
@@ -169,8 +169,10 @@ int device_suspend(pm_message_t state)
/* Check if the device got removed */
if (!list_empty(&dev->power.entry)) {
/* Move it to the dpm_off list */
- if (!error)
+ if (!error) {
+ dev->power.power_state = PMSG_SUSPEND;
list_move(&dev->power.entry, &dpm_off);
+ }
}
if (error)
printk(KERN_ERR "Could not suspend device %s: "
diff --git a/include/linux/pm.h b/include/linux/pm.h
index b2c4fde..4bfa8da 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -24,6 +24,7 @@ #define _LINUX_PM_H
#ifdef __KERNEL__
#include <linux/list.h>
+#include <linux/wait.h>
#include <asm/atomic.h>
/*
@@ -271,6 +272,9 @@ #ifdef CONFIG_PM
void * saved_state;
struct device * pm_parent;
struct list_head entry;
+ struct task_struct * resume_thread;
+ wait_queue_head_t powered_on;
+ struct list_head entry_sus;
#endif
};
next reply other threads:[~2007-10-08 19:46 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-10-08 19:46 Marcelo Tosatti [this message]
2007-10-09 15:54 ` parallel suspend/resume Alan Stern
2007-12-07 15:51 ` Pavel Machek
2007-12-07 16:22 ` Alan Stern
2007-12-07 18:01 ` David Brownell
2007-12-07 19:33 ` Alan Stern
2007-12-08 20:46 ` Rafael J. Wysocki
2007-12-10 5:10 ` David Brownell
2007-12-10 17:57 ` Alan Stern
2007-12-08 8:00 ` Oliver Neukum
2007-12-08 10:21 ` Pavel Machek
2007-12-08 11:08 ` James Courtier-Dutton
2007-12-08 12:26 ` Oliver Neukum
2007-12-08 11:24 ` Oliver Neukum
2007-12-08 15:43 ` Alan Stern
2007-12-08 20:43 ` Rafael J. Wysocki
2007-12-09 13:23 ` Oliver Neukum
2007-12-09 15:31 ` Alan Stern
2007-12-08 16:26 ` Alan Stern
2007-12-08 22:00 ` Alan Stern
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20071008194639.GA5301@dmt \
--to=marcelo@kvack.org \
--cc=linux-pm@lists.linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox