at 23.11-pre 22 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 reverseSyncCfg = pCfg.reverseSync; 25 primeEnabled = syncCfg.enable || reverseSyncCfg.enable || offloadCfg.enable; 26 nvidiaPersistencedEnabled = cfg.nvidiaPersistenced; 27 nvidiaSettings = cfg.nvidiaSettings; 28 busIDType = types.strMatching "([[:print:]]+[\:\@][0-9]{1,3}\:[0-9]{1,2}\:[0-9])?"; 29 30 ibtSupport = cfg.open || (nvidia_x11.ibtSupport or false); 31in 32 33{ 34 imports = 35 [ 36 (mkRenamedOptionModule [ "hardware" "nvidia" "optimus_prime" "enable" ] [ "hardware" "nvidia" "prime" "sync" "enable" ]) 37 (mkRenamedOptionModule [ "hardware" "nvidia" "optimus_prime" "allowExternalGpu" ] [ "hardware" "nvidia" "prime" "allowExternalGpu" ]) 38 (mkRenamedOptionModule [ "hardware" "nvidia" "prime" "sync" "allowExternalGpu" ] [ "hardware" "nvidia" "prime" "allowExternalGpu" ]) 39 (mkRenamedOptionModule [ "hardware" "nvidia" "optimus_prime" "nvidiaBusId" ] [ "hardware" "nvidia" "prime" "nvidiaBusId" ]) 40 (mkRenamedOptionModule [ "hardware" "nvidia" "optimus_prime" "intelBusId" ] [ "hardware" "nvidia" "prime" "intelBusId" ]) 41 ]; 42 43 options = { 44 hardware.nvidia.powerManagement.enable = mkOption { 45 type = types.bool; 46 default = false; 47 description = lib.mdDoc '' 48 Experimental power management through systemd. For more information, see 49 the NVIDIA docs, on Chapter 21. Configuring Power Management Support. 50 ''; 51 }; 52 53 hardware.nvidia.powerManagement.finegrained = mkOption { 54 type = types.bool; 55 default = false; 56 description = lib.mdDoc '' 57 Experimental power management of PRIME offload. For more information, see 58 the NVIDIA docs, chapter 22. PCI-Express runtime power management. 59 ''; 60 }; 61 62 hardware.nvidia.modesetting.enable = mkOption { 63 type = types.bool; 64 default = false; 65 description = lib.mdDoc '' 66 Enable kernel modesetting when using the NVIDIA proprietary driver. 67 68 Enabling this fixes screen tearing when using Optimus via PRIME (see 69 {option}`hardware.nvidia.prime.sync.enable`. This is not enabled 70 by default because it is not officially supported by NVIDIA and would not 71 work with SLI. 72 ''; 73 }; 74 75 hardware.nvidia.prime.nvidiaBusId = mkOption { 76 type = busIDType; 77 default = ""; 78 example = "PCI:1:0:0"; 79 description = lib.mdDoc '' 80 Bus ID of the NVIDIA GPU. You can find it using lspci; for example if lspci 81 shows the NVIDIA GPU at "01:00.0", set this option to "PCI:1:0:0". 82 ''; 83 }; 84 85 hardware.nvidia.prime.intelBusId = mkOption { 86 type = busIDType; 87 default = ""; 88 example = "PCI:0:2:0"; 89 description = lib.mdDoc '' 90 Bus ID of the Intel GPU. You can find it using lspci; for example if lspci 91 shows the Intel GPU at "00:02.0", set this option to "PCI:0:2:0". 92 ''; 93 }; 94 95 hardware.nvidia.prime.amdgpuBusId = mkOption { 96 type = busIDType; 97 default = ""; 98 example = "PCI:4:0:0"; 99 description = lib.mdDoc '' 100 Bus ID of the AMD APU. You can find it using lspci; for example if lspci 101 shows the AMD APU at "04:00.0", set this option to "PCI:4:0:0". 102 ''; 103 }; 104 105 hardware.nvidia.prime.sync.enable = mkOption { 106 type = types.bool; 107 default = false; 108 description = lib.mdDoc '' 109 Enable NVIDIA Optimus support using the NVIDIA proprietary driver via PRIME. 110 If enabled, the NVIDIA GPU will be always on and used for all rendering, 111 while enabling output to displays attached only to the integrated Intel/AMD 112 GPU without a multiplexer. 113 114 Note that this option only has any effect if the "nvidia" driver is specified 115 in {option}`services.xserver.videoDrivers`, and it should preferably 116 be the only driver there. 117 118 If this is enabled, then the bus IDs of the NVIDIA and Intel/AMD GPUs have to 119 be specified ({option}`hardware.nvidia.prime.nvidiaBusId` and 120 {option}`hardware.nvidia.prime.intelBusId` or 121 {option}`hardware.nvidia.prime.amdgpuBusId`). 122 123 If you enable this, you may want to also enable kernel modesetting for the 124 NVIDIA driver ({option}`hardware.nvidia.modesetting.enable`) in order 125 to prevent tearing. 126 127 Note that this configuration will only be successful when a display manager 128 for which the {option}`services.xserver.displayManager.setupCommands` 129 option is supported is used. 130 ''; 131 }; 132 133 hardware.nvidia.prime.allowExternalGpu = mkOption { 134 type = types.bool; 135 default = false; 136 description = lib.mdDoc '' 137 Configure X to allow external NVIDIA GPUs when using Prime [Reverse] sync optimus. 138 ''; 139 }; 140 141 hardware.nvidia.prime.offload.enable = mkOption { 142 type = types.bool; 143 default = false; 144 description = lib.mdDoc '' 145 Enable render offload support using the NVIDIA proprietary driver via PRIME. 146 147 If this is enabled, then the bus IDs of the NVIDIA and Intel/AMD GPUs have to 148 be specified ({option}`hardware.nvidia.prime.nvidiaBusId` and 149 {option}`hardware.nvidia.prime.intelBusId` or 150 {option}`hardware.nvidia.prime.amdgpuBusId`). 151 ''; 152 }; 153 154 hardware.nvidia.prime.offload.enableOffloadCmd = mkOption { 155 type = types.bool; 156 default = false; 157 description = lib.mdDoc '' 158 Adds a `nvidia-offload` convenience script to {option}`environment.systemPackages` 159 for offloading programs to an nvidia device. To work, should have also enabled 160 {option}`hardware.nvidia.prime.offload.enable` or {option}`hardware.nvidia.prime.reverseSync.enable`. 161 162 Example usage `nvidia-offload sauerbraten_client`. 163 ''; 164 }; 165 166 hardware.nvidia.prime.reverseSync.enable = mkOption { 167 type = types.bool; 168 default = false; 169 description = lib.mdDoc '' 170 Warning: This feature is relatively new, depending on your system this might 171 work poorly. AMD support, especially so. 172 See: https://forums.developer.nvidia.com/t/the-all-new-outputsink-feature-aka-reverse-prime/129828 173 174 Enable NVIDIA Optimus support using the NVIDIA proprietary driver via reverse 175 PRIME. If enabled, the Intel/AMD GPU will be used for all rendering, while 176 enabling output to displays attached only to the NVIDIA GPU without a 177 multiplexer. 178 179 Note that this option only has any effect if the "nvidia" driver is specified 180 in {option}`services.xserver.videoDrivers`, and it should preferably 181 be the only driver there. 182 183 If this is enabled, then the bus IDs of the NVIDIA and Intel/AMD GPUs have to 184 be specified ({option}`hardware.nvidia.prime.nvidiaBusId` and 185 {option}`hardware.nvidia.prime.intelBusId` or 186 {option}`hardware.nvidia.prime.amdgpuBusId`). 187 188 If you enable this, you may want to also enable kernel modesetting for the 189 NVIDIA driver ({option}`hardware.nvidia.modesetting.enable`) in order 190 to prevent tearing. 191 192 Note that this configuration will only be successful when a display manager 193 for which the {option}`services.xserver.displayManager.setupCommands` 194 option is supported is used. 195 ''; 196 }; 197 198 hardware.nvidia.nvidiaSettings = mkOption { 199 default = true; 200 type = types.bool; 201 description = lib.mdDoc '' 202 Whether to add nvidia-settings, NVIDIA's GUI configuration tool, to 203 systemPackages. 204 ''; 205 }; 206 207 hardware.nvidia.nvidiaPersistenced = mkOption { 208 default = false; 209 type = types.bool; 210 description = lib.mdDoc '' 211 Update for NVIDA GPU headless mode, i.e. nvidia-persistenced. It ensures all 212 GPUs stay awake even during headless mode. 213 ''; 214 }; 215 216 hardware.nvidia.forceFullCompositionPipeline = lib.mkOption { 217 default = false; 218 type = types.bool; 219 description = lib.mdDoc '' 220 Whether to force-enable the full composition pipeline. 221 This sometimes fixes screen tearing issues. 222 This has been reported to reduce the performance of some OpenGL applications and may produce issues in WebGL. 223 It also drastically increases the time the driver needs to clock down after load. 224 ''; 225 }; 226 227 hardware.nvidia.package = lib.mkOption { 228 type = types.package; 229 default = config.boot.kernelPackages.nvidiaPackages.stable; 230 defaultText = literalExpression "config.boot.kernelPackages.nvidiaPackages.stable"; 231 description = lib.mdDoc '' 232 The NVIDIA X11 derivation to use. 233 ''; 234 example = literalExpression "config.boot.kernelPackages.nvidiaPackages.legacy_340"; 235 }; 236 237 hardware.nvidia.open = lib.mkOption { 238 type = lib.types.bool; 239 default = false; 240 description = lib.mdDoc '' 241 Whether to use the open source kernel module 242 ''; 243 }; 244 }; 245 246 config = let 247 igpuDriver = if pCfg.intelBusId != "" then "modesetting" else "amdgpu"; 248 igpuBusId = if pCfg.intelBusId != "" then pCfg.intelBusId else pCfg.amdgpuBusId; 249 in mkIf enabled { 250 assertions = [ 251 { 252 assertion = primeEnabled -> pCfg.intelBusId == "" || pCfg.amdgpuBusId == ""; 253 message = '' 254 You cannot configure both an Intel iGPU and an AMD APU. Pick the one corresponding to your processor. 255 ''; 256 } 257 258 { 259 assertion = offloadCfg.enableOffloadCmd -> offloadCfg.enable || reverseSyncCfg.enable; 260 message = '' 261 Offload command requires offloading or reverse prime sync to be enabled. 262 ''; 263 } 264 265 { 266 assertion = primeEnabled -> pCfg.nvidiaBusId != "" && (pCfg.intelBusId != "" || pCfg.amdgpuBusId != ""); 267 message = '' 268 When NVIDIA PRIME is enabled, the GPU bus IDs must configured. 269 ''; 270 } 271 272 { 273 assertion = offloadCfg.enable -> versionAtLeast nvidia_x11.version "435.21"; 274 message = "NVIDIA PRIME render offload is currently only supported on versions >= 435.21."; 275 } 276 277 { 278 assertion = (reverseSyncCfg.enable && pCfg.amdgpuBusId != "") -> versionAtLeast nvidia_x11.version "470.0"; 279 message = "NVIDIA PRIME render offload for AMD APUs is currently only supported on versions >= 470 beta."; 280 } 281 282 { 283 assertion = !(syncCfg.enable && offloadCfg.enable); 284 message = "PRIME Sync and Offload cannot be both enabled"; 285 } 286 287 { 288 assertion = !(syncCfg.enable && reverseSyncCfg.enable); 289 message = "PRIME Sync and PRIME Reverse Sync cannot be both enabled"; 290 } 291 292 { 293 assertion = !(syncCfg.enable && cfg.powerManagement.finegrained); 294 message = "Sync precludes powering down the NVIDIA GPU."; 295 } 296 297 { 298 assertion = cfg.powerManagement.finegrained -> offloadCfg.enable; 299 message = "Fine-grained power management requires offload to be enabled."; 300 } 301 302 { 303 assertion = cfg.powerManagement.enable -> versionAtLeast nvidia_x11.version "430.09"; 304 message = "Required files for driver based power management only exist on versions >= 430.09."; 305 } 306 307 { 308 assertion = cfg.open -> (cfg.package ? open && cfg.package ? firmware); 309 message = "This version of NVIDIA driver does not provide a corresponding opensource kernel driver"; 310 } 311 ]; 312 313 # If Optimus/PRIME is enabled, we: 314 # - Specify the configured NVIDIA GPU bus ID in the Device section for the 315 # "nvidia" driver. 316 # - Add the AllowEmptyInitialConfiguration option to the Screen section for the 317 # "nvidia" driver, in order to allow the X server to start without any outputs. 318 # - Add a separate Device section for the Intel GPU, using the "modesetting" 319 # driver and with the configured BusID. 320 # - OR add a separate Device section for the AMD APU, using the "amdgpu" 321 # driver and with the configures BusID. 322 # - Reference that Device section from the ServerLayout section as an inactive 323 # device. 324 # - Configure the display manager to run specific `xrandr` commands which will 325 # configure/enable displays connected to the Intel iGPU / AMD APU. 326 327 # reverse sync implies offloading 328 hardware.nvidia.prime.offload.enable = mkDefault reverseSyncCfg.enable; 329 330 services.xserver.drivers = optional primeEnabled { 331 name = igpuDriver; 332 display = offloadCfg.enable; 333 modules = optionals (igpuDriver == "amdgpu") [ pkgs.xorg.xf86videoamdgpu ]; 334 deviceSection = '' 335 BusID "${igpuBusId}" 336 ${optionalString (syncCfg.enable && igpuDriver != "amdgpu") ''Option "AccelMethod" "none"''} 337 ''; 338 } ++ singleton { 339 name = "nvidia"; 340 modules = [ nvidia_x11.bin ]; 341 display = !offloadCfg.enable; 342 deviceSection = optionalString primeEnabled 343 '' 344 BusID "${pCfg.nvidiaBusId}" 345 ${optionalString pCfg.allowExternalGpu "Option \"AllowExternalGpus\""} 346 ''; 347 screenSection = 348 '' 349 Option "RandRRotation" "on" 350 '' + optionalString syncCfg.enable '' 351 Option "AllowEmptyInitialConfiguration" 352 '' + optionalString cfg.forceFullCompositionPipeline '' 353 Option "metamodes" "nvidia-auto-select +0+0 {ForceFullCompositionPipeline=On}" 354 Option "AllowIndirectGLXProtocol" "off" 355 Option "TripleBuffer" "on" 356 '' 357 ; 358 }; 359 360 services.xserver.serverLayoutSection = optionalString syncCfg.enable '' 361 Inactive "Device-${igpuDriver}[0]" 362 '' + optionalString reverseSyncCfg.enable '' 363 Inactive "Device-nvidia[0]" 364 '' + optionalString offloadCfg.enable '' 365 Option "AllowNVIDIAGPUScreens" 366 ''; 367 368 services.xserver.displayManager.setupCommands = let 369 gpuProviderName = if igpuDriver == "amdgpu" then 370 # find the name of the provider if amdgpu 371 "`${pkgs.xorg.xrandr}/bin/xrandr --listproviders | ${pkgs.gnugrep}/bin/grep -i AMD | ${pkgs.gnused}/bin/sed -n 's/^.*name://p'`" 372 else 373 igpuDriver; 374 providerCmdParams = if syncCfg.enable then "\"${gpuProviderName}\" NVIDIA-0" else "NVIDIA-G0 \"${gpuProviderName}\""; 375 in optionalString (syncCfg.enable || reverseSyncCfg.enable) '' 376 # Added by nvidia configuration module for Optimus/PRIME. 377 ${pkgs.xorg.xrandr}/bin/xrandr --setprovideroutputsource ${providerCmdParams} 378 ${pkgs.xorg.xrandr}/bin/xrandr --auto 379 ''; 380 381 environment.etc."nvidia/nvidia-application-profiles-rc" = mkIf nvidia_x11.useProfiles { 382 source = "${nvidia_x11.bin}/share/nvidia/nvidia-application-profiles-rc"; 383 }; 384 385 # 'nvidia_x11' installs it's files to /run/opengl-driver/... 386 environment.etc."egl/egl_external_platform.d".source = 387 "/run/opengl-driver/share/egl/egl_external_platform.d/"; 388 389 hardware.opengl.extraPackages = [ 390 nvidia_x11.out 391 pkgs.nvidia-vaapi-driver 392 ]; 393 hardware.opengl.extraPackages32 = [ 394 nvidia_x11.lib32 395 pkgs.pkgsi686Linux.nvidia-vaapi-driver 396 ]; 397 398 environment.systemPackages = [ nvidia_x11.bin ] 399 ++ optionals cfg.nvidiaSettings [ nvidia_x11.settings ] 400 ++ optionals nvidiaPersistencedEnabled [ nvidia_x11.persistenced ] 401 ++ optionals offloadCfg.enableOffloadCmd [ 402 (pkgs.writeShellScriptBin "nvidia-offload" '' 403 export __NV_PRIME_RENDER_OFFLOAD=1 404 export __NV_PRIME_RENDER_OFFLOAD_PROVIDER=NVIDIA-G0 405 export __GLX_VENDOR_LIBRARY_NAME=nvidia 406 export __VK_LAYER_NV_optimus=NVIDIA_only 407 exec "$@" 408 '') 409 ]; 410 411 systemd.packages = optional cfg.powerManagement.enable nvidia_x11.out; 412 413 systemd.services = let 414 baseNvidiaService = state: { 415 description = "NVIDIA system ${state} actions"; 416 417 path = with pkgs; [ kbd ]; 418 serviceConfig = { 419 Type = "oneshot"; 420 ExecStart = "${nvidia_x11.out}/bin/nvidia-sleep.sh '${state}'"; 421 }; 422 }; 423 424 nvidiaService = sleepState: (baseNvidiaService sleepState) // { 425 before = [ "systemd-${sleepState}.service" ]; 426 requiredBy = [ "systemd-${sleepState}.service" ]; 427 }; 428 429 services = (builtins.listToAttrs (map (t: nameValuePair "nvidia-${t}" (nvidiaService t)) ["hibernate" "suspend"])) 430 // { 431 nvidia-resume = (baseNvidiaService "resume") // { 432 after = [ "systemd-suspend.service" "systemd-hibernate.service" ]; 433 requiredBy = [ "systemd-suspend.service" "systemd-hibernate.service" ]; 434 }; 435 }; 436 in optionalAttrs cfg.powerManagement.enable services 437 // optionalAttrs nvidiaPersistencedEnabled { 438 "nvidia-persistenced" = mkIf nvidiaPersistencedEnabled { 439 description = "NVIDIA Persistence Daemon"; 440 wantedBy = [ "multi-user.target" ]; 441 serviceConfig = { 442 Type = "forking"; 443 Restart = "always"; 444 PIDFile = "/var/run/nvidia-persistenced/nvidia-persistenced.pid"; 445 ExecStart = "${nvidia_x11.persistenced}/bin/nvidia-persistenced --verbose"; 446 ExecStopPost = "${pkgs.coreutils}/bin/rm -rf /var/run/nvidia-persistenced"; 447 }; 448 }; 449 }; 450 451 systemd.tmpfiles.rules = optional config.virtualisation.docker.enableNvidia 452 "L+ /run/nvidia-docker/bin - - - - ${nvidia_x11.bin}/origBin" 453 ++ optional (nvidia_x11.persistenced != null && config.virtualisation.docker.enableNvidia) 454 "L+ /run/nvidia-docker/extras/bin/nvidia-persistenced - - - - ${nvidia_x11.persistenced}/origBin/nvidia-persistenced"; 455 456 boot.extraModulePackages = if cfg.open then [ nvidia_x11.open ] else [ nvidia_x11.bin ]; 457 hardware.firmware = lib.optional cfg.open nvidia_x11.firmware; 458 459 # nvidia-uvm is required by CUDA applications. 460 boot.kernelModules = [ "nvidia-uvm" ] ++ 461 optionals config.services.xserver.enable [ "nvidia" "nvidia_modeset" "nvidia_drm" ]; 462 463 # If requested enable modesetting via kernel parameter. 464 boot.kernelParams = optional (offloadCfg.enable || cfg.modesetting.enable) "nvidia-drm.modeset=1" 465 ++ optional cfg.powerManagement.enable "nvidia.NVreg_PreserveVideoMemoryAllocations=1" 466 ++ optional cfg.open "nvidia.NVreg_OpenRmEnableUnsupportedGpus=1" 467 ++ optional (config.boot.kernelPackages.kernel.kernelAtLeast "6.2" && !ibtSupport) "ibt=off"; 468 469 services.udev.extraRules = 470 '' 471 # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded. 472 KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidiactl c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) 255'" 473 KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'for i in $$(cat /proc/driver/nvidia/gpus/*/information | grep Minor | cut -d \ -f 4); do mknod -m 666 /dev/nvidia$${i} c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) $${i}; done'" 474 KERNEL=="nvidia_modeset", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-modeset c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) 254'" 475 KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 0'" 476 KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm-tools c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 1'" 477 '' + optionalString cfg.powerManagement.finegrained ( 478 optionalString (versionOlder config.boot.kernelPackages.kernel.version "5.5") '' 479 # Remove NVIDIA USB xHCI Host Controller devices, if present 480 ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1" 481 482 # Remove NVIDIA USB Type-C UCSI devices, if present 483 ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1" 484 485 # Remove NVIDIA Audio devices, if present 486 ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1" 487 '' + '' 488 # Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind 489 ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto" 490 ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto" 491 492 # Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind 493 ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on" 494 ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on" 495 ''); 496 497 boot.extraModprobeConfig = mkIf cfg.powerManagement.finegrained '' 498 options nvidia "NVreg_DynamicPowerManagement=0x02" 499 ''; 500 501 boot.blacklistedKernelModules = [ "nouveau" "nvidiafb" ]; 502 503 services.acpid.enable = true; 504 505 }; 506 507}