[RFC 13/13] PM: standby: Add sysfs attribute for modern standby transitions

Ilpo Järvinen ilpo.jarvinen at linux.intel.com
Thu Nov 28 11:45:07 UTC 2024


On Thu, 21 Nov 2024, Antheas Kapenekakis wrote:

> Add a sysfs attribute to allow informing the kernel about the current
> standby state, those being: "active", "screen_off", "sleep", and
> "resume" (to prepare turning the display on). The final modern
> standby state DRIPS is omitted, as that is entered during the kernel
> suspend process and userspace will never see it.
> 
> Signed-off-by: Antheas Kapenekakis <lkml at antheas.dev>
> ---
>  Documentation/ABI/testing/sysfs-power | 34 ++++++++++++
>  kernel/power/main.c                   | 75 +++++++++++++++++++++++++++
>  2 files changed, 109 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
> index a3942b1036e2..eff13980cc7c 100644
> --- a/Documentation/ABI/testing/sysfs-power
> +++ b/Documentation/ABI/testing/sysfs-power
> @@ -39,6 +39,40 @@ Description:
>  		See Documentation/admin-guide/pm/sleep-states.rst for more
>  		information.
>  
> +What:		/sys/power/standby
> +Date:		November 2024
> +Contact:	Antheas Kapenekakis <lkml at antheas.dev>
> +Description:
> +		The /sys/power/standby file controls the standby state of the
> +		system. Modern S0ix capable systems can enter a set of low power
> +		states while the kernel is still active. Transitioning into those
> +		states may 1) deactivate tertiary hardware, and 2) change the
> +		presentation of the device (e.g., pulse the suspend light, turn
> +		off the keyboard backlight).
> +
> +		Available states are "active" (fully active), "screen-off" (fully
> +		active but all displays of the system are off; virtual and real),
> +		"sleep" (major userspace components have been frozen; light
> +		background tasks may still run; this state may affect the power
> +		envelope of the device). The final state is DRIPS or LSP0, where
> +		the kernel suspends, and is entered by writing "mem" to
> +		/sys/power/state. There is a secondary sleep state called "resume"
> +		that can only be entered from "sleep" and is used in certain
> +		devices to boost the Power Limit (PLx) while remaining in sleep
> +		to hasten preparing for transitioning to "active".
> +
> +		Writing one of the above strings to this file causes the system
> +		to transition into the corresponding state, by firing the
> +		corresponding firmware notifications during the transition.
> +
> +		DRIPS or LSP0 (i.e., mem "s2idle") can only be entered from the
> +		"sleep" state. If the kernel is asked to transition to DRIPS from
> +		a different state, it will transition to "sleep" and then suspend.
> +		On wakeup, the kernel will transition back to the previous state.
> +
> +		See Documentation/admin-guide/pm/standby-states.rst for more
> +		information.
> +
>  What:		/sys/power/disk
>  Date:		September 2006
>  Contact:	Rafael J. Wysocki <rjw at rjwysocki.net>
> diff --git a/kernel/power/main.c b/kernel/power/main.c
> index 6254814d4817..4377fdaf4a8d 100644
> --- a/kernel/power/main.c
> +++ b/kernel/power/main.c
> @@ -748,6 +748,80 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
>  
>  power_attr(state);
>  
> +#ifdef CONFIG_SUSPEND
> +/*
> + * standby - control system s2idle standby state.
> + *
> + * show() returns available standby states, which may be "active", "screen_off",
> + * "sleep" and "resume" (still in sleep but preparing to turn on display).
> + * See Documentation/admin-guide/pm/standby-states.rst for a description of
> + * what they mean.
> + *
> + * store() accepts one of those strings, translates it into the proper
> + * enumerated value, and initiates a transition to that standby state.
> + *
> + * When the system suspends, it will first enter the state "sleep", suspend,
> + * and then restore the last state before entering "sleep". I.e., if userspace
> + * is not S0ix-aware, the transitions expected by Modern Standby devices will
> + * always be performed.
> + */
> +static ssize_t standby_show(struct kobject *kobj, struct kobj_attribute *attr,
> +			  char *buf)
> +{
> +	char *s = buf;

Instead of char *, add size_t len for the offset.

Order these to reverse xmas tree.

> +	standby_state_t i;
> +	standby_state_t curr = pm_standby_state();
> +
> +	if (curr < 0)
> +		return -EBUSY;
> +
> +	for (i = PM_STANDBY_MIN; i < PM_STANDBY_MAX; i++)
> +		if (standby_states[i])
> +			s += sprintf(s, curr == i ? "[%s] " : "%s ", standby_states[i]);

Do not use sprintf() for anything new.

For sysfs, sysfs_emit_at() (or sysfs_emit()) is the correct function.

You could consider using reverse logic + continue to bring down the 
indentation level.

> +
> +	if (s != buf)
> +		/* convert the last space to a newline */
> +		*(s - 1) = '\n';
> +	return (s - buf);
> +}
> +
> +static standby_state_t decode_standby_state(const char *buf, size_t n)
> +{
> +	standby_state_t state;
> +	char *p;
> +	int len;

size_t

> +	p = memchr(buf, '\n', n);
> +	len = p ? p - buf : n;
> +
> +	for (state = PM_STANDBY_MIN; state < PM_STANDBY_MAX; state++) {
> +		const char *label = standby_states[state];
> +
> +		if (label && len == strlen(label) && !strncmp(buf, label, len))

Isn't len == strlen(label) && !strncmp(buf, label, len) same as using just
using !strcmp() ?

> +			return state;
> +	}
> +
> +	return PM_STANDBY_MAX;
> +}
> +
> +static ssize_t standby_store(struct kobject *kobj, struct kobj_attribute *attr,
> +			   const char *buf, size_t n)
> +{
> +	int error;
> +	standby_state_t state;
> +
> +	state = decode_standby_state(buf, n);
> +
> +	if (state >= PM_STANDBY_MAX)
> +		return -EINVAL;
> +
> +	error = pm_standby_transition(state);
> +	return error ? error : n;

return error ?: n

> +}
> +
> +power_attr(standby);
> +#endif
> +
>  #ifdef CONFIG_PM_SLEEP
>  /*
>   * The 'wakeup_count' attribute, along with the functions defined in
> @@ -974,6 +1048,7 @@ static struct attribute * g[] = {
>  #ifdef CONFIG_SUSPEND
>  	&mem_sleep_attr.attr,
>  	&sync_on_suspend_attr.attr,
> +	&standby_attr.attr,
>  #endif
>  #ifdef CONFIG_PM_AUTOSLEEP
>  	&autosleep_attr.attr,
> 

-- 
 i.



More information about the dri-devel mailing list