diff --git a/src/bhyve/bhyve_device.c b/src/bhyve/bhyve_device.c index 207ac6a2dd56a490b4c590b8ab1ef84c2f06d3da..a59dfe45195ff80f5f1e63055432196f90b1590d 100644 --- a/src/bhyve/bhyve_device.c +++ b/src/bhyve/bhyve_device.c @@ -71,7 +71,8 @@ bhyveDomainPCIAddressSetCreate(virDomainDefPtr def, unsigned int nbuses) { virDomainPCIAddressSetPtr addrs; - if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL) + if ((addrs = virDomainPCIAddressSetAlloc(nbuses, + VIR_PCI_ADDRESS_EXTENSION_NONE)) == NULL) return NULL; if (virDomainPCIAddressBusSetModel(&addrs->buses[0], diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index e4ed143b76b49c21a7ffeac417f8016075889363..0c00302c13854dc1d588e68de5fa8a49f75f57bb 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -27,6 +27,7 @@ #include "virlog.h" #include "virstring.h" #include "domain_addr.h" +#include "virhashcode.h" #define VIR_FROM_THIS VIR_FROM_DOMAIN @@ -727,8 +728,93 @@ virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs, addrs->buses[addr->bus].slot[addr->slot].functions &= ~(1 << addr->function); } + +static uint32_t +virZPCIAddrKeyCode(const void *name, + uint32_t seed) +{ + unsigned int value = *((unsigned int *)name); + return virHashCodeGen(&value, sizeof(value), seed); +} + + +static bool +virZPCIAddrKeyEqual(const void *namea, + const void *nameb) +{ + return *((unsigned int *)namea) == *((unsigned int *)nameb); +} + + +static void * +virZPCIAddrKeyCopy(const void *name) +{ + unsigned int *copy; + + if (VIR_ALLOC(copy) < 0) + return NULL; + + *copy = *((unsigned int *)name); + return (void *)copy; +} + + +static void +virZPCIAddrKeyFree(void *name) +{ + VIR_FREE(name); +} + + +static void +virDomainPCIAddressSetExtensionFree(virDomainPCIAddressSetPtr addrs) +{ + if (!addrs || !addrs->zpciIds) + return; + + virHashFree(addrs->zpciIds->uids); + virHashFree(addrs->zpciIds->fids); + VIR_FREE(addrs->zpciIds); +} + + +static int +virDomainPCIAddressSetExtensionAlloc(virDomainPCIAddressSetPtr addrs, + virPCIDeviceAddressExtensionFlags extFlags) +{ + if (extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) { + if (addrs->zpciIds) + return 0; + + if (VIR_ALLOC(addrs->zpciIds) < 0) + return -1; + + if (!(addrs->zpciIds->uids = virHashCreateFull(10, NULL, + virZPCIAddrKeyCode, + virZPCIAddrKeyEqual, + virZPCIAddrKeyCopy, + virZPCIAddrKeyFree))) + goto error; + + if (!(addrs->zpciIds->fids = virHashCreateFull(10, NULL, + virZPCIAddrKeyCode, + virZPCIAddrKeyEqual, + virZPCIAddrKeyCopy, + virZPCIAddrKeyFree))) + goto error; + } + + return 0; + + error: + virDomainPCIAddressSetExtensionFree(addrs); + return -1; +} + + virDomainPCIAddressSetPtr -virDomainPCIAddressSetAlloc(unsigned int nbuses) +virDomainPCIAddressSetAlloc(unsigned int nbuses, + virPCIDeviceAddressExtensionFlags extFlags) { virDomainPCIAddressSetPtr addrs; @@ -739,6 +825,10 @@ virDomainPCIAddressSetAlloc(unsigned int nbuses) goto error; addrs->nbuses = nbuses; + + if (virDomainPCIAddressSetExtensionAlloc(addrs, extFlags) < 0) + goto error; + return addrs; error: @@ -753,6 +843,7 @@ virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs) if (!addrs) return; + virDomainPCIAddressSetExtensionFree(addrs); VIR_FREE(addrs->buses); VIR_FREE(addrs); } diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 435b3c5d7f0d61ea4886880d1eb1b14f1870b20c..8d64d6b79505408d6a07516c160558cf5fb45a03 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -116,6 +116,12 @@ typedef struct { } virDomainPCIAddressBus; typedef virDomainPCIAddressBus *virDomainPCIAddressBusPtr; +typedef struct { + virHashTablePtr uids; + virHashTablePtr fids; +} virDomainZPCIAddressIds; +typedef virDomainZPCIAddressIds *virDomainZPCIAddressIdsPtr; + struct _virDomainPCIAddressSet { virDomainPCIAddressBus *buses; size_t nbuses; @@ -125,11 +131,13 @@ struct _virDomainPCIAddressSet { bool areMultipleRootsSupported; /* If true, the guest can use the pcie-to-pci-bridge controller */ bool isPCIeToPCIBridgeSupported; + virDomainZPCIAddressIdsPtr zpciIds; }; typedef struct _virDomainPCIAddressSet virDomainPCIAddressSet; typedef virDomainPCIAddressSet *virDomainPCIAddressSetPtr; -virDomainPCIAddressSetPtr virDomainPCIAddressSetAlloc(unsigned int nbuses); +virDomainPCIAddressSetPtr virDomainPCIAddressSetAlloc(unsigned int nbuses, + virPCIDeviceAddressExtensionFlags extFlags); void virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs); diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 43bde31e81221cfabb6ea807bd7fb7464dc24de9..ae3e8f0845d9160787457a17f23c2e5acabb362a 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1510,8 +1510,12 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, size_t i; bool hasPCIeRoot = false; virDomainControllerModelPCI defaultModel; + virPCIDeviceAddressExtensionFlags extFlags = VIR_PCI_ADDRESS_EXTENSION_NONE; - if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL) + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ZPCI)) + extFlags |= VIR_PCI_ADDRESS_EXTENSION_ZPCI; + + if ((addrs = virDomainPCIAddressSetAlloc(nbuses, extFlags)) == NULL) return NULL; addrs->dryRun = dryRun;