Skip to content

Commit 97df8c1

Browse files
committed
PM: Start asynchronous resume threads upfront
It has been shown by testing that total device resume time can be reduced significantly (by as much as 50% or more) if the async threads executing some devices' resume routines are all started before the main resume thread starts to handle the "synchronous" devices. This is a consequence of the fact that the slowest devices tend to be located at the end of dpm_list, so their resume routines are started very late. Consequently, they have to wait for all the preceding "synchronous" devices before their resume routines can be started by the main resume thread, even if they are "asynchronous". By starting their async threads upfront we effectively move those devices towards the beginning of dpm_list, without breaking their ordering with respect to their parents and children. As a result, their resume routines are started much earlier and we are able to save much more device resume time this way. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
1 parent 5a2eb85 commit 97df8c1

File tree

1 file changed

+24
-19
lines changed

1 file changed

+24
-19
lines changed

drivers/base/power/main.c

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -495,12 +495,12 @@ static int legacy_resume(struct device *dev, int (*cb)(struct device *dev))
495495
}
496496

497497
/**
498-
* __device_resume - Execute "resume" callbacks for given device.
498+
* device_resume - Execute "resume" callbacks for given device.
499499
* @dev: Device to handle.
500500
* @state: PM transition of the system being carried out.
501501
* @async: If true, the device is being resumed asynchronously.
502502
*/
503-
static int __device_resume(struct device *dev, pm_message_t state, bool async)
503+
static int device_resume(struct device *dev, pm_message_t state, bool async)
504504
{
505505
int error = 0;
506506

@@ -510,6 +510,8 @@ static int __device_resume(struct device *dev, pm_message_t state, bool async)
510510
dpm_wait(dev->parent, async);
511511
down(&dev->sem);
512512

513+
dev->power.status = DPM_RESUMING;
514+
513515
if (dev->bus) {
514516
if (dev->bus->pm) {
515517
pm_dev_dbg(dev, state, "");
@@ -553,24 +555,16 @@ static void async_resume(void *data, async_cookie_t cookie)
553555
struct device *dev = (struct device *)data;
554556
int error;
555557

556-
error = __device_resume(dev, pm_transition, true);
558+
error = device_resume(dev, pm_transition, true);
557559
if (error)
558560
pm_dev_err(dev, pm_transition, " async", error);
559561
put_device(dev);
560562
}
561563

562-
static int device_resume(struct device *dev)
564+
static bool is_async(struct device *dev)
563565
{
564-
INIT_COMPLETION(dev->power.completion);
565-
566-
if (pm_async_enabled && dev->power.async_suspend
567-
&& !pm_trace_is_enabled()) {
568-
get_device(dev);
569-
async_schedule(async_resume, dev);
570-
return 0;
571-
}
572-
573-
return __device_resume(dev, pm_transition, false);
566+
return dev->power.async_suspend && pm_async_enabled
567+
&& !pm_trace_is_enabled();
574568
}
575569

576570
/**
@@ -583,22 +577,33 @@ static int device_resume(struct device *dev)
583577
static void dpm_resume(pm_message_t state)
584578
{
585579
struct list_head list;
580+
struct device *dev;
586581
ktime_t starttime = ktime_get();
587582

588583
INIT_LIST_HEAD(&list);
589584
mutex_lock(&dpm_list_mtx);
590585
pm_transition = state;
591-
while (!list_empty(&dpm_list)) {
592-
struct device *dev = to_device(dpm_list.next);
593586

587+
list_for_each_entry(dev, &dpm_list, power.entry) {
588+
if (dev->power.status < DPM_OFF)
589+
continue;
590+
591+
INIT_COMPLETION(dev->power.completion);
592+
if (is_async(dev)) {
593+
get_device(dev);
594+
async_schedule(async_resume, dev);
595+
}
596+
}
597+
598+
while (!list_empty(&dpm_list)) {
599+
dev = to_device(dpm_list.next);
594600
get_device(dev);
595-
if (dev->power.status >= DPM_OFF) {
601+
if (dev->power.status >= DPM_OFF && !is_async(dev)) {
596602
int error;
597603

598-
dev->power.status = DPM_RESUMING;
599604
mutex_unlock(&dpm_list_mtx);
600605

601-
error = device_resume(dev);
606+
error = device_resume(dev, state, false);
602607

603608
mutex_lock(&dpm_list_mtx);
604609
if (error)

0 commit comments

Comments
 (0)