On Mon, 2016-11-07 at 14:50 -0500, Laine Stump wrote:
Previously libvirt would only add pci-bridge devices automatically
when an address was requested for a device that required a legacy PCI
slot and none was available. This patch expands that support to
dmi-to-pci-bridge (which is needed in order to add a pci-bridge on a
machine with a pcie-root), and pcie-root-port (which is needed to add
a hotpluggable PCIe device). It does *not* automatically add
pcie-switch-upstream-ports or pcie-switch-downstream-ports (and
currently there are no plans for that).
[...]
Although libvirt will now automatically create a dmi-to-pci-bridge
when it's needed, the code still remains for now that forces a
dmi-to-pci-bridge on all domains with pcie-root (in
qemuDomainDefAddDefaultDevices()). That will be removed in the next
patch.
s/in the next/in a future/
For now, the pcie-root-ports are added one to a slot, which is a bit
wasteful and means it will fail after 31 total PCIe devices (30 if
there are also some PCI devices), but helps keep the changeset down
for this patch. A future patch will have 8 pcie-root-ports sharing the
functions on a single slot.
[...]
@@ -82,6 +82,30 @@
virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model)
return 0;
}
+
+static int
+virDomainPCIControllerConnectTypeToModel(virDomainPCIConnectFlags flags)
+{
+ if (flags & VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT)
+ return VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT;
Maybe adding an empty line between each branch would make
this a little more readable? Just a thought.
Also too bad these are flags and we can't use a switch()
statement here - the compiler will not warn us if we forget
to handle a VIR_PCI_CONNECT_TYPE in the future :(
[...]
@@ -351,32 +372,73 @@
virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs,
{
int add;
size_t i;
+ int model;
+ bool needDMIToPCIBridge = false;
add = addr->bus - addrs->nbuses + 1;
- i = addrs->nbuses;
if (add <= 0)
return 0;
- /* auto-grow only works when we're adding plain PCI devices */
- if (!(flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE)) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot automatically add a new PCI bus for a "
- "device requiring a slot other than standard
PCI."));
+ if (flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE) {
+ model = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE;
+
+ /* if there aren't yet any buses that will accept a
+ * pci-bridge, and the caller is asking for one, we'll need to
+ * add a dmi-to-pci-bridge first.
+ */
+ needDMIToPCIBridge = true;
+ for (i = 0; i < addrs->nbuses; i++) {
+ if (addrs->buses[i].flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) {
+ needDMIToPCIBridge = false;
+ break;
+ }
+ }
+ if (needDMIToPCIBridge && add == 1) {
+ /* we need to add at least two buses - one dmi-to-pci,
+ * and the other the requested pci-bridge
+ */
+ add++;
+ addr->bus++;
+ }
This last part got me confused for a bit, so I wouldn't mind
having a more detailed comment here. Something like
We need to add a single pci-bridge to provide the bus our
legacy PCI device will be plugged into; however, we have
also determined that the pci-bridge we're about to add
itself needs to be plugged into a dmi-to-pci-bridge. To
accomodate both requirements, we're going to add both a
dmi-to-pci-bridge and a pci-bridge, and we're going to
bump the bus number of the device by one to account for
the extra controller.
Yeah, that's quite a mouthful :/
+ } else if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE
&&
+ addrs->buses[0].model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) {
+ model = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE;
Mh, what about the case where we want to add a pci-bridge
but the machine has a pci-root instead of a pcie-root?
Shouldn't that case be handled as well?
+ } else if (flags & (VIR_PCI_CONNECT_TYPE_PCIE_DEVICE |
+ VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT)) {
+ model = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT;
+ } else {
+ int existingContModel = virDomainPCIControllerConnectTypeToModel(flags);
+
+ if (existingContModel >= 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("a PCI slot is needed to connect a PCI controller
"
+ "model='%s', but none is available, and it
"
+ "cannot be automatically added"),
+ virDomainControllerModelPCITypeToString(existingContModel));
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot automatically add a new PCI bus for a "
+ "device with connect flags %.2x"), flags);
+ }
So we error out for dmi-to-pci-bridge and
pci{,e}-expander-bus... Shouldn't we be able to plug either
into into pcie-root or pci-root?
return -1;
}
+ i = addrs->nbuses;
+
if (VIR_EXPAND_N(addrs->buses, addrs->nbuses, add) < 0)
return -1;
- for (; i < addrs->nbuses; i++) {
- /* Any time we auto-add a bus, we will want a multi-slot
- * bus. Currently the only type of bus we will auto-add is a
- * pci-bridge, which is hot-pluggable and provides standard
- * PCI slots.
+ if (needDMIToPCIBridge) {
+ /* first of the new buses is dmi-to-pci-bridge, the
+ * rest are of the requested type
*/
- virDomainPCIAddressBusSetModel(&addrs->buses[i],
- VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE);
+ virDomainPCIAddressBusSetModel(&addrs->buses[i++],
+ VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE);
virDomainPCIAddressBusSetModel() can fail, yet you're not
checking the return value neither here...
}
+
+ for (; i < addrs->nbuses; i++)
+ virDomainPCIAddressBusSetModel(&addrs->buses[i], model);
... nor here.
[...]
@@ -947,7 +934,43 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr
def,
if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model)
< 0)
goto error;
- }
+
+ if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT)
+ hasPCIeRoot = true;
+ }
+
+ if (nbuses > 0 && !addrs->buses[0].model) {
+ /* This is just here to replicate a safety measure already in
+ * an older version of this code. In practice, the root bus
+ * should have already been added at index 0 prior to
+ * assigning addresses to devices.
+ */
+ if (virDomainPCIAddressBusSetModel(&addrs->buses[0],
+ VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) <
0)
+ goto error;
+ }
+
+ /* Now fill in a reasonable model for all the buses in the set
+ * that don't yet have a corresponding controller in the domain
+ * config.
+ */
+
No empty line here.
Rest looks good, but no ACK for you quite yet :)
--
Andrea Bolognani / Red Hat / Virtualization