The function that auto-assigns PCI addresses was written with the hardcoded assumptions that any PCI bus would have slots available starting at 1 and ending at 31. This isn't true for many types of controller (some have a single slot/port at 0, some have slots/ports from 0 to 31). This patch updates that function to remove the hardcoded assumptions. It will properly find/assign addresses for devices that can only connect to pcie-(root|downstream)-port (which have minSlot/maxSlot of 0/0) or a pcie-switch-upstream-port (0/31). It still will not auto-create a new bus of the proper kind for these connections when one doesn't exist, that task is for another day. --- new in V2 src/conf/domain_addr.c | 65 +++++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 2be98c5..bc09279 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -471,24 +471,30 @@ virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, virDomainPCIConnectFlags flags) { /* default to starting the search for a free slot from - * 0000:00:00.0 + * the first slot of domain 0 bus 0... */ virDevicePCIAddress a = { 0, 0, 0, 0, false }; char *addrStr = NULL; - /* except if this search is for the exact same type of device as - * last time, continue the search from the previous match - */ - if (flags == addrs->lastFlags) - a = addrs->lastaddr; - if (addrs->nbuses == 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available")); goto error; } - /* Start the search at the last used bus and slot */ - for (a.slot++; a.bus < addrs->nbuses; a.bus++) { + /* ...unless this search is for the exact same type of device as + * last time, then continue the search from the next slot after + * the previous match. + */ + if (flags == addrs->lastFlags) { + a = addrs->lastaddr; + if (++a.slot > addrs->buses[a.bus].maxSlot && + ++a.bus < addrs->nbuses) + a.slot = addrs->buses[a.bus].minSlot; + } else { + a.slot = addrs->buses[0].minSlot; + } + + while (a.bus < addrs->nbuses) { if (!(addrStr = virDomainPCIAddressAsString(&a))) goto error; if (!virDomainPCIAddressFlagsCompatible(&a, addrStr, @@ -497,29 +503,33 @@ virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, VIR_FREE(addrStr); VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device", a.domain, a.bus); - continue; - } - for (; a.slot <= VIR_PCI_ADDRESS_SLOT_LAST; a.slot++) { - if (!virDomainPCIAddressSlotInUse(addrs, &a)) - goto success; + } else { + while (a.slot <= addrs->buses[a.bus].maxSlot) { + if (!virDomainPCIAddressSlotInUse(addrs, &a)) + goto success; - VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use", - a.domain, a.bus, a.slot); + VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use", + a.domain, a.bus, a.slot); + a.slot++; + } } - a.slot = 1; + if (++a.bus < addrs->nbuses) + a.slot = addrs->buses[a.bus].minSlot; VIR_FREE(addrStr); } /* There were no free slots after the last used one */ if (addrs->dryRun) { - /* a is already set to the first new bus and slot 1 */ + /* a is already set to the first new bus */ if (virDomainPCIAddressSetGrow(addrs, &a, flags) < 0) goto error; + /* this device will use the first slot of the new bus */ + a.slot = addrs->buses[a.bus].minSlot; goto success; } else if (flags == addrs->lastFlags) { /* Check the buses from 0 up to the last used one */ for (a.bus = 0; a.bus <= addrs->lastaddr.bus; a.bus++) { - addrStr = NULL; + a.slot = addrs->buses[a.bus].minSlot; if (!(addrStr = virDomainPCIAddressAsString(&a))) goto error; if (!virDomainPCIAddressFlagsCompatible(&a, addrStr, @@ -527,14 +537,15 @@ virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs, flags, false, false)) { VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device", a.domain, a.bus); - continue; - } - for (a.slot = 1; a.slot <= VIR_PCI_ADDRESS_SLOT_LAST; a.slot++) { - if (!virDomainPCIAddressSlotInUse(addrs, &a)) - goto success; - - VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use", - a.domain, a.bus, a.slot); + } else { + while (a.slot <= addrs->buses[a.bus].maxSlot) { + if (!virDomainPCIAddressSlotInUse(addrs, &a)) + goto success; + + VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use", + a.domain, a.bus, a.slot); + a.slot++; + } } } } -- 2.1.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list