Skip to content

Commit 9659cc0

Browse files
committed
PM: Make system-wide PM and runtime PM treat subsystems consistently
The code handling system-wide power transitions (eg. suspend-to-RAM) can in theory execute callbacks provided by the device's bus type, device type and class in each phase of the power transition. In turn, the runtime PM core code only calls one of those callbacks at a time, preferring bus type callbacks to device type or class callbacks and device type callbacks to class callbacks. It seems reasonable to make them both behave in the same way in that respect. Moreover, even though a device may belong to two subsystems (eg. bus type and device class) simultaneously, in practice power management callbacks for system-wide power transitions are always provided by only one of them (ie. if the bus type callbacks are defined, the device class ones are not and vice versa). Thus it is possible to modify the code handling system-wide power transitions so that it follows the core runtime PM code (ie. treats the subsystem callbacks as mutually exclusive). On the other hand, the core runtime PM code will choose to execute, for example, a runtime suspend callback provided by the device type even if the bus type's struct dev_pm_ops object exists, but the runtime_suspend pointer in it happens to be NULL. This is confusing, because it may lead to the execution of callbacks from different subsystems during different operations (eg. the bus type suspend callback may be executed during runtime suspend of the device, while the device type callback will be executed during system suspend). Make all of the power management code treat subsystem callbacks in a consistent way, such that: (1) If the device's type is defined (eg. dev->type is not NULL) and its pm pointer is not NULL, the callbacks from dev->type->pm will be used. (2) If dev->type is NULL or dev->type->pm is NULL, but the device's class is defined (eg. dev->class is not NULL) and its pm pointer is not NULL, the callbacks from dev->class->pm will be used. (3) If dev->type is NULL or dev->type->pm is NULL and dev->class is NULL or dev->class->pm is NULL, the callbacks from dev->bus->pm will be used provided that both dev->bus and dev->bus->pm are not NULL. Signed-off-by: Rafael J. Wysocki <[email protected]> Acked-by: Kevin Hilman <[email protected]> Reasoning-sounds-sane-to: Grant Likely <[email protected]> Acked-by: Greg Kroah-Hartman <[email protected]>
1 parent cf4fb80 commit 9659cc0

File tree

4 files changed

+92
-118
lines changed

4 files changed

+92
-118
lines changed

Documentation/power/devices.txt

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -249,23 +249,18 @@ various phases always run after tasks have been frozen and before they are
249249
unfrozen. Furthermore, the *_noirq phases run at a time when IRQ handlers have
250250
been disabled (except for those marked with the IRQ_WAKEUP flag).
251251

252-
Most phases use bus, type, and class callbacks (that is, methods defined in
253-
dev->bus->pm, dev->type->pm, and dev->class->pm). The prepare and complete
254-
phases are exceptions; they use only bus callbacks. When multiple callbacks
255-
are used in a phase, they are invoked in the order: <class, type, bus> during
256-
power-down transitions and in the opposite order during power-up transitions.
257-
For example, during the suspend phase the PM core invokes
258-
259-
dev->class->pm.suspend(dev);
260-
dev->type->pm.suspend(dev);
261-
dev->bus->pm.suspend(dev);
262-
263-
before moving on to the next device, whereas during the resume phase the core
264-
invokes
265-
266-
dev->bus->pm.resume(dev);
267-
dev->type->pm.resume(dev);
268-
dev->class->pm.resume(dev);
252+
All phases use bus, type, or class callbacks (that is, methods defined in
253+
dev->bus->pm, dev->type->pm, or dev->class->pm). These callbacks are mutually
254+
exclusive, so if the device type provides a struct dev_pm_ops object pointed to
255+
by its pm field (i.e. both dev->type and dev->type->pm are defined), the
256+
callbacks included in that object (i.e. dev->type->pm) will be used. Otherwise,
257+
if the class provides a struct dev_pm_ops object pointed to by its pm field
258+
(i.e. both dev->class and dev->class->pm are defined), the PM core will use the
259+
callbacks from that object (i.e. dev->class->pm). Finally, if the pm fields of
260+
both the device type and class objects are NULL (or those objects do not exist),
261+
the callbacks provided by the bus (that is, the callbacks from dev->bus->pm)
262+
will be used (this allows device types to override callbacks provided by bus
263+
types or classes if necessary).
269264

270265
These callbacks may in turn invoke device- or driver-specific methods stored in
271266
dev->driver->pm, but they don't have to.

Documentation/power/runtime_pm.txt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Run-time Power Management Framework for I/O Devices
22

3-
(C) 2009 Rafael J. Wysocki <[email protected]>, Novell Inc.
3+
(C) 2009-2011 Rafael J. Wysocki <[email protected]>, Novell Inc.
44
(C) 2010 Alan Stern <[email protected]>
55

66
1. Introduction
@@ -44,11 +44,12 @@ struct dev_pm_ops {
4444
};
4545

4646
The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are
47-
executed by the PM core for either the bus type, or device type (if the bus
48-
type's callback is not defined), or device class (if the bus type's and device
49-
type's callbacks are not defined) of given device. The bus type, device type
50-
and device class callbacks are referred to as subsystem-level callbacks in what
51-
follows.
47+
executed by the PM core for either the device type, or the class (if the device
48+
type's struct dev_pm_ops object does not exist), or the bus type (if the
49+
device type's and class' struct dev_pm_ops objects do not exist) of the given
50+
device (this allows device types to override callbacks provided by bus types or
51+
classes if necessary). The bus type, device type and class callbacks are
52+
referred to as subsystem-level callbacks in what follows.
5253

5354
By default, the callbacks are always invoked in process context with interrupts
5455
enabled. However, subsystems can use the pm_runtime_irq_safe() helper function

drivers/base/power/main.c

Lines changed: 64 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -428,26 +428,17 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
428428
pm_noirq_op(dev, &dev->pwr_domain->ops, state);
429429
}
430430

431-
if (dev->bus && dev->bus->pm) {
432-
pm_dev_dbg(dev, state, "EARLY ");
433-
error = pm_noirq_op(dev, dev->bus->pm, state);
434-
if (error)
435-
goto End;
436-
}
437-
438431
if (dev->type && dev->type->pm) {
439432
pm_dev_dbg(dev, state, "EARLY type ");
440433
error = pm_noirq_op(dev, dev->type->pm, state);
441-
if (error)
442-
goto End;
443-
}
444-
445-
if (dev->class && dev->class->pm) {
434+
} else if (dev->class && dev->class->pm) {
446435
pm_dev_dbg(dev, state, "EARLY class ");
447436
error = pm_noirq_op(dev, dev->class->pm, state);
437+
} else if (dev->bus && dev->bus->pm) {
438+
pm_dev_dbg(dev, state, "EARLY ");
439+
error = pm_noirq_op(dev, dev->bus->pm, state);
448440
}
449441

450-
End:
451442
TRACE_RESUME(error);
452443
return error;
453444
}
@@ -528,36 +519,34 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
528519
pm_op(dev, &dev->pwr_domain->ops, state);
529520
}
530521

531-
if (dev->bus) {
532-
if (dev->bus->pm) {
533-
pm_dev_dbg(dev, state, "");
534-
error = pm_op(dev, dev->bus->pm, state);
535-
} else if (dev->bus->resume) {
536-
pm_dev_dbg(dev, state, "legacy ");
537-
error = legacy_resume(dev, dev->bus->resume);
538-
}
539-
if (error)
540-
goto End;
541-
}
542-
543-
if (dev->type) {
544-
if (dev->type->pm) {
545-
pm_dev_dbg(dev, state, "type ");
546-
error = pm_op(dev, dev->type->pm, state);
547-
}
548-
if (error)
549-
goto End;
522+
if (dev->type && dev->type->pm) {
523+
pm_dev_dbg(dev, state, "type ");
524+
error = pm_op(dev, dev->type->pm, state);
525+
goto End;
550526
}
551527

552528
if (dev->class) {
553529
if (dev->class->pm) {
554530
pm_dev_dbg(dev, state, "class ");
555531
error = pm_op(dev, dev->class->pm, state);
532+
goto End;
556533
} else if (dev->class->resume) {
557534
pm_dev_dbg(dev, state, "legacy class ");
558535
error = legacy_resume(dev, dev->class->resume);
536+
goto End;
559537
}
560538
}
539+
540+
if (dev->bus) {
541+
if (dev->bus->pm) {
542+
pm_dev_dbg(dev, state, "");
543+
error = pm_op(dev, dev->bus->pm, state);
544+
} else if (dev->bus->resume) {
545+
pm_dev_dbg(dev, state, "legacy ");
546+
error = legacy_resume(dev, dev->bus->resume);
547+
}
548+
}
549+
561550
End:
562551
device_unlock(dev);
563552
complete_all(&dev->power.completion);
@@ -644,19 +633,18 @@ static void device_complete(struct device *dev, pm_message_t state)
644633
dev->pwr_domain->ops.complete(dev);
645634
}
646635

647-
if (dev->class && dev->class->pm && dev->class->pm->complete) {
648-
pm_dev_dbg(dev, state, "completing class ");
649-
dev->class->pm->complete(dev);
650-
}
651-
652-
if (dev->type && dev->type->pm && dev->type->pm->complete) {
636+
if (dev->type && dev->type->pm) {
653637
pm_dev_dbg(dev, state, "completing type ");
654-
dev->type->pm->complete(dev);
655-
}
656-
657-
if (dev->bus && dev->bus->pm && dev->bus->pm->complete) {
638+
if (dev->type->pm->complete)
639+
dev->type->pm->complete(dev);
640+
} else if (dev->class && dev->class->pm) {
641+
pm_dev_dbg(dev, state, "completing class ");
642+
if (dev->class->pm->complete)
643+
dev->class->pm->complete(dev);
644+
} else if (dev->bus && dev->bus->pm) {
658645
pm_dev_dbg(dev, state, "completing ");
659-
dev->bus->pm->complete(dev);
646+
if (dev->bus->pm->complete)
647+
dev->bus->pm->complete(dev);
660648
}
661649

662650
device_unlock(dev);
@@ -741,36 +729,31 @@ static pm_message_t resume_event(pm_message_t sleep_state)
741729
*/
742730
static int device_suspend_noirq(struct device *dev, pm_message_t state)
743731
{
744-
int error = 0;
745-
746-
if (dev->class && dev->class->pm) {
747-
pm_dev_dbg(dev, state, "LATE class ");
748-
error = pm_noirq_op(dev, dev->class->pm, state);
749-
if (error)
750-
goto End;
751-
}
732+
int error;
752733

753734
if (dev->type && dev->type->pm) {
754735
pm_dev_dbg(dev, state, "LATE type ");
755736
error = pm_noirq_op(dev, dev->type->pm, state);
756737
if (error)
757-
goto End;
758-
}
759-
760-
if (dev->bus && dev->bus->pm) {
738+
return error;
739+
} else if (dev->class && dev->class->pm) {
740+
pm_dev_dbg(dev, state, "LATE class ");
741+
error = pm_noirq_op(dev, dev->class->pm, state);
742+
if (error)
743+
return error;
744+
} else if (dev->bus && dev->bus->pm) {
761745
pm_dev_dbg(dev, state, "LATE ");
762746
error = pm_noirq_op(dev, dev->bus->pm, state);
763747
if (error)
764-
goto End;
748+
return error;
765749
}
766750

767751
if (dev->pwr_domain) {
768752
pm_dev_dbg(dev, state, "LATE power domain ");
769753
pm_noirq_op(dev, &dev->pwr_domain->ops, state);
770754
}
771755

772-
End:
773-
return error;
756+
return 0;
774757
}
775758

776759
/**
@@ -857,25 +840,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
857840
goto End;
858841
}
859842

843+
if (dev->type && dev->type->pm) {
844+
pm_dev_dbg(dev, state, "type ");
845+
error = pm_op(dev, dev->type->pm, state);
846+
goto Domain;
847+
}
848+
860849
if (dev->class) {
861850
if (dev->class->pm) {
862851
pm_dev_dbg(dev, state, "class ");
863852
error = pm_op(dev, dev->class->pm, state);
853+
goto Domain;
864854
} else if (dev->class->suspend) {
865855
pm_dev_dbg(dev, state, "legacy class ");
866856
error = legacy_suspend(dev, state, dev->class->suspend);
857+
goto Domain;
867858
}
868-
if (error)
869-
goto End;
870-
}
871-
872-
if (dev->type) {
873-
if (dev->type->pm) {
874-
pm_dev_dbg(dev, state, "type ");
875-
error = pm_op(dev, dev->type->pm, state);
876-
}
877-
if (error)
878-
goto End;
879859
}
880860

881861
if (dev->bus) {
@@ -886,11 +866,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
886866
pm_dev_dbg(dev, state, "legacy ");
887867
error = legacy_suspend(dev, state, dev->bus->suspend);
888868
}
889-
if (error)
890-
goto End;
891869
}
892870

893-
if (dev->pwr_domain) {
871+
Domain:
872+
if (!error && dev->pwr_domain) {
894873
pm_dev_dbg(dev, state, "power domain ");
895874
pm_op(dev, &dev->pwr_domain->ops, state);
896875
}
@@ -985,28 +964,27 @@ static int device_prepare(struct device *dev, pm_message_t state)
985964

986965
device_lock(dev);
987966

988-
if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) {
989-
pm_dev_dbg(dev, state, "preparing ");
990-
error = dev->bus->pm->prepare(dev);
991-
suspend_report_result(dev->bus->pm->prepare, error);
992-
if (error)
993-
goto End;
994-
}
995-
996-
if (dev->type && dev->type->pm && dev->type->pm->prepare) {
967+
if (dev->type && dev->type->pm) {
997968
pm_dev_dbg(dev, state, "preparing type ");
998-
error = dev->type->pm->prepare(dev);
969+
if (dev->type->pm->prepare)
970+
error = dev->type->pm->prepare(dev);
999971
suspend_report_result(dev->type->pm->prepare, error);
1000972
if (error)
1001973
goto End;
1002-
}
1003-
1004-
if (dev->class && dev->class->pm && dev->class->pm->prepare) {
974+
} else if (dev->class && dev->class->pm) {
1005975
pm_dev_dbg(dev, state, "preparing class ");
1006-
error = dev->class->pm->prepare(dev);
976+
if (dev->class->pm->prepare)
977+
error = dev->class->pm->prepare(dev);
1007978
suspend_report_result(dev->class->pm->prepare, error);
1008979
if (error)
1009980
goto End;
981+
} else if (dev->bus && dev->bus->pm) {
982+
pm_dev_dbg(dev, state, "preparing ");
983+
if (dev->bus->pm->prepare)
984+
error = dev->bus->pm->prepare(dev);
985+
suspend_report_result(dev->bus->pm->prepare, error);
986+
if (error)
987+
goto End;
1010988
}
1011989

1012990
if (dev->pwr_domain && dev->pwr_domain->ops.prepare) {

drivers/base/power/runtime.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,12 @@ static int rpm_idle(struct device *dev, int rpmflags)
214214

215215
dev->power.idle_notification = true;
216216

217-
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle)
218-
callback = dev->bus->pm->runtime_idle;
219-
else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle)
217+
if (dev->type && dev->type->pm)
220218
callback = dev->type->pm->runtime_idle;
221219
else if (dev->class && dev->class->pm)
222220
callback = dev->class->pm->runtime_idle;
221+
else if (dev->bus && dev->bus->pm)
222+
callback = dev->bus->pm->runtime_idle;
223223
else
224224
callback = NULL;
225225

@@ -382,12 +382,12 @@ static int rpm_suspend(struct device *dev, int rpmflags)
382382

383383
__update_runtime_status(dev, RPM_SUSPENDING);
384384

385-
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
386-
callback = dev->bus->pm->runtime_suspend;
387-
else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend)
385+
if (dev->type && dev->type->pm)
388386
callback = dev->type->pm->runtime_suspend;
389387
else if (dev->class && dev->class->pm)
390388
callback = dev->class->pm->runtime_suspend;
389+
else if (dev->bus && dev->bus->pm)
390+
callback = dev->bus->pm->runtime_suspend;
391391
else
392392
callback = NULL;
393393

@@ -584,12 +584,12 @@ static int rpm_resume(struct device *dev, int rpmflags)
584584
if (dev->pwr_domain)
585585
rpm_callback(dev->pwr_domain->ops.runtime_resume, dev);
586586

587-
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
588-
callback = dev->bus->pm->runtime_resume;
589-
else if (dev->type && dev->type->pm && dev->type->pm->runtime_resume)
587+
if (dev->type && dev->type->pm)
590588
callback = dev->type->pm->runtime_resume;
591589
else if (dev->class && dev->class->pm)
592590
callback = dev->class->pm->runtime_resume;
591+
else if (dev->bus && dev->bus->pm)
592+
callback = dev->bus->pm->runtime_resume;
593593
else
594594
callback = NULL;
595595

0 commit comments

Comments
 (0)