diff --git a/modules/desktop.nix b/modules/desktop.nix index 1fe9333..4b1dc68 100644 --- a/modules/desktop.nix +++ b/modules/desktop.nix @@ -15,6 +15,21 @@ services.displayManager.gdm.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 services.xserver.xkb = { layout = "us,ru"; diff --git a/modules/power.nix b/modules/power.nix index ecd00cf..de9e334 100644 --- a/modules/power.nix +++ b/modules/power.nix @@ -6,26 +6,41 @@ # resume_offset = first physical block of /var/swapfile (for hibernate from # an ext4 swapfile on LUKS). Recompute if the swapfile is recreated: # 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. # P14s G6 AMD has no S3 (Modern Standby only); this enables # suspend-then-hibernate so long sleeps drain to disk. boot.resumeDevice = "/dev/mapper/luks-71c97ce7-dd29-4b07-8d2a-8cc3985a65bd"; - # systemd-logind: when lid closes / suspend pressed, suspend first; - # if still asleep after the delay, hibernate. + # On battery: suspend-then-hibernate (s2idle then hibernate after + # 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 = { HandleLidSwitch = "suspend-then-hibernate"; + HandleLidSwitchExternalPower = "suspend"; HandleSuspendKey = "suspend-then-hibernate"; + HandlePowerKey = "hibernate"; IdleAction = "suspend-then-hibernate"; IdleActionSec = "30min"; }; - # Switch to hibernate after this long in s2idle. - systemd.sleep.settings.Sleep = { - HibernateDelaySec = "45min"; - }; + # s2idle window before transitioning to hibernate. acpi.ec_no_wakeup=1 + # (above) prevents the prior EC-driven s2idle thrash on this machine. + # 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 powerManagement.cpuFreqGovernor = "powersave";