diff --git a/mkosi.extra/usr/lib/initcpio/install/nvidia-module-selection b/mkosi.extra/usr/lib/initcpio/install/nvidia-driver-selection similarity index 51% rename from mkosi.extra/usr/lib/initcpio/install/nvidia-module-selection rename to mkosi.extra/usr/lib/initcpio/install/nvidia-driver-selection index bd55b88..4050433 100755 --- a/mkosi.extra/usr/lib/initcpio/install/nvidia-module-selection +++ b/mkosi.extra/usr/lib/initcpio/install/nvidia-driver-selection @@ -2,8 +2,8 @@ # SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL # SPDX-FileCopyrightText: 2026 Thomas Duckworth -# Necessary for letting udev control what GPUs get which drivers -# using driver_override, so nouveau or nvidia can be dynamically selected. +# Necessary for generating automatic modprobe blacklists before +# drivers load so nouveau or nvidia can be dynamically selected. # Also gives us some certainty that these are included for kernel modesetting. build() { @@ -11,8 +11,12 @@ build() { add_module "nvidia-drm" add_module "nvidia-modeset" add_module "nvidia-uvm" - add_module "nouveau" add_checked_modules "/drivers/gpu/drm" + + add_binary "/usr/lib/initcpio/nvidia-driver-selection" + + add_systemd_unit "kde-linux-nvidia-driver-selection.service" + add_symlink "/etc/systemd/system/sysinit.target.wants/kde-linux-nvidia-driver-selection.service" "/usr/lib/systemd/system/kde-linux-nvidia-driver-selection.service" } diff --git a/mkosi.extra/usr/lib/initcpio/nvidia-driver-selection b/mkosi.extra/usr/lib/initcpio/nvidia-driver-selection new file mode 100755 index 0000000..dae85f9 --- /dev/null +++ b/mkosi.extra/usr/lib/initcpio/nvidia-driver-selection @@ -0,0 +1,42 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL +# SPDX-FileCopyrightText: 2026 Thomas Duckworth + +# Checks sysfs for NVIDIA GPUs and generates a modprobe blacklist dynamically. + +mkdir -p /run/modprobe.d +mkdir -p /run/modules-load.d +USE_NVIDIA=0 +GPU_FOUND=0 + +for dev in /sys/bus/pci/devices/*; do + [ -f "$dev/vendor" ] && [ -f "$dev/device" ] && [ -f "$dev/class" ] || continue + + vendor=$(cat "$dev/vendor") + class=$(cat "$dev/class") + + # 0x10de = NVIDIA. Class 0x03* = Display controllers + if [ "$vendor" = "0x10de" ] && [[ "$class" == 0x03* ]]; then + GPU_FOUND=1 + device=$(cat "$dev/device") + dec_id=$(printf "%d" "$device") + + # 7680 (0x1e00) is the Turing (NVIDIA driver) cutoff + if [ "$dec_id" -ge 7680 ]; then + USE_NVIDIA=1 + fi + fi +done + +if [ "$GPU_FOUND" -eq 1 ]; then + if [ "$USE_NVIDIA" -eq 1 ]; then + echo "blacklist nouveau" > /run/modprobe.d/05-dynamic-gpu.conf + modprobe nvidia-drm modeset=1 + else + echo "blacklist nvidia" > /run/modprobe.d/05-dynamic-gpu.conf + echo "blacklist nvidia-drm" >> /run/modprobe.d/05-dynamic-gpu.conf + echo "blacklist nvidia-modeset" >> /run/modprobe.d/05-dynamic-gpu.conf + echo "blacklist nvidia-uvm" >> /run/modprobe.d/05-dynamic-gpu.conf + modprobe nouveau + fi +fi diff --git a/mkosi.extra/usr/lib/rebuild-efi b/mkosi.extra/usr/lib/rebuild-efi index 5df432b..dbc50cb 100755 --- a/mkosi.extra/usr/lib/rebuild-efi +++ b/mkosi.extra/usr/lib/rebuild-efi @@ -28,8 +28,8 @@ fi cat <<- EOF > mkinitcpio.conf MODULES=(overlay) BINARIES=() -FILES=(/usr/lib/udev/rules.d/05-nvidia-module-selection.rules) # Determine which driver is used at boot with udev -HOOKS=(base systemd nvidia-module-selection modconf kms keyboard block sd-encrypt filesystems fsck systemd-extension plymouth microcode sd-shutdown) +FILES=() +HOOKS=(base systemd nvidia-driver-selection modconf kms keyboard block sd-encrypt filesystems fsck systemd-extension plymouth microcode sd-shutdown) EOF echo "rw \ diff --git a/mkosi.extra/usr/lib/systemd/system/kde-linux-nvidia-driver-selection.service b/mkosi.extra/usr/lib/systemd/system/kde-linux-nvidia-driver-selection.service new file mode 100644 index 0000000..7f1e801 --- /dev/null +++ b/mkosi.extra/usr/lib/systemd/system/kde-linux-nvidia-driver-selection.service @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL +# SPDX-FileCopyrightText: 2025 Thomas Duckworth + +[Unit] +Description=Dynamic NVIDIA Driver Selection +DefaultDependencies=no +Before=systemd-udevd.service systemd-modules-load.service +ConditionPathExists=/sys/bus/pci/devices + +# This service and binary is included in the initramfs. +[Service] +Type=oneshot +ExecStart=/usr/lib/initcpio/nvidia-driver-selection +RemainAfterExit=yes diff --git a/mkosi.postinst.chroot b/mkosi.postinst.chroot index afdecce..8b5cfef 100755 --- a/mkosi.postinst.chroot +++ b/mkosi.postinst.chroot @@ -146,40 +146,6 @@ if [ -f /usr/lib/modprobe.d/nvidia-utils.conf ]; then sed -i '/blacklist nouveau/d' /usr/lib/modprobe.d/nvidia-utils.conf fi -# Generate a huge udev rule which selects the correct driver for NVIDIA graphics cards. -# This gets included in the initrd - see mkosi.extra/usr/lib/rebuild-efi -PCI_IDS="/usr/share/hwdata/pci.ids" -UDEV_RULE="/usr/lib/udev/rules.d/05-nvidia-module-selection.rules" - -echo "# Generated by mkosi.postinst.chroot" > "$UDEV_RULE" -echo "# Static driver overrides for NVIDIA GPUs based on ID ranges." >> "$UDEV_RULE" - -gawk ' - BEGIN { IGNORECASE = 1 } - # Vendor line, e.g. "10de NVIDIA Corporation". - /^10de\b/ { in_nvidia = 1; next } - # Any other vendor line (4 hex digits at start) disables in_nvidia. - /^[0-9A-Fa-f]{4}\s/ { in_nvidia = 0; next } - - # device lines are indented and begin with a 4-hex-digit device id - in_nvidia && /^\s+[0-9A-Fa-f]{4}\b/ { - device_id = gensub(/^\s+([0-9A-Fa-f]{4}).*/, "\\1", "g") - dec_id = strtonum("0x" device_id) - - # 0x1e00 (7680) is where Turing architecture begins (RTX 20-series / GTX 16-series). - # This is, currently, the cutoff for support in the open kernel modules. - if (dec_id >= 7680) { - driver = "nvidia" - } else { - driver = "nouveau" - } - - # Match only Class 03 (Display Controllers) to avoid breaking Audio/USB/Bridges. - printf "ACTION==\"add\", SUBSYSTEM==\"pci\", ATTR{vendor}==\"0x10de\", ATTR{device}==\"0x%s\", ATTR{class}==\"0x03*\", ATTR{driver_override}=\"%s\"\n", device_id, driver - } -' "$PCI_IDS" >> "$UDEV_RULE" - - cd /tmp /usr/lib/rebuild-efi mv -v ./*.efi /