diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2012-01-29 14:39:02 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-01-29 14:39:02 -0500 |
commit | 0496c8ae366724a0a2136cec09a2e277e782c126 (patch) | |
tree | 29fce6f2a0b5e445b01f4c471f1c9d3aeead3d40 /drivers/base/power/domain.c | |
parent | e470d06655e00749f6f9372e4fa4f20cea7ed7c5 (diff) |
PM / Domains: Run late/early device suspend callbacks at the right time
After the introduction of the late/early phases of device
suspend/resume during system-wide power transitions it is possible
to make the generic PM domains code execute its default late/early
device suspend/resume callbacks during those phases instead of the
corresponding _noirq phases. The _noirq device suspend/resume
phases were only used for executing those callbacks, because this
was the only way it could be done, but now we can do better.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power/domain.c')
-rw-r--r-- | drivers/base/power/domain.c | 157 |
1 files changed, 111 insertions, 46 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 978bbf7ac6af..12a03afe5305 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -820,17 +820,16 @@ static int pm_genpd_suspend(struct device *dev) | |||
820 | } | 820 | } |
821 | 821 | ||
822 | /** | 822 | /** |
823 | * pm_genpd_suspend_noirq - Late suspend of a device from an I/O PM domain. | 823 | * pm_genpd_suspend_late - Late suspend of a device from an I/O PM domain. |
824 | * @dev: Device to suspend. | 824 | * @dev: Device to suspend. |
825 | * | 825 | * |
826 | * Carry out a late suspend of a device under the assumption that its | 826 | * Carry out a late suspend of a device under the assumption that its |
827 | * pm_domain field points to the domain member of an object of type | 827 | * pm_domain field points to the domain member of an object of type |
828 | * struct generic_pm_domain representing a PM domain consisting of I/O devices. | 828 | * struct generic_pm_domain representing a PM domain consisting of I/O devices. |
829 | */ | 829 | */ |
830 | static int pm_genpd_suspend_noirq(struct device *dev) | 830 | static int pm_genpd_suspend_late(struct device *dev) |
831 | { | 831 | { |
832 | struct generic_pm_domain *genpd; | 832 | struct generic_pm_domain *genpd; |
833 | int ret; | ||
834 | 833 | ||
835 | dev_dbg(dev, "%s()\n", __func__); | 834 | dev_dbg(dev, "%s()\n", __func__); |
836 | 835 | ||
@@ -838,14 +837,28 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
838 | if (IS_ERR(genpd)) | 837 | if (IS_ERR(genpd)) |
839 | return -EINVAL; | 838 | return -EINVAL; |
840 | 839 | ||
841 | if (genpd->suspend_power_off) | 840 | return genpd->suspend_power_off ? 0 : genpd_suspend_late(genpd, dev); |
842 | return 0; | 841 | } |
843 | 842 | ||
844 | ret = genpd_suspend_late(genpd, dev); | 843 | /** |
845 | if (ret) | 844 | * pm_genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain. |
846 | return ret; | 845 | * @dev: Device to suspend. |
846 | * | ||
847 | * Stop the device and remove power from the domain if all devices in it have | ||
848 | * been stopped. | ||
849 | */ | ||
850 | static int pm_genpd_suspend_noirq(struct device *dev) | ||
851 | { | ||
852 | struct generic_pm_domain *genpd; | ||
853 | |||
854 | dev_dbg(dev, "%s()\n", __func__); | ||
855 | |||
856 | genpd = dev_to_genpd(dev); | ||
857 | if (IS_ERR(genpd)) | ||
858 | return -EINVAL; | ||
847 | 859 | ||
848 | if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) | 860 | if (genpd->suspend_power_off |
861 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | ||
849 | return 0; | 862 | return 0; |
850 | 863 | ||
851 | genpd_stop_dev(genpd, dev); | 864 | genpd_stop_dev(genpd, dev); |
@@ -862,13 +875,10 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
862 | } | 875 | } |
863 | 876 | ||
864 | /** | 877 | /** |
865 | * pm_genpd_resume_noirq - Early resume of a device from an I/O power domain. | 878 | * pm_genpd_resume_noirq - Start of resume of device in an I/O PM domain. |
866 | * @dev: Device to resume. | 879 | * @dev: Device to resume. |
867 | * | 880 | * |
868 | * Carry out an early resume of a device under the assumption that its | 881 | * Restore power to the device's PM domain, if necessary, and start the device. |
869 | * pm_domain field points to the domain member of an object of type | ||
870 | * struct generic_pm_domain representing a power domain consisting of I/O | ||
871 | * devices. | ||
872 | */ | 882 | */ |
873 | static int pm_genpd_resume_noirq(struct device *dev) | 883 | static int pm_genpd_resume_noirq(struct device *dev) |
874 | { | 884 | { |
@@ -890,13 +900,34 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
890 | */ | 900 | */ |
891 | pm_genpd_poweron(genpd); | 901 | pm_genpd_poweron(genpd); |
892 | genpd->suspended_count--; | 902 | genpd->suspended_count--; |
893 | genpd_start_dev(genpd, dev); | ||
894 | 903 | ||
895 | return genpd_resume_early(genpd, dev); | 904 | return genpd_start_dev(genpd, dev); |
896 | } | 905 | } |
897 | 906 | ||
898 | /** | 907 | /** |
899 | * pm_genpd_resume - Resume a device belonging to an I/O power domain. | 908 | * pm_genpd_resume_early - Early resume of a device in an I/O PM domain. |
909 | * @dev: Device to resume. | ||
910 | * | ||
911 | * Carry out an early resume of a device under the assumption that its | ||
912 | * pm_domain field points to the domain member of an object of type | ||
913 | * struct generic_pm_domain representing a power domain consisting of I/O | ||
914 | * devices. | ||
915 | */ | ||
916 | static int pm_genpd_resume_early(struct device *dev) | ||
917 | { | ||
918 | struct generic_pm_domain *genpd; | ||
919 | |||
920 | dev_dbg(dev, "%s()\n", __func__); | ||
921 | |||
922 | genpd = dev_to_genpd(dev); | ||
923 | if (IS_ERR(genpd)) | ||
924 | return -EINVAL; | ||
925 | |||
926 | return genpd->suspend_power_off ? 0 : genpd_resume_early(genpd, dev); | ||
927 | } | ||
928 | |||
929 | /** | ||
930 | * pm_genpd_resume - Resume of device in an I/O PM domain. | ||
900 | * @dev: Device to resume. | 931 | * @dev: Device to resume. |
901 | * | 932 | * |
902 | * Resume a device under the assumption that its pm_domain field points to the | 933 | * Resume a device under the assumption that its pm_domain field points to the |
@@ -917,7 +948,7 @@ static int pm_genpd_resume(struct device *dev) | |||
917 | } | 948 | } |
918 | 949 | ||
919 | /** | 950 | /** |
920 | * pm_genpd_freeze - Freeze a device belonging to an I/O power domain. | 951 | * pm_genpd_freeze - Freezing a device in an I/O PM domain. |
921 | * @dev: Device to freeze. | 952 | * @dev: Device to freeze. |
922 | * | 953 | * |
923 | * Freeze a device under the assumption that its pm_domain field points to the | 954 | * Freeze a device under the assumption that its pm_domain field points to the |
@@ -938,7 +969,29 @@ static int pm_genpd_freeze(struct device *dev) | |||
938 | } | 969 | } |
939 | 970 | ||
940 | /** | 971 | /** |
941 | * pm_genpd_freeze_noirq - Late freeze of a device from an I/O power domain. | 972 | * pm_genpd_freeze_late - Late freeze of a device in an I/O PM domain. |
973 | * @dev: Device to freeze. | ||
974 | * | ||
975 | * Carry out a late freeze of a device under the assumption that its | ||
976 | * pm_domain field points to the domain member of an object of type | ||
977 | * struct generic_pm_domain representing a power domain consisting of I/O | ||
978 | * devices. | ||
979 | */ | ||
980 | static int pm_genpd_freeze_late(struct device *dev) | ||
981 | { | ||
982 | struct generic_pm_domain *genpd; | ||
983 | |||
984 | dev_dbg(dev, "%s()\n", __func__); | ||
985 | |||
986 | genpd = dev_to_genpd(dev); | ||
987 | if (IS_ERR(genpd)) | ||
988 | return -EINVAL; | ||
989 | |||
990 | return genpd->suspend_power_off ? 0 : genpd_freeze_late(genpd, dev); | ||
991 | } | ||
992 | |||
993 | /** | ||
994 | * pm_genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain. | ||
942 | * @dev: Device to freeze. | 995 | * @dev: Device to freeze. |
943 | * | 996 | * |
944 | * Carry out a late freeze of a device under the assumption that its | 997 | * Carry out a late freeze of a device under the assumption that its |
@@ -949,7 +1002,6 @@ static int pm_genpd_freeze(struct device *dev) | |||
949 | static int pm_genpd_freeze_noirq(struct device *dev) | 1002 | static int pm_genpd_freeze_noirq(struct device *dev) |
950 | { | 1003 | { |
951 | struct generic_pm_domain *genpd; | 1004 | struct generic_pm_domain *genpd; |
952 | int ret; | ||
953 | 1005 | ||
954 | dev_dbg(dev, "%s()\n", __func__); | 1006 | dev_dbg(dev, "%s()\n", __func__); |
955 | 1007 | ||
@@ -957,20 +1009,31 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
957 | if (IS_ERR(genpd)) | 1009 | if (IS_ERR(genpd)) |
958 | return -EINVAL; | 1010 | return -EINVAL; |
959 | 1011 | ||
960 | if (genpd->suspend_power_off) | 1012 | return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev); |
961 | return 0; | 1013 | } |
962 | 1014 | ||
963 | ret = genpd_freeze_late(genpd, dev); | 1015 | /** |
964 | if (ret) | 1016 | * pm_genpd_thaw_noirq - Early thaw of device in an I/O PM domain. |
965 | return ret; | 1017 | * @dev: Device to thaw. |
1018 | * | ||
1019 | * Start the device, unless power has been removed from the domain already | ||
1020 | * before the system transition. | ||
1021 | */ | ||
1022 | static int pm_genpd_thaw_noirq(struct device *dev) | ||
1023 | { | ||
1024 | struct generic_pm_domain *genpd; | ||
966 | 1025 | ||
967 | genpd_stop_dev(genpd, dev); | 1026 | dev_dbg(dev, "%s()\n", __func__); |
968 | 1027 | ||
969 | return 0; | 1028 | genpd = dev_to_genpd(dev); |
1029 | if (IS_ERR(genpd)) | ||
1030 | return -EINVAL; | ||
1031 | |||
1032 | return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev); | ||
970 | } | 1033 | } |
971 | 1034 | ||
972 | /** | 1035 | /** |
973 | * pm_genpd_thaw_noirq - Early thaw of a device from an I/O power domain. | 1036 | * pm_genpd_thaw_early - Early thaw of device in an I/O PM domain. |
974 | * @dev: Device to thaw. | 1037 | * @dev: Device to thaw. |
975 | * | 1038 | * |
976 | * Carry out an early thaw of a device under the assumption that its | 1039 | * Carry out an early thaw of a device under the assumption that its |
@@ -978,7 +1041,7 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
978 | * struct generic_pm_domain representing a power domain consisting of I/O | 1041 | * struct generic_pm_domain representing a power domain consisting of I/O |
979 | * devices. | 1042 | * devices. |
980 | */ | 1043 | */ |
981 | static int pm_genpd_thaw_noirq(struct device *dev) | 1044 | static int pm_genpd_thaw_early(struct device *dev) |
982 | { | 1045 | { |
983 | struct generic_pm_domain *genpd; | 1046 | struct generic_pm_domain *genpd; |
984 | 1047 | ||
@@ -988,12 +1051,7 @@ static int pm_genpd_thaw_noirq(struct device *dev) | |||
988 | if (IS_ERR(genpd)) | 1051 | if (IS_ERR(genpd)) |
989 | return -EINVAL; | 1052 | return -EINVAL; |
990 | 1053 | ||
991 | if (genpd->suspend_power_off) | 1054 | return genpd->suspend_power_off ? 0 : genpd_thaw_early(genpd, dev); |
992 | return 0; | ||
993 | |||
994 | genpd_start_dev(genpd, dev); | ||
995 | |||
996 | return genpd_thaw_early(genpd, dev); | ||
997 | } | 1055 | } |
998 | 1056 | ||
999 | /** | 1057 | /** |
@@ -1018,13 +1076,11 @@ static int pm_genpd_thaw(struct device *dev) | |||
1018 | } | 1076 | } |
1019 | 1077 | ||
1020 | /** | 1078 | /** |
1021 | * pm_genpd_restore_noirq - Early restore of a device from an I/O power domain. | 1079 | * pm_genpd_restore_noirq - Start of restore of device in an I/O PM domain. |
1022 | * @dev: Device to resume. | 1080 | * @dev: Device to resume. |
1023 | * | 1081 | * |
1024 | * Carry out an early restore of a device under the assumption that its | 1082 | * Make sure the domain will be in the same power state as before the |
1025 | * pm_domain field points to the domain member of an object of type | 1083 | * hibernation the system is resuming from and start the device if necessary. |
1026 | * struct generic_pm_domain representing a power domain consisting of I/O | ||
1027 | * devices. | ||
1028 | */ | 1084 | */ |
1029 | static int pm_genpd_restore_noirq(struct device *dev) | 1085 | static int pm_genpd_restore_noirq(struct device *dev) |
1030 | { | 1086 | { |
@@ -1054,9 +1110,8 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
1054 | 1110 | ||
1055 | pm_genpd_poweron(genpd); | 1111 | pm_genpd_poweron(genpd); |
1056 | genpd->suspended_count--; | 1112 | genpd->suspended_count--; |
1057 | genpd_start_dev(genpd, dev); | ||
1058 | 1113 | ||
1059 | return genpd_resume_early(genpd, dev); | 1114 | return genpd_start_dev(genpd, dev); |
1060 | } | 1115 | } |
1061 | 1116 | ||
1062 | /** | 1117 | /** |
@@ -1099,11 +1154,15 @@ static void pm_genpd_complete(struct device *dev) | |||
1099 | 1154 | ||
1100 | #define pm_genpd_prepare NULL | 1155 | #define pm_genpd_prepare NULL |
1101 | #define pm_genpd_suspend NULL | 1156 | #define pm_genpd_suspend NULL |
1157 | #define pm_genpd_suspend_late NULL | ||
1102 | #define pm_genpd_suspend_noirq NULL | 1158 | #define pm_genpd_suspend_noirq NULL |
1159 | #define pm_genpd_resume_early NULL | ||
1103 | #define pm_genpd_resume_noirq NULL | 1160 | #define pm_genpd_resume_noirq NULL |
1104 | #define pm_genpd_resume NULL | 1161 | #define pm_genpd_resume NULL |
1105 | #define pm_genpd_freeze NULL | 1162 | #define pm_genpd_freeze NULL |
1163 | #define pm_genpd_freeze_late NULL | ||
1106 | #define pm_genpd_freeze_noirq NULL | 1164 | #define pm_genpd_freeze_noirq NULL |
1165 | #define pm_genpd_thaw_early NULL | ||
1107 | #define pm_genpd_thaw_noirq NULL | 1166 | #define pm_genpd_thaw_noirq NULL |
1108 | #define pm_genpd_thaw NULL | 1167 | #define pm_genpd_thaw NULL |
1109 | #define pm_genpd_restore_noirq NULL | 1168 | #define pm_genpd_restore_noirq NULL |
@@ -1450,7 +1509,7 @@ static int pm_genpd_default_suspend_late(struct device *dev) | |||
1450 | { | 1509 | { |
1451 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late; | 1510 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late; |
1452 | 1511 | ||
1453 | return cb ? cb(dev) : pm_generic_suspend_noirq(dev); | 1512 | return cb ? cb(dev) : pm_generic_suspend_late(dev); |
1454 | } | 1513 | } |
1455 | 1514 | ||
1456 | /** | 1515 | /** |
@@ -1461,7 +1520,7 @@ static int pm_genpd_default_resume_early(struct device *dev) | |||
1461 | { | 1520 | { |
1462 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early; | 1521 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early; |
1463 | 1522 | ||
1464 | return cb ? cb(dev) : pm_generic_resume_noirq(dev); | 1523 | return cb ? cb(dev) : pm_generic_resume_early(dev); |
1465 | } | 1524 | } |
1466 | 1525 | ||
1467 | /** | 1526 | /** |
@@ -1494,7 +1553,7 @@ static int pm_genpd_default_freeze_late(struct device *dev) | |||
1494 | { | 1553 | { |
1495 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; | 1554 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; |
1496 | 1555 | ||
1497 | return cb ? cb(dev) : pm_generic_freeze_noirq(dev); | 1556 | return cb ? cb(dev) : pm_generic_freeze_late(dev); |
1498 | } | 1557 | } |
1499 | 1558 | ||
1500 | /** | 1559 | /** |
@@ -1505,7 +1564,7 @@ static int pm_genpd_default_thaw_early(struct device *dev) | |||
1505 | { | 1564 | { |
1506 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; | 1565 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; |
1507 | 1566 | ||
1508 | return cb ? cb(dev) : pm_generic_thaw_noirq(dev); | 1567 | return cb ? cb(dev) : pm_generic_thaw_early(dev); |
1509 | } | 1568 | } |
1510 | 1569 | ||
1511 | /** | 1570 | /** |
@@ -1564,16 +1623,22 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1564 | genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; | 1623 | genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; |
1565 | genpd->domain.ops.prepare = pm_genpd_prepare; | 1624 | genpd->domain.ops.prepare = pm_genpd_prepare; |
1566 | genpd->domain.ops.suspend = pm_genpd_suspend; | 1625 | genpd->domain.ops.suspend = pm_genpd_suspend; |
1626 | genpd->domain.ops.suspend_late = pm_genpd_suspend_late; | ||
1567 | genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq; | 1627 | genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq; |
1568 | genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq; | 1628 | genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq; |
1629 | genpd->domain.ops.resume_early = pm_genpd_resume_early; | ||
1569 | genpd->domain.ops.resume = pm_genpd_resume; | 1630 | genpd->domain.ops.resume = pm_genpd_resume; |
1570 | genpd->domain.ops.freeze = pm_genpd_freeze; | 1631 | genpd->domain.ops.freeze = pm_genpd_freeze; |
1632 | genpd->domain.ops.freeze_late = pm_genpd_freeze_late; | ||
1571 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; | 1633 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; |
1572 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; | 1634 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; |
1635 | genpd->domain.ops.thaw_early = pm_genpd_thaw_early; | ||
1573 | genpd->domain.ops.thaw = pm_genpd_thaw; | 1636 | genpd->domain.ops.thaw = pm_genpd_thaw; |
1574 | genpd->domain.ops.poweroff = pm_genpd_suspend; | 1637 | genpd->domain.ops.poweroff = pm_genpd_suspend; |
1638 | genpd->domain.ops.poweroff_late = pm_genpd_suspend_late; | ||
1575 | genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; | 1639 | genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; |
1576 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; | 1640 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; |
1641 | genpd->domain.ops.restore_early = pm_genpd_resume_early; | ||
1577 | genpd->domain.ops.restore = pm_genpd_resume; | 1642 | genpd->domain.ops.restore = pm_genpd_resume; |
1578 | genpd->domain.ops.complete = pm_genpd_complete; | 1643 | genpd->domain.ops.complete = pm_genpd_complete; |
1579 | genpd->dev_ops.save_state = pm_genpd_default_save_state; | 1644 | genpd->dev_ops.save_state = pm_genpd_default_save_state; |