diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix index 8c3d64fceb9c..6328971492c5 100644 --- a/nixos/modules/hardware/video/nvidia.nix +++ b/nixos/modules/hardware/video/nvidia.nix @@ -52,6 +52,15 @@ in ]; options = { + hardware.nvidia.powerManagement.enable = mkOption { + type = types.bool; + default = false; + description = '' + Experimental power management through systemd. For more information, see + the NVIDIA docs, on Chapter 21. Configuring Power Management Support. + ''; + }; + hardware.nvidia.modesetting.enable = mkOption { type = types.bool; default = false; @@ -226,23 +235,51 @@ in environment.systemPackages = [ nvidia_x11.bin nvidia_x11.settings ] ++ filter (p: p != null) [ nvidia_x11.persistenced ]; + systemd.packages = optional cfg.powerManagement.enable nvidia_x11.out; + + systemd.services = let + baseNvidiaService = state: { + description = "NVIDIA system ${state} actions"; + + path = with pkgs; [ kbd ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${nvidia_x11.out}/bin/nvidia-sleep.sh '${state}'"; + }; + }; + + nvidiaService = sleepState: (baseNvidiaService sleepState) // { + before = [ "systemd-${sleepState}.service" ]; + requiredBy = [ "systemd-${sleepState}.service" ]; + }; + + services = (builtins.listToAttrs (map (t: nameValuePair "nvidia-${t}" (nvidiaService t)) ["hibernate" "suspend"])) + // { + nvidia-resume = (baseNvidiaService "resume") // { + after = [ "systemd-suspend.service" "systemd-hibernate.service" ]; + requiredBy = [ "systemd-suspend.service" "systemd-hibernate.service" ]; + }; + }; + in optionalAttrs cfg.powerManagement.enable services + // optionalAttrs nvidiaPersistencedEnabled { + "nvidia-persistenced" = mkIf nvidiaPersistencedEnabled { + description = "NVIDIA Persistence Daemon"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "forking"; + Restart = "always"; + PIDFile = "/var/run/nvidia-persistenced/nvidia-persistenced.pid"; + ExecStart = "${nvidia_x11.persistenced}/bin/nvidia-persistenced --verbose"; + ExecStopPost = "${pkgs.coreutils}/bin/rm -rf /var/run/nvidia-persistenced"; + }; + }; + }; + systemd.tmpfiles.rules = optional config.virtualisation.docker.enableNvidia "L+ /run/nvidia-docker/bin - - - - ${nvidia_x11.bin}/origBin" ++ optional (nvidia_x11.persistenced != null && config.virtualisation.docker.enableNvidia) "L+ /run/nvidia-docker/extras/bin/nvidia-persistenced - - - - ${nvidia_x11.persistenced}/origBin/nvidia-persistenced"; - systemd.services."nvidia-persistenced" = mkIf nvidiaPersistencedEnabled { - description = "NVIDIA Persistence Daemon"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "forking"; - Restart = "always"; - PIDFile = "/var/run/nvidia-persistenced/nvidia-persistenced.pid"; - ExecStart = "${nvidia_x11.persistenced}/bin/nvidia-persistenced --verbose"; - ExecStopPost = "${pkgs.coreutils}/bin/rm -rf /var/run/nvidia-persistenced"; - }; - }; - boot.extraModulePackages = [ nvidia_x11.bin ]; # nvidia-uvm is required by CUDA applications. @@ -250,7 +287,8 @@ in optionals config.services.xserver.enable [ "nvidia" "nvidia_modeset" "nvidia_drm" ]; # If requested enable modesetting via kernel parameter. - boot.kernelParams = optional (offloadCfg.enable || cfg.modesetting.enable) "nvidia-drm.modeset=1"; + boot.kernelParams = optional (offloadCfg.enable || cfg.modesetting.enable) "nvidia-drm.modeset=1" + ++ optional cfg.powerManagement.enable "nvidia.NVreg_PreserveVideoMemoryAllocations=1"; # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded. services.udev.extraRules = diff --git a/pkgs/os-specific/linux/nvidia-x11/builder.sh b/pkgs/os-specific/linux/nvidia-x11/builder.sh index 30e5d16b60f3..dbe18ace40a2 100755 --- a/pkgs/os-specific/linux/nvidia-x11/builder.sh +++ b/pkgs/os-specific/linux/nvidia-x11/builder.sh @@ -45,6 +45,17 @@ installPhase() { cp -prd tls "$out/lib/" fi + # Install systemd power management executables + if [ -e nvidia-sleep.sh ]; then + sed -E 's#(PATH=).*#\1"$PATH"#' nvidia-sleep.sh > nvidia-sleep.sh.fixed + install -Dm755 nvidia-sleep.sh.fixed $out/bin/nvidia-sleep.sh + fi + + if [ -e nvidia ]; then + sed -E "s#/usr(/bin/nvidia-sleep.sh)#$out\\1#" nvidia > nvidia.fixed + install -Dm755 nvidia.fixed $out/lib/systemd/system-sleep/nvidia + fi + for i in $lib32 $out; do rm -f $i/lib/lib{glx,nvidia-wfb}.so.* # handled separately rm -f $i/lib/libnvidia-gtk* # built from source @@ -91,7 +102,6 @@ installPhase() { done - if [ -n "$bin" ]; then # Install the X drivers. mkdir -p $bin/lib/xorg/modules @@ -167,5 +177,4 @@ installPhase() { fi } - genericBuild