diff mbox

ACPI / PM: Prefer suspend-to-idle over S3 on some systems

Message ID 3043895.8nuHiCWbDe@aspire.rjw.lan (mailing list archive)
State Mainlined
Delegated to: Rafael Wysocki
Headers show

Commit Message

Rafael J. Wysocki July 31, 2017, 9:43 p.m. UTC
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

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>
---

This patch depends on the intel-hid change at

https://patchwork.kernel.org/patch/9867703/

---
 Documentation/power/states.txt |    4 +++-
 drivers/acpi/sleep.c           |    6 ++++++
 include/linux/suspend.h        |    3 +++
 kernel/power/power.h           |    1 -
 kernel/power/suspend.c         |    4 ++--
 5 files changed, 14 insertions(+), 4 deletions(-)

Comments

Limonciello, Mario Aug. 4, 2017, 5:02 p.m. UTC | #1
> -----Original Message-----
> From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> Sent: Monday, July 31, 2017 4:43 PM
> To: Linux ACPI <linux-acpi@vger.kernel.org>
> Cc: LKML <linux-kernel@vger.kernel.org>; Len Brown <len.brown@intel.com>;
> Linux PM <linux-pm@vger.kernel.org>; Srinivas Pandruvada
> <srinivas.pandruvada@linux.intel.com>; Limonciello, Mario
> <Mario_Limonciello@Dell.com>
> Subject: [PATCH] ACPI / PM: Prefer suspend-to-idle over S3 on some systems
> 
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> 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>
> ---
> 
> This patch depends on the intel-hid change at
> 
> https://patchwork.kernel.org/patch/9867703/
> 
> ---
>  Documentation/power/states.txt |    4 +++-
>  drivers/acpi/sleep.c           |    6 ++++++
>  include/linux/suspend.h        |    3 +++
>  kernel/power/power.h           |    1 -
>  kernel/power/suspend.c         |    4 ++--
>  5 files changed, 14 insertions(+), 4 deletions(-)
> 
> Index: linux-pm/Documentation/power/states.txt
> ===================================================================
> --- linux-pm.orig/Documentation/power/states.txt
> +++ linux-pm/Documentation/power/states.txt
> @@ -35,7 +35,9 @@ only one way to cause the system to go i
>  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: linux-pm/drivers/acpi/sleep.c
> ===================================================================
> --- linux-pm.orig/drivers/acpi/sleep.c
> +++ linux-pm/drivers/acpi/sleep.c
> @@ -714,6 +714,12 @@ static int lps0_device_attach(struct acp
>  		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: linux-pm/include/linux/suspend.h
> ===================================================================
> --- linux-pm.orig/include/linux/suspend.h
> +++ linux-pm/include/linux/suspend.h
> @@ -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: linux-pm/kernel/power/suspend.c
> ===================================================================
> --- linux-pm.orig/kernel/power/suspend.c
> +++ linux-pm/kernel/power/suspend.c
> @@ -48,7 +48,7 @@ static const char * const mem_sleep_labe
>  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 platfo
>  	}
>  	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;
>  	}
> 
> Index: linux-pm/kernel/power/power.h
> ===================================================================
> --- linux-pm.orig/kernel/power/power.h
> +++ linux-pm/kernel/power/power.h
> @@ -192,7 +192,6 @@ extern void swsusp_show_speed(ktime_t, k
>  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 */

Rafael,

This patch works for me on XPS 9365.

I ran into some problems with linux-pm.git/linux-next including
this patch though.  I spent a little time debugging and sent a follow 
up patch to intel-vbtn.  It's not strictly caused by this patch, but I 
just noticed it now with this default in place.

Tested-by: Mario Limonciello <mario.limonciello@dell.com>

Thanks,
diff mbox

Patch

Index: linux-pm/Documentation/power/states.txt
===================================================================
--- linux-pm.orig/Documentation/power/states.txt
+++ linux-pm/Documentation/power/states.txt
@@ -35,7 +35,9 @@  only one way to cause the system to go i
 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: linux-pm/drivers/acpi/sleep.c
===================================================================
--- linux-pm.orig/drivers/acpi/sleep.c
+++ linux-pm/drivers/acpi/sleep.c
@@ -714,6 +714,12 @@  static int lps0_device_attach(struct acp
 		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: linux-pm/include/linux/suspend.h
===================================================================
--- linux-pm.orig/include/linux/suspend.h
+++ linux-pm/include/linux/suspend.h
@@ -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: linux-pm/kernel/power/suspend.c
===================================================================
--- linux-pm.orig/kernel/power/suspend.c
+++ linux-pm/kernel/power/suspend.c
@@ -48,7 +48,7 @@  static const char * const mem_sleep_labe
 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 platfo
 	}
 	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;
 	}
 
Index: linux-pm/kernel/power/power.h
===================================================================
--- linux-pm.orig/kernel/power/power.h
+++ linux-pm/kernel/power/power.h
@@ -192,7 +192,6 @@  extern void swsusp_show_speed(ktime_t, k
 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 */