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