vfio/pci: Hide device PCIe capability on non-express buses for PCIe VMs
When we have a PCIe VM, such as Q35, guests start to care more about valid configurations of devices relative to the VM view of the PCI topology. Windows will error with a Code 10 for an assigned device if a PCIe capability is found for a device on a conventional bus. We also have the possibility of IOMMUs, like VT-d, where the where the guest may be acutely aware of valid express capabilities on physical hardware. Some devices, like tg3 are adversely affected by this due to driver dependencies on the PCIe capability. The only solution for such devices is to attach them to an express capable bus in the VM. Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
a1a88589dc
commit
0282abf078
|
@ -28,6 +28,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "hw/pci/msi.h"
|
#include "hw/pci/msi.h"
|
||||||
#include "hw/pci/msix.h"
|
#include "hw/pci/msix.h"
|
||||||
|
#include "hw/pci/pci_bridge.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu/range.h"
|
#include "qemu/range.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
|
@ -1524,13 +1525,38 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pci_bus_is_express(vdev->pdev.bus)) {
|
if (!pci_bus_is_express(vdev->pdev.bus)) {
|
||||||
|
PCIBus *bus = vdev->pdev.bus;
|
||||||
|
PCIDevice *bridge;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use express capability as-is on PCI bus. It doesn't make much
|
* Traditionally PCI device assignment exposes the PCIe capability
|
||||||
* sense to even expose, but some drivers (ex. tg3) depend on it
|
* as-is on non-express buses. The reason being that some drivers
|
||||||
* and guests don't seem to be particular about it. We'll need
|
* simply assume that it's there, for example tg3. However when
|
||||||
* to revist this or force express devices to express buses if we
|
* we're running on a native PCIe machine type, like Q35, we need
|
||||||
* ever expose an IOMMU to the guest.
|
* to hide the PCIe capability. The reason for this is twofold;
|
||||||
|
* first Windows guests get a Code 10 error when the PCIe capability
|
||||||
|
* is exposed in this configuration. Therefore express devices won't
|
||||||
|
* work at all unless they're attached to express buses in the VM.
|
||||||
|
* Second, a native PCIe machine introduces the possibility of fine
|
||||||
|
* granularity IOMMUs supporting both translation and isolation.
|
||||||
|
* Guest code to discover the IOMMU visibility of a device, such as
|
||||||
|
* IOMMU grouping code on Linux, is very aware of device types and
|
||||||
|
* valid transitions between bus types. An express device on a non-
|
||||||
|
* express bus is not a valid combination on bare metal systems.
|
||||||
|
*
|
||||||
|
* Drivers that require a PCIe capability to make the device
|
||||||
|
* functional are simply going to need to have their devices placed
|
||||||
|
* on a PCIe bus in the VM.
|
||||||
*/
|
*/
|
||||||
|
while (!pci_bus_is_root(bus)) {
|
||||||
|
bridge = pci_bridge_get_device(bus);
|
||||||
|
bus = bridge->bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pci_bus_is_express(bus)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (pci_bus_is_root(vdev->pdev.bus)) {
|
} else if (pci_bus_is_root(vdev->pdev.bus)) {
|
||||||
/*
|
/*
|
||||||
* On a Root Complex bus Endpoints become Root Complex Integrated
|
* On a Root Complex bus Endpoints become Root Complex Integrated
|
||||||
|
|
Loading…
Reference in a new issue