at 22.05-pre 16 kB view raw
1# This module provides the proprietary NVIDIA X11 / OpenGL drivers. 2 3{ config, lib, pkgs, ... }: 4 5with lib; 6 7let 8 nvidia_x11 = let 9 drivers = config.services.xserver.videoDrivers; 10 isDeprecated = str: (hasPrefix "nvidia" str) && (str != "nvidia"); 11 hasDeprecated = drivers: any isDeprecated drivers; 12 in if (hasDeprecated drivers) then 13 throw '' 14 Selecting an nvidia driver has been modified for NixOS 19.03. The version is now set using `hardware.nvidia.package`. 15 '' 16 else if (elem "nvidia" drivers) then cfg.package else null; 17 18 enabled = nvidia_x11 != null; 19 cfg = config.hardware.nvidia; 20 21 pCfg = cfg.prime; 22 syncCfg = pCfg.sync; 23 offloadCfg = pCfg.offload; 24 primeEnabled = syncCfg.enable || offloadCfg.enable; 25 nvidiaPersistencedEnabled = cfg.nvidiaPersistenced; 26 nvidiaSettings = cfg.nvidiaSettings; 27in 28 29{ 30 imports = 31 [ 32 (mkRenamedOptionModule [ "hardware" "nvidia" "optimus_prime" "enable" ] [ "hardware" "nvidia" "prime" "sync" "enable" ]) 33 (mkRenamedOptionModule [ "hardware" "nvidia" "optimus_prime" "allowExternalGpu" ] [ "hardware" "nvidia" "prime" "sync" "allowExternalGpu" ]) 34 (mkRenamedOptionModule [ "hardware" "nvidia" "optimus_prime" "nvidiaBusId" ] [ "hardware" "nvidia" "prime" "nvidiaBusId" ]) 35 (mkRenamedOptionModule [ "hardware" "nvidia" "optimus_prime" "intelBusId" ] [ "hardware" "nvidia" "prime" "intelBusId" ]) 36 ]; 37 38 options = { 39 hardware.nvidia.powerManagement.enable = mkOption { 40 type = types.bool; 41 default = false; 42 description = '' 43 Experimental power management through systemd. For more information, see 44 the NVIDIA docs, on Chapter 21. Configuring Power Management Support. 45 ''; 46 }; 47 48 hardware.nvidia.powerManagement.finegrained = mkOption { 49 type = types.bool; 50 default = false; 51 description = '' 52 Experimental power management of PRIME offload. For more information, see 53 the NVIDIA docs, chapter 22. PCI-Express runtime power management. 54 ''; 55 }; 56 57 hardware.nvidia.modesetting.enable = mkOption { 58 type = types.bool; 59 default = false; 60 description = '' 61 Enable kernel modesetting when using the NVIDIA proprietary driver. 62 63 Enabling this fixes screen tearing when using Optimus via PRIME (see 64 <option>hardware.nvidia.prime.sync.enable</option>. This is not enabled 65 by default because it is not officially supported by NVIDIA and would not 66 work with SLI. 67 ''; 68 }; 69 70 hardware.nvidia.prime.nvidiaBusId = mkOption { 71 type = types.str; 72 default = ""; 73 example = "PCI:1:0:0"; 74 description = '' 75 Bus ID of the NVIDIA GPU. You can find it using lspci; for example if lspci 76 shows the NVIDIA GPU at "01:00.0", set this option to "PCI:1:0:0". 77 ''; 78 }; 79 80 hardware.nvidia.prime.intelBusId = mkOption { 81 type = types.str; 82 default = ""; 83 example = "PCI:0:2:0"; 84 description = '' 85 Bus ID of the Intel GPU. You can find it using lspci; for example if lspci 86 shows the Intel GPU at "00:02.0", set this option to "PCI:0:2:0". 87 ''; 88 }; 89 90 hardware.nvidia.prime.amdgpuBusId = mkOption { 91 type = types.str; 92 default = ""; 93 example = "PCI:4:0:0"; 94 description = '' 95 Bus ID of the AMD APU. You can find it using lspci; for example if lspci 96 shows the AMD APU at "04:00.0", set this option to "PCI:4:0:0". 97 ''; 98 }; 99 100 hardware.nvidia.prime.sync.enable = mkOption { 101 type = types.bool; 102 default = false; 103 description = '' 104 Enable NVIDIA Optimus support using the NVIDIA proprietary driver via PRIME. 105 If enabled, the NVIDIA GPU will be always on and used for all rendering, 106 while enabling output to displays attached only to the integrated Intel GPU 107 without a multiplexer. 108 109 Note that this option only has any effect if the "nvidia" driver is specified 110 in <option>services.xserver.videoDrivers</option>, and it should preferably 111 be the only driver there. 112 113 If this is enabled, then the bus IDs of the NVIDIA and Intel GPUs have to be 114 specified (<option>hardware.nvidia.prime.nvidiaBusId</option> and 115 <option>hardware.nvidia.prime.intelBusId</option>). 116 117 If you enable this, you may want to also enable kernel modesetting for the 118 NVIDIA driver (<option>hardware.nvidia.modesetting.enable</option>) in order 119 to prevent tearing. 120 121 Note that this configuration will only be successful when a display manager 122 for which the <option>services.xserver.displayManager.setupCommands</option> 123 option is supported is used. 124 ''; 125 }; 126 127 hardware.nvidia.prime.sync.allowExternalGpu = mkOption { 128 type = types.bool; 129 default = false; 130 description = '' 131 Configure X to allow external NVIDIA GPUs when using optimus. 132 ''; 133 }; 134 135 hardware.nvidia.prime.offload.enable = mkOption { 136 type = types.bool; 137 default = false; 138 description = '' 139 Enable render offload support using the NVIDIA proprietary driver via PRIME. 140 141 If this is enabled, then the bus IDs of the NVIDIA and Intel GPUs have to be 142 specified (<option>hardware.nvidia.prime.nvidiaBusId</option> and 143 <option>hardware.nvidia.prime.intelBusId</option>). 144 ''; 145 }; 146 147 hardware.nvidia.nvidiaSettings = mkOption { 148 default = true; 149 type = types.bool; 150 description = '' 151 Whether to add nvidia-settings, NVIDIA's GUI configuration tool, to 152 systemPackages. 153 ''; 154 }; 155 156 hardware.nvidia.nvidiaPersistenced = mkOption { 157 default = false; 158 type = types.bool; 159 description = '' 160 Update for NVIDA GPU headless mode, i.e. nvidia-persistenced. It ensures all 161 GPUs stay awake even during headless mode. 162 ''; 163 }; 164 165 hardware.nvidia.package = lib.mkOption { 166 type = lib.types.package; 167 default = config.boot.kernelPackages.nvidiaPackages.stable; 168 defaultText = literalExpression "config.boot.kernelPackages.nvidiaPackages.stable"; 169 description = '' 170 The NVIDIA X11 derivation to use. 171 ''; 172 example = literalExpression "config.boot.kernelPackages.nvidiaPackages.legacy_340"; 173 }; 174 }; 175 176 config = let 177 igpuDriver = if pCfg.intelBusId != "" then "modesetting" else "amdgpu"; 178 igpuBusId = if pCfg.intelBusId != "" then pCfg.intelBusId else pCfg.amdgpuBusId; 179 in mkIf enabled { 180 assertions = [ 181 { 182 assertion = with config.services.xserver.displayManager; gdm.nvidiaWayland -> cfg.modesetting.enable; 183 message = "You cannot use wayland with GDM without modesetting enabled for NVIDIA drivers, set `hardware.nvidia.modesetting.enable = true`"; 184 } 185 186 { 187 assertion = primeEnabled -> pCfg.intelBusId == "" || pCfg.amdgpuBusId == ""; 188 message = '' 189 You cannot configure both an Intel iGPU and an AMD APU. Pick the one corresponding to your processor. 190 ''; 191 } 192 193 { 194 assertion = primeEnabled -> pCfg.nvidiaBusId != "" && (pCfg.intelBusId != "" || pCfg.amdgpuBusId != ""); 195 message = '' 196 When NVIDIA PRIME is enabled, the GPU bus IDs must configured. 197 ''; 198 } 199 200 { 201 assertion = offloadCfg.enable -> versionAtLeast nvidia_x11.version "435.21"; 202 message = "NVIDIA PRIME render offload is currently only supported on versions >= 435.21."; 203 } 204 205 { 206 assertion = !(syncCfg.enable && offloadCfg.enable); 207 message = "Only one NVIDIA PRIME solution may be used at a time."; 208 } 209 210 { 211 assertion = !(syncCfg.enable && cfg.powerManagement.finegrained); 212 message = "Sync precludes powering down the NVIDIA GPU."; 213 } 214 215 { 216 assertion = cfg.powerManagement.finegrained -> offloadCfg.enable; 217 message = "Fine-grained power management requires offload to be enabled."; 218 } 219 220 { 221 assertion = cfg.powerManagement.enable -> ( 222 builtins.pathExists (cfg.package.out + "/bin/nvidia-sleep.sh") && 223 builtins.pathExists (cfg.package.out + "/lib/systemd/system-sleep/nvidia") 224 ); 225 message = "Required files for driver based power management don't exist."; 226 } 227 ]; 228 229 # If Optimus/PRIME is enabled, we: 230 # - Specify the configured NVIDIA GPU bus ID in the Device section for the 231 # "nvidia" driver. 232 # - Add the AllowEmptyInitialConfiguration option to the Screen section for the 233 # "nvidia" driver, in order to allow the X server to start without any outputs. 234 # - Add a separate Device section for the Intel GPU, using the "modesetting" 235 # driver and with the configured BusID. 236 # - OR add a separate Device section for the AMD APU, using the "amdgpu" 237 # driver and with the configures BusID. 238 # - Reference that Device section from the ServerLayout section as an inactive 239 # device. 240 # - Configure the display manager to run specific `xrandr` commands which will 241 # configure/enable displays connected to the Intel iGPU / AMD APU. 242 243 services.xserver.useGlamor = mkDefault offloadCfg.enable; 244 245 services.xserver.drivers = let 246 in optional primeEnabled { 247 name = igpuDriver; 248 display = offloadCfg.enable; 249 modules = optional (igpuDriver == "amdgpu") [ pkgs.xorg.xf86videoamdgpu ]; 250 deviceSection = '' 251 BusID "${igpuBusId}" 252 ${optionalString syncCfg.enable ''Option "AccelMethod" "none"''} 253 ''; 254 } ++ singleton { 255 name = "nvidia"; 256 modules = [ nvidia_x11.bin ]; 257 display = !offloadCfg.enable; 258 deviceSection = optionalString primeEnabled 259 '' 260 BusID "${pCfg.nvidiaBusId}" 261 ${optionalString syncCfg.allowExternalGpu "Option \"AllowExternalGpus\""} 262 ${optionalString cfg.powerManagement.finegrained "Option \"NVreg_DynamicPowerManagement=0x02\""} 263 ''; 264 screenSection = 265 '' 266 Option "RandRRotation" "on" 267 ${optionalString syncCfg.enable "Option \"AllowEmptyInitialConfiguration\""} 268 ''; 269 }; 270 271 services.xserver.serverLayoutSection = optionalString syncCfg.enable '' 272 Inactive "Device-${igpuDriver}[0]" 273 '' + optionalString offloadCfg.enable '' 274 Option "AllowNVIDIAGPUScreens" 275 ''; 276 277 services.xserver.displayManager.setupCommands = optionalString syncCfg.enable '' 278 # Added by nvidia configuration module for Optimus/PRIME. 279 ${pkgs.xorg.xrandr}/bin/xrandr --setprovideroutputsource ${igpuDriver} NVIDIA-0 280 ${pkgs.xorg.xrandr}/bin/xrandr --auto 281 ''; 282 283 environment.etc."nvidia/nvidia-application-profiles-rc" = mkIf nvidia_x11.useProfiles { 284 source = "${nvidia_x11.bin}/share/nvidia/nvidia-application-profiles-rc"; 285 }; 286 287 # 'nvidia_x11' installs it's files to /run/opengl-driver/... 288 environment.etc."egl/egl_external_platform.d".source = 289 "/run/opengl-driver/share/egl/egl_external_platform.d/"; 290 291 hardware.opengl.package = mkIf (!offloadCfg.enable) nvidia_x11.out; 292 hardware.opengl.package32 = mkIf (!offloadCfg.enable) nvidia_x11.lib32; 293 hardware.opengl.extraPackages = optional offloadCfg.enable nvidia_x11.out; 294 hardware.opengl.extraPackages32 = optional offloadCfg.enable nvidia_x11.lib32; 295 296 environment.systemPackages = [ nvidia_x11.bin ] 297 ++ optionals cfg.nvidiaSettings [ nvidia_x11.settings ] 298 ++ optionals nvidiaPersistencedEnabled [ nvidia_x11.persistenced ]; 299 300 systemd.packages = optional cfg.powerManagement.enable nvidia_x11.out; 301 302 systemd.services = let 303 baseNvidiaService = state: { 304 description = "NVIDIA system ${state} actions"; 305 306 path = with pkgs; [ kbd ]; 307 serviceConfig = { 308 Type = "oneshot"; 309 ExecStart = "${nvidia_x11.out}/bin/nvidia-sleep.sh '${state}'"; 310 }; 311 }; 312 313 nvidiaService = sleepState: (baseNvidiaService sleepState) // { 314 before = [ "systemd-${sleepState}.service" ]; 315 requiredBy = [ "systemd-${sleepState}.service" ]; 316 }; 317 318 services = (builtins.listToAttrs (map (t: nameValuePair "nvidia-${t}" (nvidiaService t)) ["hibernate" "suspend"])) 319 // { 320 nvidia-resume = (baseNvidiaService "resume") // { 321 after = [ "systemd-suspend.service" "systemd-hibernate.service" ]; 322 requiredBy = [ "systemd-suspend.service" "systemd-hibernate.service" ]; 323 }; 324 }; 325 in optionalAttrs cfg.powerManagement.enable services 326 // optionalAttrs nvidiaPersistencedEnabled { 327 "nvidia-persistenced" = mkIf nvidiaPersistencedEnabled { 328 description = "NVIDIA Persistence Daemon"; 329 wantedBy = [ "multi-user.target" ]; 330 serviceConfig = { 331 Type = "forking"; 332 Restart = "always"; 333 PIDFile = "/var/run/nvidia-persistenced/nvidia-persistenced.pid"; 334 ExecStart = "${nvidia_x11.persistenced}/bin/nvidia-persistenced --verbose"; 335 ExecStopPost = "${pkgs.coreutils}/bin/rm -rf /var/run/nvidia-persistenced"; 336 }; 337 }; 338 }; 339 340 systemd.tmpfiles.rules = optional config.virtualisation.docker.enableNvidia 341 "L+ /run/nvidia-docker/bin - - - - ${nvidia_x11.bin}/origBin" 342 ++ optional (nvidia_x11.persistenced != null && config.virtualisation.docker.enableNvidia) 343 "L+ /run/nvidia-docker/extras/bin/nvidia-persistenced - - - - ${nvidia_x11.persistenced}/origBin/nvidia-persistenced"; 344 345 boot.extraModulePackages = [ nvidia_x11.bin ]; 346 347 # nvidia-uvm is required by CUDA applications. 348 boot.kernelModules = [ "nvidia-uvm" ] ++ 349 optionals config.services.xserver.enable [ "nvidia" "nvidia_modeset" "nvidia_drm" ]; 350 351 # If requested enable modesetting via kernel parameter. 352 boot.kernelParams = optional (offloadCfg.enable || cfg.modesetting.enable) "nvidia-drm.modeset=1" 353 ++ optional cfg.powerManagement.enable "nvidia.NVreg_PreserveVideoMemoryAllocations=1"; 354 355 services.udev.extraRules = 356 '' 357 # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded. 358 KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidiactl c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) 255'" 359 KERNEL=="nvidia_modeset", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-modeset c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) 254'" 360 KERNEL=="card*", SUBSYSTEM=="drm", DRIVERS=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia%n c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) %n'" 361 KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 0'" 362 KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm-tools c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 0'" 363 '' + optionalString cfg.powerManagement.finegrained '' 364 # Remove NVIDIA USB xHCI Host Controller devices, if present 365 ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1" 366 367 # Remove NVIDIA USB Type-C UCSI devices, if present 368 ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1" 369 370 # Remove NVIDIA Audio devices, if present 371 ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1" 372 373 # Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind 374 ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto" 375 ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto" 376 377 # Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind 378 ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on" 379 ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on" 380 ''; 381 382 boot.extraModprobeConfig = mkIf cfg.powerManagement.finegrained '' 383 options nvidia "NVreg_DynamicPowerManagement=0x02" 384 ''; 385 386 boot.blacklistedKernelModules = [ "nouveau" "nvidiafb" ]; 387 388 services.acpid.enable = true; 389 390 }; 391 392}