nixos-lib/power.nix

203 lines
6.6 KiB
Nix

{
config,
pkgs,
lib,
myLib,
...
}:
with lib;
let
generalCfg = config.aviallon.general;
cfg = config.aviallon.power;
undervoltType = with types; nullOr (addCheck int (x: (x < 0 && x > -200)));
in
{
options.aviallon.power = {
enable = mkOption {
default = true;
example = false;
type = types.bool;
description = "Wether to enable power related tuning";
};
policy = mkOption {
default = "performance";
example = "efficiency";
description = "What to optimize towards";
type = types.enum [
"performance"
"efficiency"
];
};
powerLimit = {
enable = mkEnableOption "power limiting";
ac = {
cpu = mkOption {
default = null;
type = types.nullOr types.int;
description = "Power limit when on AC. Set to null for unlimited.";
example = 35;
};
cpuBoost = mkOption {
default = null;
type = types.nullOr types.int;
description = "Boost power limit when on AC. Set to null for unlimited.";
example = 65;
};
};
battery = {
cpu = mkOption {
default = null;
type = types.nullOr types.int;
description = "Power limit when on battery. Set to null for unlimited.";
example = 15;
};
cpuBoost = mkOption {
default = null;
type = types.nullOr types.int;
description = "Boost power limit when on battery. Set to null for unlimited.";
example = 35;
};
};
};
temperature = {
enable = mkEnableOption "Temperature limitting";
ac = {
cpu = mkOption {
default = null;
type = types.nullOr types.int;
description = "Temperature limit when on AC.";
example = 100;
};
};
battery = {
cpu = mkOption {
default = null;
type = types.nullOr types.int;
description = "Temperature limit when on battery.";
example = 60;
};
};
};
undervolt.cpu = {
enable = mkEnableOption "CPU undervolting. Unstability may be caused when using this option.";
coreOffset = mkOption {
default = null;
example = -25;
description = "CPU core offset in mV";
type = undervoltType;
};
cacheOffset = mkOption {
default = cfg.undervolt.cpu.coreOffset;
example = -25;
description = "Cache offset in mV";
type = undervoltType;
};
iGPUOffset = mkOption {
default = null;
example = -15;
description = "iGPU offset in mV";
type = undervoltType;
};
};
undervolt.gpu = {
enable = mkEnableOption "GPU undervolting.";
};
};
config = mkIf cfg.enable {
systemd.targets.ac-power = {
description = "Target is active when AC is plugged-in.";
conflicts = [ "battery-power.target" ];
unitConfig = {
ConditionACPower = true;
};
};
systemd.targets.battery-power = {
description = "Target is active when power is drawn from a battery.";
conflicts = [ "ac-power.target" ];
unitConfig = {
ConditionACPower = false;
};
};
services.udev.extraRules = ''
ACTION!="remove", KERNEL=="AC*", SUBSYSTEM=="power_supply", ATTR{online}=="0", RUN+="${pkgs.systemd}/bin/systemctl stop ac-power.target"
ACTION!="remove", KERNEL=="AC*", SUBSYSTEM=="power_supply", ATTR{online}=="1", RUN+="${pkgs.systemd}/bin/systemctl start ac-power.target"
ACTION!="remove", KERNEL=="BAT*", SUBSYSTEM=="power_supply", ATTR{status}=="Discharging", RUN+="${pkgs.systemd}/bin/systemctl start battery-power.target"
ACTION!="remove", KERNEL=="BAT*", SUBSYSTEM=="power_supply", ATTR{status}=="Charging", RUN+="${pkgs.systemd}/bin/systemctl stop battery-power.target"
ACTION!="remove", DEVPATH=="*intel-rapl:*", SUBSYSTEM=="powercap", RUN+="${pkgs.coreutils}/bin/chmod g+r '/sys%p/energy_uj'"
'';
users.groups.power = { };
systemd.services.undervolt-intel = {
script =
""
+ "${pkgs.undervolt}/bin/undervolt"
+ (optionalString (
!isNull cfg.undervolt.cpu.coreOffset
) " --core ${toString cfg.undervolt.cpu.coreOffset}")
+ (optionalString (
!isNull cfg.undervolt.cpu.cacheOffset
) " --cache ${toString cfg.undervolt.cpu.cacheOffset}")
+ (optionalString (
!isNull cfg.undervolt.cpu.iGPUOffset
) " --gpu ${toString cfg.undervolt.cpu.iGPUOffset}");
serviceConfig = {
RemainAfterExit = true;
};
wantedBy = [ "multi-user.target" ];
description = "Undervolt Intel CPUs with supported firmware.";
enable = cfg.undervolt.cpu.enable && (generalCfg.cpu.vendor == "intel");
};
systemd.services.intel-powerlimit-ac = {
script =
"${pkgs.undervolt}/bin/undervolt"
+ optionalString (
!isNull cfg.powerLimit.ac.cpu
) " --power-limit-long ${toString cfg.powerLimit.ac.cpu} 28"
+ optionalString (
!isNull cfg.powerLimit.ac.cpuBoost
) " --power-limit-short ${toString cfg.powerLimit.ac.cpuBoost} 0.1"
+ optionalString (!isNull cfg.temperature.ac.cpu) " --temp ${toString cfg.temperature.ac.cpu}";
unitConfig = {
ConditionACPower = true;
};
serviceConfig = {
RemainAfterExit = true;
};
wantedBy = [ "ac-power.target" ];
description = "Set power limit of Intel CPUs with supported firmware. AC mode.";
partOf = [ "ac-power.target" ];
enable = (cfg.powerLimit.enable || cfg.temperature.enable) && (generalCfg.cpu.vendor == "intel");
};
systemd.services.intel-powerlimit-battery = {
script =
"${pkgs.undervolt}/bin/undervolt"
+ optionalString (
!isNull cfg.powerLimit.battery.cpu
) " --power-limit-long ${toString cfg.powerLimit.battery.cpu} 28"
+ optionalString (
!isNull cfg.powerLimit.battery.cpuBoost
) " --power-limit-short ${toString cfg.powerLimit.battery.cpuBoost} 0.1"
+ optionalString (
!isNull cfg.temperature.battery.cpu
) " --temp ${toString cfg.temperature.battery.cpu}";
unitConfig = {
ConditionACPower = false;
};
serviceConfig = {
RemainAfterExit = true;
};
wantedBy = [ "battery-power.target" ];
description = "Set power limit of Intel CPUs with supported firmware. Battery mode.";
partOf = [ "battery-power.target" ];
enable = (cfg.powerLimit.enable || cfg.temperature.enable) && (generalCfg.cpu.vendor == "intel");
};
};
}