aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-10-27 04:10:16 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-11-06 07:57:47 -0500
commit05087360fd7acf2cc9b7bbb243c12765c44c7693 (patch)
tree51d845be56e5384a1d55344a7f1b97002ffeeafa
parentc4b65157aeefad29b2351a00a010e8c40ce7fd0e (diff)
ACPI / PM: Take SMART_SUSPEND driver flag into account
Make the ACPI PM domain take DPM_FLAG_SMART_SUSPEND into account in its system suspend callbacks. [Note that the pm_runtime_suspended() check in acpi_dev_needs_resume() is an optimization, because if is not passed, all of the subsequent checks may be skipped and some of them are much more overhead in general.] Also use the observation that if the device is in runtime suspend at the beginning of the "late" phase of a system-wide suspend-like transition, its state cannot change going forward (runtime PM is disabled for it at that time) until the transition is over and the subsequent system-wide PM callbacks should be skipped for it (as they generally assume the device to not be suspended), so add checks for that in acpi_subsys_suspend_late/noirq() and acpi_subsys_freeze_late/noirq(). Moreover, if acpi_subsys_resume_noirq() is called during the subsequent system-wide resume transition and if the device was left in runtime suspend previously, its runtime PM status needs to be changed to "active" as it is going to be put into the full-power state going forward, so add a check for that too in there. In turn, if acpi_subsys_thaw_noirq() runs after the device has been left in runtime suspend, the subsequent "thaw" callbacks need to be skipped for it (as they may not work correctly with a suspended device), so set the power.direct_complete flag for the device then to make the PM core skip those callbacks. On top of the above, make the analogous changes in the acpi_lpss driver that uses the ACPI PM domain callbacks. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/acpi/acpi_lpss.c13
-rw-r--r--drivers/acpi/device_pm.c113
-rw-r--r--include/linux/acpi.h10
3 files changed, 126 insertions, 10 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 04d32bdb5a95..de7385b824e1 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -849,8 +849,12 @@ static int acpi_lpss_resume(struct device *dev)
849#ifdef CONFIG_PM_SLEEP 849#ifdef CONFIG_PM_SLEEP
850static int acpi_lpss_suspend_late(struct device *dev) 850static int acpi_lpss_suspend_late(struct device *dev)
851{ 851{
852 int ret = pm_generic_suspend_late(dev); 852 int ret;
853
854 if (dev_pm_smart_suspend_and_suspended(dev))
855 return 0;
853 856
857 ret = pm_generic_suspend_late(dev);
854 return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev)); 858 return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
855} 859}
856 860
@@ -889,10 +893,17 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
889 .complete = acpi_subsys_complete, 893 .complete = acpi_subsys_complete,
890 .suspend = acpi_subsys_suspend, 894 .suspend = acpi_subsys_suspend,
891 .suspend_late = acpi_lpss_suspend_late, 895 .suspend_late = acpi_lpss_suspend_late,
896 .suspend_noirq = acpi_subsys_suspend_noirq,
897 .resume_noirq = acpi_subsys_resume_noirq,
892 .resume_early = acpi_lpss_resume_early, 898 .resume_early = acpi_lpss_resume_early,
893 .freeze = acpi_subsys_freeze, 899 .freeze = acpi_subsys_freeze,
900 .freeze_late = acpi_subsys_freeze_late,
901 .freeze_noirq = acpi_subsys_freeze_noirq,
902 .thaw_noirq = acpi_subsys_thaw_noirq,
894 .poweroff = acpi_subsys_suspend, 903 .poweroff = acpi_subsys_suspend,
895 .poweroff_late = acpi_lpss_suspend_late, 904 .poweroff_late = acpi_lpss_suspend_late,
905 .poweroff_noirq = acpi_subsys_suspend_noirq,
906 .restore_noirq = acpi_subsys_resume_noirq,
896 .restore_early = acpi_lpss_resume_early, 907 .restore_early = acpi_lpss_resume_early,
897#endif 908#endif
898 .runtime_suspend = acpi_lpss_runtime_suspend, 909 .runtime_suspend = acpi_lpss_runtime_suspend,
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index b4dcc6144e6b..3d6ec51d2bbc 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -936,7 +936,8 @@ static bool acpi_dev_needs_resume(struct device *dev, struct acpi_device *adev)
936 u32 sys_target = acpi_target_system_state(); 936 u32 sys_target = acpi_target_system_state();
937 int ret, state; 937 int ret, state;
938 938
939 if (device_may_wakeup(dev) != !!adev->wakeup.prepare_count) 939 if (!pm_runtime_suspended(dev) || !adev ||
940 device_may_wakeup(dev) != !!adev->wakeup.prepare_count)
940 return true; 941 return true;
941 942
942 if (sys_target == ACPI_STATE_S0) 943 if (sys_target == ACPI_STATE_S0)
@@ -970,9 +971,6 @@ int acpi_subsys_prepare(struct device *dev)
970 return 0; 971 return 0;
971 } 972 }
972 973
973 if (!adev || !pm_runtime_suspended(dev))
974 return 0;
975
976 return !acpi_dev_needs_resume(dev, adev); 974 return !acpi_dev_needs_resume(dev, adev);
977} 975}
978EXPORT_SYMBOL_GPL(acpi_subsys_prepare); 976EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
@@ -998,12 +996,17 @@ EXPORT_SYMBOL_GPL(acpi_subsys_complete);
998 * acpi_subsys_suspend - Run the device driver's suspend callback. 996 * acpi_subsys_suspend - Run the device driver's suspend callback.
999 * @dev: Device to handle. 997 * @dev: Device to handle.
1000 * 998 *
1001 * Follow PCI and resume devices suspended at run time before running their 999 * Follow PCI and resume devices from runtime suspend before running their
1002 * system suspend callbacks. 1000 * system suspend callbacks, unless the driver can cope with runtime-suspended
1001 * devices during system suspend and there are no ACPI-specific reasons for
1002 * resuming them.
1003 */ 1003 */
1004int acpi_subsys_suspend(struct device *dev) 1004int acpi_subsys_suspend(struct device *dev)
1005{ 1005{
1006 pm_runtime_resume(dev); 1006 if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
1007 acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
1008 pm_runtime_resume(dev);
1009
1007 return pm_generic_suspend(dev); 1010 return pm_generic_suspend(dev);
1008} 1011}
1009EXPORT_SYMBOL_GPL(acpi_subsys_suspend); 1012EXPORT_SYMBOL_GPL(acpi_subsys_suspend);
@@ -1017,12 +1020,48 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend);
1017 */ 1020 */
1018int acpi_subsys_suspend_late(struct device *dev) 1021int acpi_subsys_suspend_late(struct device *dev)
1019{ 1022{
1020 int ret = pm_generic_suspend_late(dev); 1023 int ret;
1024
1025 if (dev_pm_smart_suspend_and_suspended(dev))
1026 return 0;
1027
1028 ret = pm_generic_suspend_late(dev);
1021 return ret ? ret : acpi_dev_suspend(dev, device_may_wakeup(dev)); 1029 return ret ? ret : acpi_dev_suspend(dev, device_may_wakeup(dev));
1022} 1030}
1023EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); 1031EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late);
1024 1032
1025/** 1033/**
1034 * acpi_subsys_suspend_noirq - Run the device driver's "noirq" suspend callback.
1035 * @dev: Device to suspend.
1036 */
1037int acpi_subsys_suspend_noirq(struct device *dev)
1038{
1039 if (dev_pm_smart_suspend_and_suspended(dev))
1040 return 0;
1041
1042 return pm_generic_suspend_noirq(dev);
1043}
1044EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq);
1045
1046/**
1047 * acpi_subsys_resume_noirq - Run the device driver's "noirq" resume callback.
1048 * @dev: Device to handle.
1049 */
1050int acpi_subsys_resume_noirq(struct device *dev)
1051{
1052 /*
1053 * Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend
1054 * during system suspend, so update their runtime PM status to "active"
1055 * as they will be put into D0 going forward.
1056 */
1057 if (dev_pm_smart_suspend_and_suspended(dev))
1058 pm_runtime_set_active(dev);
1059
1060 return pm_generic_resume_noirq(dev);
1061}
1062EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq);
1063
1064/**
1026 * acpi_subsys_resume_early - Resume device using ACPI. 1065 * acpi_subsys_resume_early - Resume device using ACPI.
1027 * @dev: Device to Resume. 1066 * @dev: Device to Resume.
1028 * 1067 *
@@ -1049,11 +1088,60 @@ int acpi_subsys_freeze(struct device *dev)
1049 * runtime-suspended devices should not be touched during freeze/thaw 1088 * runtime-suspended devices should not be touched during freeze/thaw
1050 * transitions. 1089 * transitions.
1051 */ 1090 */
1052 pm_runtime_resume(dev); 1091 if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
1092 pm_runtime_resume(dev);
1093
1053 return pm_generic_freeze(dev); 1094 return pm_generic_freeze(dev);
1054} 1095}
1055EXPORT_SYMBOL_GPL(acpi_subsys_freeze); 1096EXPORT_SYMBOL_GPL(acpi_subsys_freeze);
1056 1097
1098/**
1099 * acpi_subsys_freeze_late - Run the device driver's "late" freeze callback.
1100 * @dev: Device to handle.
1101 */
1102int acpi_subsys_freeze_late(struct device *dev)
1103{
1104
1105 if (dev_pm_smart_suspend_and_suspended(dev))
1106 return 0;
1107
1108 return pm_generic_freeze_late(dev);
1109}
1110EXPORT_SYMBOL_GPL(acpi_subsys_freeze_late);
1111
1112/**
1113 * acpi_subsys_freeze_noirq - Run the device driver's "noirq" freeze callback.
1114 * @dev: Device to handle.
1115 */
1116int acpi_subsys_freeze_noirq(struct device *dev)
1117{
1118
1119 if (dev_pm_smart_suspend_and_suspended(dev))
1120 return 0;
1121
1122 return pm_generic_freeze_noirq(dev);
1123}
1124EXPORT_SYMBOL_GPL(acpi_subsys_freeze_noirq);
1125
1126/**
1127 * acpi_subsys_thaw_noirq - Run the device driver's "noirq" thaw callback.
1128 * @dev: Device to handle.
1129 */
1130int acpi_subsys_thaw_noirq(struct device *dev)
1131{
1132 /*
1133 * If the device is in runtime suspend, the "thaw" code may not work
1134 * correctly with it, so skip the driver callback and make the PM core
1135 * skip all of the subsequent "thaw" callbacks for the device.
1136 */
1137 if (dev_pm_smart_suspend_and_suspended(dev)) {
1138 dev->power.direct_complete = true;
1139 return 0;
1140 }
1141
1142 return pm_generic_thaw_noirq(dev);
1143}
1144EXPORT_SYMBOL_GPL(acpi_subsys_thaw_noirq);
1057#endif /* CONFIG_PM_SLEEP */ 1145#endif /* CONFIG_PM_SLEEP */
1058 1146
1059static struct dev_pm_domain acpi_general_pm_domain = { 1147static struct dev_pm_domain acpi_general_pm_domain = {
@@ -1065,10 +1153,17 @@ static struct dev_pm_domain acpi_general_pm_domain = {
1065 .complete = acpi_subsys_complete, 1153 .complete = acpi_subsys_complete,
1066 .suspend = acpi_subsys_suspend, 1154 .suspend = acpi_subsys_suspend,
1067 .suspend_late = acpi_subsys_suspend_late, 1155 .suspend_late = acpi_subsys_suspend_late,
1156 .suspend_noirq = acpi_subsys_suspend_noirq,
1157 .resume_noirq = acpi_subsys_resume_noirq,
1068 .resume_early = acpi_subsys_resume_early, 1158 .resume_early = acpi_subsys_resume_early,
1069 .freeze = acpi_subsys_freeze, 1159 .freeze = acpi_subsys_freeze,
1160 .freeze_late = acpi_subsys_freeze_late,
1161 .freeze_noirq = acpi_subsys_freeze_noirq,
1162 .thaw_noirq = acpi_subsys_thaw_noirq,
1070 .poweroff = acpi_subsys_suspend, 1163 .poweroff = acpi_subsys_suspend,
1071 .poweroff_late = acpi_subsys_suspend_late, 1164 .poweroff_late = acpi_subsys_suspend_late,
1165 .poweroff_noirq = acpi_subsys_suspend_noirq,
1166 .restore_noirq = acpi_subsys_resume_noirq,
1072 .restore_early = acpi_subsys_resume_early, 1167 .restore_early = acpi_subsys_resume_early,
1073#endif 1168#endif
1074 }, 1169 },
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 0ada2a948b44..dc1ebfeeb5ec 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -885,17 +885,27 @@ int acpi_dev_suspend_late(struct device *dev);
885int acpi_subsys_prepare(struct device *dev); 885int acpi_subsys_prepare(struct device *dev);
886void acpi_subsys_complete(struct device *dev); 886void acpi_subsys_complete(struct device *dev);
887int acpi_subsys_suspend_late(struct device *dev); 887int acpi_subsys_suspend_late(struct device *dev);
888int acpi_subsys_suspend_noirq(struct device *dev);
889int acpi_subsys_resume_noirq(struct device *dev);
888int acpi_subsys_resume_early(struct device *dev); 890int acpi_subsys_resume_early(struct device *dev);
889int acpi_subsys_suspend(struct device *dev); 891int acpi_subsys_suspend(struct device *dev);
890int acpi_subsys_freeze(struct device *dev); 892int acpi_subsys_freeze(struct device *dev);
893int acpi_subsys_freeze_late(struct device *dev);
894int acpi_subsys_freeze_noirq(struct device *dev);
895int acpi_subsys_thaw_noirq(struct device *dev);
891#else 896#else
892static inline int acpi_dev_resume_early(struct device *dev) { return 0; } 897static inline int acpi_dev_resume_early(struct device *dev) { return 0; }
893static inline int acpi_subsys_prepare(struct device *dev) { return 0; } 898static inline int acpi_subsys_prepare(struct device *dev) { return 0; }
894static inline void acpi_subsys_complete(struct device *dev) {} 899static inline void acpi_subsys_complete(struct device *dev) {}
895static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; } 900static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; }
901static inline int acpi_subsys_suspend_noirq(struct device *dev) { return 0; }
902static inline int acpi_subsys_resume_noirq(struct device *dev) { return 0; }
896static inline int acpi_subsys_resume_early(struct device *dev) { return 0; } 903static inline int acpi_subsys_resume_early(struct device *dev) { return 0; }
897static inline int acpi_subsys_suspend(struct device *dev) { return 0; } 904static inline int acpi_subsys_suspend(struct device *dev) { return 0; }
898static inline int acpi_subsys_freeze(struct device *dev) { return 0; } 905static inline int acpi_subsys_freeze(struct device *dev) { return 0; }
906static inline int acpi_subsys_freeze_late(struct device *dev) { return 0; }
907static inline int acpi_subsys_freeze_noirq(struct device *dev) { return 0; }
908static inline int acpi_subsys_thaw_noirq(struct device *dev) { return 0; }
899#endif 909#endif
900 910
901#ifdef CONFIG_ACPI 911#ifdef CONFIG_ACPI