summaryrefslogtreecommitdiffstats
path: root/nixos/modules/hardware/video/nvidia.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/hardware/video/nvidia.nix')
-rw-r--r--nixos/modules/hardware/video/nvidia.nix131
1 files changed, 92 insertions, 39 deletions
diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix
index d1cf7d05c1b8..97accc7b99a0 100644
--- a/nixos/modules/hardware/video/nvidia.nix
+++ b/nixos/modules/hardware/video/nvidia.nix
@@ -5,36 +5,17 @@
with lib;
let
-
- drivers = config.services.xserver.videoDrivers;
-
- # FIXME: should introduce an option like
- # ‘hardware.video.nvidia.package’ for overriding the default NVIDIA
- # driver.
- nvidiaForKernel = kernelPackages:
- if elem "nvidia" drivers then
- kernelPackages.nvidia_x11
- else if elem "nvidiaBeta" drivers then
- kernelPackages.nvidia_x11_beta
- else if elem "nvidiaVulkanBeta" drivers then
- kernelPackages.nvidia_x11_vulkan_beta
- else if elem "nvidiaLegacy304" drivers then
- kernelPackages.nvidia_x11_legacy304
- else if elem "nvidiaLegacy340" drivers then
- kernelPackages.nvidia_x11_legacy340
- else if elem "nvidiaLegacy390" drivers then
- kernelPackages.nvidia_x11_legacy390
- else null;
-
- nvidia_x11 = nvidiaForKernel config.boot.kernelPackages;
- nvidia_libs32 =
- if versionOlder nvidia_x11.version "391" then
- ((nvidiaForKernel pkgs.pkgsi686Linux.linuxPackages).override { libsOnly = true; kernel = null; }).out
- else
- (nvidiaForKernel config.boot.kernelPackages).lib32;
+ nvidia_x11 = let
+ drivers = config.services.xserver.videoDrivers;
+ isDeprecated = str: (hasPrefix "nvidia" str) && (str != "nvidia");
+ hasDeprecated = drivers: any isDeprecated drivers;
+ in if (hasDeprecated drivers) then
+ throw ''
+ Selecting an nvidia driver has been modified for NixOS 19.03. The version is now set using `hardware.nvidia.package`.
+ ''
+ else if (elem "nvidia" drivers) then cfg.package else null;
enabled = nvidia_x11 != null;
-
cfg = config.hardware.nvidia;
pCfg = cfg.prime;
@@ -63,6 +44,15 @@ in
'';
};
+ hardware.nvidia.powerManagement.finegrained = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Experimental power management of PRIME offload. For more information, see
+ the NVIDIA docs, chapter 22. PCI-Express runtime power management.
+ '';
+ };
+
hardware.nvidia.modesetting.enable = mkOption {
type = types.bool;
default = false;
@@ -96,6 +86,16 @@ in
'';
};
+ hardware.nvidia.prime.amdgpuBusId = mkOption {
+ type = types.str;
+ default = "";
+ example = "PCI:4:0:0";
+ description = ''
+ Bus ID of the AMD APU. You can find it using lspci; for example if lspci
+ shows the AMD APU at "04:00.0", set this option to "PCI:4:0:0".
+ '';
+ };
+
hardware.nvidia.prime.sync.enable = mkOption {
type = types.bool;
default = false;
@@ -151,9 +151,22 @@ in
GPUs stay awake even during headless mode.
'';
};
+
+ hardware.nvidia.package = lib.mkOption {
+ type = lib.types.package;
+ default = config.boot.kernelPackages.nvidiaPackages.stable;
+ defaultText = "config.boot.kernelPackages.nvidiaPackages.stable";
+ description = ''
+ The NVIDIA X11 derivation to use.
+ '';
+ example = "config.boot.kernelPackages.nvidiaPackages.legacy340";
+ };
};
- config = mkIf enabled {
+ config = let
+ igpuDriver = if pCfg.intelBusId != "" then "modesetting" else "amdgpu";
+ igpuBusId = if pCfg.intelBusId != "" then pCfg.intelBusId else pCfg.amdgpuBusId;
+ in mkIf enabled {
assertions = [
{
assertion = with config.services.xserver.displayManager; gdm.nvidiaWayland -> cfg.modesetting.enable;
@@ -161,7 +174,13 @@ in
}
{
- assertion = primeEnabled -> pCfg.nvidiaBusId != "" && pCfg.intelBusId != "";
+ assertion = primeEnabled -> pCfg.intelBusId == "" || pCfg.amdgpuBusId == "";
+ message = ''
+ You cannot configure both an Intel iGPU and an AMD APU. Pick the one corresponding to your processor.
+ '';
+ }
+ {
+ assertion = primeEnabled -> pCfg.nvidiaBusId != "" && (pCfg.intelBusId != "" || pCfg.amdgpuBusId != "");
message = ''
When NVIDIA PRIME is enabled, the GPU bus IDs must configured.
'';
@@ -174,6 +193,14 @@ in
assertion = !(syncCfg.enable && offloadCfg.enable);
message = "Only one NVIDIA PRIME solution may be used at a time.";
}
+ {
+ assertion = !(syncCfg.enable && cfg.powerManagement.finegrained);
+ message = "Sync precludes powering down the NVIDIA GPU.";
+ }
+ {
+ assertion = cfg.powerManagement.enable -> offloadCfg.enable;
+ message = "Fine-grained power management requires offload to be enabled.";
+ }
];
# If Optimus/PRIME is enabled, we:
@@ -183,18 +210,22 @@ in
# "nvidia" driver, in order to allow the X server to start without any outputs.
# - Add a separate Device section for the Intel GPU, using the "modesetting"
# driver and with the configured BusID.
+ # - OR add a separate Device section for the AMD APU, using the "amdgpu"
+ # driver and with the configures BusID.
# - Reference that Device section from the ServerLayout section as an inactive
# device.
# - Configure the display manager to run specific `xrandr` commands which will
- # configure/enable displays connected to the Intel GPU.
+ # configure/enable displays connected to the Intel iGPU / AMD APU.
services.xserver.useGlamor = mkDefault offloadCfg.enable;
- services.xserver.drivers = optional primeEnabled {
- name = "modesetting";
+ services.xserver.drivers = let
+ in optional primeEnabled {
+ name = igpuDriver;
display = offloadCfg.enable;
+ modules = optional (igpuDriver == "amdgpu") [ pkgs.xorg.xf86videoamdgpu ];
deviceSection = ''
- BusID "${pCfg.intelBusId}"
+ BusID "${igpuBusId}"
${optionalString syncCfg.enable ''Option "AccelMethod" "none"''}
'';
} ++ singleton {
@@ -205,6 +236,7 @@ in
''
BusID "${pCfg.nvidiaBusId}"
${optionalString syncCfg.allowExternalGpu "Option \"AllowExternalGpus\""}
+ ${optionalString cfg.powerManagement.finegrained "Option \"NVreg_DynamicPowerManagement=0x02\""}
'';
screenSection =
''
@@ -214,14 +246,14 @@ in
};
services.xserver.serverLayoutSection = optionalString syncCfg.enable ''
- Inactive "Device-modesetting[0]"
+ Inactive "Device-${igpuDriver}[0]"
'' + optionalString offloadCfg.enable ''
Option "AllowNVIDIAGPUScreens"
'';
services.xserver.displayManager.setupCommands = optionalString syncCfg.enable ''
# Added by nvidia configuration module for Optimus/PRIME.
- ${pkgs.xorg.xrandr}/bin/xrandr --setprovideroutputsource modesetting NVIDIA-0
+ ${pkgs.xorg.xrandr}/bin/xrandr --setprovideroutputsource ${igpuDriver} NVIDIA-0
${pkgs.xorg.xrandr}/bin/xrandr --auto
'';
@@ -230,9 +262,9 @@ in
};
hardware.opengl.package = mkIf (!offloadCfg.enable) nvidia_x11.out;
- hardware.opengl.package32 = mkIf (!offloadCfg.enable) nvidia_libs32;
+ hardware.opengl.package32 = mkIf (!offloadCfg.enable) nvidia_x11.lib32;
hardware.opengl.extraPackages = optional offloadCfg.enable nvidia_x11.out;
- hardware.opengl.extraPackages32 = optional offloadCfg.enable nvidia_libs32;
+ hardware.opengl.extraPackages32 = optional offloadCfg.enable nvidia_x11.lib32;
environment.systemPackages = [ nvidia_x11.bin nvidia_x11.settings ]
++ optionals nvidiaPersistencedEnabled [ nvidia_x11.persistenced ];
@@ -292,16 +324,37 @@ in
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 =
''
+ # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded.
KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidiactl c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) 255'"
KERNEL=="nvidia_modeset", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-modeset c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) 254'"
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'"
KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 0'"
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'"
+ '' + optionalString cfg.powerManagement.finegrained ''
+ # Remove NVIDIA USB xHCI Host Controller devices, if present
+ ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1"
+
+ # Remove NVIDIA USB Type-C UCSI devices, if present
+ ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1"
+
+ # Remove NVIDIA Audio devices, if present
+ ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1"
+
+ # Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind
+ ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
+ ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"
+
+ # Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind
+ ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on"
+ ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on"
'';
+ boot.extraModprobeConfig = mkIf cfg.powerManagement.finegrained ''
+ options nvidia "NVreg_DynamicPowerManagement=0x02"
+ '';
+
boot.blacklistedKernelModules = [ "nouveau" "nvidiafb" ];
services.acpid.enable = true;