Skip to content

Commit 76569fa

Browse files
Chuansheng-Liurafaeljw
authored andcommitted
PM / sleep: Asynchronous threads for resume_noirq
In analogy with commits 5af84b8 and 97df8c1, using asynchronous threads can improve the overall resume_noirq time significantly. One typical case is: In resume_noirq phase and for the PCI devices, the function pci_pm_resume_noirq() will be called, and there is one d3_delay (10ms) at least. With the way of asynchronous threads, we just need wait d3_delay time once in parallel for each calling, which saves much time to resume quickly. Signed-off-by: Chuansheng Liu <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 3d2699b commit 76569fa

File tree

1 file changed

+50
-16
lines changed

1 file changed

+50
-16
lines changed

drivers/base/power/main.c

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
469469
* The driver of @dev will not receive interrupts while this function is being
470470
* executed.
471471
*/
472-
static int device_resume_noirq(struct device *dev, pm_message_t state)
472+
static int device_resume_noirq(struct device *dev, pm_message_t state, bool async)
473473
{
474474
pm_callback_t callback = NULL;
475475
char *info = NULL;
@@ -484,6 +484,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
484484
if (!dev->power.is_noirq_suspended)
485485
goto Out;
486486

487+
dpm_wait(dev->parent, async);
488+
487489
if (dev->pm_domain) {
488490
info = "noirq power domain ";
489491
callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -507,10 +509,29 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
507509
dev->power.is_noirq_suspended = false;
508510

509511
Out:
512+
complete_all(&dev->power.completion);
510513
TRACE_RESUME(error);
511514
return error;
512515
}
513516

517+
static bool is_async(struct device *dev)
518+
{
519+
return dev->power.async_suspend && pm_async_enabled
520+
&& !pm_trace_is_enabled();
521+
}
522+
523+
static void async_resume_noirq(void *data, async_cookie_t cookie)
524+
{
525+
struct device *dev = (struct device *)data;
526+
int error;
527+
528+
error = device_resume_noirq(dev, pm_transition, true);
529+
if (error)
530+
pm_dev_err(dev, pm_transition, " async", error);
531+
532+
put_device(dev);
533+
}
534+
514535
/**
515536
* dpm_resume_noirq - Execute "noirq resume" callbacks for all devices.
516537
* @state: PM transition of the system being carried out.
@@ -520,29 +541,48 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
520541
*/
521542
static void dpm_resume_noirq(pm_message_t state)
522543
{
544+
struct device *dev;
523545
ktime_t starttime = ktime_get();
524546

525547
mutex_lock(&dpm_list_mtx);
526-
while (!list_empty(&dpm_noirq_list)) {
527-
struct device *dev = to_device(dpm_noirq_list.next);
528-
int error;
548+
pm_transition = state;
549+
550+
/*
551+
* Advanced the async threads upfront,
552+
* in case the starting of async threads is
553+
* delayed by non-async resuming devices.
554+
*/
555+
list_for_each_entry(dev, &dpm_noirq_list, power.entry) {
556+
reinit_completion(&dev->power.completion);
557+
if (is_async(dev)) {
558+
get_device(dev);
559+
async_schedule(async_resume_noirq, dev);
560+
}
561+
}
529562

563+
while (!list_empty(&dpm_noirq_list)) {
564+
dev = to_device(dpm_noirq_list.next);
530565
get_device(dev);
531566
list_move_tail(&dev->power.entry, &dpm_late_early_list);
532567
mutex_unlock(&dpm_list_mtx);
533568

534-
error = device_resume_noirq(dev, state);
535-
if (error) {
536-
suspend_stats.failed_resume_noirq++;
537-
dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
538-
dpm_save_failed_dev(dev_name(dev));
539-
pm_dev_err(dev, state, " noirq", error);
569+
if (!is_async(dev)) {
570+
int error;
571+
572+
error = device_resume_noirq(dev, state, false);
573+
if (error) {
574+
suspend_stats.failed_resume_noirq++;
575+
dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
576+
dpm_save_failed_dev(dev_name(dev));
577+
pm_dev_err(dev, state, " noirq", error);
578+
}
540579
}
541580

542581
mutex_lock(&dpm_list_mtx);
543582
put_device(dev);
544583
}
545584
mutex_unlock(&dpm_list_mtx);
585+
async_synchronize_full();
546586
dpm_show_time(starttime, state, "noirq");
547587
resume_device_irqs();
548588
cpuidle_resume();
@@ -742,12 +782,6 @@ static void async_resume(void *data, async_cookie_t cookie)
742782
put_device(dev);
743783
}
744784

745-
static bool is_async(struct device *dev)
746-
{
747-
return dev->power.async_suspend && pm_async_enabled
748-
&& !pm_trace_is_enabled();
749-
}
750-
751785
/**
752786
* dpm_resume - Execute "resume" callbacks for non-sysdev devices.
753787
* @state: PM transition of the system being carried out.

0 commit comments

Comments
 (0)