KVM vfio-passthrough to linux guest problem

I have an odd issue with using vfio passthrough of a secondary graphics adapter to Linux guests. It works just fine when I pass it through to my Windows 7 virtual machine.

My hardware is:

  • Xeon E5-2620 v3
  • intel c612 motherboard (supermicro)
  • primary (host) gpu: radeon r7 250
  • secondary (guest) gpu: radeon r9 270
  • assorted other pci-e devices (both host and guest)

This is not an exhaustive list, the important thing is the CPU, chipset, and GPU are fully PCIe ACS compliant, so each passthrough device is in its own iommu group with this configuration.

I set up both the windows and Linux guests using virt-manager, more or less akin to the process lessershoe describes in his excellent thread:

https://forums.opensuse.org/showthread.php/508101-Windows-10-KVM-with-IOMMU-guide

The problem is, when I assign the secondary GPU to the linux guest, it is never initialized. The console output alwaysredirects to the virt-manager window. If I remove the display spice and qxl video devices, then I get no output from the secondary GPU at all.

What am I missing?

Pls include all basics, all you’ve described is libvirt which can be used to manage nearly a dozen virt technologies.

Include
Virtualization technology
HostOS including version
GuestOS including version
Guest property config you attempted exactly (screenshot if necessary)

TSU

Sorry, this is KVM. I thought that vfio-passthrough implied KVM.

Host OS is openSUSE 13.2. Current kernel is 4.1.1. It happens with just about any kernel I’ve tried, going back to 3.17.6 or so.

Guest OS is literally any Linux distribution. Though I mostly stick to openSUSE 13.2, centos 7 and fedora 21/22.

Here’s the xml for the Centos guest, which isn’t working. Followed by the windows7 one, that is.

<domain type='kvm'>
  <name>centos7</name>
  <uuid>8c20124d-8a97-48f9-83ea-2cf3eefd3517</uuid>
  <memory unit='KiB'>4194304</memory>
  <currentMemory unit='KiB'>4194304</currentMemory>
  <vcpu placement='static'>4</vcpu>
  <os>
    <type arch='x86_64' machine='pc-i440fx-2.1'>hvm</type>
    <bootmenu enable='yes'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <cpu mode='custom' match='exact'>
    <model fallback='allow'>SandyBridge</model>
  </cpu>
  <clock offset='utc'>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='hpet' present='no'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <pm>
    <suspend-to-mem enabled='no'/>
    <suspend-to-disk enabled='no'/>
  </pm>
  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>
    <disk type='block' device='cdrom'>
      <driver name='qemu' type='raw'/>
      <target dev='hda' bus='ide'/>
      <readonly/>
      <boot order='2'/>
      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
    </disk>
    <disk type='block' device='disk'>
      <driver name='qemu' type='raw' cache='none' io='native'/>
      <source dev='/dev/vgraid/centos7'/>
      <target dev='vda' bus='virtio'/>
      <boot order='1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
    </disk>
    <controller type='usb' index='0' model='ich9-ehci1'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x7'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci1'>
      <master startport='0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0' multifunction='on'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci2'>
      <master startport='2'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x1'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci3'>
      <master startport='4'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'/>
    <controller type='ide' index='0'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <controller type='virtio-serial' index='0'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </controller>
    <interface type='bridge'>
      <mac address='52:54:00:21:c4:19'/>
      <source bridge='br0'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <console type='pty'>
      <target type='virtio' port='0'/>
    </console>
    <channel type='unix'>
      <source mode='bind' path='/var/lib/libvirt/qemu/channel/target/centos7.org.qemu.guest_agent.0'/>
      <target type='virtio' name='org.qemu.guest_agent.0'/>
      <address type='virtio-serial' controller='0' bus='0' port='1'/>
    </channel>
    <channel type='spicevmc'>
      <target type='virtio' name='com.redhat.spice.0'/>
      <address type='virtio-serial' controller='0' bus='0' port='2'/>
    </channel>
    <input type='tablet' bus='usb'/>
    <sound model='ich6'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </sound>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
        <address domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
        <address domain='0x0000' bus='0x03' slot='0x00' function='0x1'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/>
    </hostdev>
    <redirdev bus='usb' type='spicevmc'>
    </redirdev>
    <redirdev bus='usb' type='spicevmc'>
    </redirdev>
    <redirdev bus='usb' type='spicevmc'>
    </redirdev>
    <redirdev bus='usb' type='spicevmc'>
    </redirdev>
    <memballoon model='virtio'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
    </memballoon>
    <rng model='virtio'>
      <backend model='random'>/dev/random</backend>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
    </rng>
  </devices>
</domain>

<domain type='kvm'>
  <name>win7</name>
  <uuid>abe1315f-0f9d-4146-9c9c-442a66e3c981</uuid>
  <memory unit='KiB'>8388608</memory>
  <currentMemory unit='KiB'>8388608</currentMemory>
  <vcpu placement='static' current='4'>16</vcpu>
  <os>
    <type arch='x86_64' machine='pc-i440fx-2.1'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <cpu mode='custom' match='exact'>
    <model fallback='allow'>SandyBridge</model>
    <topology sockets='1' cores='4' threads='4'/>
  </cpu>
  <clock offset='localtime'>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='hpet' present='no'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <pm>
    <suspend-to-mem enabled='no'/>
    <suspend-to-disk enabled='no'/>
  </pm>
  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>
    <disk type='block' device='disk'>
      <driver name='qemu' type='raw' cache='writeback'/>
      <source dev='/dev/vgraid/windows7-test'/>
      <target dev='vda' bus='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/>
    </disk>
    <controller type='usb' index='0' model='ich9-ehci1'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x7'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci1'>
      <master startport='0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0' multifunction='on'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci2'>
      <master startport='2'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x1'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci3'>
      <master startport='4'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'/>
    <controller type='ide' index='0'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <controller type='virtio-serial' index='0'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </controller>
    <interface type='bridge'>
      <mac address='00:16:3e:63:e8:65'/>
      <source bridge='br0'/>
      <model type='rtl8139'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <target port='0'/>
    </serial>
    <console type='pty'>
      <target type='serial' port='0'/>
    </console>
    <channel type='spicevmc'>
      <target type='virtio' name='com.redhat.spice.0'/>
      <address type='virtio-serial' controller='0' bus='0' port='1'/>
    </channel>
    <input type='tablet' bus='usb'/>
    <input type='mouse' bus='ps2'/>
    <input type='keyboard' bus='ps2'/>
    <graphics type='spice' autoport='yes'/>
    <video>
      <model type='cirrus' vram='9216' heads='1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
        <address domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
        <address domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
        <address domain='0x0000' bus='0x03' slot='0x00' function='0x1'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
    </hostdev>
    <redirdev bus='usb' type='spicevmc'>
    </redirdev>
    <redirdev bus='usb' type='spicevmc'>
    </redirdev>
    <redirdev bus='usb' type='spicevmc'>
    </redirdev>
    <redirdev bus='usb' type='spicevmc'>
    </redirdev>
    <memballoon model='virtio'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
    </memballoon>
  </devices>
</domain>

The passthrough devices on this system are 01:00.0, a USB3 controller, 03:00.0 + 03:00.1 (the Radeon 270).

When the GPU is assigned, and I remove the qemu graphics and spice thing, the linux guest won’t even boot. If I remove the GPU and put the qemu graphics back, but leave the USB controller, the guest boots fine, and passed through USB controller works just fine.

I suspect that KVM on openSUSE does not support the hardware pass through method you’re trying to implement (vfio).

Although in general SUSE 11 SP3 documentation ordinarily should not be consulted to support openSUSE, the KVM documentation is the exception
https://www.suse.com/documentation/sles11/singlehtml/book_kvm/book_kvm.html

In it, down in the appendix which lists supported and unsupported commands, I see some vfio commands. You didn’t describe how you’re trying to implement passthrough, I suspect if you’re trying to implement by command line then you’re bypassing the guidance the libvirt vm manager would provide to implement a supported method

See…
In section A.3.2 “Unsupported qemu-kvm Command Line Options”
https://www.suse.com/documentation/sles11/singlehtml/book_kvm/book_kvm.html#app.kvm.qemu-commands.unsupported

Read this documentation to implement an alternative method (or open up vm manager and configure the Guest properties that way).

TSU

I did use virt-manager to create the guest machines, and also to assign the PCI devices. The xml is just the output of virsh dumpxml for those machines.

This is most certainly using vfio

 alcyone:~ # lspci -v -s 03:00.003:00.0 
VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Curacao PRO [Radeon R9 270] (prog-if 00 [VGA controller])
    Subsystem: ASUSTeK Computer Inc. Device 048d
    Physical Slot: 15
    Flags: bus master, fast devsel, latency 0, IRQ 109
    Memory at e0000000 (64-bit, prefetchable) [size=256]
    Memory at fbc00000 (64-bit, non-prefetchable) [size=256]
    I/O ports at d000 [size=256]
    Expansion ROM at fbc40000 [disabled] [size=128]
    Capabilities: [48] Vendor Specific Information: Len=08 <?>
    Capabilities: [50] Power Management version 3
    Capabilities: [58] Express Legacy Endpoint, MSI 00
    Capabilities: [a0] MSI: Enable+ Count=1/1 Maskable- 64bit+
    Capabilities: [100] Vendor Specific Information: ID=0001 Rev=1 Len=010 <?>
    Capabilities: [150] Advanced Error Reporting
    Capabilities: [270] #19
    Capabilities: [2b0] Address Translation Service (ATS)
    Capabilities: [2c0] #13
    Capabilities: [2d0] #1b
    Kernel driver in use: vfio-pci
    Kernel modules: radeon

The problem isn’t the passthrough, that part works. The problem is getting the linux guests to use the passed through GPU as the display device instead of any virtual GPU that qemu presents. If I remove the virtual graphics, then the guests fail to boot.[/size][/size][/size][/size]

OK,
I think I found what you need.

The information you posted isn’t sufficient to provide an answer (the xml dumps don’t describe your graphic card method of connection at all, in fact your Windows dump describes using the spice protocol which may be nothing more than how vm manager is connecting to the Guest) but your lspci does describe the card configured using the vfio driver.

So,
Let’s start with understanding what vfio is. The following is the official documentation/description with the following critical ideas

Once you understand what it is and more or less what it exposes, my guess is that may explain why vfio pass-through may be difficult or impossible for KVM to support, connecting to a vfio device is too different than other devices with supported PCI passthrough.

But, there appears to be a solution at the following online document, the highlights include

  • Although KVM does not support, the “older” QEMU does, so with the commands in this document you can modify your libvirt vm manager connection to the hypervisor to implement full QEMU instead. In a nutshell, today KVM and QEMU are something like 98% merged, but since QEMU is full emulation it has better capabilities supporting diverse hardware than KVM, but with the penalty losing the performance that KVM paravirtualization provides. In this case though, I suspect the DMA characteristics of vfio may compensate somewhat for any QEMU deficiencies.
  • I’m providing the link starting at “PCI pass through” for full understanding of the entire picture although you should not implement anything in this first section that describes normal PCI pass through. The section that follows describes setting up the IOMMU Groups and then Device Assignment.

https://www.suse.com/documentation/sles-12/book_virt/data/cha_qemu_running_devices.html#kvm_pciback

Note that the documentation describes starting a Guest from the machine type “qemu-system-ARCH” but you can select any type of machine you want, more likely an x64 system (but since you’re running full qemu you can specify any kind of machine, maybe even some ancient 8088 :slight_smile: a TRS-80 or the extinct Alpha 64). Just fooling, of course any really odd machine will require more emulation with a likely greater performance penalty. But, read the QEMU documentation to learn how to list available machine types, CPU, specifying memory and disk and more.

I don’t see instructions for using vm manager to manage a Guest with a vfio device, so I’m not sure how that would be done, maybe you’ll figure out something.

HTH, post back here with your success or additional issues…
TSU