aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/main.c
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 /drivers/base/power/main.c
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>
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r--drivers/base/power/main.c150
1 files changed, 64 insertions, 86 deletions
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) {