All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Rafael J. Wysocki" <rjw@sisk.pl>
To: linux-pm <linux-pm@lists.linux-foundation.org>
Cc: linux-acpi <linux-acpi@vger.kernel.org>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Zhang Rui <rui.zhang@intel.com>, Len Brown <lenb@kernel.org>,
	Alan Stern <stern@rowland.harvard.edu>,
	Arjan van de Ven <arjan@linux.intel.com>
Subject: [RFC][PATCH 2/3] PM: Asynchronous suspend of devices
Date: Wed, 12 Aug 2009 22:21:20 +0200	[thread overview]
Message-ID: <200908122221.20568.rjw@sisk.pl> (raw)
In-Reply-To: <200908122218.13975.rjw@sisk.pl>

The patch below extends the mechanism introduced by the previous
patch to the suspend part of the PM core.

Asynchronous suspend is slightly more complicated, because in this
case child devices need to be waited for by their parents, so each
parent has to wait on power.comp for each of its children.  Apart
from this, if any of the suspend callbacks executed asynchronously
returns error code, the entire suspend has to be terminated and
rolled back.
---
 drivers/base/power/main.c |  133 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 119 insertions(+), 14 deletions(-)

Index: linux-2.6/drivers/base/power/main.c
===================================================================
--- linux-2.6.orig/drivers/base/power/main.c
+++ linux-2.6/drivers/base/power/main.c
@@ -194,6 +194,19 @@ static void device_pm_wait(struct device
 		wait_for_completion(&master->power.comp);
 }
 
+static int device_pm_wait_wrapper(struct device *dev, void *data)
+{
+	struct device *parent = (struct device *)data;
+
+	device_pm_wait(parent, dev);
+	return 0;
+}
+
+static void device_pm_wait_for_children(struct device *parent)
+{
+	device_for_each_child(parent, parent, device_pm_wait_wrapper);
+}
+
 /**
  *	pm_op - execute the PM operation appropiate for given PM event
  *	@dev:	Device.
@@ -639,6 +652,8 @@ EXPORT_SYMBOL_GPL(dpm_resume_end);
 
 /*------------------------- Suspend routines -------------------------*/
 
+static int async_error;
+
 /**
  *	resume_event - return a PM message representing the resume event
  *	               corresponding to given sleep state.
@@ -659,26 +674,61 @@ static pm_message_t resume_event(pm_mess
 }
 
 /**
- *	device_suspend_noirq - Shut down one device (late suspend).
- *	@dev:	Device.
- *	@state: PM transition of the system being carried out.
+ * __device_suspend_noirq - Execute a "late" suspend callback for given device.
+ * @dev: Device to suspend.
+ * @state: PM transition of the system being carried out.
  *
- *	This is called with interrupts off and only a single CPU running.
+ * The driver of the device won't receive interrupts while this function is
+ * being executed.
  */
-static int device_suspend_noirq(struct device *dev, pm_message_t state)
+static int __device_suspend_noirq(struct device *dev, pm_message_t state)
 {
 	int error = 0;
 
-	if (!dev->bus)
-		return 0;
+	device_pm_wait_for_children(dev);
 
-	if (dev->bus->pm) {
+	if (dev->bus && dev->bus->pm) {
 		pm_dev_dbg(dev, state, "LATE ");
 		error = pm_noirq_op(dev, dev->bus->pm, state);
 	}
+
+	complete_all(&dev->power.comp);
+
 	return error;
 }
 
+static void async_suspend_noirq(void *data, async_cookie_t cookie)
+{
+	struct device *dev = (struct device *)data;
+	int error = async_error;
+
+	if (error)
+		return;
+
+	pm_dev_dbg(dev, dev->power.async_state, "async LATE ");
+	error = __device_suspend_noirq(dev, dev->power.async_state);
+	if (error) {
+		pm_dev_err(dev, dev->power.async_state, " async LATE", error);
+		dev->power.status = DPM_OFF;
+	}
+	put_device(dev);
+
+	if (error && !async_error)
+		async_error = error;
+}
+
+static int device_suspend_noirq(struct device *dev, pm_message_t state)
+{
+	if (dev->power.async_suspend) {
+		get_device(dev);
+		dev->power.async_state = state;
+		async_schedule(async_suspend_noirq, dev);
+		return 0;
+	}
+
+	return __device_suspend_noirq(dev, state);
+}
+
 /**
  *	dpm_suspend_noirq - Power down all regular (non-sysdev) devices.
  *	@state: PM transition of the system being carried out.
@@ -696,13 +746,19 @@ int dpm_suspend_noirq(pm_message_t state
 	suspend_device_irqs();
 	mutex_lock(&dpm_list_mtx);
 	list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
+		dev->power.status = DPM_OFF_IRQ;
 		error = device_suspend_noirq(dev, state);
 		if (error) {
 			pm_dev_err(dev, state, " late", error);
+			dev->power.status = DPM_OFF;
+			break;
+		}
+		if (async_error) {
+			error = async_error;
 			break;
 		}
-		dev->power.status = DPM_OFF_IRQ;
 	}
+	dpm_synchronize_noirq();
 	mutex_unlock(&dpm_list_mtx);
 	if (error)
 		dpm_resume_noirq(resume_event(state));
@@ -711,14 +767,15 @@ int dpm_suspend_noirq(pm_message_t state
 EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
 
 /**
- *	device_suspend - Save state of one device.
- *	@dev:	Device.
- *	@state: PM transition of the system being carried out.
+ * __device_suspend - Execute suspend callbacks for given device.
+ * @dev: Device to suspend.
+ * @state: PM transition of the system being carried out.
  */
-static int device_suspend(struct device *dev, pm_message_t state)
+static int __device_suspend(struct device *dev, pm_message_t state)
 {
 	int error = 0;
 
+	device_pm_wait_for_children(dev);
 	down(&dev->sem);
 
 	if (dev->class) {
@@ -755,10 +812,51 @@ static int device_suspend(struct device 
 	}
  End:
 	up(&dev->sem);
+	complete_all(&dev->power.comp);
 
 	return error;
 }
 
+static void async_suspend(void *data, async_cookie_t cookie)
+{
+	struct device *dev = (struct device *)data;
+	int error;
+
+	pm_dev_dbg(dev, dev->power.async_state, "async ");
+
+	mutex_lock(&dpm_list_mtx);
+	error = async_error;
+	mutex_unlock(&dpm_list_mtx);
+	if (error)
+		goto End;
+
+	error = __device_suspend(dev, dev->power.async_state);
+	if (error) {
+		pm_dev_err(dev, dev->power.async_state, " async", error);
+
+		mutex_lock(&dpm_list_mtx);
+		dev->power.status = DPM_SUSPENDING;
+		if (!async_error)
+			async_error = error;
+		mutex_unlock(&dpm_list_mtx);
+	}
+
+ End:
+	put_device(dev);
+}
+
+static int device_suspend(struct device *dev, pm_message_t state)
+{
+	if (dev->power.async_suspend) {
+		get_device(dev);
+		dev->power.async_state = state;
+		async_schedule(async_suspend, dev);
+		return 0;
+	}
+
+	return __device_suspend(dev, state);
+}
+
 /**
  *	dpm_suspend - Suspend every device.
  *	@state: PM transition of the system being carried out.
@@ -776,6 +874,7 @@ static int dpm_suspend(pm_message_t stat
 		struct device *dev = to_device(dpm_list.prev);
 
 		get_device(dev);
+		dev->power.status = DPM_OFF;
 		mutex_unlock(&dpm_list_mtx);
 
 		error = device_suspend(dev, state);
@@ -783,16 +882,21 @@ static int dpm_suspend(pm_message_t stat
 		mutex_lock(&dpm_list_mtx);
 		if (error) {
 			pm_dev_err(dev, state, "", error);
+			dev->power.status = DPM_SUSPENDING;
 			put_device(dev);
 			break;
 		}
-		dev->power.status = DPM_OFF;
 		if (!list_empty(&dev->power.entry))
 			list_move(&dev->power.entry, &list);
 		put_device(dev);
+		if (async_error) {
+			error = async_error;
+			break;
+		}
 	}
 	list_splice(&list, dpm_list.prev);
 	mutex_unlock(&dpm_list_mtx);
+	dpm_synchronize();
 	return error;
 }
 
@@ -848,6 +952,7 @@ static int dpm_prepare(pm_message_t stat
 	INIT_LIST_HEAD(&list);
 	mutex_lock(&dpm_list_mtx);
 	transition_started = true;
+	async_error = 0;
 	while (!list_empty(&dpm_list)) {
 		struct device *dev = to_device(dpm_list.next);
 

  parent reply	other threads:[~2009-08-12 20:21 UTC|newest]

Thread overview: 152+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-08-12 20:18 [RFC][PATCH 0/3] PM: Asynchronous suspend and resume Rafael J. Wysocki
2009-08-12 20:20 ` [RFC][PATCH 1/3] PM: Asynchronous resume of devices Rafael J. Wysocki
2009-08-12 20:20   ` Rafael J. Wysocki
2009-08-14 16:33   ` Pavel Machek
2009-08-15 20:59     ` Rafael J. Wysocki
2009-08-15 20:59     ` Rafael J. Wysocki
2009-08-22  9:24       ` Pavel Machek
2009-08-22 21:45         ` Rafael J. Wysocki
2009-08-22 21:45         ` Rafael J. Wysocki
2009-08-22  9:24       ` Pavel Machek
2009-08-14 16:33   ` Pavel Machek
2009-08-12 20:21 ` Rafael J. Wysocki [this message]
2009-08-14 16:35   ` [RFC][PATCH 2/3] PM: Asynchronous suspend " Pavel Machek
2009-08-14 16:35   ` Pavel Machek
2009-08-15 21:04     ` Rafael J. Wysocki
2009-08-15 21:04     ` Rafael J. Wysocki
2009-08-22  9:25       ` Pavel Machek
2009-08-22  9:25       ` Pavel Machek
2009-08-22 21:46         ` Rafael J. Wysocki
2009-08-22 21:46         ` Rafael J. Wysocki
2009-08-12 20:21 ` Rafael J. Wysocki
2009-08-12 20:22 ` [RFC][PATCH 3/3] PM: Asynchronous suspend and resume for ACPI battery Rafael J. Wysocki
2009-08-12 20:22   ` Rafael J. Wysocki
2009-08-12 21:12 ` [RFC][PATCH 0/3] PM: Asynchronous suspend and resume Alan Stern
2009-08-12 21:12 ` Alan Stern
2009-08-12 21:43   ` Rafael J. Wysocki
2009-08-13  8:18     ` Zhang Rui
2009-08-13  8:18       ` Zhang Rui
2009-08-13 18:08       ` Rafael J. Wysocki
2009-08-13 18:08         ` Rafael J. Wysocki
2009-08-14  3:24         ` Zhang Rui
2009-08-14 11:58           ` Rafael J. Wysocki
2009-08-14 11:58           ` Rafael J. Wysocki
2009-08-14 11:58             ` Rafael J. Wysocki
2009-08-14  3:24         ` Zhang Rui
2009-08-13 18:08       ` Rafael J. Wysocki
2009-08-13  8:18     ` Zhang Rui
2009-08-13 14:45     ` Alan Stern
2009-08-13 18:28       ` Rafael J. Wysocki
2009-08-13 18:39         ` Alan Stern
2009-08-13 21:10           ` Rafael J. Wysocki
2009-08-13 21:10           ` Rafael J. Wysocki
2009-08-13 18:39         ` Alan Stern
2009-08-13 18:28       ` Rafael J. Wysocki
2009-08-13 14:45     ` Alan Stern
2009-08-13 21:53     ` Rafael J. Wysocki
2009-08-13 21:53     ` Rafael J. Wysocki
2009-08-14 14:45       ` Alan Stern
2009-08-14 19:12         ` Rafael J. Wysocki
2009-08-14 21:21           ` Alan Stern
2009-08-14 21:31             ` Rafael J. Wysocki
2009-08-14 21:31             ` Rafael J. Wysocki
2009-08-14 21:37               ` Alan Stern
2009-08-14 21:37               ` Alan Stern
2009-08-16 10:29               ` [linux-pm] " Rafael J. Wysocki
2009-08-16 10:29                 ` Rafael J. Wysocki
2009-08-16 10:29               ` Rafael J. Wysocki
2009-08-14 21:21           ` Alan Stern
2009-08-14 19:12         ` Rafael J. Wysocki
2009-08-14 14:45       ` Alan Stern
2009-08-12 21:43   ` Rafael J. Wysocki
2009-08-14 16:33 ` Pavel Machek
2009-08-15 21:00   ` Rafael J. Wysocki
2009-08-15 21:00   ` Rafael J. Wysocki
2009-08-14 16:33 ` Pavel Machek
2009-08-17  0:15 ` [RFC][PATCH 0/7] PM: Asynchronous suspend and resume (updated) Rafael J. Wysocki
2009-08-17  0:15   ` Rafael J. Wysocki
2009-08-17  0:16   ` [RFC][PATCH 1/7] PM: Update kerneldoc comments in drivers/base/power/main.c Rafael J. Wysocki
2009-08-19 21:57     ` Rafael J. Wysocki
2009-08-19 21:57     ` Rafael J. Wysocki
2009-08-19 22:00       ` Randy Dunlap
2009-08-19 22:00       ` Randy Dunlap
2009-08-19 22:06       ` Greg KH
2009-08-19 22:06       ` Greg KH
2009-08-19 22:28       ` Alan Stern
2009-08-19 23:14         ` Rafael J. Wysocki
2009-08-20 14:00           ` Alan Stern
2009-08-20 14:00           ` Alan Stern
2009-08-19 23:14         ` Rafael J. Wysocki
2009-08-19 22:28       ` Alan Stern
2009-08-26 15:44     ` Pavel Machek
2009-08-26 15:44     ` Pavel Machek
2009-08-17  0:16   ` Rafael J. Wysocki
2009-08-17  0:17   ` [RFC][PATCH 2/7] PM: Framework for representing PM links between devices Rafael J. Wysocki
2009-08-21 22:27     ` [RFC][PATCH 2/7 update] " Rafael J. Wysocki
2009-08-21 22:27     ` Rafael J. Wysocki
2009-08-17  0:17   ` [RFC][PATCH 2/7] " Rafael J. Wysocki
2009-08-17  0:18   ` [RFC][PATCH 3/7] PM: Asynchronous resume of I/O devices Rafael J. Wysocki
2009-08-23 22:09     ` [RFC][PATCH 3/7 updated] " Rafael J. Wysocki
2009-08-23 22:09     ` Rafael J. Wysocki
2009-08-17  0:18   ` [RFC][PATCH 3/7] " Rafael J. Wysocki
2009-08-17  0:19   ` [RFC][PATCH 4/7] PM: Asynchronous suspend " Rafael J. Wysocki
2009-08-17  0:19   ` Rafael J. Wysocki
2009-08-17  0:20   ` [RFC][PATCH 5/7] PM: Asynchronous suspend and resume of PCI devices Rafael J. Wysocki
2009-08-18  6:57     ` Zhang Rui
2009-08-18  6:57     ` Zhang Rui
2009-08-18  6:57       ` Zhang Rui
2009-08-18 13:47       ` Alan Stern
2009-08-18 13:47       ` Alan Stern
2009-08-17  0:20   ` Rafael J. Wysocki
2009-08-17  0:20   ` [RFC][PATCH 6/7] PM: Asynchronous suspend and resume of ACPI devices Rafael J. Wysocki
2009-08-17  0:20   ` Rafael J. Wysocki
2009-08-17  0:21   ` [RFC][PATCH 7/7] PM: Asynchronous suspend and resume of i8042 Rafael J. Wysocki
2009-08-17  0:21   ` Rafael J. Wysocki
2009-08-18  7:03     ` Zhang Rui
2009-08-18  7:03     ` Zhang Rui
2009-08-18  7:03       ` Zhang Rui
2009-08-18 19:57       ` Rafael J. Wysocki
2009-08-18 19:57       ` Rafael J. Wysocki
2009-08-18 23:40         ` Rafael J. Wysocki
2009-08-18 23:40           ` Rafael J. Wysocki
2009-08-18 23:40         ` Rafael J. Wysocki
2009-08-26 15:43       ` Pavel Machek
2009-08-26 15:43       ` Pavel Machek
2009-08-18  1:59   ` [RFC][PATCH 0/7] PM: Asynchronous suspend and resume (updated) Zhang Rui
2009-08-18  1:59   ` Zhang Rui
2009-08-18  7:16   ` Zhang Rui
2009-08-18  7:16     ` Zhang Rui
2009-08-18 20:01     ` Rafael J. Wysocki
2009-08-18 20:01       ` Rafael J. Wysocki
2009-08-18 23:58       ` Rafael J. Wysocki
2009-08-18 23:58       ` Rafael J. Wysocki
2009-08-18 23:58         ` Rafael J. Wysocki
2009-08-19  1:05         ` Zhang Rui
2009-08-19  1:05         ` Zhang Rui
2009-08-19  1:05           ` Zhang Rui
2009-08-19 21:02           ` Rafael J. Wysocki
2009-08-19 21:02           ` Rafael J. Wysocki
2009-08-21  7:40             ` Zhang Rui
2009-08-21  7:40             ` Zhang Rui
2009-08-18 20:01     ` Rafael J. Wysocki
2009-08-26 15:44     ` Pavel Machek
2009-08-26 15:44     ` Pavel Machek
2009-08-18  7:16   ` Zhang Rui
2009-08-18 14:04   ` Alan Stern
2009-08-18 19:56     ` Rafael J. Wysocki
2009-08-18 20:22       ` Alan Stern
2009-08-18 20:22       ` Alan Stern
2009-08-18 22:33         ` Rafael J. Wysocki
2009-08-18 22:33         ` Rafael J. Wysocki
2009-08-19 14:07           ` Alan Stern
2009-08-19 14:07           ` Alan Stern
2009-08-19 21:17             ` Rafael J. Wysocki
2009-08-19 22:34               ` Alan Stern
2009-08-20 15:56                 ` Rafael J. Wysocki
2009-08-20 15:56                 ` Rafael J. Wysocki
2009-08-19 22:34               ` Alan Stern
2009-08-19 21:17             ` Rafael J. Wysocki
2009-08-18 19:56     ` Rafael J. Wysocki
2009-08-26 13:20     ` Pavel Machek
2009-08-26 13:20     ` Pavel Machek
2009-08-18 14:04   ` 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=200908122221.20568.rjw@sisk.pl \
    --to=rjw@sisk.pl \
    --cc=arjan@linux.intel.com \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@lists.linux-foundation.org \
    --cc=rui.zhang@intel.com \
    --cc=stern@rowland.harvard.edu \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.