Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+126 -10
+12 -1
drivers/acpi/acpi_lpss.c
··· 849 849 #ifdef CONFIG_PM_SLEEP 850 850 static int acpi_lpss_suspend_late(struct device *dev) 851 851 { 852 - int ret = pm_generic_suspend_late(dev); 852 + int ret; 853 853 854 + if (dev_pm_smart_suspend_and_suspended(dev)) 855 + return 0; 856 + 857 + ret = pm_generic_suspend_late(dev); 854 858 return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev)); 855 859 } 856 860 ··· 893 889 .complete = acpi_subsys_complete, 894 890 .suspend = acpi_subsys_suspend, 895 891 .suspend_late = acpi_lpss_suspend_late, 892 + .suspend_noirq = acpi_subsys_suspend_noirq, 893 + .resume_noirq = acpi_subsys_resume_noirq, 896 894 .resume_early = acpi_lpss_resume_early, 897 895 .freeze = acpi_subsys_freeze, 896 + .freeze_late = acpi_subsys_freeze_late, 897 + .freeze_noirq = acpi_subsys_freeze_noirq, 898 + .thaw_noirq = acpi_subsys_thaw_noirq, 898 899 .poweroff = acpi_subsys_suspend, 899 900 .poweroff_late = acpi_lpss_suspend_late, 901 + .poweroff_noirq = acpi_subsys_suspend_noirq, 902 + .restore_noirq = acpi_subsys_resume_noirq, 900 903 .restore_early = acpi_lpss_resume_early, 901 904 #endif 902 905 .runtime_suspend = acpi_lpss_runtime_suspend,
+104 -9
drivers/acpi/device_pm.c
··· 936 936 u32 sys_target = acpi_target_system_state(); 937 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 941 return true; 941 942 942 943 if (sys_target == ACPI_STATE_S0) ··· 971 970 return 0; 972 971 } 973 972 974 - if (!adev || !pm_runtime_suspended(dev)) 975 - return 0; 976 - 977 973 return !acpi_dev_needs_resume(dev, adev); 978 974 } 979 975 EXPORT_SYMBOL_GPL(acpi_subsys_prepare); ··· 996 998 * acpi_subsys_suspend - Run the device driver's suspend callback. 997 999 * @dev: Device to handle. 998 1000 * 999 - * Follow PCI and resume devices suspended at run time before running their 1000 - * system suspend callbacks. 1001 + * Follow PCI and resume devices from runtime suspend before running their 1002 + * system suspend callbacks, unless the driver can cope with runtime-suspended 1003 + * devices during system suspend and there are no ACPI-specific reasons for 1004 + * resuming them. 1001 1005 */ 1002 1006 int acpi_subsys_suspend(struct device *dev) 1003 1007 { 1004 - pm_runtime_resume(dev); 1008 + if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || 1009 + acpi_dev_needs_resume(dev, ACPI_COMPANION(dev))) 1010 + pm_runtime_resume(dev); 1011 + 1005 1012 return pm_generic_suspend(dev); 1006 1013 } 1007 1014 EXPORT_SYMBOL_GPL(acpi_subsys_suspend); ··· 1020 1017 */ 1021 1018 int acpi_subsys_suspend_late(struct device *dev) 1022 1019 { 1023 - int ret = pm_generic_suspend_late(dev); 1020 + int ret; 1021 + 1022 + if (dev_pm_smart_suspend_and_suspended(dev)) 1023 + return 0; 1024 + 1025 + ret = pm_generic_suspend_late(dev); 1024 1026 return ret ? ret : acpi_dev_suspend(dev, device_may_wakeup(dev)); 1025 1027 } 1026 1028 EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); 1029 + 1030 + /** 1031 + * acpi_subsys_suspend_noirq - Run the device driver's "noirq" suspend callback. 1032 + * @dev: Device to suspend. 1033 + */ 1034 + int acpi_subsys_suspend_noirq(struct device *dev) 1035 + { 1036 + if (dev_pm_smart_suspend_and_suspended(dev)) 1037 + return 0; 1038 + 1039 + return pm_generic_suspend_noirq(dev); 1040 + } 1041 + EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq); 1042 + 1043 + /** 1044 + * acpi_subsys_resume_noirq - Run the device driver's "noirq" resume callback. 1045 + * @dev: Device to handle. 1046 + */ 1047 + int acpi_subsys_resume_noirq(struct device *dev) 1048 + { 1049 + /* 1050 + * Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend 1051 + * during system suspend, so update their runtime PM status to "active" 1052 + * as they will be put into D0 going forward. 1053 + */ 1054 + if (dev_pm_smart_suspend_and_suspended(dev)) 1055 + pm_runtime_set_active(dev); 1056 + 1057 + return pm_generic_resume_noirq(dev); 1058 + } 1059 + EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq); 1027 1060 1028 1061 /** 1029 1062 * acpi_subsys_resume_early - Resume device using ACPI. ··· 1088 1049 * runtime-suspended devices should not be touched during freeze/thaw 1089 1050 * transitions. 1090 1051 */ 1091 - pm_runtime_resume(dev); 1052 + if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) 1053 + pm_runtime_resume(dev); 1054 + 1092 1055 return pm_generic_freeze(dev); 1093 1056 } 1094 1057 EXPORT_SYMBOL_GPL(acpi_subsys_freeze); 1095 1058 1059 + /** 1060 + * acpi_subsys_freeze_late - Run the device driver's "late" freeze callback. 1061 + * @dev: Device to handle. 1062 + */ 1063 + int acpi_subsys_freeze_late(struct device *dev) 1064 + { 1065 + 1066 + if (dev_pm_smart_suspend_and_suspended(dev)) 1067 + return 0; 1068 + 1069 + return pm_generic_freeze_late(dev); 1070 + } 1071 + EXPORT_SYMBOL_GPL(acpi_subsys_freeze_late); 1072 + 1073 + /** 1074 + * acpi_subsys_freeze_noirq - Run the device driver's "noirq" freeze callback. 1075 + * @dev: Device to handle. 1076 + */ 1077 + int acpi_subsys_freeze_noirq(struct device *dev) 1078 + { 1079 + 1080 + if (dev_pm_smart_suspend_and_suspended(dev)) 1081 + return 0; 1082 + 1083 + return pm_generic_freeze_noirq(dev); 1084 + } 1085 + EXPORT_SYMBOL_GPL(acpi_subsys_freeze_noirq); 1086 + 1087 + /** 1088 + * acpi_subsys_thaw_noirq - Run the device driver's "noirq" thaw callback. 1089 + * @dev: Device to handle. 1090 + */ 1091 + int acpi_subsys_thaw_noirq(struct device *dev) 1092 + { 1093 + /* 1094 + * If the device is in runtime suspend, the "thaw" code may not work 1095 + * correctly with it, so skip the driver callback and make the PM core 1096 + * skip all of the subsequent "thaw" callbacks for the device. 1097 + */ 1098 + if (dev_pm_smart_suspend_and_suspended(dev)) { 1099 + dev->power.direct_complete = true; 1100 + return 0; 1101 + } 1102 + 1103 + return pm_generic_thaw_noirq(dev); 1104 + } 1105 + EXPORT_SYMBOL_GPL(acpi_subsys_thaw_noirq); 1096 1106 #endif /* CONFIG_PM_SLEEP */ 1097 1107 1098 1108 static struct dev_pm_domain acpi_general_pm_domain = { ··· 1153 1065 .complete = acpi_subsys_complete, 1154 1066 .suspend = acpi_subsys_suspend, 1155 1067 .suspend_late = acpi_subsys_suspend_late, 1068 + .suspend_noirq = acpi_subsys_suspend_noirq, 1069 + .resume_noirq = acpi_subsys_resume_noirq, 1156 1070 .resume_early = acpi_subsys_resume_early, 1157 1071 .freeze = acpi_subsys_freeze, 1072 + .freeze_late = acpi_subsys_freeze_late, 1073 + .freeze_noirq = acpi_subsys_freeze_noirq, 1074 + .thaw_noirq = acpi_subsys_thaw_noirq, 1158 1075 .poweroff = acpi_subsys_suspend, 1159 1076 .poweroff_late = acpi_subsys_suspend_late, 1077 + .poweroff_noirq = acpi_subsys_suspend_noirq, 1078 + .restore_noirq = acpi_subsys_resume_noirq, 1160 1079 .restore_early = acpi_subsys_resume_early, 1161 1080 #endif 1162 1081 },
+10
include/linux/acpi.h
··· 885 885 int acpi_subsys_prepare(struct device *dev); 886 886 void acpi_subsys_complete(struct device *dev); 887 887 int acpi_subsys_suspend_late(struct device *dev); 888 + int acpi_subsys_suspend_noirq(struct device *dev); 889 + int acpi_subsys_resume_noirq(struct device *dev); 888 890 int acpi_subsys_resume_early(struct device *dev); 889 891 int acpi_subsys_suspend(struct device *dev); 890 892 int acpi_subsys_freeze(struct device *dev); 893 + int acpi_subsys_freeze_late(struct device *dev); 894 + int acpi_subsys_freeze_noirq(struct device *dev); 895 + int acpi_subsys_thaw_noirq(struct device *dev); 891 896 #else 892 897 static inline int acpi_dev_resume_early(struct device *dev) { return 0; } 893 898 static inline int acpi_subsys_prepare(struct device *dev) { return 0; } 894 899 static inline void acpi_subsys_complete(struct device *dev) {} 895 900 static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; } 901 + static inline int acpi_subsys_suspend_noirq(struct device *dev) { return 0; } 902 + static inline int acpi_subsys_resume_noirq(struct device *dev) { return 0; } 896 903 static inline int acpi_subsys_resume_early(struct device *dev) { return 0; } 897 904 static inline int acpi_subsys_suspend(struct device *dev) { return 0; } 898 905 static inline int acpi_subsys_freeze(struct device *dev) { return 0; } 906 + static inline int acpi_subsys_freeze_late(struct device *dev) { return 0; } 907 + static inline int acpi_subsys_freeze_noirq(struct device *dev) { return 0; } 908 + static inline int acpi_subsys_thaw_noirq(struct device *dev) { return 0; } 899 909 #endif 900 910 901 911 #ifdef CONFIG_ACPI