Issue with dual GPUs failing to start or showing incorrect output.
Issue with dual GPUs failing to start or showing incorrect output.
Hey there, I recently reinstalled my old GTX 970 into the system to run games like Control and Oblivion, and I’m using it in a VM. I also started using DaVinci Resolve with H264/H265 formats. There were several problems when I added the second GPU—my BIOS didn’t appear at all, and the monitors didn’t receive any signal no matter which GPU I connected. Even though I could access it, nothing happened when I rapidly pressed DEL. Linux displayed the usual debug messages at startup, but they vanished quickly and then disappeared again, turning off the monitors because of no input. Windows 10 handled it better; both GPUs were detected and functioning properly (FurMark confirmed it). I’ve tried using another GPU in the past, but I’ve cleaned up all related entries from GRUB and didn’t reinstall the OS after switching to the RX 6600 XT. I also attempted to remove all other PCIe devices except the Linux SSD, but that didn’t resolve the BIOS issue. I haven’t reinstalled drivers after the upgrade, though I’m not very familiar with that process. I’ve also tried turning the system off and on, switching GPUs, repositioning the cards, removing other PCIe devices, and even changing the PCI settings on my motherboard. I moved the 970 to a different slot for testing, re-seated the GPUs multiple times, and even tried using a different display adapter. I haven’t changed RAM or tried moving the OS to a SATA SSD, nor have I swapped CPUs. I’m still trying to figure out what’s wrong—everything seems fine without the second GPU, and I suspect there might be a deeper hardware problem. Could it be related to power delivery or insufficient PCIe lanes? Both cards have separate power connections, and Windows specs show everything looks good. I’m hoping someone can shed some light on this situation.
Hello! I don't have any specialized knowledge on this topic, but your suggestion could be helpful. If the board and cards function correctly on Windows, it suggests a possible issue with the hardware rather than a software problem. I would consider these steps: Use a live distribution from a bootable USB to confirm functionality, check if the new and nvidia kernel modules are excluded in the Mint installation, and verify the GPU-pass-through configuration. If needed, follow the guidance in the referenced article carefully. I don’t have prior experience with this setup.
I suspect the issue occurred while trying to boot, possibly due to a black screen in BIOS or during startup. I won’t attempt any fixes now that I’m unsure, as I’ve considered selecting a boot option. I’ll try again later.
I encountered a similar problem when attempting to use my R9 270X, which was resolved by ensuring IOMMU was activated in the BIOS. Start the system with the kernel option 'iommu=pt' to allow passthrough. If you're using an Intel processor, also set 'intel_iommu=on'.
It's not about missing the GPU in Linux, but the display output isn't functioning even in BIOS. I think all virtualization options are turned on, which could be the problem. I don't want to reset the BIOS since I've adjusted many settings, but it seems like the simplest fix might be needed.
Time for a backup and pictures of your changed settings... Once you get it working in bios with the GTX 970 alone, boot to you linux flavour or choice and get the pcids for your "passthrough" boot config, so you can craft your GRUB_CMDLINE_LINUX="iommu=pt vfio-pci.ids=xxxx:yyyy,xxxx:zzzz pcie_acs_override=downstream,multifunction" I'm not sure you need `pcie_acs_override`, but meh, I have it. If you want you can build this line using windows and the device manager, xxxx is the vendor id, yyyy is the device id for your gpu, and zzzz is the device id for the associated HDMI audio stream(s). Considering the linux nvidia drivers are all literal dogshit, using windows to get the id's is a good idea, then by the time you get to booting linux the GTX 970 is `hidden` from the kernel/udev and the nvidia driver has less chance of shitting the bed. I have a video I point people towards when doing passthrough HERE , the guy is doing the most complex form of passthrough so will inevitably talk about all the settings and concepts you need to be aware of for a less complex set-up. Personally - I'd be "optionally" passing the 6600 between both OS's (virtual and native) in a similar manner to the guy in the vid, that way I have the best GPU available for any games I choose to play, but that is an extra layer of complication that you can add once you get things behaving in the "normal" way first... I'll drop some /etc/default/grub segments that give you options to boot with a "selected" card available for passthrough: #/etc/default/grub GRUB_CMDLINE_LINUX_VHOST_CARD1="iommu=pt vfio-pci.ids=x1x1x1x1:y1y1y1y1,x1x1x1x1:z1z1z1z1 pcie_acs_override=downstream,multifunction" GRUB_CMDLINE_LINUX_VHOST_CARD2="iommu=pt vfio-pci.ids=x2x2x2x2:y2y2y2y2,x2x2x2x2:z2z2z2z2 pcie_acs_override=downstream,multifunction" Then create /etc/grub.d/51_custom_card1_vhost that looks like: #! /bin/sh set -e # grub-mkconfig helper script. # Copyright © 2006,2007,2008,2009,2010 Free Software Foundation, Inc. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRUB is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GRUB. If not, see <http://www.gnu.org/licenses/>. prefix="/usr" exec_prefix="/usr" datarootdir="/usr/share" . "$pkgdatadir/grub-mkconfig_lib" export TEXTDOMAIN=grub export TEXTDOMAINDIR="${datarootdir}/locale" CLASS="--class gnu-linux --class gnu --class os" if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU/Linux else OS="${GRUB_DISTRIBUTOR} VHost Card 1 GNU/Linux" CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}" fi # loop-AES arranges things so that /dev/loop/X can be our root device, but # the initrds that Linux uses don't like that. case ${GRUB_DEVICE} in /dev/loop/*|/dev/loop[0-9]) GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` ;; esac # Default to disabling partition uuid support to maintian compatibility with # older kernels. GRUB_DISABLE_LINUX_PARTUUID=${GRUB_DISABLE_LINUX_PARTUUID-true} # btrfs may reside on multiple devices. We cannot pass them as value of root= parameter # and mounting btrfs requires user space scanning, so force UUID in this case. if ( [ "x${GRUB_DEVICE_UUID}" = "x" ] && [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] ) \ || ( [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ && [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ] ) \ || ( ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ && ! test -e "/dev/disk/by-partuuid/${GRUB_DEVICE_PARTUUID}" ) \ || ( test -e "${GRUB_DEVICE}" && uses_abstraction "${GRUB_DEVICE}" lvm ); then LINUX_ROOT_DEVICE=${GRUB_DEVICE} elif [ "x${GRUB_DEVICE_UUID}" = "x" ] \ || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ]; then LINUX_ROOT_DEVICE=PARTUUID=${GRUB_DEVICE_PARTUUID} else LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} fi case x"$GRUB_FS" in xbtrfs) rootsubvol="`make_system_path_relative_to_its_root /`" rootsubvol="${rootsubvol#/}" if [ "x${rootsubvol}" != x ]; then GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" fi;; xzfs) rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true` bootfs="`make_system_path_relative_to_its_root / | sed -e "s,@$,,"`" LINUX_ROOT_DEVICE="ZFS=${rpool}${bootfs%/}" ;; esac title_correction_code= linux_entry () { os="$1" version="$2" type="$3" args="$4" if [ -z "$boot_device_id" ]; then boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" fi if [ x$type != xsimple ] ; then case $type in recovery) title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;; *) title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;; esac if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")" fi echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" else echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" fi if [ x$type != xrecovery ] ; then save_default_entry | grub_add_tab fi # Use ELILO's generic "efifb" when it's known to be available. # FIXME: We need an interface to select vesafb in case efifb can't be used. if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then echo " load_video" | sed "s/^/$submenu_indentation/" if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \ && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then echo ' if [ "x$grub_platform" = xefi ]; then' | sed "s/^/$submenu_indentation/" echo " set gfxpayload=keep" | sed "s/^/$submenu_indentation/" echo ' fi' | sed "s/^/$submenu_indentation/" fi else if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then echo " load_video" | sed "s/^/$submenu_indentation/" fi echo " set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/" fi echo " insmod gzio" | sed "s/^/$submenu_indentation/" if [ x$dirname = x/ ]; then if [ -z "${prepare_root_cache}" ]; then prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | grub_add_tab)" fi printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/" else if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)" fi printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/" fi message="$(gettext_printf "Loading Linux %s ..." ${version})" sed "s/^/$submenu_indentation/" << EOF echo '$(echo "$message" | grub_quote)' linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} EOF if test -n "${initrd}" ; then # TRANSLATORS: ramdisk isn't identifier. Should be translated. message="$(gettext_printf "Loading initial ramdisk ...")" initrd_path= for i in ${initrd}; do initrd_path="${initrd_path} ${rel_dirname}/${i}" done sed "s/^/$submenu_indentation/" << EOF echo '$(echo "$message" | grub_quote)' initrd $(echo $initrd_path) EOF fi sed "s/^/$submenu_indentation/" << EOF } EOF } machine=`uname -m` globs="$GRUB_LINUX_KERNEL_GLOBS" [ -z "$globs" ] && case "x$machine" in xi?86 | xx86_64) globs="/boot/vmlinuz-* /vmlinuz-* /boot/kernel-*" ;; *) globs="/boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-*" ;; esac list= for i in ${globs} ; do if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi done prepare_boot_cache= prepare_root_cache= boot_device_id= title_correction_code= # Extra indentation to add to menu entries in a submenu. We're not in a submenu # yet, so it's empty. In a submenu it will be equal to '\t' (one tab). submenu_indentation="" is_top_level=true while [ "x$list" != "x" ] ; do linux=`version_find_latest $list` gettext_printf "Found linux image: %s\n" "$linux" >&2 basename=`basename $linux` dirname=`dirname $linux` rel_dirname=`make_system_path_relative_to_its_root $dirname` version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` alt_version=`echo $version | sed -e "s,\.old$,,g"` linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" initrd_early= for i in ${GRUB_EARLY_INITRD_LINUX_STOCK} \ ${GRUB_EARLY_INITRD_LINUX_CUSTOM}; do if test -e "${dirname}/${i}" ; then initrd_early="${initrd_early} ${i}" fi done initrd_real= for i in "initrd.img-${version}" "initrd-${version}.img" \ "initrd-${alt_version}.img.old" "initrd-${version}.gz" \ "initrd-${alt_version}.gz.old" "initrd-${version}" \ "initramfs-${version}.img" "initramfs-${alt_version}.img.old" \ "initrd.img-${alt_version}" "initrd-${alt_version}.img" \ "initrd-${alt_version}" "initramfs-${alt_version}.img" \ "initramfs-genkernel-${version}" \ "initramfs-genkernel-${alt_version}" \ "initramfs-genkernel-${GENKERNEL_ARCH}-${version}" \ "initramfs-genkernel-${GENKERNEL_ARCH}-${alt_version}"; do if test -e "${dirname}/${i}" ; then initrd_real="${i}" break fi done initrd= if test -n "${initrd_early}" || test -n "${initrd_real}"; then initrd="${initrd_early} ${initrd_real}" initrd_display= for i in ${initrd}; do initrd_display="${initrd_display} ${dirname}/${i}" done gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 fi config= for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do if test -e "${i}" ; then config="${i}" break fi done initramfs= if test -n "${config}" ; then initramfs=`grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"` fi if test -z "${initramfs}" && test -z "${initrd_real}" ; then # "UUID=" and "ZFS=" magic is parsed by initrd or initramfs. Since there's # no initrd or builtin initramfs, it can't work here. if [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] \ || [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ]; then linux_root_device_thisversion=${GRUB_DEVICE} else linux_root_device_thisversion=PARTUUID=${GRUB_DEVICE_PARTUUID} fi fi # The GRUB_DISABLE_SUBMENU option used to be different than others since it was # mentioned in the documentation that has to be set to 'y' instead of 'true' to # enable it. This caused a lot of confusion to users that set the option to 'y', # 'yes' or 'true'. This was fixed but all of these values must be supported now. if [ "x${GRUB_DISABLE_SUBMENU}" = xyes ] || [ "x${GRUB_DISABLE_SUBMENU}" = xy ]; then GRUB_DISABLE_SUBMENU="true" fi if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then linux_entry "${OS}" "${version}" simple \ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_VHOST_CARD1}" submenu_indentation="$grub_tab" if [ -z "$boot_device_id" ]; then boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" fi # TRANSLATORS: %s is replaced with an OS name echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {" is_top_level=false fi linux_entry "${OS}" "${version}" advanced \ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_VHOST_CARD1}" if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then linux_entry "${OS}" "${version}" recovery \ "single ${GRUB_CMDLINE_LINUX}" fi list=`echo $list | tr ' ' '\n' | fgrep -vx "$linux" | tr '\n' ' '` done # If at least one kernel was found, then we need to # add a closing '}' for the submenu command. if [ x"$is_top_level" != xtrue ]; then echo '}' fi echo "$title_correction_code" and a /etc/grub.d/52_custom_card2_vhost that does an s/CARD1/CARD2/ on the above. Disclaimer: I use static kernels w/o module loading, so initrd's and similar are a layer of useless nonsense for me; the above grub helper script(s) should work with these things regardless (as I "stole" them), but you may need to tinker depending on your linux flavour.
I managed to get the system running with two GPUs and there were no BIOS problems. I adjusted some settings in GRUB, but I don’t know why. It seems computers handle things differently. I’ve heard PCIe IDs shift when cards change, which is why I installed the card and began virtualizing it right away. The NVIDIA chip is meant for Windows only, so I’m planning to block it for Linux as recommended in some guides. This would be cool, but it might cause trouble later. I’m pulling the “BuT sOmeTIes” card because I think it could help me run a VM for rendering while gaming on Linux. I’m worried I might not fully grasp this, but I’ll try to study it more thoroughly today.