_("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:
static int
virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus,
virPCIDeviceAddressPtr searchAddr,
- int function ATTRIBUTE_UNUSED,
+ int function,
virDomainPCIConnectFlags flags,
bool *found)
{
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++;
virDomainDeviceInfoPtr dev,
virDomainPCIConnectFlags flags)
{
- return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, 0);
+ return virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1);
}
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
* 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 {
qemuDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
virDomainDeviceInfoPtr dev)
{
- return qemuDomainPCIAddressReserveNextAddr(addrs, dev, 0);
+ return qemuDomainPCIAddressReserveNextAddr(addrs, dev, -1);
}