PM / sleep: Add flags to indicate platform firmware involvement
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 6 Oct 2015 22:49:34 +0000 (00:49 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 14 Oct 2015 00:17:33 +0000 (02:17 +0200)
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>
drivers/acpi/sleep.c
include/linux/suspend.h
kernel/power/suspend.c

index 2f0d4db40a9e8aa078787b177d138322fdd6c0b9..a0b4d781e606e248159ee21c1d53810a91ff5ad6 100644 (file)
@@ -487,6 +487,8 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
                pr_err("ACPI does not support sleep state S%u\n", acpi_state);
                return -ENOSYS;
        }
+       if (acpi_state > ACPI_STATE_S1)
+               pm_set_suspend_via_firmware();
 
        acpi_pm_start(acpi_state);
        return 0;
@@ -522,6 +524,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
                if (error)
                        return error;
                pr_info(PREFIX "Low-level resume complete\n");
+               pm_set_resume_via_firmware();
                break;
        }
        trace_suspend_resume(TPS("acpi_suspend"), acpi_state, false);
index 33aaf9a9596c1d86381880132cc11226949495e6..8b6ec7ef0854e0f51fd94e38dbf7b831c9015f6c 100644 (file)
@@ -202,6 +202,36 @@ struct platform_freeze_ops {
 extern void suspend_set_ops(const struct platform_suspend_ops *ops);
 extern int suspend_valid_only_mem(suspend_state_t state);
 
+extern unsigned int pm_suspend_global_flags;
+
+#define PM_SUSPEND_FLAG_FW_SUSPEND     (1 << 0)
+#define PM_SUSPEND_FLAG_FW_RESUME      (1 << 1)
+
+static inline void pm_suspend_clear_flags(void)
+{
+       pm_suspend_global_flags = 0;
+}
+
+static inline void pm_set_suspend_via_firmware(void)
+{
+       pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_SUSPEND;
+}
+
+static inline void pm_set_resume_via_firmware(void)
+{
+       pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME;
+}
+
+static inline bool pm_suspend_via_firmware(void)
+{
+       return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_SUSPEND);
+}
+
+static inline bool pm_resume_via_firmware(void)
+{
+       return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME);
+}
+
 /* Suspend-to-idle state machnine. */
 enum freeze_state {
        FREEZE_STATE_NONE,      /* Not suspended/suspending. */
@@ -241,6 +271,12 @@ extern int pm_suspend(suspend_state_t state);
 #else /* !CONFIG_SUSPEND */
 #define suspend_valid_only_mem NULL
 
+static inline void pm_suspend_clear_flags(void) {}
+static inline void pm_set_suspend_via_firmware(void) {}
+static inline void pm_set_resume_via_firmware(void) {}
+static inline bool pm_suspend_via_firmware(void) { return false; }
+static inline bool pm_resume_via_firmware(void) { return false; }
+
 static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}
 static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
 static inline bool idle_should_freeze(void) { return false; }
index 7e4cda4a8dd9d5386bc657ef0c3a37851417a637..f9fe133c13e24de8e91f4ea81abebe6c58a3fd23 100644 (file)
@@ -35,6 +35,9 @@
 const char *pm_labels[] = { "mem", "standby", "freeze", NULL };
 const char *pm_states[PM_SUSPEND_MAX];
 
+unsigned int pm_suspend_global_flags;
+EXPORT_SYMBOL_GPL(pm_suspend_global_flags);
+
 static const struct platform_suspend_ops *suspend_ops;
 static const struct platform_freeze_ops *freeze_ops;
 static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head);
@@ -493,6 +496,7 @@ static int enter_state(suspend_state_t state)
 #endif
 
        pr_debug("PM: Preparing system for sleep (%s)\n", pm_states[state]);
+       pm_suspend_clear_flags();
        error = suspend_prepare(state);
        if (error)
                goto Unlock;