power: stabilize suspend-then-hibernate on P14s G6 AMD

acpi.ec_no_wakeup=1 stops EC interrupts from thrashing s2idle, and a
dconf system-db override disables gsd-power's sleep handlers so logind
owns all sleep/idle policy (gsd was re-waking before HibernateDelaySec).
Split lid/suspend policy by power source (s-t-h on battery, plain suspend
on AC), map power key to hibernate, drop HibernateDelaySec to 15min while
re-validating thermals, and disable USB-device wakeup via udev.
This commit is contained in:
Sergei Poljanski 2026-06-02 14:07:07 +03:00
commit a72fb75811
Signed by: asxpi
GPG key ID: 4F8851660FA4121B
2 changed files with 37 additions and 7 deletions

View file

@ -15,6 +15,21 @@
services.displayManager.gdm.enable = true; services.displayManager.gdm.enable = true;
services.desktopManager.gnome.enable = true; services.desktopManager.gnome.enable = true;
# Let systemd-logind own all sleep/idle policy. gsd-power otherwise
# second-guesses suspend-then-hibernate and re-wakes the machine before
# HibernateDelaySec elapses (observed on P14s G6 AMD). Set via dconf
# system db (gsettings-overrides only compiles desktop/shell/mutter
# schemas, so a g-s-d plugin override there is silently dropped).
programs.dconf.profiles.user.databases = [{
settings = {
"org/gnome/settings-daemon/plugins/power" = {
sleep-inactive-battery-type = "nothing";
sleep-inactive-ac-type = "nothing";
power-button-action = "nothing";
};
};
}];
# Configure keymap in X11 # Configure keymap in X11
services.xserver.xkb = { services.xserver.xkb = {
layout = "us,ru"; layout = "us,ru";

View file

@ -6,26 +6,41 @@
# resume_offset = first physical block of /var/swapfile (for hibernate from # resume_offset = first physical block of /var/swapfile (for hibernate from
# an ext4 swapfile on LUKS). Recompute if the swapfile is recreated: # an ext4 swapfile on LUKS). Recompute if the swapfile is recreated:
# sudo filefrag -v /var/swapfile | awk 'NR==4{gsub(/\.\./,""); print $4}' # sudo filefrag -v /var/swapfile | awk 'NR==4{gsub(/\.\./,""); print $4}'
boot.kernelParams = [ "amd_pstate=active" "resume_offset=1769472" ]; # acpi.ec_no_wakeup=1: prevents EC wakeups from draining battery in s2idle
# on P14s G6 AMD. See https://lore.kernel.org/all/ZnFYpWHJ5Ml724Nv@ohnotp/
boot.kernelParams = [ "amd_pstate=active" "resume_offset=1769472" "acpi.ec_no_wakeup=1" ];
# Hibernate / resume from encrypted swapfile on LUKS root. # Hibernate / resume from encrypted swapfile on LUKS root.
# P14s G6 AMD has no S3 (Modern Standby only); this enables # P14s G6 AMD has no S3 (Modern Standby only); this enables
# suspend-then-hibernate so long sleeps drain to disk. # suspend-then-hibernate so long sleeps drain to disk.
boot.resumeDevice = "/dev/mapper/luks-71c97ce7-dd29-4b07-8d2a-8cc3985a65bd"; boot.resumeDevice = "/dev/mapper/luks-71c97ce7-dd29-4b07-8d2a-8cc3985a65bd";
# systemd-logind: when lid closes / suspend pressed, suspend first; # On battery: suspend-then-hibernate (s2idle then hibernate after
# if still asleep after the delay, hibernate. # HibernateDelaySec). Previously this looped suspend->wake->suspend due
# to ACPI EC interrupts, but acpi.ec_no_wakeup=1 (above) plus disabling
# gsd-power's sleep handlers (in desktop.nix via dconf) makes it stable.
# On AC, plain suspend (s2idle) is fine.
services.logind.settings.Login = { services.logind.settings.Login = {
HandleLidSwitch = "suspend-then-hibernate"; HandleLidSwitch = "suspend-then-hibernate";
HandleLidSwitchExternalPower = "suspend";
HandleSuspendKey = "suspend-then-hibernate"; HandleSuspendKey = "suspend-then-hibernate";
HandlePowerKey = "hibernate";
IdleAction = "suspend-then-hibernate"; IdleAction = "suspend-then-hibernate";
IdleActionSec = "30min"; IdleActionSec = "30min";
}; };
# Switch to hibernate after this long in s2idle. # s2idle window before transitioning to hibernate. acpi.ec_no_wakeup=1
systemd.sleep.settings.Sleep = { # (above) prevents the prior EC-driven s2idle thrash on this machine.
HibernateDelaySec = "45min"; # Conservative value while bag-thermal behavior is being re-validated;
}; # raise to 30-45min once confirmed safe.
systemd.sleep.settings.Sleep.HibernateDelaySec = "15min";
# Stop USB devices (e.g. Aerox 3 WL receiver) from waking the machine
# from s2idle. Only usb_device nodes have power/wakeup; matching on the
# devtype avoids "Invalid operator for ATTRS" on udev verification.
services.udev.extraRules = ''
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{power/wakeup}="disabled"
'';
# CPU frequency scaling # CPU frequency scaling
powerManagement.cpuFreqGovernor = "powersave"; powerManagement.cpuFreqGovernor = "powersave";