Proxmox GPU Passthrough: IOMMU, VFIO, and the AMD Reset Bug
How to pass a GPU through to a Proxmox VE guest: IOMMU groups, VFIO binding, the AMD vendor-reset problem, and where passthrough actually breaks.
GPU passthrough on Proxmox VE comes down to four things, in this order:
- IOMMU enabled on the host, in firmware and on the kernel command line.
- A clean IOMMU group containing the GPU and nothing you need on the host.
- vfio-pci bound to the card at boot, before any host driver can claim it.
- A q35 + OVMF guest, because a PCIe device in a PCI-only machine type is a dead end.
Everything else, including most of the forum folklore, is troubleshooting for when one of those four is wrong.
Passthrough is the one Proxmox feature where the hypervisor is not really in control. You are handing a physical PCIe device to a guest and asking the firmware, the IOMMU, the GPU’s own reset logic, and the guest driver to all cooperate. When it works it is close to bare metal. When it fails it usually needs a host reboot, which is a very different risk profile from anything else you run on the box.
Enable IOMMU, then prove it took
The IOMMU is what makes passthrough safe. It gives the guest a translated address space so a device doing DMA cannot write into host memory or another guest’s memory. Without an active IOMMU there is nothing for VFIO to build those mappings on, so the device never attaches and the VM fails to start.
Two places have to agree:
- Firmware. Enable VT-d on Intel, or IOMMU / AMD-Vi on AMD. On consumer boards the setting is often buried, and note that “SVM Mode” is the virtualization extension, not the IOMMU. Also enable Above 4G Decoding if offered. Modern GPUs expose large 64-bit BARs that need address space above the 4 GB line, and on many boards this is the setting that lets them map.
- The kernel command line. Where it goes depends on how the host boots. A GRUB install takes
GRUB_CMDLINE_LINUX_DEFAULTin/etc/default/grubplusupdate-grub. A systemd-boot install (common on ZFS root) takes/etc/kernel/cmdlineplusproxmox-boot-tool refresh. Editing the wrong one and rebooting into an unchanged command line is the most common reason people believe IOMMU “does not work” on their board.
On recent kernels the IOMMU is often enabled automatically when the hardware supports it, so intel_iommu=on may be redundant rather than wrong. Do not assume either way. Verify:
dmesg | grep -e DMAR -e IOMMU -e AMD-Vi
ls /sys/kernel/iommu_groups/
If /sys/kernel/iommu_groups/ is empty, the IOMMU is not active and nothing downstream will work. Fix that before touching anything else.
Read your IOMMU groups before you plan the build
An IOMMU group is the smallest unit the hardware can isolate. You pass through a whole group or nothing. If your GPU shares a group with the onboard NIC or the SATA controller, you cannot pass the GPU without also handing the guest your network or your boot disks.
List the groups:
#!/bin/bash
shopt -s nullglob
for g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do
echo "IOMMU Group ${g##*/}:"
for d in "$g"/devices/*; do
echo -e "\t$(lspci -nns "${d##*/}")"
done
done
What good looks like: the GPU’s video function and its HDMI audio function alone in a group, sometimes with a USB controller and a UCSI controller on newer cards. Those all belong to the card and all go to the guest together.
What bad looks like: a sprawling group with everything hanging off the chipset. That is normal for PCIe slots wired to the PCH on consumer boards, and it is a hardware and firmware property, not something you configure away. The slot directly off the CPU is your best candidate. Platform choice decides this, which is why it belongs in the Proxmox hardware requirements conversation rather than being discovered after the parts arrive.
The Proxmox kernel does carry the ACS override patch, exposed as a pcie_acs_override= boot parameter. Be clear about what it does: it tells the kernel to pretend devices are isolated when the hardware never claimed they were. It can split a group and make passthrough work, and it removes the guarantee that a buggy guest driver cannot reach a neighbouring device by peer-to-peer DMA. For a single-user homelab that is often an acceptable trade. For anything multi-tenant it is not.
Bind the card to vfio-pci at boot
The race you are trying to win is simple. If amdgpu, nouveau, nvidia, or the framebuffer driver claims the card during boot, it is dirty by the time you want it. Bind vfio-pci first.
Load the modules, in /etc/modules:
vfio
vfio_iommu_type1
vfio_pci
Older guides also list vfio_virqfd. On current kernels that was folded into the vfio core and no longer exists as a separate module, so leaving it in produces a harmless load failure at boot that people then chase for an hour.
Claim the device by ID. Get the vendor:device IDs from lspci -nn for both the video and audio functions, then create /etc/modprobe.d/vfio.conf. The pair below belongs to one specific card and is there to show the format, not to be copied:
options vfio-pci ids=1002:73bf,1002:ab28
And blacklist or defer the host drivers in /etc/modprobe.d/blacklist.conf:
blacklist nouveau
blacklist nvidia
blacklist amdgpu
blacklist radeon
Blacklisting is blunt and will also stop a second GPU of the same vendor from working on the host. If the host needs to keep another card from the same vendor, use softdep lines to order vfio-pci ahead of the native driver instead, and let the ID match pick the right card.
Then rebuild the initramfs and reboot:
update-initramfs -u -k all
Verify afterwards. This is the check that tells you whether the previous three steps actually worked:
lspci -nnk -s 01:00
You want Kernel driver in use: vfio-pci on both functions. Anything else and the guest will fail to start, or worse, start and take the host’s display with it.
Configure the guest so PCIe actually exists
Proxmox defaults do not suit passthrough. Set these when creating the VM:
- Machine type: q35. The i440fx machine has no PCI Express bus, so a PCIe GPU attaches as plain PCI and modern drivers object.
- BIOS: OVMF (UEFI), with an EFI disk added. A card whose vBIOS is UEFI-capable will initialise cleanly. A genuinely old legacy-only card may need SeaBIOS or a dumped ROM file, which is a much rougher path.
- Add the PCI device under Hardware, ticking All Functions so the HDMI audio function goes with the video function, plus PCI-Express. Tick Primary GPU only if the guest is driving the physical display output.
The resulting config line looks like hostpci0: 0000:01:00,pcie=1,x-vga=1. Note the address has no function suffix, which is what “all functions” means.
On clusters, recent Proxmox versions let you define a named PCI resource mapping at the datacenter level so the VM config refers to a mapping rather than a raw bus address, which matters because PCI addresses differ between machines. It makes the guest easier to start on another node, not migratable while running. Plan a Proxmox cluster around that limitation rather than against it.
The AMD reset problem
This is the failure mode that surprises people most, because the first boot works perfectly.
Many AMD GPUs, particularly the Polaris, Vega, and early Navi generations, do not implement a working PCIe Function Level Reset. When the guest shuts down, the card is left in a state the host cannot bring back. The second VM start hangs, or the host logs something like Unable to change power state from D3cold to D0, device inaccessible. From that point the only reliable recovery is a full host reboot, which on a hypervisor means taking down every other guest on the box.
The community fix is the out-of-tree vendor-reset kernel module, which implements the vendor-specific reset sequences those ASICs need. Practically:
- Install the Proxmox kernel headers and build it via DKMS so it survives kernel upgrades. A passthrough host that silently loses vendor-reset after an update looks exactly like the original bug coming back.
- Tell the kernel to use the device-specific method, via a udev rule setting
reset_methodtodevice_specificfor the card, or by writing to/sys/bus/pci/devices/<addr>/reset_methodon kernels that expose it. - Check your specific ASIC against the project’s supported list. Coverage is per-generation, and newer AMD generations largely fixed the underlying reset behaviour, so the module is unnecessary there.
Treat an out-of-tree DKMS module on a hypervisor as a maintenance commitment, not a one-time fix. If that is unappealing, buying a card generation that resets properly is the cheaper answer.
The NVIDIA equivalent people still worry about, the driver refusing to load with Error 43 inside a VM, is largely historical. NVIDIA enabled virtualization support in its consumer drivers some years ago. If you hit it on current drivers, suspect the machine type, a missing vBIOS ROM, or an unclean vfio bind before reaching for the old hidden=1 and kvm=off workarounds.
Honest failure modes
Things that will bite you, none of which are your configuration being sloppy:
- The host is using the GPU as its console. If the card is the boot display, the efi framebuffer holds it. Setting the firmware’s primary display to the iGPU or another slot is the clean fix. Blacklisting the framebuffer on the kernel command line also works, at the cost of a blind host console.
- Single-GPU passthrough is fragile. It can be made to work with bind and unbind hook scripts, but you lose local console access whenever the guest is running. Do not attempt it on a host you cannot reach over the network or out-of-band.
- No live migration, and no RAM-state snapshots. A passed-through device has internal state the hypervisor cannot save or move, so Proxmox blocks both. This does not rule out Proxmox high availability outright: with a resource mapping defined on every candidate node, HA can still cold-restart the guest elsewhere after a node failure. What breaks is anything expecting a live move, including a node-maintenance policy set to migrate, which will fail and retry. Back the VM up properly either way, through your backup and restore strategy.
- Memory is pinned. The device DMAs into guest RAM, so the full allocation is committed up front and ballooning is off. Size the host accordingly.
- Resizable BAR misbehaves on some boards. If a large-BAR card fails to map, toggling ReBAR off is a legitimate diagnostic step.
- Guests are picky about machine type after install. Changing the q35 version or BIOS type on an installed and activated Windows guest can trigger reactivation and driver reinstalls.
When not to bother
Passthrough is the right tool for a gaming VM, a workstation guest, or a CUDA workload that needs the whole card. It is frequently the wrong tool for media transcoding.
If the goal is hardware transcoding for Jellyfin or Plex, an unprivileged LXC container with the render device passed in is far less brittle. There is no reset bug, no IOMMU group problem, the host keeps the card, and several containers can share it. The trade-offs are covered in LXC vs VM on Proxmox, and for transcoding the container usually wins.
Partitioning approaches such as SR-IOV on supported integrated graphics, or vGPU on datacenter cards, can serve several guests from one device. Support is uneven, some of it is out-of-tree, and the datacenter path carries licensing. Verify support for your exact hardware before designing around it.
Next steps
- Confirm the platform can do this at all before buying: Proxmox hardware requirements.
- If you are starting from scratch, get the host right first with how to install Proxmox VE.
- When the VM will not start, work the symptom against Proxmox troubleshooting: common issues.
Related
Proxmox LXC vs VM: Which One Should You Use?
LXC containers or KVM virtual machines on Proxmox VE? A practical guide to overhead, isolation, privileged vs unprivileged, and when passthrough forces a VM.
Proxmox VE vs TrueNAS SCALE: Which Should Be the Host?
Proxmox VE vs TrueNAS SCALE: which one belongs on bare metal, when to run TrueNAS as a Proxmox VM, and why HBA passthrough is non-negotiable.
How to Install Proxmox VE: Step-by-Step Install Guide
Install Proxmox VE from ISO to first boot: the installer walkthrough, choosing ext4 vs ZFS, switching to the no-subscription repo, and a first-boot checklist.