[PATCH v2 4/5] acpi/x86: s2idle: call Display On/Off as part of callbacks and rename

Antheas Kapenekakis
2024-09-22T17:24:32Z

Move the Display On/Off notifications into dedicated callbacks that gate
the ACPI mutex, so they can be called outside of the suspend path.
This fixes issues on certain devices that expect kernel drivers to be
fully active during the calls, and allows for the flexibility of calling
them as part of a more elaborate userspace suspend sequence (such as
with "Screen Off" in Windows Modern Standby).

In addition, rename the notifications from "screen_" to "display_", as
there is no documentation referring to them as screen, either by
Intel or Microsoft.

Co-developed-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
drivers/acpi/x86/s2idle.c | 89 +++++++++++++++++++++++++++------------
1 file changed, 62 insertions(+), 27 deletions(-)

diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
index dd0b40b9bbe8..a17e28b91326 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
@@ -39,8 +39,8 @@ static const struct acpi_device_id lps0_device_ids[] = {
#define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"

#define ACPI_LPS0_GET_DEVICE_CONSTRAINTS 1
-#define ACPI_LPS0_SCREEN_OFF 3
-#define ACPI_LPS0_SCREEN_ON 4
+#define ACPI_LPS0_DISPLAY_OFF 3
+#define ACPI_LPS0_DISPLAY_ON 4
#define ACPI_LPS0_ENTRY 5
#define ACPI_LPS0_EXIT 6
#define ACPI_LPS0_MS_ENTRY 7
@@ -50,8 +50,8 @@ static const struct acpi_device_id lps0_device_ids[] = {
#define ACPI_LPS0_DSM_UUID_AMD "e3f32452-febc-43ce-9039-932122d37721"
#define ACPI_LPS0_ENTRY_AMD 2
#define ACPI_LPS0_EXIT_AMD 3
-#define ACPI_LPS0_SCREEN_OFF_AMD 4
-#define ACPI_LPS0_SCREEN_ON_AMD 5
+#define ACPI_LPS0_DISPLAY_OFF_AMD 4
+#define ACPI_LPS0_DISPLAY_ON_AMD 5

static acpi_handle lps0_device_handle;
static guid_t lps0_dsm_guid;
@@ -60,6 +60,7 @@ static int lps0_dsm_func_mask;
static guid_t lps0_dsm_guid_microsoft;
static int lps0_dsm_func_mask_microsoft;
static int lps0_dsm_state;
+static bool lsp0_dsm_in_display_off;

/* Device constraint entry structure */
struct lpi_device_info {
@@ -361,9 +362,9 @@ static const char *acpi_sleep_dsm_state_to_str(unsigned int state)
{
if (lps0_dsm_func_mask_microsoft || !acpi_s2idle_vendor_amd()) {
switch (state) {
- case ACPI_LPS0_SCREEN_OFF:
+ case ACPI_LPS0_DISPLAY_OFF:
return "screen off";
- case ACPI_LPS0_SCREEN_ON:
+ case ACPI_LPS0_DISPLAY_ON:
return "screen on";
case ACPI_LPS0_ENTRY:
return "lps0 entry";
@@ -376,9 +377,9 @@ static const char *acpi_sleep_dsm_state_to_str(unsigned int state)
}
} else {
switch (state) {
- case ACPI_LPS0_SCREEN_ON_AMD:
+ case ACPI_LPS0_DISPLAY_ON_AMD:
return "screen on";
- case ACPI_LPS0_SCREEN_OFF_AMD:
+ case ACPI_LPS0_DISPLAY_OFF_AMD:
return "screen off";
case ACPI_LPS0_ENTRY_AMD:
return "lps0 entry";
@@ -539,27 +540,69 @@ static struct acpi_scan_handler lps0_handler = {
.attach = lps0_device_attach,
};

-int acpi_s2idle_prepare_late(void)
+static int acpi_s2idle_display_off(void)
{
- struct acpi_s2idle_dev_ops *handler;
-
if (!lps0_device_handle || sleep_no_lps0)
return 0;

- if (pm_debug_messages_on)
- lpi_check_constraints();
+ if (unlikely(WARN_ON(lsp0_dsm_in_display_off)))
+ return -EINVAL;
+
+ lsp0_dsm_in_display_off = true;
+ acpi_scan_lock_acquire();

- /* Screen off */
+ /* Display off */
if (lps0_dsm_func_mask > 0)
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
- ACPI_LPS0_SCREEN_OFF_AMD :
- ACPI_LPS0_SCREEN_OFF,
+ ACPI_LPS0_DISPLAY_OFF_AMD :
+ ACPI_LPS0_DISPLAY_OFF,
lps0_dsm_func_mask, lps0_dsm_guid);

if (lps0_dsm_func_mask_microsoft > 0)
- acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_DISPLAY_OFF,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);

+ acpi_scan_lock_release();
+
+ return 0;
+}
+
+static int acpi_s2idle_display_on(void)
+{
+ if (!lps0_device_handle || sleep_no_lps0)
+ return 0;
+
+ if (unlikely(WARN_ON(!lsp0_dsm_in_display_off)))
+ return -EINVAL;
+
+ lsp0_dsm_in_display_off = false;
+ acpi_scan_lock_acquire();
+
+ /* Display on */
+ if (lps0_dsm_func_mask_microsoft > 0)
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_DISPLAY_ON,
+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+ if (lps0_dsm_func_mask > 0)
+ acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
+ ACPI_LPS0_DISPLAY_ON_AMD :
+ ACPI_LPS0_DISPLAY_ON,
+ lps0_dsm_func_mask, lps0_dsm_guid);
+
+ acpi_scan_lock_release();
+
+ return 0;
+}
+
+int acpi_s2idle_prepare_late(void)
+{
+ struct acpi_s2idle_dev_ops *handler;
+
+ if (!lps0_device_handle || sleep_no_lps0)
+ return 0;
+
+ if (pm_debug_messages_on)
+ lpi_check_constraints();
+
/* LPS0 entry */
if (lps0_dsm_func_mask > 0 && acpi_s2idle_vendor_amd())
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY_AMD,
@@ -623,19 +666,10 @@ void acpi_s2idle_restore_early(void)
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
}
-
- /* Screen on */
- if (lps0_dsm_func_mask_microsoft > 0)
- acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
- lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
- if (lps0_dsm_func_mask > 0)
- acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
- ACPI_LPS0_SCREEN_ON_AMD :
- ACPI_LPS0_SCREEN_ON,
- lps0_dsm_func_mask, lps0_dsm_guid);
}

static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
+ .display_off = acpi_s2idle_display_off,
.begin = acpi_s2idle_begin,
.prepare = acpi_s2idle_prepare,
.prepare_late = acpi_s2idle_prepare_late,
@@ -644,6 +678,7 @@ static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
.restore_early = acpi_s2idle_restore_early,
.restore = acpi_s2idle_restore,
.end = acpi_s2idle_end,
+ .display_on = acpi_s2idle_display_on,
};

void __init acpi_s2idle_setup(void)
--
2.46.1