A pci-bridge has *almost* the same rules as a legacy PCI endpoint
device for where it can be automatically connected, and until now both
had been considered identical. There is one pairing that is okay when
specifically requested by the user (i.e. manual assignment), but we
want to avoid it when auto-assigning addresses - plugging a pci-bridge
directly into pcie-root (it is cleaner to plug in a dmi-to-pci-bridge,
then plug the pci-bridge into that).
In order to allow that difference, this patch makes a separate
CONNECT_TYPE for pci-bridge, and uses it to restrict auto-assigned
addresses for pci-bridges to be only on pci-root, pci-expander-bus,
dmi-to-pci-bridge, or on another pci-bridge.
NB: As with other discouraged-but-seem-to-work configurations
(e.g. plugging a legacy PCI device into a pcie-root-port) if someone
*really* wants to, they can still force a pci-bridge to be plugged
into pcie-root (by manually specifying its PCI address.)
---
src/conf/domain_addr.c | 29 ++++++++++++++++++++++-------
src/conf/domain_addr.h | 4 +++-
2 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index c533edb..88e44df 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -51,11 +51,14 @@ virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI
model)
return 0;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
- /* pci-bridge is treated like a standard
- * PCI endpoint device, because it can plug into any
- * standard PCI slot (it just can't be hotplugged).
+ /* pci-bridge is treated like a standard PCI endpoint device
+ * when its address is manually assigned, but needs special
+ * treatment when auto-assigning addresses (in that case we
+ * avoid plugging into anything except pci-root,
+ * dmi-to-pci-bridge, pci-expander-bus, or another
+ * pci-bridge).
*/
- return VIR_PCI_CONNECT_TYPE_PCI_DEVICE;
+ return VIR_PCI_CONNECT_TYPE_PCI_BRIDGE;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
return VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS;
@@ -110,6 +113,12 @@ virDomainPCIAddressFlagsCompatible(virPCIDeviceAddressPtr addr,
*/
if (devFlags & VIR_PCI_CONNECT_HOTPLUGGABLE)
busFlags |= VIR_PCI_CONNECT_HOTPLUGGABLE;
+ /* if the device is a pci-bridge, allow manually
+ * assigning to any bus that would also accept a
+ * standard PCI device.
+ */
+ if (devFlags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE)
+ devFlags |= VIR_PCI_CONNECT_TYPE_PCI_DEVICE;
}
/* If this bus doesn't allow the type of connection (PCI
@@ -138,6 +147,8 @@ virDomainPCIAddressFlagsCompatible(virPCIDeviceAddressPtr addr,
connectStr = "pci-expander-bus";
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS) {
connectStr = "pcie-expander-bus";
+ } else if (devFlags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) {
+ connectStr = "pci-bridge";
} else {
/* this should never happen. If it does, there is a
* bug in the code that sets the flag bits for devices.
@@ -247,19 +258,22 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
bus->flags = (VIR_PCI_CONNECT_HOTPLUGGABLE |
VIR_PCI_CONNECT_TYPE_PCI_DEVICE |
+ VIR_PCI_CONNECT_TYPE_PCI_BRIDGE |
VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS);
bus->minSlot = 1;
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
bus->flags = (VIR_PCI_CONNECT_HOTPLUGGABLE |
- VIR_PCI_CONNECT_TYPE_PCI_DEVICE);
+ VIR_PCI_CONNECT_TYPE_PCI_DEVICE |
+ VIR_PCI_CONNECT_TYPE_PCI_BRIDGE);
bus->minSlot = 1;
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
break;
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
bus->flags = (VIR_PCI_CONNECT_HOTPLUGGABLE |
- VIR_PCI_CONNECT_TYPE_PCI_DEVICE);
+ VIR_PCI_CONNECT_TYPE_PCI_DEVICE |
+ VIR_PCI_CONNECT_TYPE_PCI_BRIDGE);
bus->minSlot = 0;
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
break;
@@ -280,7 +294,8 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
/* slots 0 - 31, standard PCI slots,
* but *not* hot-pluggable */
- bus->flags = VIR_PCI_CONNECT_TYPE_PCI_DEVICE;
+ bus->flags = (VIR_PCI_CONNECT_TYPE_PCI_DEVICE |
+ VIR_PCI_CONNECT_TYPE_PCI_BRIDGE);
bus->minSlot = 0;
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
break;
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index 596cd4c..0072a08 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -43,6 +43,7 @@ typedef enum {
VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE = 1 << 6,
VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS = 1 << 7,
VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS = 1 << 8,
+ VIR_PCI_CONNECT_TYPE_PCI_BRIDGE = 1 << 9,
} virDomainPCIConnectFlags;
/* a combination of all bits that describe the type of connections
@@ -55,7 +56,8 @@ typedef enum {
VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT | \
VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE | \
VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS | \
- VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS)
+ VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS | \
+ VIR_PCI_CONNECT_TYPE_PCI_BRIDGE)
/* combination of all bits that could be used to connect a normal
* endpoint device (i.e. excluding the connection possible between an
--
2.7.4