aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-02-18 17:20:21 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-03-14 19:43:17 -0400
commit9659cc0678b954f187290c6e8b247a673c5d37e1 (patch)
treeb9b391d2397b0583757dd1529a85d714dbb81697
parentcf4fb80ca3d591cae366ae8364e3c3f7a68bd249 (diff)
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 <rjw@sisk.pl> Acked-by: Kevin Hilman <khilman@ti.com> Reasoning-sounds-sane-to: Grant Likely <grant.likely@secretlab.ca> Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--Documentation/power/devices.txt29
-rw-r--r--Documentation/power/runtime_pm.txt13
-rw-r--r--drivers/base/power/main.c150
-rw-r--r--drivers/base/power/runtime.c18
4 files changed, 92 insertions, 118 deletions
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index df1a5cb10c42..f023ba6bba62 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -249,23 +249,18 @@ various phases always run after tasks have been frozen and before they are
249unfrozen. Furthermore, the *_noirq phases run at a time when IRQ handlers have 249unfrozen. Furthermore, the *_noirq phases run at a time when IRQ handlers have
250been disabled (except for those marked with the IRQ_WAKEUP flag). 250been disabled (except for those marked with the IRQ_WAKEUP flag).
251 251
252Most phases use bus, type, and class callbacks (that is, methods defined in 252All phases use bus, type, or class callbacks (that is, methods defined in
253dev->bus->pm, dev->type->pm, and dev->class->pm). The prepare and complete 253dev->bus->pm, dev->type->pm, or dev->class->pm). These callbacks are mutually
254phases are exceptions; they use only bus callbacks. When multiple callbacks 254exclusive, so if the device type provides a struct dev_pm_ops object pointed to
255are used in a phase, they are invoked in the order: <class, type, bus> during 255by its pm field (i.e. both dev->type and dev->type->pm are defined), the
256power-down transitions and in the opposite order during power-up transitions. 256callbacks included in that object (i.e. dev->type->pm) will be used. Otherwise,
257For example, during the suspend phase the PM core invokes 257if the class provides a struct dev_pm_ops object pointed to by its pm field
258 258(i.e. both dev->class and dev->class->pm are defined), the PM core will use the
259 dev->class->pm.suspend(dev); 259callbacks from that object (i.e. dev->class->pm). Finally, if the pm fields of
260 dev->type->pm.suspend(dev); 260both the device type and class objects are NULL (or those objects do not exist),
261 dev->bus->pm.suspend(dev); 261the callbacks provided by the bus (that is, the callbacks from dev->bus->pm)
262 262will be used (this allows device types to override callbacks provided by bus
263before moving on to the next device, whereas during the resume phase the core 263types or classes if necessary).
264invokes
265
266 dev->bus->pm.resume(dev);
267 dev->type->pm.resume(dev);
268 dev->class->pm.resume(dev);
269 264
270These callbacks may in turn invoke device- or driver-specific methods stored in 265These callbacks may in turn invoke device- or driver-specific methods stored in
271dev->driver->pm, but they don't have to. 266dev->driver->pm, but they don't have to.
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index ffe55ffa540a..654097b130b4 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -1,6 +1,6 @@
1Run-time Power Management Framework for I/O Devices 1Run-time Power Management Framework for I/O Devices
2 2
3(C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. 3(C) 2009-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
4(C) 2010 Alan Stern <stern@rowland.harvard.edu> 4(C) 2010 Alan Stern <stern@rowland.harvard.edu>
5 5
61. Introduction 61. Introduction
@@ -44,11 +44,12 @@ struct dev_pm_ops {
44}; 44};
45 45
46The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are 46The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are
47executed by the PM core for either the bus type, or device type (if the bus 47executed by the PM core for either the device type, or the class (if the device
48type's callback is not defined), or device class (if the bus type's and device 48type's struct dev_pm_ops object does not exist), or the bus type (if the
49type's callbacks are not defined) of given device. The bus type, device type 49device type's and class' struct dev_pm_ops objects do not exist) of the given
50and device class callbacks are referred to as subsystem-level callbacks in what 50device (this allows device types to override callbacks provided by bus types or
51follows. 51classes if necessary). The bus type, device type and class callbacks are
52referred to as subsystem-level callbacks in what follows.
52 53
53By default, the callbacks are always invoked in process context with interrupts 54By default, the callbacks are always invoked in process context with interrupts
54enabled. However, subsystems can use the pm_runtime_irq_safe() helper function 55enabled. However, subsystems can use the pm_runtime_irq_safe() helper function
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 05b989139b54..052dc53eef38 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -428,26 +428,17 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
428 pm_noirq_op(dev, &dev->pwr_domain->ops, state); 428 pm_noirq_op(dev, &dev->pwr_domain->ops, state);
429 } 429 }
430 430
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
438 if (dev->type && dev->type->pm) { 431 if (dev->type && dev->type->pm) {
439 pm_dev_dbg(dev, state, "EARLY type "); 432 pm_dev_dbg(dev, state, "EARLY type ");
440 error = pm_noirq_op(dev, dev->type->pm, state); 433 error = pm_noirq_op(dev, dev->type->pm, state);
441 if (error) 434 } else if (dev->class && dev->class->pm) {
442 goto End;
443 }
444
445 if (dev->class && dev->class->pm) {
446 pm_dev_dbg(dev, state, "EARLY class "); 435 pm_dev_dbg(dev, state, "EARLY class ");
447 error = pm_noirq_op(dev, dev->class->pm, state); 436 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);
448 } 440 }
449 441
450End:
451 TRACE_RESUME(error); 442 TRACE_RESUME(error);
452 return error; 443 return error;
453} 444}
@@ -528,36 +519,34 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
528 pm_op(dev, &dev->pwr_domain->ops, state); 519 pm_op(dev, &dev->pwr_domain->ops, state);
529 } 520 }
530 521
531 if (dev->bus) { 522 if (dev->type && dev->type->pm) {
532 if (dev->bus->pm) { 523 pm_dev_dbg(dev, state, "type ");
533 pm_dev_dbg(dev, state, ""); 524 error = pm_op(dev, dev->type->pm, state);
534 error = pm_op(dev, dev->bus->pm, state); 525 goto End;
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;
550 } 526 }
551 527
552 if (dev->class) { 528 if (dev->class) {
553 if (dev->class->pm) { 529 if (dev->class->pm) {
554 pm_dev_dbg(dev, state, "class "); 530 pm_dev_dbg(dev, state, "class ");
555 error = pm_op(dev, dev->class->pm, state); 531 error = pm_op(dev, dev->class->pm, state);
532 goto End;
556 } else if (dev->class->resume) { 533 } else if (dev->class->resume) {
557 pm_dev_dbg(dev, state, "legacy class "); 534 pm_dev_dbg(dev, state, "legacy class ");
558 error = legacy_resume(dev, dev->class->resume); 535 error = legacy_resume(dev, dev->class->resume);
536 goto End;
559 } 537 }
560 } 538 }
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
561 End: 550 End:
562 device_unlock(dev); 551 device_unlock(dev);
563 complete_all(&dev->power.completion); 552 complete_all(&dev->power.completion);
@@ -644,19 +633,18 @@ static void device_complete(struct device *dev, pm_message_t state)
644 dev->pwr_domain->ops.complete(dev); 633 dev->pwr_domain->ops.complete(dev);
645 } 634 }
646 635
647 if (dev->class && dev->class->pm && dev->class->pm->complete) { 636 if (dev->type && dev->type->pm) {
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) {
653 pm_dev_dbg(dev, state, "completing type "); 637 pm_dev_dbg(dev, state, "completing type ");
654 dev->type->pm->complete(dev); 638 if (dev->type->pm->complete)
655 } 639 dev->type->pm->complete(dev);
656 640 } else if (dev->class && dev->class->pm) {
657 if (dev->bus && dev->bus->pm && dev->bus->pm->complete) { 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) {
658 pm_dev_dbg(dev, state, "completing "); 645 pm_dev_dbg(dev, state, "completing ");
659 dev->bus->pm->complete(dev); 646 if (dev->bus->pm->complete)
647 dev->bus->pm->complete(dev);
660 } 648 }
661 649
662 device_unlock(dev); 650 device_unlock(dev);
@@ -741,27 +729,23 @@ static pm_message_t resume_event(pm_message_t sleep_state)
741 */ 729 */
742static int device_suspend_noirq(struct device *dev, pm_message_t state) 730static int device_suspend_noirq(struct device *dev, pm_message_t state)
743{ 731{
744 int error = 0; 732 int error;
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 }
752 733
753 if (dev->type && dev->type->pm) { 734 if (dev->type && dev->type->pm) {
754 pm_dev_dbg(dev, state, "LATE type "); 735 pm_dev_dbg(dev, state, "LATE type ");
755 error = pm_noirq_op(dev, dev->type->pm, state); 736 error = pm_noirq_op(dev, dev->type->pm, state);
756 if (error) 737 if (error)
757 goto End; 738 return error;
758 } 739 } else if (dev->class && dev->class->pm) {
759 740 pm_dev_dbg(dev, state, "LATE class ");
760 if (dev->bus && dev->bus->pm) { 741 error = pm_noirq_op(dev, dev->class->pm, state);
742 if (error)
743 return error;
744 } else if (dev->bus && dev->bus->pm) {
761 pm_dev_dbg(dev, state, "LATE "); 745 pm_dev_dbg(dev, state, "LATE ");
762 error = pm_noirq_op(dev, dev->bus->pm, state); 746 error = pm_noirq_op(dev, dev->bus->pm, state);
763 if (error) 747 if (error)
764 goto End; 748 return error;
765 } 749 }
766 750
767 if (dev->pwr_domain) { 751 if (dev->pwr_domain) {
@@ -769,8 +753,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
769 pm_noirq_op(dev, &dev->pwr_domain->ops, state); 753 pm_noirq_op(dev, &dev->pwr_domain->ops, state);
770 } 754 }
771 755
772End: 756 return 0;
773 return error;
774} 757}
775 758
776/** 759/**
@@ -857,25 +840,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
857 goto End; 840 goto End;
858 } 841 }
859 842
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
860 if (dev->class) { 849 if (dev->class) {
861 if (dev->class->pm) { 850 if (dev->class->pm) {
862 pm_dev_dbg(dev, state, "class "); 851 pm_dev_dbg(dev, state, "class ");
863 error = pm_op(dev, dev->class->pm, state); 852 error = pm_op(dev, dev->class->pm, state);
853 goto Domain;
864 } else if (dev->class->suspend) { 854 } else if (dev->class->suspend) {
865 pm_dev_dbg(dev, state, "legacy class "); 855 pm_dev_dbg(dev, state, "legacy class ");
866 error = legacy_suspend(dev, state, dev->class->suspend); 856 error = legacy_suspend(dev, state, dev->class->suspend);
857 goto Domain;
867 } 858 }
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;
879 } 859 }
880 860
881 if (dev->bus) { 861 if (dev->bus) {
@@ -886,11 +866,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
886 pm_dev_dbg(dev, state, "legacy "); 866 pm_dev_dbg(dev, state, "legacy ");
887 error = legacy_suspend(dev, state, dev->bus->suspend); 867 error = legacy_suspend(dev, state, dev->bus->suspend);
888 } 868 }
889 if (error)
890 goto End;
891 } 869 }
892 870
893 if (dev->pwr_domain) { 871 Domain:
872 if (!error && dev->pwr_domain) {
894 pm_dev_dbg(dev, state, "power domain "); 873 pm_dev_dbg(dev, state, "power domain ");
895 pm_op(dev, &dev->pwr_domain->ops, state); 874 pm_op(dev, &dev->pwr_domain->ops, state);
896 } 875 }
@@ -985,28 +964,27 @@ static int device_prepare(struct device *dev, pm_message_t state)
985 964
986 device_lock(dev); 965 device_lock(dev);
987 966
988 if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) { 967 if (dev->type && dev->type->pm) {
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) {
997 pm_dev_dbg(dev, state, "preparing type "); 968 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);
999 suspend_report_result(dev->type->pm->prepare, error); 971 suspend_report_result(dev->type->pm->prepare, error);
1000 if (error) 972 if (error)
1001 goto End; 973 goto End;
1002 } 974 } else if (dev->class && dev->class->pm) {
1003
1004 if (dev->class && dev->class->pm && dev->class->pm->prepare) {
1005 pm_dev_dbg(dev, state, "preparing class "); 975 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);
1007 suspend_report_result(dev->class->pm->prepare, error); 978 suspend_report_result(dev->class->pm->prepare, error);
1008 if (error) 979 if (error)
1009 goto End; 980 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;
1010 } 988 }
1011 989
1012 if (dev->pwr_domain && dev->pwr_domain->ops.prepare) { 990 if (dev->pwr_domain && dev->pwr_domain->ops.prepare) {
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 25edc9a3a489..54597c859ecb 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -214,12 +214,12 @@ static int rpm_idle(struct device *dev, int rpmflags)
214 214
215 dev->power.idle_notification = true; 215 dev->power.idle_notification = true;
216 216
217 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) 217 if (dev->type && dev->type->pm)
218 callback = dev->bus->pm->runtime_idle;
219 else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle)
220 callback = dev->type->pm->runtime_idle; 218 callback = dev->type->pm->runtime_idle;
221 else if (dev->class && dev->class->pm) 219 else if (dev->class && dev->class->pm)
222 callback = dev->class->pm->runtime_idle; 220 callback = dev->class->pm->runtime_idle;
221 else if (dev->bus && dev->bus->pm)
222 callback = dev->bus->pm->runtime_idle;
223 else 223 else
224 callback = NULL; 224 callback = NULL;
225 225
@@ -382,12 +382,12 @@ static int rpm_suspend(struct device *dev, int rpmflags)
382 382
383 __update_runtime_status(dev, RPM_SUSPENDING); 383 __update_runtime_status(dev, RPM_SUSPENDING);
384 384
385 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) 385 if (dev->type && dev->type->pm)
386 callback = dev->bus->pm->runtime_suspend;
387 else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend)
388 callback = dev->type->pm->runtime_suspend; 386 callback = dev->type->pm->runtime_suspend;
389 else if (dev->class && dev->class->pm) 387 else if (dev->class && dev->class->pm)
390 callback = dev->class->pm->runtime_suspend; 388 callback = dev->class->pm->runtime_suspend;
389 else if (dev->bus && dev->bus->pm)
390 callback = dev->bus->pm->runtime_suspend;
391 else 391 else
392 callback = NULL; 392 callback = NULL;
393 393
@@ -584,12 +584,12 @@ static int rpm_resume(struct device *dev, int rpmflags)
584 if (dev->pwr_domain) 584 if (dev->pwr_domain)
585 rpm_callback(dev->pwr_domain->ops.runtime_resume, dev); 585 rpm_callback(dev->pwr_domain->ops.runtime_resume, dev);
586 586
587 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) 587 if (dev->type && dev->type->pm)
588 callback = dev->bus->pm->runtime_resume;
589 else if (dev->type && dev->type->pm && dev->type->pm->runtime_resume)
590 callback = dev->type->pm->runtime_resume; 588 callback = dev->type->pm->runtime_resume;
591 else if (dev->class && dev->class->pm) 589 else if (dev->class && dev->class->pm)
592 callback = dev->class->pm->runtime_resume; 590 callback = dev->class->pm->runtime_resume;
591 else if (dev->bus && dev->bus->pm)
592 callback = dev->bus->pm->runtime_resume;
593 else 593 else
594 callback = NULL; 594 callback = NULL;
595 595