mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 04:25:18 +00:00
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:
parent
8f4008713a
commit
48d39cf96d
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -949,7 +949,7 @@ static int
|
||||
qemuDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDomainDeviceInfoPtr dev)
|
||||
{
|
||||
return qemuDomainPCIAddressReserveNextAddr(addrs, dev, 0);
|
||||
return qemuDomainPCIAddressReserveNextAddr(addrs, dev, -1);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user