mbox series

[RFC,00/13] acpi/x86: s2idle: implement Modern Standby transition states and expose to userspace

Message ID 20241121172239.119590-1-lkml@antheas.dev
Headers show
Series acpi/x86: s2idle: implement Modern Standby transition states and expose to userspace | expand

Message

Antheas Kapenekakis Nov. 21, 2024, 5:22 p.m. UTC
The following series moves the _DSM 3,4,7,8 firmware notifications outside
the suspend sequence, and makes them part of a transition function, where
the system can transition freely between them when it is not suspended.
This transition function is exposed to userspace, which now gains the
ability to control the presentation of the device (e.g., pulse the suspend
light) without forcing the kernel to suspend. In addition, it adds support
for the _DSM 9 call Turn Display On, which was introduced in Windows 22H2
and aims to speed up device wake-up while remaining in the "Sleep" state.
If userspace is not standby aware, the kernel will bring the system into
the "Sleep" state before beginning the suspend sequence.

This series requires a bit of background on how modern standby works in
Windows. Windows has a concept of "Modern Standby" [1], where it performs
an elaborate userspace and kernel suspend choreography while the device is
inactive in order to maintain fast wake-up times and connectivity while the
display of the device is off. This is done through 5 hardware states and
the OS takes the liberty of transitioning between them, by following a set
of rules (e.g., "Adaptive Hibernate").

```
                                 \/-> "Hibernate (S4)"
"Active" <-> "Screen Off" <-> "Sleep" <-> "DRIPS"
                  /\-  "Resume"  <-         <-
```

When the display is on and the user is interacting with the device, it is
in the "Active" state. The moment the display turns off, the device
transitions to the "Screen Off" state, where hardware and userspace are
fully active. Userspace will then decide when appropriate to freeze major
components (such as the DE) and transition into the "Sleep" state, where
the kernel is still active and connectivity is maintained. Finally, the
conventional "Suspend-to-idle" path can be used to bring the system into
the deepest runtime idle platform state (DRIPS) state, which is named
"s2idle" in the Linux kernel.

After wake-up, the system re-transitions into the "Sleep" state, where
userspace can run housekeeping and/or hibernate if the wake-up was not user
initiated (e.g., timer). If user-initiated, userspace can hasten the
transition out of the "Sleep" state by transitioning into the state
"Resume" that certain devices use to boost the Power Limit (PLx) while
remaining in sleep (support for this new notification is rare). Then, it
transitions back into "Screen Off" and "Active" to prepare for the user.

All transitions between these states feature unique firmware notifications
[3] that change the presentation of the device (e.g., pulse the suspend
light, turn off RGB). For more information, see the docs in [8]. Making
these transitions accessible from userspace moves them out of the suspend
sequence and has them happen while the kernel is fully active, mirroring
Windows.

As a side effect, this patch series completely fixes the ROG Ally
controller issue [5], which expects for .5s to lapse before its
controller's USB hub goes into D3 and otherwise malfunctions. It also fixes
an issue present in (allegedly only) older firmwares where they check the
USB subsystem is not in D3 before allowing the controller to wake up while
in powersave mode (for avoiding spurious wake-ups). As such, this patch
series is also a universal fix for the ROG Ally controller.

Moreover, this patch series allows turning off the controller and RGB of
most Windows handhelds (OneXPlayer, Lenovo Legion Go, GPD, and Asus ROG
Ally), opening the possibility of implementing suspend-then-hibernate and
other standby features, such as background downloads, without waking up the
RGB/controller of those devices. A Thinkpad T14 2021 was also tested, and
it pulses its suspend light during sleep.

There is still the question of where LSP0 entry/exit (_DSM 5,6) should be
fired or whether they should be fired in the path to hibernation. However,
as they cause no issues currently, and they fire when software activity has
seized, they are fine where they are.

It is important to note that the effects of these _DSMs persist during
reboots. I.e., if the Legion Go reboots while in the "Sleep" state, it will
boot into the "Sleep" state and have its controller disabled and suspend
light pulsing. The reboot persistence is undesirable, so the reboot path
will need to include a transition to active prior to reboot (not
included in this series). This is not the case after shutdown and
hibernation, where the device boots into the "Active" state.

The issue of DPMS is still present. Currently, gamescope and KDE (at least)
do not fire DPMS before suspending. This causes an undesirable frozen
screen while the system is suspending and looks quite ugly in general. This
is especially true if the firmware notifications fire earlier. Therefore,
should the kernel fire DPMS before forcing the transition to sleep for
backwards compat.? If yes, it will be quite the effort. Moreover, should
the kernel allow graphics drivers hook the transition function and block
transitions to "Screen Off" if there is an active CRTC? As that would be a
significant undertaking, there should be proof that there exists such a
device that has an issue firing the notifications with an active CRTC.

A variant of this series has been tested by thousands of users by now,
where the notifications fire around .5s before the CRTC is disabled and no
ill-effects have found in regard to this quirk. AFAIK, it is a visual
quirk. Making DPMS fire before the backwards compat. transition is a good
idea in any case, as it will sync the 200ms between Display Off/Sleep Entry
firing and the graphics driver turning off the display, but it might not be
worth the effort.

We are currently testing a DPMS patch for gamescope and it completely fixes
this visual quirk while allowing for e.g., hibernation without turning on
the screen. The DPMS gamescope patch + performing the transitions in
userspace in such a way where it blends the Ally's suspend delay halves the
user perceived delay to sleep and results in a very professional
presentation. This presentation extends to other devices as well, such as
the Legion Go.

Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/prepare-hardware-for-modern-standby [1]
Link: https://learn.microsoft.com/en-us/windows-hardware/customize/power-settings/adaptive-hibernate [2]
Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-firmware-notifications [3]
Link: https://github.com/hhd-dev/hwinfo/tree/master/devices [4]
Link: https://git.kernel.org/pub/scm/linux/kernel/git/superm1/linux.git/log/?h=superm1/dsm-screen-on-off [5]
Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2719 [6]
Link: https://dl.dell.com/manuals/all-products/esuprt_solutions_int/esuprt_solutions_int_solutions_resources/client-mobile-solution-resources_white-papers45_en-us.pdf [7]
File: Documentation/admin-guide/pm/standby-states.rst [8]

Changes from previous series (`acpi/x86: s2idle: move Display off/on calls
  outside suspend (fixes ROG Ally suspend)`):
  - Separate Display On/Off rename into its own commit (suggested by Hans)
  - Move delay quirks into s2idle.c (suggested by Hans)
  - Add documentation on Documentation/admin-guide/pm/standby-states.rst
  - Callbacks are now static and a transition function is used
  - Fixed all checkpatch warnings
  - The rest of the series is completely re-written

Antheas Kapenekakis (13):
  Documentation: PM: Add documentation for S0ix Standby States
  acpi/x86: s2idle: add support for Display Off and Display On callbacks
  acpi/x86: s2idle: add support for Sleep Entry and Sleep Exit callbacks
  acpi/x86: s2idle: add support for Turn On Display callback
  acpi/x86: s2idle: add modern standby transition function
  acpi/x86: s2idle: rename Screen On/Off to Display On/Off
  acpi/x86: s2idle: call Display On/Off as part of callbacks
  acpi/x86: s2idle: rename MS Exit/Entry to Sleep Exit/Entry
  acpi/x86: s2idle: call Sleep Entry/Exit as part of callbacks
  acpi/x86: s2idle: add Turn On Display and call as part of callback
  acpi/x86: s2idle: add quirk table for modern standby delays
  platform/x86: asus-wmi: remove Ally (1st gen) and Ally X suspend quirk
  PM: standby: Add sysfs attribute for modern standby transitions

 Documentation/ABI/testing/sysfs-power         |  34 +++
 .../admin-guide/pm/standby-states.rst         | 133 ++++++++++
 Documentation/admin-guide/pm/system-wide.rst  |   1 +
 drivers/acpi/x86/s2idle.c                     | 249 ++++++++++++++----
 drivers/platform/x86/asus-wmi.c               |  54 ----
 include/linux/suspend.h                       |  16 ++
 kernel/power/main.c                           |  75 ++++++
 kernel/power/power.h                          |   1 +
 kernel/power/suspend.c                        | 154 +++++++++++
 9 files changed, 616 insertions(+), 101 deletions(-)
 create mode 100644 Documentation/admin-guide/pm/standby-states.rst

Comments

Antheas Kapenekakis Nov. 21, 2024, 7:11 p.m. UTC | #1
On Thu, 21 Nov 2024 at 19:58, Mario Limonciello
<mario.limonciello@amd.com> wrote:
>
> On 11/21/2024 11:22, Antheas Kapenekakis wrote:
> > Add documentation about the S0ix Standby States that will be exposed
> > to userspace as part of this series.
> >
> > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> > ---
> >   .../admin-guide/pm/standby-states.rst         | 133 ++++++++++++++++++
> >   Documentation/admin-guide/pm/system-wide.rst  |   1 +
> >   2 files changed, 134 insertions(+)
> >   create mode 100644 Documentation/admin-guide/pm/standby-states.rst
> >
> > diff --git a/Documentation/admin-guide/pm/standby-states.rst b/Documentation/admin-guide/pm/standby-states.rst
> > new file mode 100644
> > index 000000000000..96727574312d
> > --- /dev/null
> > +++ b/Documentation/admin-guide/pm/standby-states.rst
> > @@ -0,0 +1,133 @@
> > +.. SPDX-License-Identifier: GPL-2.0
> > +.. include:: <isonum.txt>
> > +
> > +=====================
> > +S0ix Standby States
> > +=====================
> > +
> > +:Copyright: |copy| 2024 Antheas Kapenekakis
> > +
> > +:Author: Antheas Kapenekakis <lkml@antheas.dev>
> > +
> > +With the advent of modern mobile devices, users have become accustomed to instant
> > +wake-up times and always-on connectivity. To meet these expectations, modern
> > +standby was created, which is a standard that allows the platform to seamlessly
> > +transition between an S3-like low-power idle state and a set of low power active
> > +states, where connectivity is maintained, and the system is responsive to user
> > +input. Current x86 hardware supports 5 different standby states, which are:
> > +"Deepest run-time idle platform state" or "DRIPS" (S3-like), "Sleep", "Resume",
> > +"Screen Off", and "Active".
> > +
> > +The system begins in the "Active" state. Either due to user inactivity or
> > +user action (e.g., pressing the power button), it transitions to the "Screen Off"
> > +state.
>
> So are you implicitly suggesting that userspace should be responsible
> for *telling* the kernel that the screen is off?  I feel some DRM
> helpers are missing to make it easy, but after such helpers are made the
> kernel "should" be able to easily tell this on it's own.

There are two issues with this
  1) Windows implements a 5 second grace period on idle before firing
that firmware notification [1]. This is also a partial debounce, the
kernel cannot do that reliably or with the finesse required for such a
notification
  2) Windows clearly states virtual or real and virtual can really
mean anything here.

In the end, only systemd and the compositor know if both conditions 1
and 2 are met and as such can be responsible for the notification.

However, if that notification firing before certain CRTCs are
deactivated causes issues, such DRM helpers could be used to block the
transition

Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/display--sleep--and-hibernate-idle-timers
[1]

> > Afterwards, it is free to transition between the "Sleep", "DRIPS", and
> > +"Screen Off" states until user action is received. Once that happens, the system
> > +begins to transition to the "Active" state. From "DRIPS" or "Sleep", it
> > +transitions to "Resume", where the Power Limit (PLx) is restored to its normal
> > +level, to speed up finishing "Sleep". Then, it transitions to "Screen Off".
> > +If on "Screen Off" or after the transition, the display is prepared to turn on
> > +and the system transitions to "Active" alongside turning it on.
> > +
> > +To maintain battery life, in the Windows implementation, the system is allocated
> > +a maximum percentage of battery and time it can use while staying in idle states.
> > +By default, this is 5% of battery or up to 2 days, where the system designer/OEM
> > +is able to tweak these values. If the system exceeds either the battery
> > +percentage or time limit, it enters Hibernation (S4), through a concept
> > +called "Adaptive Hibernate".
> > +
> > +
> > +S0ix Standby States
> > +==================================
> > +The following idle states are supported::
> > +
> > +                 ↓→  <Hibernate (S4)>
>
> I think S4 distracts in this context.

Sure, can be removed.

> > +    <DRIPS> ↔ <Sleep> ↔ <Screen Off> ↔ <Active>
> > +        →       →  <Resume>  ↑
> > +
> > +.. _s2idle_drips:
> > +
> > +DRIPS
> > +-----
> > +
> > +The "Deepest run-time idle platform state" or "DRIPS" is the lowest power idle
> > +state that the system can enter. It is similar to the S3 state, with the
> > +difference that the system may wake up faster than S3 and due to a larger number
> > +of interrupts (e.g., fingerprint sensor, touchpad, touchscreen). This state
> > +is entered when the system is told to suspend to idle, through conventional
> > +means (see :doc:`sleep states <sleep-states>`). The system can only transition
> > +to "DRIPS" while it is in the "Sleep" state. If it is not, the kernel will
> > +automatically transition to the "Sleep" state before beginning the suspend
> > +sequence and restore the previous state afterwards. After the kernel has
> > +suspended, the notifications LSP0 Entry and Exit are used.
> > +
> > +.. _s2idle_sleep:
> > +
> > +Sleep
> > +-----
> > +
> > +The "Sleep" state is a low power idle state where the kernel is fully active.
> > +However, userspace has been partially frozen, particularly desktop applications,
> > +and only essential "value adding" activities are allowed to run. This is not
> > +enforced by the kernel and is the responsibility of userspace (e.g., systemd).
> > +Hardware wise, the Sleep Entry and Exit firmware notifications are fired, which
> > +may lower the Power Limit (PLx), pulse the suspend light, turn off the keyboard
> > +lighting or disable a handheld device's gamepad. This state is associated with
> > +the firmware notifications "Sleep Entry" and "Sleep Exit".
> > +
> > +.. _s2idle_resume:
> > +
> > +Resume
> > +------
> > +
> > +The "Resume" state is a faux "Sleep" state that is used to fire the Turn On
> > +Display firmware notification when the system is in the "Sleep" state but
> > +intends to turn on the display. It solves the problem of system designers
> > +limiting the Power Limit (PLx) while the system is in the "Sleep" state causing
>
> AFAIK, PLx is an Intel specific acronym, it's probably better to be more
> generic in documentation.  You mentioned PLx in a commit too.

Microsoft used this term in their documentation [2]. Can update to
generic terms.

Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-firmware-notifications#turn-on-display-notification-function-9
[2]

> > +the system to wake up slower than desired. This firmware notification is used
> > +to restore the normal Power Limit of the system, while having it stay in the
> > +"Sleep" state.  As such, the system can only transition to the "Resume" state
> > +while in the "Sleep" state and cannot re-transition to the "Sleep" state
> > +afterwards.
> > +
> > +.. _s2idle_screen_off:
> > +
> > +Screen Off
> > +----------
> > +
> > +The "Screen Off" state is the state the system enters when all its displays
> > +(virtual or real) turn off. It is used to signify the user is not actively
> > +using the system. The associated firmware notifications of "Display On" and
> > +"Display Off" are used by manufacturers to turn off certain hardware
> > +components that are associated with the display being on, e.g., a handheld
> > +device's controller and RGB. Windows implements a 5-second grace period
> > +before firing this callback when the screen turns off due to inactivity.
> > +
> > +.. _s2idle_active:
> > +
> > +Active
> > +------
> > +
> > +Finally, the "Active" state is the default state of the system and the one it
> > +has when it is turned on. It is the state where the system is fully operational,
> > +the displays of the device are on, and the user is actively interacting with
> > +the system.
> > +
> > +Basic ``sysfs`` Interface for S0ix Standby transitions
> > +=============================================================
> > +
> > +The file :file:`/sys/power/standby` can be used to transition the system between
> > +the different standby states. The file accepts the following values: ``active``,
> > +``screen_off``, ``sleep``, and ``resume``. File writes will block until the
> > +transition completes. It will return ``-EINVAL`` when asking for an unsupported
> > +state or, e.g., requesting ``resume`` when not in the ``sleep`` state. If there
> > +is an error during the transition, the transition will pause on the last
> > +error-free state and return an error. The file can be read to retrieve the
> > +current state (and potential ones) using the following format:
> > +``[active] screen_off sleep resume``. The state "DRIPS" is omitted, as it is
> > +entered through the conventional suspend to idle path and userspace will never
> > +be able to see its value due to being suspended.
>
> If you follow my above suggestion, I think this file is totally
> unnecessary and then there is no compatibility issue.
>
> It would mean that userspace if it wants to see this "screen off" state
> and associated performance needs to do literally just that - turn the
> screens off.

Please see the reasoning above for Display On/Off. Also, you omitted
sleep and resume, which have no hardware analogues you can hook into
and are just as important if not more than Display On/Off.

> > +
> > +Before entering the "Screen Off" state or suspending, it is recommended that
> > +userspace marks all CRTCs as inactive (DPMS). Otherwise, there will be a split
> > +second where the display of the device is on, but the presentation of the system
> > +is inactive (e.g., the power button pulses), which is undesirable.
> > \ No newline at end of file
> > diff --git a/Documentation/admin-guide/pm/system-wide.rst b/Documentation/admin-guide/pm/system-wide.rst
> > index 1a1924d71006..411775fae4ac 100644
> > --- a/Documentation/admin-guide/pm/system-wide.rst
> > +++ b/Documentation/admin-guide/pm/system-wide.rst
> > @@ -8,4 +8,5 @@ System-Wide Power Management
> >      :maxdepth: 2
> >
> >      sleep-states
> > +   standby-states
> >      suspend-flows
>
Mario Limonciello Nov. 21, 2024, 7:40 p.m. UTC | #2
On 11/21/2024 13:11, Antheas Kapenekakis wrote:
> On Thu, 21 Nov 2024 at 19:58, Mario Limonciello
> <mario.limonciello@amd.com> wrote:
>>
>> On 11/21/2024 11:22, Antheas Kapenekakis wrote:
>>> Add documentation about the S0ix Standby States that will be exposed
>>> to userspace as part of this series.
>>>
>>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
>>> ---
>>>    .../admin-guide/pm/standby-states.rst         | 133 ++++++++++++++++++
>>>    Documentation/admin-guide/pm/system-wide.rst  |   1 +
>>>    2 files changed, 134 insertions(+)
>>>    create mode 100644 Documentation/admin-guide/pm/standby-states.rst
>>>
>>> diff --git a/Documentation/admin-guide/pm/standby-states.rst b/Documentation/admin-guide/pm/standby-states.rst
>>> new file mode 100644
>>> index 000000000000..96727574312d
>>> --- /dev/null
>>> +++ b/Documentation/admin-guide/pm/standby-states.rst
>>> @@ -0,0 +1,133 @@
>>> +.. SPDX-License-Identifier: GPL-2.0
>>> +.. include:: <isonum.txt>
>>> +
>>> +=====================
>>> +S0ix Standby States
>>> +=====================
>>> +
>>> +:Copyright: |copy| 2024 Antheas Kapenekakis
>>> +
>>> +:Author: Antheas Kapenekakis <lkml@antheas.dev>
>>> +
>>> +With the advent of modern mobile devices, users have become accustomed to instant
>>> +wake-up times and always-on connectivity. To meet these expectations, modern
>>> +standby was created, which is a standard that allows the platform to seamlessly
>>> +transition between an S3-like low-power idle state and a set of low power active
>>> +states, where connectivity is maintained, and the system is responsive to user
>>> +input. Current x86 hardware supports 5 different standby states, which are:
>>> +"Deepest run-time idle platform state" or "DRIPS" (S3-like), "Sleep", "Resume",
>>> +"Screen Off", and "Active".
>>> +
>>> +The system begins in the "Active" state. Either due to user inactivity or
>>> +user action (e.g., pressing the power button), it transitions to the "Screen Off"
>>> +state.
>>
>> So are you implicitly suggesting that userspace should be responsible
>> for *telling* the kernel that the screen is off?  I feel some DRM
>> helpers are missing to make it easy, but after such helpers are made the
>> kernel "should" be able to easily tell this on it's own.
> 
> There are two issues with this
>    1) Windows implements a 5 second grace period on idle before firing
> that firmware notification [1]. This is also a partial debounce, the
> kernel cannot do that reliably or with the finesse required for such a
> notification

Why can't the kernel do this?  I'm thinking something like this pseudo 
code that is triggered when number of enabled CRTCs changes:

if (in_suspend_sequence)
	return;
switch (old_num_displays) {
case 0:
	display_on_cb();
default:
	schedule_delayed_work(&drm_s2idle_wq);
}

Then if the "normal" suspend sequence is started the delayed work is 
cancelled.

If the "normal" suspend sequence doesn't start when it fires then it 
would call the display off callback.

>    2) Windows clearly states virtual or real and virtual can really
> mean anything here.

In the context of the kernel, to me this is a DRM driver that has made 
outputs that are not tied to a physical display.  Does it mean anything 
else?  They should still be DRM connectors, and they should still have a 
CRTC AFAICT.

> 
> In the end, only systemd and the compositor know if both conditions 1
> and 2 are met and as such can be responsible for the notification.
> 
> However, if that notification firing before certain CRTCs are
> deactivated causes issues, such DRM helpers could be used to block the
> transition
> 
> Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/display--sleep--and-hibernate-idle-timers
> [1]
> 
>>> Afterwards, it is free to transition between the "Sleep", "DRIPS", and
>>> +"Screen Off" states until user action is received. Once that happens, the system
>>> +begins to transition to the "Active" state. From "DRIPS" or "Sleep", it
>>> +transitions to "Resume", where the Power Limit (PLx) is restored to its normal
>>> +level, to speed up finishing "Sleep". Then, it transitions to "Screen Off".
>>> +If on "Screen Off" or after the transition, the display is prepared to turn on
>>> +and the system transitions to "Active" alongside turning it on.
>>> +
>>> +To maintain battery life, in the Windows implementation, the system is allocated
>>> +a maximum percentage of battery and time it can use while staying in idle states.
>>> +By default, this is 5% of battery or up to 2 days, where the system designer/OEM
>>> +is able to tweak these values. If the system exceeds either the battery
>>> +percentage or time limit, it enters Hibernation (S4), through a concept
>>> +called "Adaptive Hibernate".
>>> +
>>> +
>>> +S0ix Standby States
>>> +==================================
>>> +The following idle states are supported::
>>> +
>>> +                 ↓→  <Hibernate (S4)>
>>
>> I think S4 distracts in this context.
> 
> Sure, can be removed.
> 
>>> +    <DRIPS> ↔ <Sleep> ↔ <Screen Off> ↔ <Active>
>>> +        →       →  <Resume>  ↑
>>> +
>>> +.. _s2idle_drips:
>>> +
>>> +DRIPS
>>> +-----
>>> +
>>> +The "Deepest run-time idle platform state" or "DRIPS" is the lowest power idle
>>> +state that the system can enter. It is similar to the S3 state, with the
>>> +difference that the system may wake up faster than S3 and due to a larger number
>>> +of interrupts (e.g., fingerprint sensor, touchpad, touchscreen). This state
>>> +is entered when the system is told to suspend to idle, through conventional
>>> +means (see :doc:`sleep states <sleep-states>`). The system can only transition
>>> +to "DRIPS" while it is in the "Sleep" state. If it is not, the kernel will
>>> +automatically transition to the "Sleep" state before beginning the suspend
>>> +sequence and restore the previous state afterwards. After the kernel has
>>> +suspended, the notifications LSP0 Entry and Exit are used.
>>> +
>>> +.. _s2idle_sleep:
>>> +
>>> +Sleep
>>> +-----
>>> +
>>> +The "Sleep" state is a low power idle state where the kernel is fully active.
>>> +However, userspace has been partially frozen, particularly desktop applications,
>>> +and only essential "value adding" activities are allowed to run. This is not
>>> +enforced by the kernel and is the responsibility of userspace (e.g., systemd).
>>> +Hardware wise, the Sleep Entry and Exit firmware notifications are fired, which
>>> +may lower the Power Limit (PLx), pulse the suspend light, turn off the keyboard
>>> +lighting or disable a handheld device's gamepad. This state is associated with
>>> +the firmware notifications "Sleep Entry" and "Sleep Exit".
>>> +
>>> +.. _s2idle_resume:
>>> +
>>> +Resume
>>> +------
>>> +
>>> +The "Resume" state is a faux "Sleep" state that is used to fire the Turn On
>>> +Display firmware notification when the system is in the "Sleep" state but
>>> +intends to turn on the display. It solves the problem of system designers
>>> +limiting the Power Limit (PLx) while the system is in the "Sleep" state causing
>>
>> AFAIK, PLx is an Intel specific acronym, it's probably better to be more
>> generic in documentation.  You mentioned PLx in a commit too.
> 
> Microsoft used this term in their documentation [2]. Can update to
> generic terms.
> 
> Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-firmware-notifications#turn-on-display-notification-function-9
> [2]
> 
>>> +the system to wake up slower than desired. This firmware notification is used
>>> +to restore the normal Power Limit of the system, while having it stay in the
>>> +"Sleep" state.  As such, the system can only transition to the "Resume" state
>>> +while in the "Sleep" state and cannot re-transition to the "Sleep" state
>>> +afterwards.
>>> +
>>> +.. _s2idle_screen_off:
>>> +
>>> +Screen Off
>>> +----------
>>> +
>>> +The "Screen Off" state is the state the system enters when all its displays
>>> +(virtual or real) turn off. It is used to signify the user is not actively
>>> +using the system. The associated firmware notifications of "Display On" and
>>> +"Display Off" are used by manufacturers to turn off certain hardware
>>> +components that are associated with the display being on, e.g., a handheld
>>> +device's controller and RGB. Windows implements a 5-second grace period
>>> +before firing this callback when the screen turns off due to inactivity.
>>> +
>>> +.. _s2idle_active:
>>> +
>>> +Active
>>> +------
>>> +
>>> +Finally, the "Active" state is the default state of the system and the one it
>>> +has when it is turned on. It is the state where the system is fully operational,
>>> +the displays of the device are on, and the user is actively interacting with
>>> +the system.
>>> +
>>> +Basic ``sysfs`` Interface for S0ix Standby transitions
>>> +=============================================================
>>> +
>>> +The file :file:`/sys/power/standby` can be used to transition the system between
>>> +the different standby states. The file accepts the following values: ``active``,
>>> +``screen_off``, ``sleep``, and ``resume``. File writes will block until the
>>> +transition completes. It will return ``-EINVAL`` when asking for an unsupported
>>> +state or, e.g., requesting ``resume`` when not in the ``sleep`` state. If there
>>> +is an error during the transition, the transition will pause on the last
>>> +error-free state and return an error. The file can be read to retrieve the
>>> +current state (and potential ones) using the following format:
>>> +``[active] screen_off sleep resume``. The state "DRIPS" is omitted, as it is
>>> +entered through the conventional suspend to idle path and userspace will never
>>> +be able to see its value due to being suspended.
>>
>> If you follow my above suggestion, I think this file is totally
>> unnecessary and then there is no compatibility issue.
>>
>> It would mean that userspace if it wants to see this "screen off" state
>> and associated performance needs to do literally just that - turn the
>> screens off.
> 
> Please see the reasoning above for Display On/Off. Also, you omitted
> sleep and resume, which have no hardware analogues you can hook into
> and are just as important if not more than Display On/Off.

I suppose I'm not seeing the argument yet for why "sleep" and HW DRIPS 
need to be different.  What kind of things would be allowed to run in 
this state?  Who draws that line?

As it stands today the kernel freezes all tasks when suspending, so in 
this "half" suspend state I feel like there would need to be some sort 
of allow list, no?

> 
>>> +
>>> +Before entering the "Screen Off" state or suspending, it is recommended that
>>> +userspace marks all CRTCs as inactive (DPMS). Otherwise, there will be a split
>>> +second where the display of the device is on, but the presentation of the system
>>> +is inactive (e.g., the power button pulses), which is undesirable.
>>> \ No newline at end of file
>>> diff --git a/Documentation/admin-guide/pm/system-wide.rst b/Documentation/admin-guide/pm/system-wide.rst
>>> index 1a1924d71006..411775fae4ac 100644
>>> --- a/Documentation/admin-guide/pm/system-wide.rst
>>> +++ b/Documentation/admin-guide/pm/system-wide.rst
>>> @@ -8,4 +8,5 @@ System-Wide Power Management
>>>       :maxdepth: 2
>>>
>>>       sleep-states
>>> +   standby-states
>>>       suspend-flows
>>
Antheas Kapenekakis Nov. 21, 2024, 8:33 p.m. UTC | #3
On Thu, 21 Nov 2024 at 20:40, Mario Limonciello
<mario.limonciello@amd.com> wrote:
>
> On 11/21/2024 13:11, Antheas Kapenekakis wrote:
> > On Thu, 21 Nov 2024 at 19:58, Mario Limonciello
> > <mario.limonciello@amd.com> wrote:
> >>
> >> On 11/21/2024 11:22, Antheas Kapenekakis wrote:
> >>> Add documentation about the S0ix Standby States that will be exposed
> >>> to userspace as part of this series.
> >>>
> >>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> >>> ---
> >>>    .../admin-guide/pm/standby-states.rst         | 133 ++++++++++++++++++
> >>>    Documentation/admin-guide/pm/system-wide.rst  |   1 +
> >>>    2 files changed, 134 insertions(+)
> >>>    create mode 100644 Documentation/admin-guide/pm/standby-states.rst
> >>>
> >>> diff --git a/Documentation/admin-guide/pm/standby-states.rst b/Documentation/admin-guide/pm/standby-states.rst
> >>> new file mode 100644
> >>> index 000000000000..96727574312d
> >>> --- /dev/null
> >>> +++ b/Documentation/admin-guide/pm/standby-states.rst
> >>> @@ -0,0 +1,133 @@
> >>> +.. SPDX-License-Identifier: GPL-2.0
> >>> +.. include:: <isonum.txt>
> >>> +
> >>> +=====================
> >>> +S0ix Standby States
> >>> +=====================
> >>> +
> >>> +:Copyright: |copy| 2024 Antheas Kapenekakis
> >>> +
> >>> +:Author: Antheas Kapenekakis <lkml@antheas.dev>
> >>> +
> >>> +With the advent of modern mobile devices, users have become accustomed to instant
> >>> +wake-up times and always-on connectivity. To meet these expectations, modern
> >>> +standby was created, which is a standard that allows the platform to seamlessly
> >>> +transition between an S3-like low-power idle state and a set of low power active
> >>> +states, where connectivity is maintained, and the system is responsive to user
> >>> +input. Current x86 hardware supports 5 different standby states, which are:
> >>> +"Deepest run-time idle platform state" or "DRIPS" (S3-like), "Sleep", "Resume",
> >>> +"Screen Off", and "Active".
> >>> +
> >>> +The system begins in the "Active" state. Either due to user inactivity or
> >>> +user action (e.g., pressing the power button), it transitions to the "Screen Off"
> >>> +state.
> >>
> >> So are you implicitly suggesting that userspace should be responsible
> >> for *telling* the kernel that the screen is off?  I feel some DRM
> >> helpers are missing to make it easy, but after such helpers are made the
> >> kernel "should" be able to easily tell this on it's own.
> >
> > There are two issues with this
> >    1) Windows implements a 5 second grace period on idle before firing
> > that firmware notification [1]. This is also a partial debounce, the
> > kernel cannot do that reliably or with the finesse required for such a
> > notification
>
> Why can't the kernel do this?  I'm thinking something like this pseudo
> code that is triggered when number of enabled CRTCs changes:
>
> if (in_suspend_sequence)
>         return;
> switch (old_num_displays) {
> case 0:
>         display_on_cb();
> default:
>         schedule_delayed_work(&drm_s2idle_wq);
> }
>
> Then if the "normal" suspend sequence is started the delayed work is
> cancelled.
>
> If the "normal" suspend sequence doesn't start when it fires then it
> would call the display off callback.

Fundamentally, it is more complicated and error prone than 2 systemd
suspend targets that fire at the same time DEs lock the lock screen
(or any init system for that matter). This pseudocode also hardcodes
the delay and does not debounce the display on callback.

There is the theoretical risk of a device misbehaving if the callbacks
fire at the wrong time. But this risk is theoretical and could be
solved by a device driver quirk that blocks the transition for that
specific device. Which is also much simpler than trying to hardcode an
implementation that works with all devices.

> >    2) Windows clearly states virtual or real and virtual can really
> > mean anything here.
>
> In the context of the kernel, to me this is a DRM driver that has made
> outputs that are not tied to a physical display.  Does it mean anything
> else?  They should still be DRM connectors, and they should still have a
> CRTC AFAICT.

For all the devices I tested, the display calls change the
presentation of the device such as RGB or aux devices that drain power
during suspend. I do not see a connection to DRM. This points me to
userspace being more appropriate for handling this. It also solves all
UX edge cases because userspace knows when it is inactive.

Userspace handling this will not be backwards compatible in the sense
that it will not fire when the displays turn off with current
userspace. But it preserves current behavior and as such it is not a
breaking change.

> >
> > In the end, only systemd and the compositor know if both conditions 1
> > and 2 are met and as such can be responsible for the notification.
> >
> > However, if that notification firing before certain CRTCs are
> > deactivated causes issues, such DRM helpers could be used to block the
> > transition
> >
> > Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/display--sleep--and-hibernate-idle-timers
> > [1]
> >
> >>> Afterwards, it is free to transition between the "Sleep", "DRIPS", and
> >>> +"Screen Off" states until user action is received. Once that happens, the system
> >>> +begins to transition to the "Active" state. From "DRIPS" or "Sleep", it
> >>> +transitions to "Resume", where the Power Limit (PLx) is restored to its normal
> >>> +level, to speed up finishing "Sleep". Then, it transitions to "Screen Off".
> >>> +If on "Screen Off" or after the transition, the display is prepared to turn on
> >>> +and the system transitions to "Active" alongside turning it on.
> >>> +
> >>> +To maintain battery life, in the Windows implementation, the system is allocated
> >>> +a maximum percentage of battery and time it can use while staying in idle states.
> >>> +By default, this is 5% of battery or up to 2 days, where the system designer/OEM
> >>> +is able to tweak these values. If the system exceeds either the battery
> >>> +percentage or time limit, it enters Hibernation (S4), through a concept
> >>> +called "Adaptive Hibernate".
> >>> +
> >>> +
> >>> +S0ix Standby States
> >>> +==================================
> >>> +The following idle states are supported::
> >>> +
> >>> +                 ↓→  <Hibernate (S4)>
> >>
> >> I think S4 distracts in this context.
> >
> > Sure, can be removed.
> >
> >>> +    <DRIPS> ↔ <Sleep> ↔ <Screen Off> ↔ <Active>
> >>> +        →       →  <Resume>  ↑
> >>> +
> >>> +.. _s2idle_drips:
> >>> +
> >>> +DRIPS
> >>> +-----
> >>> +
> >>> +The "Deepest run-time idle platform state" or "DRIPS" is the lowest power idle
> >>> +state that the system can enter. It is similar to the S3 state, with the
> >>> +difference that the system may wake up faster than S3 and due to a larger number
> >>> +of interrupts (e.g., fingerprint sensor, touchpad, touchscreen). This state
> >>> +is entered when the system is told to suspend to idle, through conventional
> >>> +means (see :doc:`sleep states <sleep-states>`). The system can only transition
> >>> +to "DRIPS" while it is in the "Sleep" state. If it is not, the kernel will
> >>> +automatically transition to the "Sleep" state before beginning the suspend
> >>> +sequence and restore the previous state afterwards. After the kernel has
> >>> +suspended, the notifications LSP0 Entry and Exit are used.
> >>> +
> >>> +.. _s2idle_sleep:
> >>> +
> >>> +Sleep
> >>> +-----
> >>> +
> >>> +The "Sleep" state is a low power idle state where the kernel is fully active.
> >>> +However, userspace has been partially frozen, particularly desktop applications,
> >>> +and only essential "value adding" activities are allowed to run. This is not
> >>> +enforced by the kernel and is the responsibility of userspace (e.g., systemd).
> >>> +Hardware wise, the Sleep Entry and Exit firmware notifications are fired, which
> >>> +may lower the Power Limit (PLx), pulse the suspend light, turn off the keyboard
> >>> +lighting or disable a handheld device's gamepad. This state is associated with
> >>> +the firmware notifications "Sleep Entry" and "Sleep Exit".
> >>> +
> >>> +.. _s2idle_resume:
> >>> +
> >>> +Resume
> >>> +------
> >>> +
> >>> +The "Resume" state is a faux "Sleep" state that is used to fire the Turn On
> >>> +Display firmware notification when the system is in the "Sleep" state but
> >>> +intends to turn on the display. It solves the problem of system designers
> >>> +limiting the Power Limit (PLx) while the system is in the "Sleep" state causing
> >>
> >> AFAIK, PLx is an Intel specific acronym, it's probably better to be more
> >> generic in documentation.  You mentioned PLx in a commit too.
> >
> > Microsoft used this term in their documentation [2]. Can update to
> > generic terms.
> >
> > Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-firmware-notifications#turn-on-display-notification-function-9
> > [2]
> >
> >>> +the system to wake up slower than desired. This firmware notification is used
> >>> +to restore the normal Power Limit of the system, while having it stay in the
> >>> +"Sleep" state.  As such, the system can only transition to the "Resume" state
> >>> +while in the "Sleep" state and cannot re-transition to the "Sleep" state
> >>> +afterwards.
> >>> +
> >>> +.. _s2idle_screen_off:
> >>> +
> >>> +Screen Off
> >>> +----------
> >>> +
> >>> +The "Screen Off" state is the state the system enters when all its displays
> >>> +(virtual or real) turn off. It is used to signify the user is not actively
> >>> +using the system. The associated firmware notifications of "Display On" and
> >>> +"Display Off" are used by manufacturers to turn off certain hardware
> >>> +components that are associated with the display being on, e.g., a handheld
> >>> +device's controller and RGB. Windows implements a 5-second grace period
> >>> +before firing this callback when the screen turns off due to inactivity.
> >>> +
> >>> +.. _s2idle_active:
> >>> +
> >>> +Active
> >>> +------
> >>> +
> >>> +Finally, the "Active" state is the default state of the system and the one it
> >>> +has when it is turned on. It is the state where the system is fully operational,
> >>> +the displays of the device are on, and the user is actively interacting with
> >>> +the system.
> >>> +
> >>> +Basic ``sysfs`` Interface for S0ix Standby transitions
> >>> +=============================================================
> >>> +
> >>> +The file :file:`/sys/power/standby` can be used to transition the system between
> >>> +the different standby states. The file accepts the following values: ``active``,
> >>> +``screen_off``, ``sleep``, and ``resume``. File writes will block until the
> >>> +transition completes. It will return ``-EINVAL`` when asking for an unsupported
> >>> +state or, e.g., requesting ``resume`` when not in the ``sleep`` state. If there
> >>> +is an error during the transition, the transition will pause on the last
> >>> +error-free state and return an error. The file can be read to retrieve the
> >>> +current state (and potential ones) using the following format:
> >>> +``[active] screen_off sleep resume``. The state "DRIPS" is omitted, as it is
> >>> +entered through the conventional suspend to idle path and userspace will never
> >>> +be able to see its value due to being suspended.
> >>
> >> If you follow my above suggestion, I think this file is totally
> >> unnecessary and then there is no compatibility issue.
> >>
> >> It would mean that userspace if it wants to see this "screen off" state
> >> and associated performance needs to do literally just that - turn the
> >> screens off.
> >
> > Please see the reasoning above for Display On/Off. Also, you omitted
> > sleep and resume, which have no hardware analogues you can hook into
> > and are just as important if not more than Display On/Off.
>
> I suppose I'm not seeing the argument yet for why "sleep" and HW DRIPS
> need to be different.  What kind of things would be allowed to run in
> this state?  Who draws that line?

The most useful thing would be maintaining some basic connectivity so
that the device can resume faster if it suspended a couple of minutes
before and handling transitions such as to hibernation. The transition
to hibernation is especially important, as if both DPMS and the sleep
transition fire the transition looks proper. Being able to run certain
maintenance tasks without changing the presentation of the device from
sleep (e.g., the APM timer to check the battery level) is important.

Even without that, if userspace transitions to sleep and fires DPMS
before beginning freezing and the suspend sequence, it halfs the user
perceived delay to sleep. It is a big deal. This is a planned feature
for the next version of bazzite so I am testing it right now. It looks
really professional.

> As it stands today the kernel freezes all tasks when suspending, so in
> this "half" suspend state I feel like there would need to be some sort
> of allow list, no?

I do sympathize with this. The most important part would be to lower
the power limit of the device which the manufacturers can already do
via the notification and perhaps other kernel drivers could do too.
Non-root software can be limited by the init system in general.

As a side note, after all tasks have frozen, including compositors,
you can fire DPMS safely before beginning the suspend sequence for
backwards compatibility and to lower the span the old framebuffer is
shown. This would be a useful addition to this series.

> >
> >>> +
> >>> +Before entering the "Screen Off" state or suspending, it is recommended that
> >>> +userspace marks all CRTCs as inactive (DPMS). Otherwise, there will be a split
> >>> +second where the display of the device is on, but the presentation of the system
> >>> +is inactive (e.g., the power button pulses), which is undesirable.
> >>> \ No newline at end of file
> >>> diff --git a/Documentation/admin-guide/pm/system-wide.rst b/Documentation/admin-guide/pm/system-wide.rst
> >>> index 1a1924d71006..411775fae4ac 100644
> >>> --- a/Documentation/admin-guide/pm/system-wide.rst
> >>> +++ b/Documentation/admin-guide/pm/system-wide.rst
> >>> @@ -8,4 +8,5 @@ System-Wide Power Management
> >>>       :maxdepth: 2
> >>>
> >>>       sleep-states
> >>> +   standby-states
> >>>       suspend-flows
> >>
>
Antheas Kapenekakis Nov. 21, 2024, 9:23 p.m. UTC | #4
On Thu, 21 Nov 2024 at 22:08, Mario Limonciello
<mario.limonciello@amd.com> wrote:
>
> On 11/21/2024 14:33, Antheas Kapenekakis wrote:
> > On Thu, 21 Nov 2024 at 20:40, Mario Limonciello
> > <mario.limonciello@amd.com> wrote:
> >>
> >> On 11/21/2024 13:11, Antheas Kapenekakis wrote:
> >>> On Thu, 21 Nov 2024 at 19:58, Mario Limonciello
> >>> <mario.limonciello@amd.com> wrote:
> >>>>
> >>>> On 11/21/2024 11:22, Antheas Kapenekakis wrote:
> >>>>> Add documentation about the S0ix Standby States that will be exposed
> >>>>> to userspace as part of this series.
> >>>>>
> >>>>> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
> >>>>> ---
> >>>>>     .../admin-guide/pm/standby-states.rst         | 133 ++++++++++++++++++
> >>>>>     Documentation/admin-guide/pm/system-wide.rst  |   1 +
> >>>>>     2 files changed, 134 insertions(+)
> >>>>>     create mode 100644 Documentation/admin-guide/pm/standby-states.rst
> >>>>>
> >>>>> diff --git a/Documentation/admin-guide/pm/standby-states.rst b/Documentation/admin-guide/pm/standby-states.rst
> >>>>> new file mode 100644
> >>>>> index 000000000000..96727574312d
> >>>>> --- /dev/null
> >>>>> +++ b/Documentation/admin-guide/pm/standby-states.rst
> >>>>> @@ -0,0 +1,133 @@
> >>>>> +.. SPDX-License-Identifier: GPL-2.0
> >>>>> +.. include:: <isonum.txt>
> >>>>> +
> >>>>> +=====================
> >>>>> +S0ix Standby States
> >>>>> +=====================
> >>>>> +
> >>>>> +:Copyright: |copy| 2024 Antheas Kapenekakis
> >>>>> +
> >>>>> +:Author: Antheas Kapenekakis <lkml@antheas.dev>
> >>>>> +
> >>>>> +With the advent of modern mobile devices, users have become accustomed to instant
> >>>>> +wake-up times and always-on connectivity. To meet these expectations, modern
> >>>>> +standby was created, which is a standard that allows the platform to seamlessly
> >>>>> +transition between an S3-like low-power idle state and a set of low power active
> >>>>> +states, where connectivity is maintained, and the system is responsive to user
> >>>>> +input. Current x86 hardware supports 5 different standby states, which are:
> >>>>> +"Deepest run-time idle platform state" or "DRIPS" (S3-like), "Sleep", "Resume",
> >>>>> +"Screen Off", and "Active".
> >>>>> +
> >>>>> +The system begins in the "Active" state. Either due to user inactivity or
> >>>>> +user action (e.g., pressing the power button), it transitions to the "Screen Off"
> >>>>> +state.
> >>>>
> >>>> So are you implicitly suggesting that userspace should be responsible
> >>>> for *telling* the kernel that the screen is off?  I feel some DRM
> >>>> helpers are missing to make it easy, but after such helpers are made the
> >>>> kernel "should" be able to easily tell this on it's own.
> >>>
> >>> There are two issues with this
> >>>     1) Windows implements a 5 second grace period on idle before firing
> >>> that firmware notification [1]. This is also a partial debounce, the
> >>> kernel cannot do that reliably or with the finesse required for such a
> >>> notification
> >>
> >> Why can't the kernel do this?  I'm thinking something like this pseudo
> >> code that is triggered when number of enabled CRTCs changes:
> >>
> >> if (in_suspend_sequence)
> >>          return;
> >> switch (old_num_displays) {
> >> case 0:
> >>          display_on_cb();
> >> default:
> >>          schedule_delayed_work(&drm_s2idle_wq);
> >> }
> >>
> >> Then if the "normal" suspend sequence is started the delayed work is
> >> cancelled.
> >>
> >> If the "normal" suspend sequence doesn't start when it fires then it
> >> would call the display off callback.
> >
> > Fundamentally, it is more complicated and error prone than 2 systemd
> > suspend targets that fire at the same time DEs lock the lock screen
> > (or any init system for that matter).
>
> 2 userspace jobs for the suspend sequence firing at same time vying for
> similar resources?

One presuspend target and one post suspend target

> That sounds inherently racy.
>
> > This pseudocode also hardcodes
> > the delay and does not debounce the display on callback.
> >
>
> If sticking to the Microsoft way of doing this, then it would be
> hardcoded.  But yeah if going this direction it "could" be something
> configurable by userspace.
>
> An actual implementation would need some locking protection like a mutex.
>
> > There is the theoretical risk of a device misbehaving if the callbacks
> > fire at the wrong time. But this risk is theoretical and could be
> > solved by a device driver quirk that blocks the transition for that
> > specific device. Which is also much simpler than trying to hardcode an
> > implementation that works with all devices.
> >
> >>>     2) Windows clearly states virtual or real and virtual can really
> >>> mean anything here.
> >>
> >> In the context of the kernel, to me this is a DRM driver that has made
> >> outputs that are not tied to a physical display.  Does it mean anything
> >> else?  They should still be DRM connectors, and they should still have a
> >> CRTC AFAICT.
> >
> > For all the devices I tested, the display calls change the
> > presentation of the device such as RGB or aux devices that drain power
> > during suspend. I do not see a connection to DRM. This points me to
> > userspace being more appropriate for handling this. It also solves all
> > UX edge cases because userspace knows when it is inactive.
> >
> > Userspace handling this will not be backwards compatible in the sense
> > that it will not fire when the displays turn off with current
> > userspace. But it preserves current behavior and as such it is not a
> > breaking change.
> >
> >>>
> >>> In the end, only systemd and the compositor know if both conditions 1
> >>> and 2 are met and as such can be responsible for the notification.
> >>>
> >>> However, if that notification firing before certain CRTCs are
> >>> deactivated causes issues, such DRM helpers could be used to block the
> >>> transition
> >>>
> >>> Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/display--sleep--and-hibernate-idle-timers
> >>> [1]
> >>>
> >>>>> Afterwards, it is free to transition between the "Sleep", "DRIPS", and
> >>>>> +"Screen Off" states until user action is received. Once that happens, the system
> >>>>> +begins to transition to the "Active" state. From "DRIPS" or "Sleep", it
> >>>>> +transitions to "Resume", where the Power Limit (PLx) is restored to its normal
> >>>>> +level, to speed up finishing "Sleep". Then, it transitions to "Screen Off".
> >>>>> +If on "Screen Off" or after the transition, the display is prepared to turn on
> >>>>> +and the system transitions to "Active" alongside turning it on.
> >>>>> +
> >>>>> +To maintain battery life, in the Windows implementation, the system is allocated
> >>>>> +a maximum percentage of battery and time it can use while staying in idle states.
> >>>>> +By default, this is 5% of battery or up to 2 days, where the system designer/OEM
> >>>>> +is able to tweak these values. If the system exceeds either the battery
> >>>>> +percentage or time limit, it enters Hibernation (S4), through a concept
> >>>>> +called "Adaptive Hibernate".
> >>>>> +
> >>>>> +
> >>>>> +S0ix Standby States
> >>>>> +==================================
> >>>>> +The following idle states are supported::
> >>>>> +
> >>>>> +                 ↓→  <Hibernate (S4)>
> >>>>
> >>>> I think S4 distracts in this context.
> >>>
> >>> Sure, can be removed.
> >>>
> >>>>> +    <DRIPS> ↔ <Sleep> ↔ <Screen Off> ↔ <Active>
> >>>>> +        →       →  <Resume>  ↑
> >>>>> +
> >>>>> +.. _s2idle_drips:
> >>>>> +
> >>>>> +DRIPS
> >>>>> +-----
> >>>>> +
> >>>>> +The "Deepest run-time idle platform state" or "DRIPS" is the lowest power idle
> >>>>> +state that the system can enter. It is similar to the S3 state, with the
> >>>>> +difference that the system may wake up faster than S3 and due to a larger number
> >>>>> +of interrupts (e.g., fingerprint sensor, touchpad, touchscreen). This state
> >>>>> +is entered when the system is told to suspend to idle, through conventional
> >>>>> +means (see :doc:`sleep states <sleep-states>`). The system can only transition
> >>>>> +to "DRIPS" while it is in the "Sleep" state. If it is not, the kernel will
> >>>>> +automatically transition to the "Sleep" state before beginning the suspend
> >>>>> +sequence and restore the previous state afterwards. After the kernel has
> >>>>> +suspended, the notifications LSP0 Entry and Exit are used.
> >>>>> +
> >>>>> +.. _s2idle_sleep:
> >>>>> +
> >>>>> +Sleep
> >>>>> +-----
> >>>>> +
> >>>>> +The "Sleep" state is a low power idle state where the kernel is fully active.
> >>>>> +However, userspace has been partially frozen, particularly desktop applications,
> >>>>> +and only essential "value adding" activities are allowed to run. This is not
> >>>>> +enforced by the kernel and is the responsibility of userspace (e.g., systemd).
> >>>>> +Hardware wise, the Sleep Entry and Exit firmware notifications are fired, which
> >>>>> +may lower the Power Limit (PLx), pulse the suspend light, turn off the keyboard
> >>>>> +lighting or disable a handheld device's gamepad. This state is associated with
> >>>>> +the firmware notifications "Sleep Entry" and "Sleep Exit".
> >>>>> +
> >>>>> +.. _s2idle_resume:
> >>>>> +
> >>>>> +Resume
> >>>>> +------
> >>>>> +
> >>>>> +The "Resume" state is a faux "Sleep" state that is used to fire the Turn On
> >>>>> +Display firmware notification when the system is in the "Sleep" state but
> >>>>> +intends to turn on the display. It solves the problem of system designers
> >>>>> +limiting the Power Limit (PLx) while the system is in the "Sleep" state causing
> >>>>
> >>>> AFAIK, PLx is an Intel specific acronym, it's probably better to be more
> >>>> generic in documentation.  You mentioned PLx in a commit too.
> >>>
> >>> Microsoft used this term in their documentation [2]. Can update to
> >>> generic terms.
> >>>
> >>> Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-firmware-notifications#turn-on-display-notification-function-9
> >>> [2]
> >>>
> >>>>> +the system to wake up slower than desired. This firmware notification is used
> >>>>> +to restore the normal Power Limit of the system, while having it stay in the
> >>>>> +"Sleep" state.  As such, the system can only transition to the "Resume" state
> >>>>> +while in the "Sleep" state and cannot re-transition to the "Sleep" state
> >>>>> +afterwards.
> >>>>> +
> >>>>> +.. _s2idle_screen_off:
> >>>>> +
> >>>>> +Screen Off
> >>>>> +----------
> >>>>> +
> >>>>> +The "Screen Off" state is the state the system enters when all its displays
> >>>>> +(virtual or real) turn off. It is used to signify the user is not actively
> >>>>> +using the system. The associated firmware notifications of "Display On" and
> >>>>> +"Display Off" are used by manufacturers to turn off certain hardware
> >>>>> +components that are associated with the display being on, e.g., a handheld
> >>>>> +device's controller and RGB. Windows implements a 5-second grace period
> >>>>> +before firing this callback when the screen turns off due to inactivity.
> >>>>> +
> >>>>> +.. _s2idle_active:
> >>>>> +
> >>>>> +Active
> >>>>> +------
> >>>>> +
> >>>>> +Finally, the "Active" state is the default state of the system and the one it
> >>>>> +has when it is turned on. It is the state where the system is fully operational,
> >>>>> +the displays of the device are on, and the user is actively interacting with
> >>>>> +the system.
> >>>>> +
> >>>>> +Basic ``sysfs`` Interface for S0ix Standby transitions
> >>>>> +=============================================================
> >>>>> +
> >>>>> +The file :file:`/sys/power/standby` can be used to transition the system between
> >>>>> +the different standby states. The file accepts the following values: ``active``,
> >>>>> +``screen_off``, ``sleep``, and ``resume``. File writes will block until the
> >>>>> +transition completes. It will return ``-EINVAL`` when asking for an unsupported
> >>>>> +state or, e.g., requesting ``resume`` when not in the ``sleep`` state. If there
> >>>>> +is an error during the transition, the transition will pause on the last
> >>>>> +error-free state and return an error. The file can be read to retrieve the
> >>>>> +current state (and potential ones) using the following format:
> >>>>> +``[active] screen_off sleep resume``. The state "DRIPS" is omitted, as it is
> >>>>> +entered through the conventional suspend to idle path and userspace will never
> >>>>> +be able to see its value due to being suspended.
> >>>>
> >>>> If you follow my above suggestion, I think this file is totally
> >>>> unnecessary and then there is no compatibility issue.
> >>>>
> >>>> It would mean that userspace if it wants to see this "screen off" state
> >>>> and associated performance needs to do literally just that - turn the
> >>>> screens off.
> >>>
> >>> Please see the reasoning above for Display On/Off. Also, you omitted
> >>> sleep and resume, which have no hardware analogues you can hook into
> >>> and are just as important if not more than Display On/Off.
> >>
> >> I suppose I'm not seeing the argument yet for why "sleep" and HW DRIPS
> >> need to be different.  What kind of things would be allowed to run in
> >> this state?  Who draws that line?
> >
> > The most useful thing would be maintaining some basic connectivity so
> > that the device can resume faster if it suspended a couple of minutes
> > before and handling transitions such as to hibernation. The transition
> > to hibernation is especially important, as if both DPMS and the sleep
> > transition fire the transition looks proper. Being able to run certain
> > maintenance tasks without changing the presentation of the device from
> > sleep (e.g., the APM timer to check the battery level) is important.
> >
>
> These points still seem to argue for "display on" vs "display off"
> though, not a "sleep" vs "HW DRIPS".

So the way the spec is designed is that the sleep entry points are the
ones that pulse the suspend light in new devices. The display off
turns off the keyboard backlight.

Just tested my thinkpad and on state screen_off it turns off the
keyboard light. It also pulses the suspend light. But its a 2021 intel
model so I suspect it predates the Sleep entry points. The legion Go
uses the sleep points.

In any case, 90% of this patch series is controlling when the suspend
light pulses and turning off the keyboard backlight.

>
> > Even without that, if userspace transitions to sleep and fires DPMS
> > before beginning freezing and the suspend sequence, it halfs the user
> > perceived delay to sleep. It is a big deal. This is a planned feature
> > for the next version of bazzite so I am testing it right now. It looks
> > really professional.
> >
>
> I feel that what you're mostly vying for is "Dark Resume", which is
> something that exists in the Chrome OS world:
>
> https://chromium.googlesource.com/chromiumos/platform2/+/HEAD/power_manager/docs/dark_resume.md
>
> I feel with cooperation between the compositor and the initiator of
> suspend the same thing can be done outside of ChromeOS.
>
> >> As it stands today the kernel freezes all tasks when suspending, so in
> >> this "half" suspend state I feel like there would need to be some sort
> >> of allow list, no?
> >
> > I do sympathize with this. The most important part would be to lower
> > the power limit of the device which the manufacturers can already do
> > via the notification and perhaps other kernel drivers could do too.
> > Non-root software can be limited by the init system in general.
>
> Why does the power limit specifically need to be lowered?  The goal is
> to avoid excessive power consumption in this kind of state, right?

Moreso to avoid overheating in a bag

> There are lots of other things that can be done to accomplish this:
> For example:
> * CPU boost be turned off
> * EPP bias be adjusted to efficiency
> * NVME APST can be tuned (idle timeout and transition latency tolerance)
> See this table for more info on what Microsoft does while in Modern
> Standby:
> https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/power-management-for-storage-hardware-devices-nvme
> See this comment in the kernel:
> https://github.com/torvalds/linux/blob/4a4be1ad3a6efea16c56615f31117590fd881358/drivers/nvme/host/core.c#L2503
> * Wifi power savings can be enacted
>
> Those are all things clearly that userspace can accomplish.
>
> What I'm getting at is perhaps the "suspend initiator" would be better
> to do things than change the flow from the kernel.
>
> 1) Freeze relevant tasks
> 2) Work with the compositor to disable the display
> 3) Save/restore EPP, boost, APST and WPS values.
> 4) After a timeout (or whatever reason) when ready to go into "HW DRIPS"
> then it can call the traditional suspend routine.
>
> Then when the system wakes up from "HW DRIPS" the "suspend initiator"
> can decide when to restore all those values, work with compositor to
> turn on the display etc.

Yes, that is indeed what I am planning to work on. This patch series is part of.

Systemd already has an applet that does some of that [1], and it can
also calculate hibernate offsets, handle APM timer for battery
warnings, and freeze userspace as of 255.

It would also be able to transition between DRIPS to hibernation after
a certain battery drop. It is quite limited now but the structure is
there.

[1] https://github.com/systemd/systemd/blob/main/src/sleep/sleep.c

> >
> > As a side note, after all tasks have frozen, including compositors,
> > you can fire DPMS safely before beginning the suspend sequence for
> > backwards compatibility and to lower the span the old framebuffer is
> > shown. This would be a useful addition to this series.
> >
> >>>
> >>>>> +
> >>>>> +Before entering the "Screen Off" state or suspending, it is recommended that
> >>>>> +userspace marks all CRTCs as inactive (DPMS). Otherwise, there will be a split
> >>>>> +second where the display of the device is on, but the presentation of the system
> >>>>> +is inactive (e.g., the power button pulses), which is undesirable.
> >>>>> \ No newline at end of file
> >>>>> diff --git a/Documentation/admin-guide/pm/system-wide.rst b/Documentation/admin-guide/pm/system-wide.rst
> >>>>> index 1a1924d71006..411775fae4ac 100644
> >>>>> --- a/Documentation/admin-guide/pm/system-wide.rst
> >>>>> +++ b/Documentation/admin-guide/pm/system-wide.rst
> >>>>> @@ -8,4 +8,5 @@ System-Wide Power Management
> >>>>>        :maxdepth: 2
> >>>>>
> >>>>>        sleep-states
> >>>>> +   standby-states
> >>>>>        suspend-flows
> >>>>
> >>
>
Xaver Hugl Nov. 22, 2024, 7:25 p.m. UTC | #5
Am Do., 21. Nov. 2024 um 18:22 Uhr schrieb Antheas Kapenekakis
<lkml@antheas.dev>:
>
> The following series moves the _DSM 3,4,7,8 firmware notifications outside
> the suspend sequence, and makes them part of a transition function, where
> the system can transition freely between them when it is not suspended.
> This transition function is exposed to userspace, which now gains the
> ability to control the presentation of the device (e.g., pulse the suspend
> light) without forcing the kernel to suspend. In addition, it adds support
> for the _DSM 9 call Turn Display On, which was introduced in Windows 22H2
> and aims to speed up device wake-up while remaining in the "Sleep" state.
> If userspace is not standby aware, the kernel will bring the system into
> the "Sleep" state before beginning the suspend sequence.
>
> This series requires a bit of background on how modern standby works in
> Windows. Windows has a concept of "Modern Standby" [1], where it performs
> an elaborate userspace and kernel suspend choreography while the device is
> inactive in order to maintain fast wake-up times and connectivity while the
> display of the device is off. This is done through 5 hardware states and
> the OS takes the liberty of transitioning between them, by following a set
> of rules (e.g., "Adaptive Hibernate").
>
> ```
>                                  \/-> "Hibernate (S4)"
> "Active" <-> "Screen Off" <-> "Sleep" <-> "DRIPS"
>                   /\-  "Resume"  <-         <-
> ```
>
> When the display is on and the user is interacting with the device, it is
> in the "Active" state. The moment the display turns off, the device
> transitions to the "Screen Off" state, where hardware and userspace are
> fully active. Userspace will then decide when appropriate to freeze major
> components (such as the DE) and transition into the "Sleep" state, where
> the kernel is still active and connectivity is maintained. Finally, the
> conventional "Suspend-to-idle" path can be used to bring the system into
> the deepest runtime idle platform state (DRIPS) state, which is named
> "s2idle" in the Linux kernel.
>
> After wake-up, the system re-transitions into the "Sleep" state, where
> userspace can run housekeeping and/or hibernate if the wake-up was not user
> initiated (e.g., timer). If user-initiated, userspace can hasten the
> transition out of the "Sleep" state by transitioning into the state
> "Resume" that certain devices use to boost the Power Limit (PLx) while
> remaining in sleep (support for this new notification is rare). Then, it
> transitions back into "Screen Off" and "Active" to prepare for the user.
>
> All transitions between these states feature unique firmware notifications
> [3] that change the presentation of the device (e.g., pulse the suspend
> light, turn off RGB). For more information, see the docs in [8]. Making
> these transitions accessible from userspace moves them out of the suspend
> sequence and has them happen while the kernel is fully active, mirroring
> Windows.
>
> As a side effect, this patch series completely fixes the ROG Ally
> controller issue [5], which expects for .5s to lapse before its
> controller's USB hub goes into D3 and otherwise malfunctions. It also fixes
> an issue present in (allegedly only) older firmwares where they check the
> USB subsystem is not in D3 before allowing the controller to wake up while
> in powersave mode (for avoiding spurious wake-ups). As such, this patch
> series is also a universal fix for the ROG Ally controller.
>
> Moreover, this patch series allows turning off the controller and RGB of
> most Windows handhelds (OneXPlayer, Lenovo Legion Go, GPD, and Asus ROG
> Ally), opening the possibility of implementing suspend-then-hibernate and
> other standby features, such as background downloads, without waking up the
> RGB/controller of those devices. A Thinkpad T14 2021 was also tested, and
> it pulses its suspend light during sleep.
>
> There is still the question of where LSP0 entry/exit (_DSM 5,6) should be
> fired or whether they should be fired in the path to hibernation. However,
> as they cause no issues currently, and they fire when software activity has
> seized, they are fine where they are.
>
> It is important to note that the effects of these _DSMs persist during
> reboots. I.e., if the Legion Go reboots while in the "Sleep" state, it will
> boot into the "Sleep" state and have its controller disabled and suspend
> light pulsing. The reboot persistence is undesirable, so the reboot path
> will need to include a transition to active prior to reboot (not
> included in this series). This is not the case after shutdown and
> hibernation, where the device boots into the "Active" state.
>
> The issue of DPMS is still present. Currently, gamescope and KDE (at least)
> do not fire DPMS before suspending. This causes an undesirable frozen
> screen while the system is suspending and looks quite ugly in general. This
> is especially true if the firmware notifications fire earlier. Therefore,
> should the kernel fire DPMS before forcing the transition to sleep for
> backwards compat.?

FWIW in KDE we already planned to turn the screen off before suspend
to deal better with spurious wakeups, and that'll be in the next
version of Plasma. I think it's fine if you just leave this up to
userspace, and maybe write to wayland-devel, so that other compositor
developers are aware they should do the same.

> If yes, it will be quite the effort. Moreover, should
> the kernel allow graphics drivers hook the transition function and block
> transitions to "Screen Off" if there is an active CRTC? As that would be a
> significant undertaking, there should be proof that there exists such a
> device that has an issue firing the notifications with an active CRTC.
>
> A variant of this series has been tested by thousands of users by now,
> where the notifications fire around .5s before the CRTC is disabled and no
> ill-effects have found in regard to this quirk. AFAIK, it is a visual
> quirk. Making DPMS fire before the backwards compat. transition is a good
> idea in any case, as it will sync the 200ms between Display Off/Sleep Entry
> firing and the graphics driver turning off the display, but it might not be
> worth the effort.
>
> We are currently testing a DPMS patch for gamescope and it completely fixes
> this visual quirk while allowing for e.g., hibernation without turning on
> the screen. The DPMS gamescope patch + performing the transitions in
> userspace in such a way where it blends the Ally's suspend delay halves the
> user perceived delay to sleep and results in a very professional
> presentation. This presentation extends to other devices as well, such as
> the Legion Go.
>
> Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/prepare-hardware-for-modern-standby [1]
> Link: https://learn.microsoft.com/en-us/windows-hardware/customize/power-settings/adaptive-hibernate [2]
> Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-firmware-notifications [3]
> Link: https://github.com/hhd-dev/hwinfo/tree/master/devices [4]
> Link: https://git.kernel.org/pub/scm/linux/kernel/git/superm1/linux.git/log/?h=superm1/dsm-screen-on-off [5]
> Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2719 [6]
> Link: https://dl.dell.com/manuals/all-products/esuprt_solutions_int/esuprt_solutions_int_solutions_resources/client-mobile-solution-resources_white-papers45_en-us.pdf [7]
> File: Documentation/admin-guide/pm/standby-states.rst [8]
>
> Changes from previous series (`acpi/x86: s2idle: move Display off/on calls
>   outside suspend (fixes ROG Ally suspend)`):
>   - Separate Display On/Off rename into its own commit (suggested by Hans)
>   - Move delay quirks into s2idle.c (suggested by Hans)
>   - Add documentation on Documentation/admin-guide/pm/standby-states.rst
>   - Callbacks are now static and a transition function is used
>   - Fixed all checkpatch warnings
>   - The rest of the series is completely re-written
>
> Antheas Kapenekakis (13):
>   Documentation: PM: Add documentation for S0ix Standby States
>   acpi/x86: s2idle: add support for Display Off and Display On callbacks
>   acpi/x86: s2idle: add support for Sleep Entry and Sleep Exit callbacks
>   acpi/x86: s2idle: add support for Turn On Display callback
>   acpi/x86: s2idle: add modern standby transition function
>   acpi/x86: s2idle: rename Screen On/Off to Display On/Off
>   acpi/x86: s2idle: call Display On/Off as part of callbacks
>   acpi/x86: s2idle: rename MS Exit/Entry to Sleep Exit/Entry
>   acpi/x86: s2idle: call Sleep Entry/Exit as part of callbacks
>   acpi/x86: s2idle: add Turn On Display and call as part of callback
>   acpi/x86: s2idle: add quirk table for modern standby delays
>   platform/x86: asus-wmi: remove Ally (1st gen) and Ally X suspend quirk
>   PM: standby: Add sysfs attribute for modern standby transitions
>
>  Documentation/ABI/testing/sysfs-power         |  34 +++
>  .../admin-guide/pm/standby-states.rst         | 133 ++++++++++
>  Documentation/admin-guide/pm/system-wide.rst  |   1 +
>  drivers/acpi/x86/s2idle.c                     | 249 ++++++++++++++----
>  drivers/platform/x86/asus-wmi.c               |  54 ----
>  include/linux/suspend.h                       |  16 ++
>  kernel/power/main.c                           |  75 ++++++
>  kernel/power/power.h                          |   1 +
>  kernel/power/suspend.c                        | 154 +++++++++++
>  9 files changed, 616 insertions(+), 101 deletions(-)
>  create mode 100644 Documentation/admin-guide/pm/standby-states.rst
>
> --
> 2.47.0
>
>
Antheas Kapenekakis Nov. 22, 2024, 11:55 p.m. UTC | #6
On Fri, 22 Nov 2024 at 20:26, Xaver Hugl <xaver.hugl@kde.org> wrote:
>
> Am Do., 21. Nov. 2024 um 18:22 Uhr schrieb Antheas Kapenekakis
> <lkml@antheas.dev>:
> >
> > The following series moves the _DSM 3,4,7,8 firmware notifications outside
> > the suspend sequence, and makes them part of a transition function, where
> > the system can transition freely between them when it is not suspended.
> > This transition function is exposed to userspace, which now gains the
> > ability to control the presentation of the device (e.g., pulse the suspend
> > light) without forcing the kernel to suspend. In addition, it adds support
> > for the _DSM 9 call Turn Display On, which was introduced in Windows 22H2
> > and aims to speed up device wake-up while remaining in the "Sleep" state.
> > If userspace is not standby aware, the kernel will bring the system into
> > the "Sleep" state before beginning the suspend sequence.
> >
> > This series requires a bit of background on how modern standby works in
> > Windows. Windows has a concept of "Modern Standby" [1], where it performs
> > an elaborate userspace and kernel suspend choreography while the device is
> > inactive in order to maintain fast wake-up times and connectivity while the
> > display of the device is off. This is done through 5 hardware states and
> > the OS takes the liberty of transitioning between them, by following a set
> > of rules (e.g., "Adaptive Hibernate").
> >
> > ```
> >                                  \/-> "Hibernate (S4)"
> > "Active" <-> "Screen Off" <-> "Sleep" <-> "DRIPS"
> >                   /\-  "Resume"  <-         <-
> > ```
> >
> > When the display is on and the user is interacting with the device, it is
> > in the "Active" state. The moment the display turns off, the device
> > transitions to the "Screen Off" state, where hardware and userspace are
> > fully active. Userspace will then decide when appropriate to freeze major
> > components (such as the DE) and transition into the "Sleep" state, where
> > the kernel is still active and connectivity is maintained. Finally, the
> > conventional "Suspend-to-idle" path can be used to bring the system into
> > the deepest runtime idle platform state (DRIPS) state, which is named
> > "s2idle" in the Linux kernel.
> >
> > After wake-up, the system re-transitions into the "Sleep" state, where
> > userspace can run housekeeping and/or hibernate if the wake-up was not user
> > initiated (e.g., timer). If user-initiated, userspace can hasten the
> > transition out of the "Sleep" state by transitioning into the state
> > "Resume" that certain devices use to boost the Power Limit (PLx) while
> > remaining in sleep (support for this new notification is rare). Then, it
> > transitions back into "Screen Off" and "Active" to prepare for the user.
> >
> > All transitions between these states feature unique firmware notifications
> > [3] that change the presentation of the device (e.g., pulse the suspend
> > light, turn off RGB). For more information, see the docs in [8]. Making
> > these transitions accessible from userspace moves them out of the suspend
> > sequence and has them happen while the kernel is fully active, mirroring
> > Windows.
> >
> > As a side effect, this patch series completely fixes the ROG Ally
> > controller issue [5], which expects for .5s to lapse before its
> > controller's USB hub goes into D3 and otherwise malfunctions. It also fixes
> > an issue present in (allegedly only) older firmwares where they check the
> > USB subsystem is not in D3 before allowing the controller to wake up while
> > in powersave mode (for avoiding spurious wake-ups). As such, this patch
> > series is also a universal fix for the ROG Ally controller.
> >
> > Moreover, this patch series allows turning off the controller and RGB of
> > most Windows handhelds (OneXPlayer, Lenovo Legion Go, GPD, and Asus ROG
> > Ally), opening the possibility of implementing suspend-then-hibernate and
> > other standby features, such as background downloads, without waking up the
> > RGB/controller of those devices. A Thinkpad T14 2021 was also tested, and
> > it pulses its suspend light during sleep.
> >
> > There is still the question of where LSP0 entry/exit (_DSM 5,6) should be
> > fired or whether they should be fired in the path to hibernation. However,
> > as they cause no issues currently, and they fire when software activity has
> > seized, they are fine where they are.
> >
> > It is important to note that the effects of these _DSMs persist during
> > reboots. I.e., if the Legion Go reboots while in the "Sleep" state, it will
> > boot into the "Sleep" state and have its controller disabled and suspend
> > light pulsing. The reboot persistence is undesirable, so the reboot path
> > will need to include a transition to active prior to reboot (not
> > included in this series). This is not the case after shutdown and
> > hibernation, where the device boots into the "Active" state.
> >
> > The issue of DPMS is still present. Currently, gamescope and KDE (at least)
> > do not fire DPMS before suspending. This causes an undesirable frozen
> > screen while the system is suspending and looks quite ugly in general. This
> > is especially true if the firmware notifications fire earlier. Therefore,
> > should the kernel fire DPMS before forcing the transition to sleep for
> > backwards compat.?
>
> FWIW in KDE we already planned to turn the screen off before suspend
> to deal better with spurious wakeups, and that'll be in the next
> version of Plasma. I think it's fine if you just leave this up to
> userspace, and maybe write to wayland-devel, so that other compositor
> developers are aware they should do the same.

This is really good to hear! I think that that is the proper solution,
along with instantly transitioning to screen off. This way the
keyboard backlight and the screen turn off instantly as the user
presses the power button. The fastest the kernel can do it is after
userspace freeze, which takes around .5s.

I still think we will have to do something in-kernel compat though, as
if we don't there is around 300ms between the device suspend light
starting to pulse and the drm driver turning off the display
currently. While it is a small visual regression, it is a regression
nonetheless and there are devices that depend on the USB subsystem
being up when the firmware notifications fire, so it cannot happen
after drm suspends.

We have not had any other reports whatsoever though and it is not as
if anyone has noticed this quirk.

@Mario while bisecting the hibernation issue, I also tested the Ally
with powersave on on a 6.10 stock kernel. While the controller does
wake up, setting RGB stops working after a few suspends

> > If yes, it will be quite the effort. Moreover, should
> > the kernel allow graphics drivers hook the transition function and block
> > transitions to "Screen Off" if there is an active CRTC? As that would be a
> > significant undertaking, there should be proof that there exists such a
> > device that has an issue firing the notifications with an active CRTC.
> >
> > A variant of this series has been tested by thousands of users by now,
> > where the notifications fire around .5s before the CRTC is disabled and no
> > ill-effects have found in regard to this quirk. AFAIK, it is a visual
> > quirk. Making DPMS fire before the backwards compat. transition is a good
> > idea in any case, as it will sync the 200ms between Display Off/Sleep Entry
> > firing and the graphics driver turning off the display, but it might not be
> > worth the effort.
> >
> > We are currently testing a DPMS patch for gamescope and it completely fixes
> > this visual quirk while allowing for e.g., hibernation without turning on
> > the screen. The DPMS gamescope patch + performing the transitions in
> > userspace in such a way where it blends the Ally's suspend delay halves the
> > user perceived delay to sleep and results in a very professional
> > presentation. This presentation extends to other devices as well, such as
> > the Legion Go.
> >
> > Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/prepare-hardware-for-modern-standby [1]
> > Link: https://learn.microsoft.com/en-us/windows-hardware/customize/power-settings/adaptive-hibernate [2]
> > Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-firmware-notifications [3]
> > Link: https://github.com/hhd-dev/hwinfo/tree/master/devices [4]
> > Link: https://git.kernel.org/pub/scm/linux/kernel/git/superm1/linux.git/log/?h=superm1/dsm-screen-on-off [5]
> > Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2719 [6]
> > Link: https://dl.dell.com/manuals/all-products/esuprt_solutions_int/esuprt_solutions_int_solutions_resources/client-mobile-solution-resources_white-papers45_en-us.pdf [7]
> > File: Documentation/admin-guide/pm/standby-states.rst [8]
> >
> > Changes from previous series (`acpi/x86: s2idle: move Display off/on calls
> >   outside suspend (fixes ROG Ally suspend)`):
> >   - Separate Display On/Off rename into its own commit (suggested by Hans)
> >   - Move delay quirks into s2idle.c (suggested by Hans)
> >   - Add documentation on Documentation/admin-guide/pm/standby-states.rst
> >   - Callbacks are now static and a transition function is used
> >   - Fixed all checkpatch warnings
> >   - The rest of the series is completely re-written
> >
> > Antheas Kapenekakis (13):
> >   Documentation: PM: Add documentation for S0ix Standby States
> >   acpi/x86: s2idle: add support for Display Off and Display On callbacks
> >   acpi/x86: s2idle: add support for Sleep Entry and Sleep Exit callbacks
> >   acpi/x86: s2idle: add support for Turn On Display callback
> >   acpi/x86: s2idle: add modern standby transition function
> >   acpi/x86: s2idle: rename Screen On/Off to Display On/Off
> >   acpi/x86: s2idle: call Display On/Off as part of callbacks
> >   acpi/x86: s2idle: rename MS Exit/Entry to Sleep Exit/Entry
> >   acpi/x86: s2idle: call Sleep Entry/Exit as part of callbacks
> >   acpi/x86: s2idle: add Turn On Display and call as part of callback
> >   acpi/x86: s2idle: add quirk table for modern standby delays
> >   platform/x86: asus-wmi: remove Ally (1st gen) and Ally X suspend quirk
> >   PM: standby: Add sysfs attribute for modern standby transitions
> >
> >  Documentation/ABI/testing/sysfs-power         |  34 +++
> >  .../admin-guide/pm/standby-states.rst         | 133 ++++++++++
> >  Documentation/admin-guide/pm/system-wide.rst  |   1 +
> >  drivers/acpi/x86/s2idle.c                     | 249 ++++++++++++++----
> >  drivers/platform/x86/asus-wmi.c               |  54 ----
> >  include/linux/suspend.h                       |  16 ++
> >  kernel/power/main.c                           |  75 ++++++
> >  kernel/power/power.h                          |   1 +
> >  kernel/power/suspend.c                        | 154 +++++++++++
> >  9 files changed, 616 insertions(+), 101 deletions(-)
> >  create mode 100644 Documentation/admin-guide/pm/standby-states.rst
> >
> > --
> > 2.47.0
> >
> >
Antheas Kapenekakis Dec. 6, 2024, 9:37 p.m. UTC | #7
Hi Rafael,
since 6.13-rc1 is out, hopefully you can have a look over the next few days

We have deployed a variant of this patchset now on desktop builds as
well for over 2 months now, and we haven't had any regressions
reported. We have also been using it on handheld builds, where for the
last 2 or so weeks we transition to the sleep state and fire the dpms
as part of the systemd sleep target, and it makes a big difference in
how devices look when suspending and hibernating.

Essentially, as soon as the suspend animation plays, the screen and
rgb of the devices turn off instantly, and the power light of devices
that have it as part of the sleep call begins to flash. Then, after a
few seconds, the fan of the devices turns off. Before, they'd show a
stale framebuffer and have the RGB be on until almost the suspend
sequence is over.

This is also true for hibernation, where before the RGB lights of the
devices would stay on during the suspend sequence and the device would
show a stale frame buffer on the screen. Now the devices look like
they are suspended while initializing hibernation and then just turn
off

Maybe I need to shoot a video with it..

So I'd love to hear your thoughts. Can you expand on what you mean by
not backwards compatible?

I know that it is not backwards compatible in the way where if the
compositor/init system are not aware of it, the display on/off
notifications will not fire automatically when the displays turn off.

Antheas

On Thu, 21 Nov 2024 at 18:41, Rafael J. Wysocki <rafael@kernel.org> wrote:
>
> On Thu, Nov 21, 2024 at 6:28 PM Antheas Kapenekakis <lkml@antheas.dev> wrote:
> >
> > The following series moves the _DSM 3,4,7,8 firmware notifications outside
> > the suspend sequence, and makes them part of a transition function, where
> > the system can transition freely between them when it is not suspended.
> > This transition function is exposed to userspace, which now gains the
> > ability to control the presentation of the device (e.g., pulse the suspend
> > light) without forcing the kernel to suspend. In addition, it adds support
> > for the _DSM 9 call Turn Display On, which was introduced in Windows 22H2
> > and aims to speed up device wake-up while remaining in the "Sleep" state.
> > If userspace is not standby aware, the kernel will bring the system into
> > the "Sleep" state before beginning the suspend sequence.
>
> I'll get to this when 6.13-rc1 is out, but I can tell you right away
> that some of the above cannot be done without breaking backwards
> compatibility.
>
> > This series requires a bit of background on how modern standby works in
> > Windows. Windows has a concept of "Modern Standby" [1], where it performs
> > an elaborate userspace and kernel suspend choreography while the device is
> > inactive in order to maintain fast wake-up times and connectivity while the
> > display of the device is off. This is done through 5 hardware states and
> > the OS takes the liberty of transitioning between them, by following a set
> > of rules (e.g., "Adaptive Hibernate").
> >
> > ```
> >                                  \/-> "Hibernate (S4)"
> > "Active" <-> "Screen Off" <-> "Sleep" <-> "DRIPS"
> >                   /\-  "Resume"  <-         <-
> > ```
> >
> > When the display is on and the user is interacting with the device, it is
> > in the "Active" state. The moment the display turns off, the device
> > transitions to the "Screen Off" state, where hardware and userspace are
> > fully active. Userspace will then decide when appropriate to freeze major
> > components (such as the DE) and transition into the "Sleep" state, where
> > the kernel is still active and connectivity is maintained. Finally, the
> > conventional "Suspend-to-idle" path can be used to bring the system into
> > the deepest runtime idle platform state (DRIPS) state, which is named
> > "s2idle" in the Linux kernel.
> >
> > After wake-up, the system re-transitions into the "Sleep" state, where
> > userspace can run housekeeping and/or hibernate if the wake-up was not user
> > initiated (e.g., timer). If user-initiated, userspace can hasten the
> > transition out of the "Sleep" state by transitioning into the state
> > "Resume" that certain devices use to boost the Power Limit (PLx) while
> > remaining in sleep (support for this new notification is rare). Then, it
> > transitions back into "Screen Off" and "Active" to prepare for the user.
> >
> > All transitions between these states feature unique firmware notifications
> > [3] that change the presentation of the device (e.g., pulse the suspend
> > light, turn off RGB). For more information, see the docs in [8]. Making
> > these transitions accessible from userspace moves them out of the suspend
> > sequence and has them happen while the kernel is fully active, mirroring
> > Windows.
> >
> > As a side effect, this patch series completely fixes the ROG Ally
> > controller issue [5], which expects for .5s to lapse before its
> > controller's USB hub goes into D3 and otherwise malfunctions. It also fixes
> > an issue present in (allegedly only) older firmwares where they check the
> > USB subsystem is not in D3 before allowing the controller to wake up while
> > in powersave mode (for avoiding spurious wake-ups). As such, this patch
> > series is also a universal fix for the ROG Ally controller.
> >
> > Moreover, this patch series allows turning off the controller and RGB of
> > most Windows handhelds (OneXPlayer, Lenovo Legion Go, GPD, and Asus ROG
> > Ally), opening the possibility of implementing suspend-then-hibernate and
> > other standby features, such as background downloads, without waking up the
> > RGB/controller of those devices. A Thinkpad T14 2021 was also tested, and
> > it pulses its suspend light during sleep.
> >
> > There is still the question of where LSP0 entry/exit (_DSM 5,6) should be
> > fired or whether they should be fired in the path to hibernation. However,
> > as they cause no issues currently, and they fire when software activity has
> > seized, they are fine where they are.
> >
> > It is important to note that the effects of these _DSMs persist during
> > reboots. I.e., if the Legion Go reboots while in the "Sleep" state, it will
> > boot into the "Sleep" state and have its controller disabled and suspend
> > light pulsing. The reboot persistence is undesirable, so the reboot path
> > will need to include a transition to active prior to reboot (not
> > included in this series). This is not the case after shutdown and
> > hibernation, where the device boots into the "Active" state.
> >
> > The issue of DPMS is still present. Currently, gamescope and KDE (at least)
> > do not fire DPMS before suspending. This causes an undesirable frozen
> > screen while the system is suspending and looks quite ugly in general. This
> > is especially true if the firmware notifications fire earlier. Therefore,
> > should the kernel fire DPMS before forcing the transition to sleep for
> > backwards compat.? If yes, it will be quite the effort. Moreover, should
> > the kernel allow graphics drivers hook the transition function and block
> > transitions to "Screen Off" if there is an active CRTC? As that would be a
> > significant undertaking, there should be proof that there exists such a
> > device that has an issue firing the notifications with an active CRTC.
> >
> > A variant of this series has been tested by thousands of users by now,
> > where the notifications fire around .5s before the CRTC is disabled and no
> > ill-effects have found in regard to this quirk. AFAIK, it is a visual
> > quirk. Making DPMS fire before the backwards compat. transition is a good
> > idea in any case, as it will sync the 200ms between Display Off/Sleep Entry
> > firing and the graphics driver turning off the display, but it might not be
> > worth the effort.
> >
> > We are currently testing a DPMS patch for gamescope and it completely fixes
> > this visual quirk while allowing for e.g., hibernation without turning on
> > the screen. The DPMS gamescope patch + performing the transitions in
> > userspace in such a way where it blends the Ally's suspend delay halves the
> > user perceived delay to sleep and results in a very professional
> > presentation. This presentation extends to other devices as well, such as
> > the Legion Go.
> >
> > Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/prepare-hardware-for-modern-standby [1]
> > Link: https://learn.microsoft.com/en-us/windows-hardware/customize/power-settings/adaptive-hibernate [2]
> > Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-firmware-notifications [3]
> > Link: https://github.com/hhd-dev/hwinfo/tree/master/devices [4]
> > Link: https://git.kernel.org/pub/scm/linux/kernel/git/superm1/linux.git/log/?h=superm1/dsm-screen-on-off [5]
> > Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2719 [6]
> > Link: https://dl.dell.com/manuals/all-products/esuprt_solutions_int/esuprt_solutions_int_solutions_resources/client-mobile-solution-resources_white-papers45_en-us.pdf [7]
> > File: Documentation/admin-guide/pm/standby-states.rst [8]
> >
> > Changes from previous series (`acpi/x86: s2idle: move Display off/on calls
> >   outside suspend (fixes ROG Ally suspend)`):
> >   - Separate Display On/Off rename into its own commit (suggested by Hans)
> >   - Move delay quirks into s2idle.c (suggested by Hans)
> >   - Add documentation on Documentation/admin-guide/pm/standby-states.rst
> >   - Callbacks are now static and a transition function is used
> >   - Fixed all checkpatch warnings
> >   - The rest of the series is completely re-written
> >
> > Antheas Kapenekakis (13):
> >   Documentation: PM: Add documentation for S0ix Standby States
> >   acpi/x86: s2idle: add support for Display Off and Display On callbacks
> >   acpi/x86: s2idle: add support for Sleep Entry and Sleep Exit callbacks
> >   acpi/x86: s2idle: add support for Turn On Display callback
> >   acpi/x86: s2idle: add modern standby transition function
> >   acpi/x86: s2idle: rename Screen On/Off to Display On/Off
> >   acpi/x86: s2idle: call Display On/Off as part of callbacks
> >   acpi/x86: s2idle: rename MS Exit/Entry to Sleep Exit/Entry
> >   acpi/x86: s2idle: call Sleep Entry/Exit as part of callbacks
> >   acpi/x86: s2idle: add Turn On Display and call as part of callback
> >   acpi/x86: s2idle: add quirk table for modern standby delays
> >   platform/x86: asus-wmi: remove Ally (1st gen) and Ally X suspend quirk
> >   PM: standby: Add sysfs attribute for modern standby transitions
> >
> >  Documentation/ABI/testing/sysfs-power         |  34 +++
> >  .../admin-guide/pm/standby-states.rst         | 133 ++++++++++
> >  Documentation/admin-guide/pm/system-wide.rst  |   1 +
> >  drivers/acpi/x86/s2idle.c                     | 249 ++++++++++++++----
> >  drivers/platform/x86/asus-wmi.c               |  54 ----
> >  include/linux/suspend.h                       |  16 ++
> >  kernel/power/main.c                           |  75 ++++++
> >  kernel/power/power.h                          |   1 +
> >  kernel/power/suspend.c                        | 154 +++++++++++
> >  9 files changed, 616 insertions(+), 101 deletions(-)
> >  create mode 100644 Documentation/admin-guide/pm/standby-states.rst
> >
> > --
> > 2.47.0
> >
> >