aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
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
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')
-rw-r--r--drivers/base/power/main.c150
-rw-r--r--drivers/base/power/runtime.c18
2 files changed, 73 insertions, 95 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) {
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