conf: aggregate multiple devices on a slot when assigning PCI addresses

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.
This commit is contained in:
Laine Stump 2016-10-19 14:15:01 -04:00
parent 8f4008713a
commit 48d39cf96d
3 changed files with 64 additions and 13 deletions

View File

@ -564,8 +564,20 @@ virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
_("Attempted double use of PCI Address %s"), 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:
@ -693,7 +705,7 @@ virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs)
static int
virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus,
virPCIDeviceAddressPtr searchAddr,
int function ATTRIBUTE_UNUSED,
int function,
virDomainPCIConnectFlags flags,
bool *found)
{
@ -716,6 +728,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++;
@ -863,7 +902,7 @@ virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
virDomainDeviceInfoPtr dev,
virDomainPCIConnectFlags flags)
{
return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, 0);
return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1);
}

View File

@ -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 {

View File

@ -949,7 +949,7 @@ static int
qemuDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
virDomainDeviceInfoPtr dev)
{
return qemuDomainPCIAddressReserveNextAddr(addrs, dev, 0);
return qemuDomainPCIAddressReserveNextAddr(addrs, dev, -1);
}