at 24.11-pre 5.3 kB view raw
1{ config, pkgs, lib, ... }: 2 3with lib; 4let 5 cfg = config.services.undervolt; 6 7 mkPLimit = limit: window: 8 if (limit == null && window == null) then null 9 else assert asserts.assertMsg (limit != null && window != null) "Both power limit and window must be set"; 10 "${toString limit} ${toString window}"; 11 cliArgs = lib.cli.toGNUCommandLine {} { 12 inherit (cfg) 13 verbose 14 temp 15 turbo 16 ; 17 # `core` and `cache` are both intentionally set to `cfg.coreOffset` as according to the undervolt docs: 18 # 19 # Core or Cache offsets have no effect. It is not possible to set different offsets for 20 # CPU Core and Cache. The CPU will take the smaller of the two offsets, and apply that to 21 # both CPU and Cache. A warning message will be displayed if you attempt to set different offsets. 22 core = cfg.coreOffset; 23 cache = cfg.coreOffset; 24 gpu = cfg.gpuOffset; 25 uncore = cfg.uncoreOffset; 26 analogio = cfg.analogioOffset; 27 28 temp-bat = cfg.tempBat; 29 temp-ac = cfg.tempAc; 30 31 power-limit-long = mkPLimit cfg.p1.limit cfg.p1.window; 32 power-limit-short = mkPLimit cfg.p2.limit cfg.p2.window; 33 }; 34in 35{ 36 options.services.undervolt = { 37 enable = mkEnableOption '' 38 Undervolting service for Intel CPUs. 39 40 Warning: This service is not endorsed by Intel and may permanently damage your hardware. Use at your own risk 41 ''; 42 43 verbose = mkOption { 44 type = types.bool; 45 default = false; 46 description = '' 47 Whether to enable verbose logging. 48 ''; 49 }; 50 51 package = mkPackageOption pkgs "undervolt" { }; 52 53 coreOffset = mkOption { 54 type = types.nullOr types.int; 55 default = null; 56 description = '' 57 The amount of voltage in mV to offset the CPU cores by. 58 ''; 59 }; 60 61 gpuOffset = mkOption { 62 type = types.nullOr types.int; 63 default = null; 64 description = '' 65 The amount of voltage in mV to offset the GPU by. 66 ''; 67 }; 68 69 uncoreOffset = mkOption { 70 type = types.nullOr types.int; 71 default = null; 72 description = '' 73 The amount of voltage in mV to offset uncore by. 74 ''; 75 }; 76 77 analogioOffset = mkOption { 78 type = types.nullOr types.int; 79 default = null; 80 description = '' 81 The amount of voltage in mV to offset analogio by. 82 ''; 83 }; 84 85 temp = mkOption { 86 type = types.nullOr types.int; 87 default = null; 88 description = '' 89 The temperature target in Celsius degrees. 90 ''; 91 }; 92 93 tempAc = mkOption { 94 type = types.nullOr types.int; 95 default = null; 96 description = '' 97 The temperature target on AC power in Celsius degrees. 98 ''; 99 }; 100 101 tempBat = mkOption { 102 type = types.nullOr types.int; 103 default = null; 104 description = '' 105 The temperature target on battery power in Celsius degrees. 106 ''; 107 }; 108 109 turbo = mkOption { 110 type = types.nullOr types.int; 111 default = null; 112 description = '' 113 Changes the Intel Turbo feature status (1 is disabled and 0 is enabled). 114 ''; 115 }; 116 117 p1.limit = mkOption { 118 type = with types; nullOr int; 119 default = null; 120 description = '' 121 The P1 Power Limit in Watts. 122 Both limit and window must be set. 123 ''; 124 }; 125 p1.window = mkOption { 126 type = with types; nullOr (oneOf [ float int ]); 127 default = null; 128 description = '' 129 The P1 Time Window in seconds. 130 Both limit and window must be set. 131 ''; 132 }; 133 134 p2.limit = mkOption { 135 type = with types; nullOr int; 136 default = null; 137 description = '' 138 The P2 Power Limit in Watts. 139 Both limit and window must be set. 140 ''; 141 }; 142 p2.window = mkOption { 143 type = with types; nullOr (oneOf [ float int ]); 144 default = null; 145 description = '' 146 The P2 Time Window in seconds. 147 Both limit and window must be set. 148 ''; 149 }; 150 151 useTimer = mkOption { 152 type = types.bool; 153 default = false; 154 description = '' 155 Whether to set a timer that applies the undervolt settings every 30s. 156 This will cause spam in the journal but might be required for some 157 hardware under specific conditions. 158 Enable this if your undervolt settings don't hold. 159 ''; 160 }; 161 }; 162 163 config = mkIf cfg.enable { 164 hardware.cpu.x86.msr.enable = true; 165 166 environment.systemPackages = [ cfg.package ]; 167 168 systemd.services.undervolt = { 169 description = "Intel Undervolting Service"; 170 171 # Apply undervolt on boot, nixos generation switch and resume 172 wantedBy = [ "multi-user.target" "post-resume.target" ]; 173 after = [ "post-resume.target" ]; # Not sure why but it won't work without this 174 175 serviceConfig = { 176 Type = "oneshot"; 177 Restart = "no"; 178 ExecStart = "${cfg.package}/bin/undervolt ${toString cliArgs}"; 179 }; 180 }; 181 182 systemd.timers.undervolt = mkIf cfg.useTimer { 183 description = "Undervolt timer to ensure voltage settings are always applied"; 184 partOf = [ "undervolt.service" ]; 185 wantedBy = [ "multi-user.target" ]; 186 timerConfig = { 187 OnBootSec = "2min"; 188 OnUnitActiveSec = "30"; 189 }; 190 }; 191 }; 192}