blob: 58d6a4f8e569f38c1b9aa44a729476bffb467f11 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.tlp;
enableRDW = config.networking.networkmanager.enable;
# TODO: Use this for having proper parameters in the future
mkTlpConfig =
tlpConfig:
lib.generators.toKeyValue {
mkKeyValue = lib.generators.mkKeyValueDefault {
mkValueString = val: if lib.isList val then "\"" + (toString val) + "\"" else toString val;
} "=";
} tlpConfig;
in
{
###### interface
options = {
services.tlp = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to enable the TLP power management daemon.";
};
pd = {
enable = lib.mkEnableOption "the power-rofiles-daemon like DBus interface for TLP";
package = lib.mkPackageOption pkgs "tlp-pd" { };
};
settings = lib.mkOption {
type =
with lib.types;
attrsOf (oneOf [
bool
int
float
str
(listOf str)
]);
default = { };
example = {
SATA_LINKPWR_ON_BAT = "med_power_with_dipm";
USB_BLACKLIST_PHONE = 1;
};
description = ''
Options passed to TLP. See <https://linrunner.de/tlp> for all supported options..
'';
};
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
description = ''
Verbatim additional configuration variables for TLP.
DEPRECATED: use services.tlp.settings instead.
'';
};
package = lib.mkOption {
type = lib.types.package;
default = pkgs.tlp.override { inherit enableRDW; };
defaultText = "pkgs.tlp.override { enableRDW = config.networking.networkmanager.enable; }";
description = "The tlp package to use.";
};
};
};
###### implementation
config = lib.mkIf cfg.enable {
hardware.cpu.x86.msr.enable = true;
warnings = lib.optional (cfg.extraConfig != "") ''
Using config.services.tlp.extraConfig is deprecated and will become unsupported in a future release. Use config.services.tlp.settings instead.
'';
assertions = [
{
assertion = cfg.enable -> config.powerManagement.scsiLinkPolicy == null;
message = ''
`services.tlp.enable` and `config.powerManagement.scsiLinkPolicy` cannot be set both.
Set `services.tlp.settings.SATA_LINKPWR_ON_AC` and `services.tlp.settings.SATA_LINKPWR_ON_BAT` instead.
'';
}
{
assertion = cfg.pd.enable -> !config.services.power-profiles-daemon.enable;
message = ''
`services.tlp.pd` and `services.power-profiles-daemon` cannot be enabled together,
because they are using the same dbus interface and have the same functionality.
Generally, `services.tlp.pd` should be preferred as upstream does not recommend
using tlp together with power-profiles-daemon.
Set `services.power-profiles-daemon.enable` to `false` to resolve this error.
'';
}
{
assertion = cfg.pd.enable -> !(config.services.tuned.enable && config.services.tuned.ppdSupport);
message = ''
`services.tlp.pd` and `services.tuned.ppdSupport` cannot be enabled together,
because they are using the same dbus interface and have the same functionality.
'';
}
];
environment.etc = {
"tlp.conf".text = (mkTlpConfig cfg.settings) + cfg.extraConfig;
}
// lib.optionalAttrs enableRDW {
"NetworkManager/dispatcher.d/99tlp-rdw-nm".source =
"${cfg.package}/lib/NetworkManager/dispatcher.d/99tlp-rdw-nm";
};
environment.systemPackages = [
cfg.package
]
++ lib.optionals cfg.pd.enable [ cfg.pd.package ];
services.tlp.settings =
let
cfg = config.powerManagement;
maybeDefault = val: lib.mkIf (val != null) (lib.mkDefault val);
in
{
CPU_SCALING_GOVERNOR_ON_AC = maybeDefault cfg.cpuFreqGovernor;
CPU_SCALING_GOVERNOR_ON_BAT = maybeDefault cfg.cpuFreqGovernor;
CPU_SCALING_MIN_FREQ_ON_AC = maybeDefault cfg.cpufreq.min;
CPU_SCALING_MAX_FREQ_ON_AC = maybeDefault cfg.cpufreq.max;
CPU_SCALING_MIN_FREQ_ON_BAT = maybeDefault cfg.cpufreq.min;
CPU_SCALING_MAX_FREQ_ON_BAT = maybeDefault cfg.cpufreq.max;
};
services.udev.packages = [ cfg.package ];
systemd = {
# use native tlp instead because it can also differentiate between AC/BAT
services.cpufreq.enable = false;
packages = [
cfg.package
]
++ lib.optionals cfg.pd.enable [ cfg.pd.package ];
# XXX: These must always be disabled/masked according to [1].
#
# [1]: https://github.com/linrunner/TLP/blob/a9ada09e0821f275ce5f93dc80a4d81a7ff62ae4/tlp-stat.in#L319
sockets.systemd-rfkill.enable = false;
services.systemd-rfkill.enable = false;
services.tlp = {
# XXX: The service should reload whenever the configuration changes,
# otherwise newly set power options remain inactive until reboot (or
# manual unit restart.)
restartTriggers = [ config.environment.etc."tlp.conf".source ];
# XXX: When using systemd.packages (which we do above) the [Install]
# section of systemd units does not work (citation needed) so we manually
# enforce it here.
wantedBy = [ "multi-user.target" ];
};
services.tlp-sleep = {
# XXX: When using systemd.packages (which we do above) the [Install]
# section of systemd units does not work (citation needed) so we manually
# enforce it here.
before = [ "sleep.target" ];
wantedBy = [ "sleep.target" ];
# XXX: `tlp suspend` requires /var/lib/tlp to exist in order to save
# some stuff in there. There is no way, that I know of, to do this in
# the package itself, so we do it here instead making sure the unit
# won't fail due to the save dir not existing.
serviceConfig.StateDirectory = "tlp";
};
services.tlp-pd = lib.mkIf cfg.pd.enable {
# have to define again because [Install] in included file not honored
# https://github.com/NixOS/nixpkgs/issues/81138
wantedBy = [ "graphical.target" ];
};
};
};
}
|