ACPI / PM: Prefer suspend-to-idle over S3 on some systems
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 31 Jul 2017 21:43:18 +0000 (23:43 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 4 Aug 2017 23:51:26 +0000 (01:51 +0200)
Modify the ACPI system sleep support setup code to select
suspend-to-idle as the default system sleep state if
(1) the ACPI_FADT_LOW_POWER_S0 flag is set in the FADT and
(2) the Low Power Idle S0 _DSM interface has been discovered and
(3) the default sleep state was not selected from the kernel command
line.

The main motivation for this change is that systems where the (1) and
(2) conditions are met typically ship with OSes that don't exercise
the S3 path in the platform firmware which remains untested and turns
out to be non-functional at least in some cases.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Mario Limonciello <mario.limonciello@dell.com>
Documentation/power/states.txt
drivers/acpi/sleep.c
include/linux/suspend.h
kernel/power/power.h
kernel/power/suspend.c

index bc4548245a2431349b3d24655ab3b73794b7a10a..205e45ad7c6517fc94df7575b98e853397c61841 100644 (file)
@@ -35,7 +35,9 @@ only one way to cause the system to go into the Suspend-To-RAM state (write
 The default suspend mode (ie. the one to be used without writing anything into
 /sys/power/mem_sleep) is either "deep" (if Suspend-To-RAM is supported) or
 "s2idle", but it can be overridden by the value of the "mem_sleep_default"
-parameter in the kernel command line.
+parameter in the kernel command line.  On some ACPI-based systems, depending on
+the information in the FADT, the default may be "s2idle" even if Suspend-To-RAM
+is supported.
 
 The properties of all of the sleep states are described below.
 
index be17664736b2f12388148580ccb0b2f0450c348e..b363283dfcd9e207978f10df4cb6495cef3996b2 100644 (file)
@@ -714,6 +714,12 @@ static int lps0_device_attach(struct acpi_device *adev,
                if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) {
                        lps0_dsm_func_mask = bitmask;
                        lps0_device_handle = adev->handle;
+                       /*
+                        * Use suspend-to-idle by default if the default
+                        * suspend mode was not set from the command line.
+                        */
+                       if (mem_sleep_default > PM_SUSPEND_MEM)
+                               mem_sleep_current = PM_SUSPEND_FREEZE;
                }
 
                acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
index 97e394feabdb963105feb06101721b85357f3b2a..8c3b0b1e67866d673dfcb09532192daab8cba98d 100644 (file)
@@ -196,6 +196,9 @@ struct platform_freeze_ops {
 };
 
 #ifdef CONFIG_SUSPEND
+extern suspend_state_t mem_sleep_current;
+extern suspend_state_t mem_sleep_default;
+
 /**
  * suspend_set_ops - set platform dependent suspend operations
  * @ops: The new suspend operations to set.
index 268c1b0afc289219c7f8d41a5f2c857ba253b3ca..1d2d761e3c25008fbacc139e445cbbc8a325c9d9 100644 (file)
@@ -192,7 +192,6 @@ extern void swsusp_show_speed(ktime_t, ktime_t, unsigned int, char *);
 extern const char * const pm_labels[];
 extern const char *pm_states[];
 extern const char *mem_sleep_states[];
-extern suspend_state_t mem_sleep_current;
 
 extern int suspend_devices_and_enter(suspend_state_t state);
 #else /* !CONFIG_SUSPEND */
index 4bce46ddc2cdaedff55bd52f419647074e7902a9..0639d3a79852d9ce125438d6649e7ccf6479de17 100644 (file)
@@ -48,7 +48,7 @@ static const char * const mem_sleep_labels[] = {
 const char *mem_sleep_states[PM_SUSPEND_MAX];
 
 suspend_state_t mem_sleep_current = PM_SUSPEND_FREEZE;
-static suspend_state_t mem_sleep_default = PM_SUSPEND_MEM;
+suspend_state_t mem_sleep_default = PM_SUSPEND_MAX;
 suspend_state_t pm_suspend_target_state;
 EXPORT_SYMBOL_GPL(pm_suspend_target_state);
 
@@ -216,7 +216,7 @@ void suspend_set_ops(const struct platform_suspend_ops *ops)
        }
        if (valid_state(PM_SUSPEND_MEM)) {
                mem_sleep_states[PM_SUSPEND_MEM] = mem_sleep_labels[PM_SUSPEND_MEM];
-               if (mem_sleep_default == PM_SUSPEND_MEM)
+               if (mem_sleep_default >= PM_SUSPEND_MEM)
                        mem_sleep_current = PM_SUSPEND_MEM;
        }