From: Kaiyen Chang <kaiyen.chang@intel.com>
To: rafael@kernel.org, pavel@ucw.cz, len.brown@intel.com,
gregkh@linuxfoundation.org, linux-pm@vger.kernel.org,
linux-kernel@vger.kernel.org
Cc: kaiyen.chang@intel.com
Subject: [PATCH v2 1/1] PM: Start asynchronous suspend threads upfront
Date: Tue, 18 Jun 2024 20:13:27 +0800 [thread overview]
Message-ID: <20240618121327.2177-2-kaiyen.chang@intel.com> (raw)
In-Reply-To: <20240618121327.2177-1-kaiyen.chang@intel.com>
Currently, when performing a suspend operation, all devices on the
dpm_list must wait for the "synchronous" devices that are listed
after them to complete before the main suspend thread can start
their suspend routines, even if they are "asynchronous". If the
suspend routine of a synchronous device must enter a waiting state
for some reason, it will cause the main suspend thread to go to
sleep, thereby delaying the processing of all subsequent devices,
including asynchronous ones, ultimately extending the overall
suspend time.
By starting the asynchronous suspend threads upfront, we can allow
the system to handle the suspend routines of these asynchronous
devices in parallel, without waiting for the suspend routines of
the synchronous devices listed after them to complete, and without
breaking their order with respect to their parents and children.
This way, even if the main suspend thread is blocked, these
asynchronous suspend threads can continue to run without being
affected.
Signed-off-by: Kaiyen Chang <kaiyen.chang@intel.com>
---
Change from v1: Fix some unclear parts in the commit messages.
---
drivers/base/power/main.c | 90 +++++++++++++++++++++++++--------------
1 file changed, 57 insertions(+), 33 deletions(-)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 4a67e83300e1..6ddd6ef36625 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1283,6 +1283,7 @@ static void async_suspend_noirq(void *data, async_cookie_t cookie)
static int dpm_noirq_suspend_devices(pm_message_t state)
{
+ struct device *dev;
ktime_t starttime = ktime_get();
int error = 0;
@@ -1293,26 +1294,33 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
mutex_lock(&dpm_list_mtx);
+ /*
+ * Trigger the suspend of "async" devices upfront so they don't have to
+ * wait for the "non-async" ones that don't depend on them.
+ */
+
+ list_for_each_entry_reverse(dev, &dpm_late_early_list, power.entry)
+ dpm_async_fn(dev, async_suspend_noirq);
+
while (!list_empty(&dpm_late_early_list)) {
- struct device *dev = to_device(dpm_late_early_list.prev);
+ dev = to_device(dpm_late_early_list.prev);
list_move(&dev->power.entry, &dpm_noirq_list);
- if (dpm_async_fn(dev, async_suspend_noirq))
- continue;
-
- get_device(dev);
+ if (!dev->power.async_in_progress) {
+ get_device(dev);
- mutex_unlock(&dpm_list_mtx);
+ mutex_unlock(&dpm_list_mtx);
- error = device_suspend_noirq(dev, state, false);
+ error = device_suspend_noirq(dev, state, false);
- put_device(dev);
+ put_device(dev);
- mutex_lock(&dpm_list_mtx);
+ mutex_lock(&dpm_list_mtx);
- if (error || async_error)
- break;
+ if (error || async_error)
+ break;
+ }
}
mutex_unlock(&dpm_list_mtx);
@@ -1454,6 +1462,7 @@ static void async_suspend_late(void *data, async_cookie_t cookie)
*/
int dpm_suspend_late(pm_message_t state)
{
+ struct device *dev;
ktime_t starttime = ktime_get();
int error = 0;
@@ -1466,26 +1475,33 @@ int dpm_suspend_late(pm_message_t state)
mutex_lock(&dpm_list_mtx);
+ /*
+ * Trigger the suspend of "async" devices upfront so they don't have to
+ * wait for the "non-async" ones that don't depend on them.
+ */
+
+ list_for_each_entry_reverse(dev, &dpm_suspended_list, power.entry)
+ dpm_async_fn(dev, async_suspend_late);
+
while (!list_empty(&dpm_suspended_list)) {
- struct device *dev = to_device(dpm_suspended_list.prev);
+ dev = to_device(dpm_suspended_list.prev);
list_move(&dev->power.entry, &dpm_late_early_list);
- if (dpm_async_fn(dev, async_suspend_late))
- continue;
-
- get_device(dev);
+ if (!dev->power.async_in_progress) {
+ get_device(dev);
- mutex_unlock(&dpm_list_mtx);
+ mutex_unlock(&dpm_list_mtx);
- error = device_suspend_late(dev, state, false);
+ error = device_suspend_late(dev, state, false);
- put_device(dev);
+ put_device(dev);
- mutex_lock(&dpm_list_mtx);
+ mutex_lock(&dpm_list_mtx);
- if (error || async_error)
- break;
+ if (error || async_error)
+ break;
+ }
}
mutex_unlock(&dpm_list_mtx);
@@ -1719,6 +1735,7 @@ static void async_suspend(void *data, async_cookie_t cookie)
*/
int dpm_suspend(pm_message_t state)
{
+ struct device *dev;
ktime_t starttime = ktime_get();
int error = 0;
@@ -1733,26 +1750,33 @@ int dpm_suspend(pm_message_t state)
mutex_lock(&dpm_list_mtx);
+ /*
+ * Trigger the suspend of "async" devices upfront so they don't have to
+ * wait for the "non-async" ones that don't depend on them.
+ */
+
+ list_for_each_entry_reverse(dev, &dpm_prepared_list, power.entry)
+ dpm_async_fn(dev, async_suspend);
+
while (!list_empty(&dpm_prepared_list)) {
- struct device *dev = to_device(dpm_prepared_list.prev);
+ dev = to_device(dpm_prepared_list.prev);
list_move(&dev->power.entry, &dpm_suspended_list);
- if (dpm_async_fn(dev, async_suspend))
- continue;
-
- get_device(dev);
+ if (!dev->power.async_in_progress) {
+ get_device(dev);
- mutex_unlock(&dpm_list_mtx);
+ mutex_unlock(&dpm_list_mtx);
- error = device_suspend(dev, state, false);
+ error = device_suspend(dev, state, false);
- put_device(dev);
+ put_device(dev);
- mutex_lock(&dpm_list_mtx);
+ mutex_lock(&dpm_list_mtx);
- if (error || async_error)
- break;
+ if (error || async_error)
+ break;
+ }
}
mutex_unlock(&dpm_list_mtx);
--
2.34.1
next prev parent reply other threads:[~2024-06-18 12:13 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-18 12:13 [PATCH v2 0/1] PM: Start asynchronous suspend threads upfront Kaiyen Chang
2024-06-18 12:13 ` Kaiyen Chang [this message]
2024-06-18 17:27 ` [PATCH v2 1/1] " Rafael J. Wysocki
2024-06-20 9:21 ` Chang, Kaiyen
2024-07-02 13:20 ` Rafael J. Wysocki
2024-08-16 8:33 ` Chang, Kaiyen
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=20240618121327.2177-2-kaiyen.chang@intel.com \
--to=kaiyen.chang@intel.com \
--cc=gregkh@linuxfoundation.org \
--cc=len.brown@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=pavel@ucw.cz \
--cc=rafael@kernel.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