If a PCI device has VIR_PCI_CONNECT_AGGREGATE_SLOT set in its pciConnectFlags, then during address assignment we allow multiple instances of this type of device to be auto-assigned to multiple functions on the same device. A slot is used for aggregating multiple devices only if the first device assigned to that slot had VIR_PCI_CONNECT_AGGREGATE_SLOT set. but any device types that have AGGREGATE_SLOT set might be mix/matched on the same slot. (NB: libvirt should never set the AGGREGATE_SLOT flag for a device type that might need to be hotplugged. Currently it is only planned for pcie-root-port and possibly other PCI controller types, and none of those are hotpluggable anyway) There aren't yet any devices that use this flag. That will be in a later patch. --- src/conf/domain_addr.c | 45 +++++++++++++++++++++++++++++++++++++++--- src/conf/domain_addr.h | 30 +++++++++++++++++++--------- src/qemu/qemu_domain_address.c | 2 +- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index dcd384a..a607d25 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -506,8 +506,20 @@ virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, addrStr); goto cleanup; } + + /* if this is the first function to be reserved on this slot, and + * the device it's being reserved for can aggregate multiples on a + * slot, set the slot's aggregate flag. + */ + if (!bus->slot[addr->slot].functions && + flags & VIR_PCI_CONNECT_AGGREGATE_SLOT) { + bus->slot[addr->slot].aggregate = true; + } + + /* mark the requested function as reserved */ bus->slot[addr->slot].functions |= (1 << addr->function); - VIR_DEBUG("Reserving PCI address %s", addrStr); + VIR_DEBUG("Reserving PCI address %s (aggregate='%s')", addrStr, + bus->slot[addr->slot].aggregate ? "true" : "false"); ret = 0; cleanup: @@ -636,7 +648,7 @@ virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs) static int virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus, virPCIDeviceAddressPtr searchAddr, - int function ATTRIBUTE_UNUSED, + int function, virDomainPCIConnectFlags flags, bool *found) { @@ -659,6 +671,33 @@ virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus, break; } + if (flags & VIR_PCI_CONNECT_AGGREGATE_SLOT && + bus->slot[searchAddr->slot].aggregate) { + /* slot and device are okay with aggregating devices */ + if ((bus->slot[searchAddr->slot].functions & + (1 << searchAddr->function)) == 0) { + *found = true; + break; + } + + /* also check for *any* unused function if caller + * sent function = -1 + */ + if (function == -1) { + while (searchAddr->function < 8) { + if ((bus->slot[searchAddr->slot].functions & + (1 << searchAddr->function)) == 0) { + *found = true; + break; /* out of inner while */ + } + searchAddr->function++; + } + if (*found) + break; /* out of outer while */ + searchAddr->function = 0; /* reset for next try */ + } + } + VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use", searchAddr->domain, searchAddr->bus, searchAddr->slot); searchAddr->slot++; @@ -805,7 +844,7 @@ virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev, virDomainPCIConnectFlags flags) { - return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, 0); + return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1); } diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 1b36877..705e033 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -32,18 +32,23 @@ typedef enum { VIR_PCI_CONNECT_HOTPLUGGABLE = 1 << 0, /* is hotplug needed/supported */ + /* set for devices that can share a single slot in auto-assignment + * (by assigning one device to each of the 8 functions on the slot) + */ + VIR_PCI_CONNECT_AGGREGATE_SLOT = 1 << 1, + /* kinds of devices as a bitmap so they can be combined (some PCI * controllers permit connecting multiple types of devices) */ - VIR_PCI_CONNECT_TYPE_PCI_DEVICE = 1 << 1, - VIR_PCI_CONNECT_TYPE_PCIE_DEVICE = 1 << 2, - VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT = 1 << 3, - VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT = 1 << 4, - VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT = 1 << 5, - 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, + VIR_PCI_CONNECT_TYPE_PCI_DEVICE = 1 << 2, + VIR_PCI_CONNECT_TYPE_PCIE_DEVICE = 1 << 3, + VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT = 1 << 4, + VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT = 1 << 5, + VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_DOWNSTREAM_PORT = 1 << 6, + VIR_PCI_CONNECT_TYPE_DMI_TO_PCI_BRIDGE = 1 << 7, + VIR_PCI_CONNECT_TYPE_PCI_EXPANDER_BUS = 1 << 8, + VIR_PCI_CONNECT_TYPE_PCIE_EXPANDER_BUS = 1 << 9, + VIR_PCI_CONNECT_TYPE_PCI_BRIDGE = 1 << 10, } virDomainPCIConnectFlags; /* a combination of all bits that describe the type of connections @@ -75,6 +80,13 @@ typedef struct { * in use by a device, or clear if it isn't. */ uint8_t functions; + + /* aggregate is true if this slot has only devices with + * VIR_PCI_CONNECT_AGGREGATE assigned to its functions (meaning + * that other devices with the same flags could also be + * auto-assigned to the other functions) + */ + bool aggregate; } virDomainPCIAddressSlot; typedef struct { diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 03be3aa..2fa6b2b 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -803,7 +803,7 @@ static int qemuDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev) { - return qemuDomainPCIAddressReserveNextAddr(addrs, dev, 0); + return qemuDomainPCIAddressReserveNextAddr(addrs, dev, -1); } -- 2.7.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list