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

PM / sleep: Add flags to indicate platform firmware involvement

There are quite a few cases in which device drivers, bus types or
even the PM core itself may benefit from knowing whether or not
the platform firmware will be involved in the upcoming system power
transition (during system suspend) or whether or not it was involved
in it (during system resume).

For this reason, introduce global system suspend flags that can be
used by the platform code to expose that information for the benefit
of the other parts of the kernel and make the ACPI core set them
as appropriate.

Users of the new flags will be added later.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

+43
+3
drivers/acpi/sleep.c
··· 487 487 pr_err("ACPI does not support sleep state S%u\n", acpi_state); 488 488 return -ENOSYS; 489 489 } 490 + if (acpi_state > ACPI_STATE_S1) 491 + pm_set_suspend_via_firmware(); 490 492 491 493 acpi_pm_start(acpi_state); 492 494 return 0; ··· 524 522 if (error) 525 523 return error; 526 524 pr_info(PREFIX "Low-level resume complete\n"); 525 + pm_set_resume_via_firmware(); 527 526 break; 528 527 } 529 528 trace_suspend_resume(TPS("acpi_suspend"), acpi_state, false);
+36
include/linux/suspend.h
··· 202 202 extern void suspend_set_ops(const struct platform_suspend_ops *ops); 203 203 extern int suspend_valid_only_mem(suspend_state_t state); 204 204 205 + extern unsigned int pm_suspend_global_flags; 206 + 207 + #define PM_SUSPEND_FLAG_FW_SUSPEND (1 << 0) 208 + #define PM_SUSPEND_FLAG_FW_RESUME (1 << 1) 209 + 210 + static inline void pm_suspend_clear_flags(void) 211 + { 212 + pm_suspend_global_flags = 0; 213 + } 214 + 215 + static inline void pm_set_suspend_via_firmware(void) 216 + { 217 + pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_SUSPEND; 218 + } 219 + 220 + static inline void pm_set_resume_via_firmware(void) 221 + { 222 + pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME; 223 + } 224 + 225 + static inline bool pm_suspend_via_firmware(void) 226 + { 227 + return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_SUSPEND); 228 + } 229 + 230 + static inline bool pm_resume_via_firmware(void) 231 + { 232 + return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME); 233 + } 234 + 205 235 /* Suspend-to-idle state machnine. */ 206 236 enum freeze_state { 207 237 FREEZE_STATE_NONE, /* Not suspended/suspending. */ ··· 270 240 extern int pm_suspend(suspend_state_t state); 271 241 #else /* !CONFIG_SUSPEND */ 272 242 #define suspend_valid_only_mem NULL 243 + 244 + static inline void pm_suspend_clear_flags(void) {} 245 + static inline void pm_set_suspend_via_firmware(void) {} 246 + static inline void pm_set_resume_via_firmware(void) {} 247 + static inline bool pm_suspend_via_firmware(void) { return false; } 248 + static inline bool pm_resume_via_firmware(void) { return false; } 273 249 274 250 static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} 275 251 static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
+4
kernel/power/suspend.c
··· 35 35 const char *pm_labels[] = { "mem", "standby", "freeze", NULL }; 36 36 const char *pm_states[PM_SUSPEND_MAX]; 37 37 38 + unsigned int pm_suspend_global_flags; 39 + EXPORT_SYMBOL_GPL(pm_suspend_global_flags); 40 + 38 41 static const struct platform_suspend_ops *suspend_ops; 39 42 static const struct platform_freeze_ops *freeze_ops; 40 43 static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head); ··· 496 493 #endif 497 494 498 495 pr_debug("PM: Preparing system for sleep (%s)\n", pm_states[state]); 496 + pm_suspend_clear_flags(); 499 497 error = suspend_prepare(state); 500 498 if (error) 501 499 goto Unlock;