Message ID | 20241121172239.119590-1-lkml@antheas.dev (mailing list archive) |
---|---|
Headers | show |
Series | acpi/x86: s2idle: implement Modern Standby transition states and expose to userspace | expand |
On Thu, 21 Nov 2024 at 19:16, Mario Limonciello <mario.limonciello@amd.com> wrote: > > On 11/21/2024 11:22, Antheas Kapenekakis wrote: > > Add a new function to transition modern standby states and call it > > as part of the suspend sequence to make sure it begins under the > > Modern Standby "Sleep" state. > > > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev> > > --- > > include/linux/suspend.h | 11 ++++ > > kernel/power/power.h | 1 + > > kernel/power/suspend.c | 127 ++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 139 insertions(+) > > > > diff --git a/include/linux/suspend.h b/include/linux/suspend.h > > index 01ee64321cda..b8fe781d8026 100644 > > --- a/include/linux/suspend.h > > +++ b/include/linux/suspend.h > > @@ -40,6 +40,15 @@ typedef int __bitwise suspend_state_t; > > #define PM_SUSPEND_MIN PM_SUSPEND_TO_IDLE > > #define PM_SUSPEND_MAX ((__force suspend_state_t) 4) > > > > +typedef int __bitwise standby_state_t; > > As this is series is working on emulating semantics of "Modern Standby" > on Windows, why not name it all "modern_standby"? > > IE > > modern_standby_state_t > PM_MODERN_STANDBY_ACTIVE > PM_MODERN_STANDBY_SCREEN_OFF I would rather keep the name more generalizable. Modern Standby is the Microsoft term. That was the idea behind it at least. If other drivers want to hook into this, I think it would be desirable as well. As far as the s2ildle x86 semantics thats up in the air htough. > > + > > +#define PM_STANDBY_ACTIVE ((__force standby_state_t) 0) > > +#define PM_STANDBY_SCREEN_OFF ((__force standby_state_t) 1) > > +#define PM_STANDBY_SLEEP ((__force standby_state_t) 2) > > +#define PM_STANDBY_RESUME ((__force standby_state_t) 3) > > +#define PM_STANDBY_MIN PM_STANDBY_ACTIVE > > +#define PM_STANDBY_MAX ((__force standby_state_t) 4) > > + > > /** > > * struct platform_suspend_ops - Callbacks for managing platform dependent > > * system sleep states. > > @@ -281,6 +290,8 @@ extern void arch_suspend_enable_irqs(void); > > > > extern int pm_suspend(suspend_state_t state); > > extern bool sync_on_suspend_enabled; > > +extern int pm_standby_transition(standby_state_t state); > > +extern int pm_standby_state(void); > > #else /* !CONFIG_SUSPEND */ > > #define suspend_valid_only_mem NULL > > > > diff --git a/kernel/power/power.h b/kernel/power/power.h > > index de0e6b1077f2..4ee067cd0d4d 100644 > > --- a/kernel/power/power.h > > +++ b/kernel/power/power.h > > @@ -207,6 +207,7 @@ extern void swsusp_show_speed(ktime_t, ktime_t, unsigned int, char *); > > extern const char * const pm_labels[]; > > extern const char *pm_states[]; > > extern const char *mem_sleep_states[]; > > +extern const char *standby_states[]; > > > > extern int suspend_devices_and_enter(suspend_state_t state); > > #else /* !CONFIG_SUSPEND */ > > diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c > > index a42e8514ee7a..1865db71a0c2 100644 > > --- a/kernel/power/suspend.c > > +++ b/kernel/power/suspend.c > > @@ -45,12 +45,21 @@ static const char * const mem_sleep_labels[] = { > > [PM_SUSPEND_MEM] = "deep", > > }; > > const char *mem_sleep_states[PM_SUSPEND_MAX]; > > +static const char * const standby_labels[] = { > > + [PM_STANDBY_ACTIVE] = "active", > > + [PM_STANDBY_SCREEN_OFF] = "screen_off", > > + [PM_STANDBY_SLEEP] = "sleep", > > + [PM_STANDBY_RESUME] = "resume", > > +}; > > +const char *standby_states[PM_STANDBY_MAX]; > > > > suspend_state_t mem_sleep_current = PM_SUSPEND_TO_IDLE; > > suspend_state_t mem_sleep_default = PM_SUSPEND_MAX; > > suspend_state_t pm_suspend_target_state; > > EXPORT_SYMBOL_GPL(pm_suspend_target_state); > > > > +standby_state_t standby_current = PM_STANDBY_ACTIVE; > > + > > unsigned int pm_suspend_global_flags; > > EXPORT_SYMBOL_GPL(pm_suspend_global_flags); > > > > @@ -188,6 +197,16 @@ void __init pm_states_init(void) > > * initialize mem_sleep_states[] accordingly here. > > */ > > mem_sleep_states[PM_SUSPEND_TO_IDLE] = mem_sleep_labels[PM_SUSPEND_TO_IDLE]; > > + /* All systems support the "active" state. */ > > + standby_states[PM_STANDBY_ACTIVE] = standby_labels[PM_STANDBY_ACTIVE]; > > + /* > > + * Not all systems support these states, where they will have increased > > + * power consumption. If deemed necessary, they should be gated to not > > + * mislead userspace. > > + */ > > + standby_states[PM_STANDBY_SCREEN_OFF] = standby_labels[PM_STANDBY_SCREEN_OFF]; > > + standby_states[PM_STANDBY_SLEEP] = standby_labels[PM_STANDBY_SLEEP]; > > + standby_states[PM_STANDBY_RESUME] = standby_labels[PM_STANDBY_RESUME]; > > Shouldn't these states only be enabled when LPS0 support was found? IE > shouldn't they be enabled by acpi_register_lps0_dev() and disabled by > acpi_unregister_lps0_dev() This is a place i want to look more into. Yes I agree that these states should be hidden. However, we have the issue right now where s2idle is globally enabled too, even if the platform does not support S3 or advertise S0 support in the FADT. Windows correctly hibernates Ayaneo devices that do not advertise either for example, where linux just makes them enter a semi broken state. Ayaneo has started releasing updated BIOSes that fix that though so that fixes that issue until another manufacturer decides to do that. I would also like to see if it is possible to hide individual states if the hardware does not support them. However, I think ACPI does not advertise support for any of these states. IE you either support all of them or none of them through the UUID existing. > > } > > > > static int __init mem_sleep_default_setup(char *str) > > @@ -354,6 +373,108 @@ static bool platform_suspend_again(suspend_state_t state) > > suspend_ops->suspend_again() : false; > > } > > > > +static int platform_standby_transition_internal(standby_state_t state) > > +{ > > + int error; > > + > > + if (state == standby_current) > > + return 0; > > + if (state > PM_STANDBY_MAX) > > + return -EINVAL; > > + > > + pm_pr_dbg("Transitioning from standby state %s to %s\n", > > + standby_states[standby_current], standby_states[state]); > > + > > + /* Resume can only be entered if we are on the sleep state. */ > > + if (state == PM_STANDBY_RESUME) { > > + if (standby_current != PM_STANDBY_SLEEP) > > + return -EINVAL; > > + standby_current = PM_STANDBY_RESUME; > > + return platform_standby_turn_on_display(); > > + } > > + > > + /* > > + * The system should not be able to re-enter Sleep from resume as it > > + * is undefined behavior. As part of setting the state to "Resume", > > + * were promised a transition to "Screen Off" or "Active". > > + */ > > + if (standby_current == PM_STANDBY_RESUME && state == PM_STANDBY_SLEEP) > > + return -EINVAL; > > + > > + /* Resume is the Sleep state logic-wise. */ > > + if (standby_current == PM_STANDBY_RESUME) > > + standby_current = PM_STANDBY_SLEEP; > > + > > + if (standby_current < state) { > > + for (; standby_current < state; standby_current++) { > > + switch (standby_current + 1) { > > + case PM_STANDBY_SCREEN_OFF: > > + error = platform_standby_display_off(); > > + break; > > + case PM_STANDBY_SLEEP: > > + error = platform_standby_sleep_entry(); > > + break; > > + } > > + > > + if (error) > > + return error; > > + } > > + } else if (standby_current > state) { > > + for (; standby_current > state; standby_current--) { > > + switch (standby_current) { > > + case PM_STANDBY_SLEEP: > > + error = platform_standby_sleep_exit(); > > + break; > > + case PM_STANDBY_SCREEN_OFF: > > + error = platform_standby_display_on(); > > + break; > > + } > > + > > + if (error) > > + return error; > > + } > > + } > > + > > + return 0; > > +} > > + > > +/** > > + * pm_standby_transition - Transition between Modern Standby states > > + * > > + * Fires the appropriate firmware notifications to transition to the requested > > + * state. Returns an error if the transition fails. The function does not > > + * rollback. It is up to userspace to handle the error and re-transition when > > + * appropriate. > > + */ > > +int pm_standby_transition(standby_state_t state) > > +{ > > + unsigned int sleep_flags; > > + int error; > > + > > + sleep_flags = lock_system_sleep(); > > + error = platform_standby_transition_internal(state); > > + unlock_system_sleep(sleep_flags); > > + > > + return error; > > +} > > +EXPORT_SYMBOL_GPL(pm_standby_transition); > > + > > +/** > > + * pm_standby_state - Returns the current standby state > > + */ > > +int pm_standby_state(void) > > +{ > > + unsigned int sleep_flags; > > + int state; > > + > > + sleep_flags = lock_system_sleep(); > > + state = standby_current; > > + unlock_system_sleep(sleep_flags); > > + > > + return state; > > +} > > +EXPORT_SYMBOL_GPL(pm_standby_state); > > + > > #ifdef CONFIG_PM_DEBUG > > static unsigned int pm_test_delay = 5; > > module_param(pm_test_delay, uint, 0644); > > @@ -586,6 +707,7 @@ static void suspend_finish(void) > > static int enter_state(suspend_state_t state) > > { > > int error; > > + standby_state_t standby_prior; > > > > trace_suspend_resume(TPS("suspend_enter"), state, true); > > if (state == PM_SUSPEND_TO_IDLE) { > > @@ -601,6 +723,9 @@ static int enter_state(suspend_state_t state) > > if (!mutex_trylock(&system_transition_mutex)) > > return -EBUSY; > > > > + standby_prior = standby_current; > > + platform_standby_transition_internal(PM_STANDBY_SLEEP); > > + > > if (state == PM_SUSPEND_TO_IDLE) > > s2idle_begin(); > > > > @@ -630,6 +755,8 @@ static int enter_state(suspend_state_t state) > > pm_pr_dbg("Finishing wakeup.\n"); > > suspend_finish(); > > Unlock: > > + platform_standby_transition_internal(standby_prior); > > + > > mutex_unlock(&system_transition_mutex); > > return error; > > } >
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 > >>>> > >> >