From: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.com>
Today's aggregate flag with the slot being true for pcie-root-ports
is not enough as there will more number of aggregates depending on
the number of Multifunction PCI cards assigned to the domain.
The aggregate is changed to unsigned int. Zero means Not Applicable,
1 is reserved for the pcie-root-ports and >= 2 for the the PCI
Multifunction cards(coming..).
Signed-off-by: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413(a)gmail.com>
---
src/conf/device_conf.h | 1 +
src/conf/domain_addr.c | 45 ++++++++++++------
src/conf/domain_addr.h | 38 +++++++--------
src/qemu/qemu_domain_address.c | 84 ++++++++++++++++++++++++++++------
src/qemu/qemu_domain_address.h | 9 ++++
5 files changed, 127 insertions(+), 50 deletions(-)
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h
index e091d7cfe2..d8649daa6d 100644
--- a/src/conf/device_conf.h
+++ b/src/conf/device_conf.h
@@ -170,6 +170,7 @@ struct _virDomainDeviceInfo {
*/
int pciAddrExtFlags; /* enum virDomainPCIAddressExtensionFlags */
char *loadparm;
+ unsigned int aggregateSlotIdx; /* Used when the aggregate flag is set */
/* PCI devices will only be automatically placed on a PCI bus
* that shares the same isolation group */
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index 607ba56efd..8e4817689e 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -297,7 +297,7 @@ virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI
model)
return VIR_PCI_CONNECT_TYPE_PCIE_TO_PCI_BRIDGE;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
- return VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT | VIR_PCI_CONNECT_AGGREGATE_SLOT;
+ return VIR_PCI_CONNECT_TYPE_PCIE_ROOT_PORT;
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
return VIR_PCI_CONNECT_TYPE_PCIE_SWITCH_UPSTREAM_PORT;
@@ -827,6 +827,7 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr
addrs,
virPCIDeviceAddressPtr addr,
virDomainPCIConnectFlags flags,
unsigned int isolationGroup,
+ unsigned int aggregateSlotIdx,
bool fromConfig)
{
int ret = -1;
@@ -859,9 +860,14 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr
addrs,
* 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;
+ if (!bus->slot[addr->slot].functions && aggregateSlotIdx > 0) {
+ bus->slot[addr->slot].aggregateSlotIdx = aggregateSlotIdx;
+ } else if (bus->slot[addr->slot].aggregateSlotIdx !=
+ aggregateSlotIdx && fromConfig) {
+ bus->slot[addr->slot].aggregateSlotIdx = 0;
+ VIR_DEBUG("PCI functions of %.4x:%.2x is aggregated to slot %u"
+ "because of user assigned address %s",
+ addr->domain, addr->bus, aggregateSlotIdx, addrStr);
}
if (virDomainPCIAddressBusIsEmpty(bus) && !bus->isolationGroupLocked) {
@@ -886,8 +892,8 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr
addrs,
/* mark the requested function as reserved */
bus->slot[addr->slot].functions |= (1 << addr->function);
- VIR_DEBUG("Reserving PCI address %s (aggregate='%s')", addrStr,
- bus->slot[addr->slot].aggregate ? "true" :
"false");
+ VIR_DEBUG("Reserving PCI address %s (aggregateSlotIdx='%d')",
+ addrStr, bus->slot[addr->slot].aggregateSlotIdx);
ret = 0;
cleanup:
@@ -900,10 +906,11 @@ int
virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr addr,
virDomainPCIConnectFlags flags,
- unsigned int isolationGroup)
+ unsigned int isolationGroup,
+ unsigned int aggregateSlotIdx)
{
return virDomainPCIAddressReserveAddrInternal(addrs, addr, flags,
- isolationGroup, true);
+ isolationGroup, aggregateSlotIdx,
true);
}
int
@@ -940,6 +947,7 @@ virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
if (virDomainPCIAddressReserveAddrInternal(addrs, &dev->addr.pci,
flags, dev->isolationGroup,
+ dev->aggregateSlotIdx,
true) < 0) {
goto cleanup;
}
@@ -1109,6 +1117,7 @@ virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs)
static int
virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus,
virPCIDeviceAddressPtr searchAddr,
+ unsigned int aggregateSlotIdx,
int function,
virDomainPCIConnectFlags flags,
bool *found)
@@ -1132,8 +1141,8 @@ virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr
bus,
break;
}
- if (flags & VIR_PCI_CONNECT_AGGREGATE_SLOT &&
- bus->slot[searchAddr->slot].aggregate) {
+ if (bus->slot[searchAddr->slot].aggregateSlotIdx > 0 &&
+ bus->slot[searchAddr->slot].aggregateSlotIdx == aggregateSlotIdx)
{
/* slot and device are okay with aggregating devices */
if ((bus->slot[searchAddr->slot].functions &
(1 << searchAddr->function)) == 0) {
@@ -1178,6 +1187,7 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr next_addr,
virDomainPCIConnectFlags flags,
unsigned int isolationGroup,
+ unsigned int aggregateSlotIdx,
int function)
{
virPCIDeviceAddress a = { 0 };
@@ -1206,7 +1216,9 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
a.slot = bus->minSlot;
- if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a, function,
+ if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a,
+ aggregateSlotIdx,
+ function,
flags, &found) < 0) {
return -1;
}
@@ -1230,7 +1242,9 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
a.slot = bus->minSlot;
- if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a, function,
+ if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a,
+ aggregateSlotIdx,
+ function,
flags, &found) < 0) {
return -1;
}
@@ -1288,12 +1302,13 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr
addrs,
{
virPCIDeviceAddress addr;
- if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags,
- dev->isolationGroup, function) < 0)
+ if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, dev->isolationGroup,
+ dev->aggregateSlotIdx, function) < 0)
return -1;
if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags,
- dev->isolationGroup, false) < 0)
+ dev->isolationGroup,
+ dev->aggregateSlotIdx, false) < 0)
return -1;
addr.extFlags = dev->addr.pci.extFlags;
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index dcb90618f8..65dbdb3286 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -34,24 +34,19 @@ typedef enum {
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 << 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,
- VIR_PCI_CONNECT_TYPE_PCIE_TO_PCI_BRIDGE = 1 << 11,
+ 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_PCIE_TO_PCI_BRIDGE = 1 << 10,
} virDomainPCIConnectFlags;
/* a combination of all bits that describe the type of connections
@@ -85,12 +80,12 @@ typedef struct {
*/
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)
+ /* aggregate is greater than zero if this slot has only devices with
+ * VIR_PCI_CONNECT_AGGREGATE assigned to its functions and
+ * that other devices with the same aggregateSlotIdx could also be
+ * auto-assigned to the other functions on this slot)
*/
- bool aggregate;
+ unsigned int aggregateSlotIdx;
} virDomainPCIAddressSlot;
typedef struct {
@@ -168,7 +163,8 @@ int
virDomainPCIAddressExtensionReserveNextAddr(virDomainPCIAddressSetPtr addrs,
int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr addr,
virDomainPCIConnectFlags flags,
- unsigned int isolationGroup)
+ unsigned int isolationGroup,
+ unsigned int agregateSlotIdx)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index b663e05391..bff81082ef 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -24,6 +24,7 @@
#include "qemu_domain_address.h"
#include "qemu_domain.h"
#include "viralloc.h"
+#include "virhostdev.h"
#include "virerror.h"
#include "virlog.h"
@@ -1408,6 +1409,54 @@ qemuDomainSetupIsolationGroups(virDomainDefPtr def)
}
+void
+qemuDomainSetDeviceSlotAggregateIdx(virDomainDefPtr def G_GNUC_UNUSED,
+ virDomainDeviceDefPtr dev)
+{
+ virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev);
+
+ if (!info)
+ return;
+
+ info->aggregateSlotIdx = 0;
+
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
+ virDomainControllerDefPtr cont = dev->data.controller;
+ if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
+ cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT) {
+ info->aggregateSlotIdx = 1;
+ }
+ }
+
+ return;
+}
+
+
+static int
+qemuDomainFillDeviceSlotAggregationIter(virDomainDefPtr def,
+ virDomainDeviceDefPtr dev,
+ virDomainDeviceInfoPtr info G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ qemuDomainSetDeviceSlotAggregateIdx(def, dev);
+
+ return 0;
+}
+
+
+static int
+qemuDomainSetupSlotAggregation(virDomainDefPtr def)
+{
+ if (virDomainDeviceInfoIterate(def,
+ qemuDomainFillDeviceSlotAggregationIter,
+ NULL) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
/**
* qemuDomainFillDevicePCIConnectFlags:
*
@@ -1579,7 +1628,8 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def G_GNUC_UNUSED,
if (virDomainPCIAddressReserveAddr(addrs, addr,
info->pciConnectFlags,
- info->isolationGroup) < 0) {
+ info->isolationGroup,
+ info->aggregateSlotIdx) < 0) {
return -1;
}
@@ -1772,7 +1822,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
continue;
}
if (addrs->nbuses &&
- virDomainPCIAddressReserveAddr(addrs, &cont->info.addr.pci, flags, 0)
< 0)
+ virDomainPCIAddressReserveAddr(addrs, &cont->info.addr.pci, flags, 0,
0) < 0)
return -1;
}
@@ -1781,11 +1831,11 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
memset(&tmp_addr, 0, sizeof(tmp_addr));
tmp_addr.slot = 1;
/* ISA Bridge at 00:01.0 */
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0) < 0)
return -1;
/* Bridge at 00:01.3 */
tmp_addr.function = 3;
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0) < 0)
return -1;
}
@@ -1826,7 +1876,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
return -1;
}
} else {
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) <
0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0)
< 0)
return -1;
primaryVideo->info.addr.pci = tmp_addr;
primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
@@ -1849,7 +1899,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
VIR_DEBUG("PCI address 0:0:2.0 in use, future addition of a video"
" device will not be possible without manual"
" intervention");
- } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
{
+ } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0) <
0) {
return -1;
}
}
@@ -1919,7 +1969,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
assign = true;
}
if (assign) {
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0)
< 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0)
< 0)
return -1;
cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
@@ -1942,7 +1992,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
memset(&tmp_addr, 0, sizeof(tmp_addr));
tmp_addr.slot = 0x1E;
if (!virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0)
< 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0)
< 0)
return -1;
cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
@@ -1966,12 +2016,12 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
tmp_addr.slot = 0x1F;
tmp_addr.function = 0;
tmp_addr.multi = VIR_TRISTATE_SWITCH_ON;
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0) < 0)
return -1;
tmp_addr.function = 3;
tmp_addr.multi = VIR_TRISTATE_SWITCH_ABSENT;
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0) < 0)
return -1;
}
@@ -2008,7 +2058,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
return -1;
}
} else {
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) <
0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0)
< 0)
return -1;
primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
primaryVideo->info.addr.pci = tmp_addr;
@@ -2034,7 +2084,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
" device will not be possible without manual"
" intervention");
virResetLastError();
- } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
{
+ } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0) <
0) {
return -1;
}
}
@@ -2055,7 +2105,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
!virDeviceInfoPCIAddressIsWanted(&sound->info)) {
continue;
}
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0, 0) <
0)
return -1;
sound->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
@@ -2257,7 +2307,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def,
/* Reserve this function on the slot we found */
if (virDomainPCIAddressReserveAddr(addrs, &addr,
cont->info.pciConnectFlags,
- cont->info.isolationGroup) < 0)
{
+ cont->info.isolationGroup,
+ cont->info.aggregateSlotIdx) <
0) {
return -1;
}
@@ -2631,6 +2682,9 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
if (qemuDomainSetupIsolationGroups(def) < 0)
goto cleanup;
+ if (qemuDomainSetupSlotAggregation(def) < 0)
+ goto cleanup;
+
if (nbuses > 0) {
/* 1st pass to figure out how many PCI bridges we need */
if (!(addrs = qemuDomainPCIAddressSetCreate(def, qemuCaps, nbuses, true)))
@@ -2751,6 +2805,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
dev.data.controller = def->controllers[contIndex];
/* set connect flags so it will be properly addressed */
qemuDomainFillDevicePCIConnectFlags(def, &dev, qemuCaps, driver);
+ qemuDomainSetDeviceSlotAggregateIdx(def, &dev);
/* Reserve an address for the controller. pci-root and pcie-root
* controllers don't plug into any other PCI controller, hence
@@ -3224,6 +3279,7 @@ qemuDomainEnsurePCIAddress(virDomainObjPtr obj,
return 0;
qemuDomainFillDevicePCIConnectFlags(obj->def, dev, priv->qemuCaps, driver);
+ qemuDomainSetDeviceSlotAggregateIdx(obj->def, dev);
qemuDomainFillDevicePCIExtensionFlags(dev, info, priv->qemuCaps);
diff --git a/src/qemu/qemu_domain_address.h b/src/qemu/qemu_domain_address.h
index bf04e6bfdb..d7f06dd430 100644
--- a/src/qemu/qemu_domain_address.h
+++ b/src/qemu/qemu_domain_address.h
@@ -53,6 +53,15 @@ int qemuDomainFillDeviceIsolationGroup(virDomainDefPtr def,
virDomainDeviceDefPtr dev)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+void
+qemuDomainSetDeviceSlotAggregateIdx(virDomainDefPtr def,
+ virDomainDeviceDefPtr dev);
+
+int
+qemuDomainDefDeviceFindSlotAggregateIdx(virDomainDefPtr def,
+ virDomainDeviceDefPtr dev);
+
+
void qemuDomainReleaseDeviceAddress(virDomainObjPtr vm,
virDomainDeviceInfoPtr info);
--
2.24.1