Introduce apci-generic-initiator device to the domain XML. Example definition:
<acpi-generic-initiator> <pci-dev>dev0</pci-dev> <numa-node>1</numa-node> </acpi-generic-initiator> This enables partitioning of PCI resources into multiple isolated instances, each requiring a dedicated NUMA node definition, that can be represented by the acpi-generic-initiator object. Link: https://mail.gnu.org/archive/html/qemu-arm/2024-03/msg00358.html Signed-off-by: Andrea Righi <ari...@nvidia.com> --- docs/formatdomain.rst | 36 +++++ src/ch/ch_domain.c | 1 + src/conf/domain_conf.c | 138 ++++++++++++++++++ src/conf/domain_conf.h | 14 ++ src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 37 +++++ src/conf/schemas/domaincommon.rng | 14 ++ src/conf/virconftypes.h | 2 + src/hyperv/hyperv_driver.c | 1 + src/libxl/libxl_driver.c | 6 + src/lxc/lxc_driver.c | 6 + src/qemu/qemu_alias.c | 11 ++ src/qemu/qemu_command.c | 1 + src/qemu/qemu_domain.c | 2 + src/qemu/qemu_domain_address.c | 4 + src/qemu/qemu_driver.c | 3 + src/qemu/qemu_hotplug.c | 5 + src/qemu/qemu_postparse.c | 1 + src/qemu/qemu_validate.c | 1 + src/test/test_driver.c | 4 + .../acpi-generic-initiator.x86_64-latest.args | 55 +++++++ .../acpi-generic-initiator.x86_64-latest.xml | 1 + .../acpi-generic-initiator.xml | 94 ++++++++++++ tests/qemuxmlconftest.c | 1 + 24 files changed, 439 insertions(+) create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.args create mode 120000 tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.xml diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index d3c04d8b2a..3eeafade67 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -9152,6 +9152,42 @@ The ``virtio`` IOMMU devices can further have ``address`` element as described in `Device addresses`_ (address has to by type of ``pci``). +ACPI generic initiator +~~~~~~~~~~~~~~~~~~~~~~ + +The ACPI Generic Initiator device (GI) allows associating a PCI device with +a specific NUMA node in the guest through the ACPI Generic Initiator +namespace. + +This is required for certain accelerator configurations, such as NVIDIA +Multi-Instance GPU (MIG), where each virtual instance must be exposed to +the guest as a separate NUMA node. + +:since:`Since v11.5.0` + +:: + + ... + <acpi-generic-initiator> + <pci-dev>dev0</pci-dev> + <numa-node>1</numa-node> + </acpi-generic-initiator> + ... + +The ``acpi-generic-initiator`` element has the following child elements: + +``pci-dev`` + Mandatory. Refers to the alias of a PCI device defined in the domain + configuration. + +``numa-node`` + Mandatory. Specifies the guest NUMA node that the PCI device should be + associated with through the GI mechanism. + +Multiple ``acpi-generic-initiator`` elements can be defined to map different PCI +devices to different guest NUMA nodes. + + Vsock ~~~~~ diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index 7231fdc49f..95d835f07f 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -164,6 +164,7 @@ chValidateDomainDeviceDef(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_CHR: case VIR_DOMAIN_DEVICE_HOSTDEV: case VIR_DOMAIN_DEVICE_RNG: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: break; case VIR_DOMAIN_DEVICE_LEASE: diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index cb096f2e1e..dcc0c82f70 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -342,6 +342,7 @@ VIR_ENUM_IMPL(virDomainDevice, "audio", "crypto", "pstore", + "acpiinitiator", ); VIR_ENUM_IMPL(virDomainDiskDevice, @@ -3489,6 +3490,17 @@ virDomainHostdevDefNew(void) } +virDomainAcpiInitiatorDef * +virDomainAcpiInitiatorDefNew(void) +{ + virDomainAcpiInitiatorDef *def; + + def = g_new0(virDomainAcpiInitiatorDef, 1); + + return def; +} + + static virDomainTPMDef * virDomainTPMDefNew(virDomainXMLOption *xmlopt) { @@ -3549,6 +3561,16 @@ void virDomainHostdevDefFree(virDomainHostdevDef *def) g_free(def); } +void +virDomainAcpiInitiatorDefFree(virDomainAcpiInitiatorDef *def) +{ + if (!def) + return; + + g_free(def->pciDev); + g_free(def); +} + void virDomainHubDefFree(virDomainHubDef *def) { if (!def) @@ -3711,6 +3733,9 @@ void virDomainDeviceDefFree(virDomainDeviceDef *def) case VIR_DOMAIN_DEVICE_PSTORE: virDomainPstoreDefFree(def->data.pstore); break; + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: + virDomainAcpiInitiatorDefFree(def->data.acpiinitiator); + break; case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_NONE: break; @@ -4695,6 +4720,8 @@ virDomainDeviceGetInfo(const virDomainDeviceDef *device) return &device->data.crypto->info; case VIR_DOMAIN_DEVICE_PSTORE: return &device->data.pstore->info; + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: + return &device->data.acpiinitiator->info; /* The following devices do not contain virDomainDeviceInfo */ case VIR_DOMAIN_DEVICE_LEASE: @@ -4803,6 +4830,9 @@ virDomainDeviceSetData(virDomainDeviceDef *device, case VIR_DOMAIN_DEVICE_PSTORE: device->data.pstore = devicedata; break; + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: + device->data.acpiinitiator = devicedata; + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LAST: break; @@ -5028,6 +5058,13 @@ virDomainDeviceInfoIterateFlags(virDomainDef *def, return rc; } + device.type = VIR_DOMAIN_DEVICE_ACPI_INITIATOR; + for (i = 0; i < def->nacpiinitiator; i++) { + device.data.acpiinitiator = def->acpiinitiator[i]; + if ((rc = cb(def, &device, &def->acpiinitiator[i]->info, opaque)) != 0) + return rc; + } + /* If the flag below is set, make sure @cb can handle @info being NULL */ if (iteratorFlags & DOMAIN_DEVICE_ITERATE_MISSING_INFO) { device.type = VIR_DOMAIN_DEVICE_GRAPHICS; @@ -5088,6 +5125,7 @@ virDomainDeviceInfoIterateFlags(virDomainDef *def, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: break; } #endif @@ -13671,6 +13709,49 @@ virDomainHostdevDefParseXML(virDomainXMLOption *xmlopt, } +static virDomainAcpiInitiatorDef * +virDomainAcpiInitiatorDefParseXML(virDomainXMLOption *xmlopt, + xmlNodePtr node, + xmlXPathContextPtr ctxt, + unsigned int flags) +{ + g_autoptr(virDomainAcpiInitiatorDef) def = virDomainAcpiInitiatorDefNew(); + g_autofree char *tmp = NULL; + + VIR_XPATH_NODE_AUTORESTORE(ctxt) + + ctxt->node = node; + + if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to parse device information")); + return NULL; + } + + def->pciDev = virXPathString("string(./pci-dev)", ctxt); + if (!def->pciDev) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing initiator pci-dev")); + return NULL; + } + + tmp = virXPathString("string(./numa-node)", ctxt); + if (tmp) { + if (virStrToLong_i(tmp, NULL, 10, &def->numaNode) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("invalid value for numa-node: '%1$s'"), tmp); + return NULL; + } + } else { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing initiator numa-node")); + return NULL; + } + + return g_steal_pointer(&def); +} + + static virDomainRedirdevDef * virDomainRedirdevDefParseXML(virDomainXMLOption *xmlopt, xmlNodePtr node, @@ -14734,6 +14815,12 @@ virDomainDeviceDefParse(const char *xmlStr, return NULL; } break; + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: + if (!(dev->data.acpiinitiator = virDomainAcpiInitiatorDefParseXML(xmlopt, node, + ctxt, flags))) { + return NULL; + } + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LAST: break; @@ -20162,6 +20249,24 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt, } VIR_FREE(nodes); + /* analysis of the acpi generic initiator */ + if ((n = virXPathNodeSet("./devices/acpi-generic-initiator", ctxt, &nodes)) < 0) + return NULL; + + if (n) + def->acpiinitiator = g_new0(virDomainAcpiInitiatorDef *, n); + + for (i = 0; i < n; i++) { + virDomainAcpiInitiatorDef *acpiinitiator; + + acpiinitiator = virDomainAcpiInitiatorDefParseXML(xmlopt, nodes[i], ctxt, flags); + if (!acpiinitiator) + return NULL; + + def->acpiinitiator[def->nacpiinitiator++] = acpiinitiator; + } + VIR_FREE(nodes); + /* analysis of the user namespace mapping */ if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0) return NULL; @@ -21103,6 +21208,17 @@ virDomainHostdevDefCheckABIStability(virDomainHostdevDef *src, } +static bool +virDomainAcpiInitiatorDefCheckABIStability(virDomainAcpiInitiatorDef *src, + virDomainAcpiInitiatorDef *dst) +{ + if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info)) + return false; + + return true; +} + + static bool virDomainSmartcardDefCheckABIStability(virDomainSmartcardDef *src, virDomainSmartcardDef *dst) @@ -22465,6 +22581,12 @@ virDomainDefCheckABIStabilityFlags(virDomainDef *src, goto error; } + for (i = 0; i < src->nacpiinitiator; i++) { + if (!virDomainAcpiInitiatorDefCheckABIStability(src->acpiinitiator[i], + dst->acpiinitiator[i])) + goto error; + } + if ((!src->redirfilter && dst->redirfilter) || (src->redirfilter && !dst->redirfilter)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, @@ -22635,6 +22757,7 @@ virDomainDefCheckABIStabilityFlags(virDomainDef *src, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: break; } #endif @@ -28920,6 +29043,17 @@ virDomainPstoreDefFormat(virBuffer *buf, return 0; } +static void +virDomainAcpiInitiatorDefFormat(virBuffer *buf, + virDomainAcpiInitiatorDef *acpiinitiator) +{ + g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + + virBufferEscapeString(&childBuf, "<pci-dev>%s</pci-dev>\n", acpiinitiator->pciDev); + virBufferAsprintf(&childBuf, "<numa-node>%d</numa-node>\n", acpiinitiator->numaNode); + + virXMLFormatElement(buf, "acpi-generic-initiator", NULL, &childBuf); +} int virDomainDefFormatInternal(virDomainDef *def, @@ -29409,6 +29543,9 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def, if (def->pstore) virDomainPstoreDefFormat(buf, def->pstore, flags); + for (n = 0; n < def->nacpiinitiator; n++) + virDomainAcpiInitiatorDefFormat(buf, def->acpiinitiator[n]); + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</devices>\n"); @@ -29569,6 +29706,7 @@ virDomainDeviceIsUSB(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: break; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 984e5bfc76..6105ab956b 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -88,6 +88,7 @@ typedef enum { VIR_DOMAIN_DEVICE_AUDIO, VIR_DOMAIN_DEVICE_CRYPTO, VIR_DOMAIN_DEVICE_PSTORE, + VIR_DOMAIN_DEVICE_ACPI_INITIATOR, VIR_DOMAIN_DEVICE_LAST } virDomainDeviceType; @@ -122,6 +123,7 @@ struct _virDomainDeviceDef { virDomainAudioDef *audio; virDomainCryptoDef *crypto; virDomainPstoreDef *pstore; + virDomainAcpiInitiatorDef *acpiinitiator; } data; }; @@ -353,6 +355,12 @@ typedef enum { VIR_DOMAIN_STARTUP_POLICY_LAST } virDomainStartupPolicy; +struct _virDomainAcpiInitiatorDef { + char *pciDev; + int numaNode; + virDomainDeviceInfo info; +}; + /* basic device for direct passthrough */ struct _virDomainHostdevDef { /* If 'parentnet' is non-NULL it means this host dev was @@ -3296,6 +3304,9 @@ struct _virDomainDef { size_t ntpms; virDomainTPMDef **tpms; + size_t nacpiinitiator; + virDomainAcpiInitiatorDef **acpiinitiator; + /* Only 1 */ virDomainMemballoonDef *memballoon; virDomainNVRAMDef *nvram; @@ -3781,6 +3792,9 @@ virDomainVideoDef *virDomainVideoDefNew(virDomainXMLOption *xmlopt); void virDomainVideoDefFree(virDomainVideoDef *def); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainVideoDef, virDomainVideoDefFree); void virDomainVideoDefClear(virDomainVideoDef *def); +virDomainAcpiInitiatorDef *virDomainAcpiInitiatorDefNew(void); +void virDomainAcpiInitiatorDefFree(virDomainAcpiInitiatorDef *def); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainAcpiInitiatorDef, virDomainAcpiInitiatorDefFree); virDomainHostdevDef *virDomainHostdevDefNew(void); void virDomainHostdevDefFree(virDomainHostdevDef *def); void virDomainHubDefFree(virDomainHubDef *def); diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c index a07ec8d94e..b297755477 100644 --- a/src/conf/domain_postparse.c +++ b/src/conf/domain_postparse.c @@ -760,6 +760,7 @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: ret = 0; break; diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index 40edecef83..675fc9f768 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -2388,6 +2388,40 @@ virDomainHostdevDefValidate(const virDomainHostdevDef *hostdev) } +static int +virDomainAcpiInitiatorDefValidate(const virDomainDef *def, + const virDomainAcpiInitiatorDef *acpiinitiator) +{ + const size_t nodeCount = virDomainNumaGetNodeCount(def->numa); + + if (!nodeCount) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("No NUMA node defined")); + return -1; + } + + if (acpiinitiator->numaNode >= nodeCount) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("invalid acpi-generic-initiator NUMA node %1$u"), + acpiinitiator->numaNode); + return -1; + } + + if (acpiinitiator->pciDev[0] == '\0') { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("acpi-generic-initiator must have a PCI device assigned")); + return -1; + } + + if (acpiinitiator->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("acpi-generic-initiator must have a device address type None")); + return -1; + } + + return 0; +} + /** * virDomainMemoryGetMappedSize: * @mem: memory device definition @@ -3328,6 +3362,9 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_PSTORE: return virDomainPstoreDefValidate(dev->data.pstore); + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: + return virDomainAcpiInitiatorDefValidate(def, dev->data.acpiinitiator); + case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_WATCHDOG: case VIR_DOMAIN_DEVICE_HUB: diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 9782dca147..cb8441aa83 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -6924,6 +6924,7 @@ <ref name="shmem"/> <ref name="memorydev"/> <ref name="crypto"/> + <ref name="acpi-generic-initiator"/> </choice> </zeroOrMore> <zeroOrMore> @@ -7666,6 +7667,19 @@ </element> </define> + <define name="acpi-generic-initiator"> + <element name="acpi-generic-initiator"> + <interleave> + <element name="pci-dev"> + <ref name="aliasName"/> + </element> + <element name="numa-node"> + <ref name="unsignedInt"/> + </element> + </interleave> + </element> + </define> + <define name="crypto"> <element name="crypto"> <attribute name="model"> diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index 93fc9c9217..ea37593980 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -122,6 +122,8 @@ typedef struct _virDomainHostdevCaps virDomainHostdevCaps; typedef struct _virDomainHostdevDef virDomainHostdevDef; +typedef struct _virDomainAcpiInitiatorDef virDomainAcpiInitiatorDef; + typedef struct _virDomainHostdevSubsys virDomainHostdevSubsys; typedef struct _virDomainHostdevSubsysMediatedDev virDomainHostdevSubsysMediatedDev; diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 0c17ef16ec..7361b2fbb7 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -3124,6 +3124,7 @@ hypervDomainAttachDeviceFlags(virDomainPtr domain, const char *xml, unsigned int case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_INTERNAL_ERROR, _("Attaching devices of type %1$d is not implemented"), dev->type); return -1; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 308c0372aa..1f698dc570 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -3492,6 +3492,7 @@ libxlDomainAttachDeviceLive(libxlDriverPrivate *driver, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be attached"), virDomainDeviceTypeToString(dev->type)); @@ -3596,6 +3597,7 @@ libxlDomainAttachDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent attach of device is not supported")); return -1; @@ -3965,6 +3967,7 @@ libxlDomainDetachDeviceLive(libxlDriverPrivate *driver, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be detached"), virDomainDeviceTypeToString(dev->type)); @@ -4056,6 +4059,7 @@ libxlDomainDetachDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent detach of device is not supported")); return -1; @@ -4119,6 +4123,7 @@ libxlDomainUpdateDeviceLive(virDomainObj *vm, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be updated"), virDomainDeviceTypeToString(dev->type)); @@ -4182,6 +4187,7 @@ libxlDomainUpdateDeviceConfig(virDomainDef *vmdef, virDomainDeviceDef *dev) case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent update of device is not supported")); return -1; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 80cf07d2e5..51071958e8 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -3020,6 +3020,7 @@ lxcDomainAttachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent attach of device is not supported")); break; @@ -3086,6 +3087,7 @@ lxcDomainUpdateDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent update of device is not supported")); break; @@ -3168,6 +3170,7 @@ lxcDomainDetachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("persistent detach of device is not supported")); break; @@ -3270,6 +3273,7 @@ lxcDomainAttachDeviceMknodHelper(pid_t pid G_GNUC_UNUSED, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected device type %1$d"), data->def->type); @@ -3946,6 +3950,7 @@ lxcDomainAttachDeviceLive(virLXCDriver *driver, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be attached"), virDomainDeviceTypeToString(dev->type)); @@ -4364,6 +4369,7 @@ lxcDomainDetachDeviceLive(virLXCDriver *driver, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%1$s' cannot be detached"), virDomainDeviceTypeToString(dev->type)); diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index a27c688d79..a1e9e70492 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -681,6 +681,14 @@ qemuAssignDevicePstoreAlias(virDomainPstoreDef *pstore) pstore->info.alias = g_strdup("pstore0"); } +static void +qemuAssignDeviceAcpiInitiatorAlias(virDomainAcpiInitiatorDef *acpiinitiator, + int idx) +{ + if (!acpiinitiator->info.alias) + acpiinitiator->info.alias = g_strdup_printf("gi%d", idx); +} + int qemuAssignDeviceAliases(virDomainDef *def) @@ -773,6 +781,9 @@ qemuAssignDeviceAliases(virDomainDef *def) } if (def->pstore) qemuAssignDevicePstoreAlias(def->pstore); + for (i = 0; i < def->nacpiinitiator; i++) { + qemuAssignDeviceAcpiInitiatorAlias(def->acpiinitiator[i], i); + } return 0; } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 4e4f1e87eb..cf9529dafc 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1011,6 +1011,7 @@ qemuBuildVirtioDevGetConfigDev(const virDomainDeviceDef *device, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: default: break; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index a2c7c88a7e..6c0c41c3f4 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -8820,6 +8820,7 @@ qemuDomainPrepareChardevSourceOne(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: break; } @@ -10710,6 +10711,7 @@ qemuDomainDeviceBackendChardevForeachOne(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: /* no chardev backend */ break; } diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 96a9ca9b14..5037e4a9ea 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -471,6 +471,7 @@ qemuDomainDeviceSupportZPCI(virDomainDeviceDef *device) case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: break; case VIR_DOMAIN_DEVICE_NONE: @@ -825,6 +826,9 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev, return pciFlags; } + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: + return 0; + case VIR_DOMAIN_DEVICE_MEMBALLOON: switch (dev->data.memballoon->model) { case VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO_TRANSITIONAL: diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ac72ea5cb0..36acedc1f6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6914,6 +6914,7 @@ qemuDomainAttachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent attach of device '%1$s' is not supported"), @@ -7133,6 +7134,7 @@ qemuDomainDetachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent detach of device '%1$s' is not supported"), @@ -7259,6 +7261,7 @@ qemuDomainUpdateDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent update of device '%1$s' is not supported"), diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index e9568af125..3376d4d2b5 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -3563,6 +3563,7 @@ qemuDomainAttachDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live attach of device '%1$s' is not supported"), @@ -5533,6 +5534,7 @@ qemuDomainRemoveAuditDevice(virDomainObj *vm, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: /* libvirt doesn't yet support detaching these devices */ break; @@ -5638,6 +5640,7 @@ qemuDomainRemoveDevice(virQEMUDriver *driver, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("don't know how to remove a %1$s device"), @@ -6540,6 +6543,7 @@ qemuDomainDetachDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live detach of device '%1$s' is not supported"), @@ -7531,6 +7535,7 @@ qemuDomainUpdateDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("live update of device '%1$s' is not supported"), diff --git a/src/qemu/qemu_postparse.c b/src/qemu/qemu_postparse.c index 9c2427970d..9611f46831 100644 --- a/src/qemu/qemu_postparse.c +++ b/src/qemu/qemu_postparse.c @@ -959,6 +959,7 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_RNG: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: ret = 0; break; diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index adba3e4a89..5ead231dd0 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -5793,6 +5793,7 @@ qemuValidateDomainDeviceDef(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_PSTORE: return qemuValidateDomainDeviceDefPstore(dev->data.pstore, def, qemuCaps); + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_NONE: diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 25335d9002..1a086f5f47 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -10460,6 +10460,7 @@ testDomainAttachDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live attach of device '%1$s' is not supported"), @@ -10603,6 +10604,7 @@ testDomainUpdateDevice(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent update of device '%1$s' is not supported"), @@ -10975,6 +10977,7 @@ testDomainRemoveDevice(testDriver *driver, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live detach of device '%1$s' is not supported"), @@ -11046,6 +11049,7 @@ testDomainDetachDeviceLive(testDriver *driver, case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: case VIR_DOMAIN_DEVICE_PSTORE: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live detach of device '%1$s' is not supported"), diff --git a/tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.args b/tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.args new file mode 100644 index 0000000000..1a8ac0dfc7 --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.args @@ -0,0 +1,55 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest2 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest2/.local/share \ +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest2/.cache \ +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest2/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=QEMUGuest2,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-QEMUGuest2/master-key.aes"}' \ +-machine q35,usb=off,dump-guest-core=off,acpi=off \ +-accel tcg \ +-cpu qemu64 \ +-m size=8388608k \ +-overcommit mem-lock=off \ +-smp 16,sockets=16,cores=1,threads=1 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node0","size":8589934592}' \ +-numa node,nodeid=0,cpus=0-15,memdev=ram-node0 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node1","size":0}' \ +-numa node,nodeid=1,memdev=ram-node1 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node2","size":0}' \ +-numa node,nodeid=2,memdev=ram-node2 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node3","size":0}' \ +-numa node,nodeid=3,memdev=ram-node3 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node4","size":0}' \ +-numa node,nodeid=4,memdev=ram-node4 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node5","size":0}' \ +-numa node,nodeid=5,memdev=ram-node5 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node6","size":0}' \ +-numa node,nodeid=6,memdev=ram-node6 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node7","size":0}' \ +-numa node,nodeid=7,memdev=ram-node7 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node8","size":0}' \ +-numa node,nodeid=8,memdev=ram-node8 \ +-uuid c7a5fdbd-edaf-9466-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-boot strict=on \ +-device '{"driver":"pcie-root-port","port":8,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x1"}' \ +-device '{"driver":"pcie-root-port","port":9,"chassis":2,"id":"pci.2","bus":"pcie.0","addr":"0x1.0x1"}' \ +-device '{"driver":"qemu-xhci","id":"usb","bus":"pci.1","addr":"0x0"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-global ICH9-LPC.noreboot=off \ +-watchdog-action reset \ +-device '{"driver":"vfio-pci","host":"0000:06:12.1","id":"hostdev0","bus":"pcie.0","addr":"0x2"}' \ +-device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pcie.0","addr":"0x6"}' \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.xml b/tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.xml new file mode 120000 index 0000000000..0e61738945 --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.xml @@ -0,0 +1 @@ +acpi-generic-initiator.xml \ No newline at end of file diff --git a/tests/qemuxmlconfdata/acpi-generic-initiator.xml b/tests/qemuxmlconfdata/acpi-generic-initiator.xml new file mode 100644 index 0000000000..6a5485f191 --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-generic-initiator.xml @@ -0,0 +1,94 @@ +<domain type='qemu'> + <name>QEMUGuest2</name> + <uuid>c7a5fdbd-edaf-9466-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>16</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + <numa> + <cell id='0' cpus='0-15' memory='8388608' unit='KiB'/> + <cell id='1' memory='0' unit='KiB'/> + <cell id='2' memory='0' unit='KiB'/> + <cell id='3' memory='0' unit='KiB'/> + <cell id='4' memory='0' unit='KiB'/> + <cell id='5' memory='0' unit='KiB'/> + <cell id='6' memory='0' unit='KiB'/> + <cell id='7' memory='0' unit='KiB'/> + <cell id='8' memory='0' unit='KiB'/> + </numa> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='usb' index='0' model='qemu-xhci'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <hostdev mode='subsystem' type='pci' managed='yes'> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </hostdev> + <watchdog model='itco' action='reset'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </memballoon> + <acpi-generic-initiator> + <pci-dev>hostdev0</pci-dev> + <numa-node>1</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <pci-dev>hostdev0</pci-dev> + <numa-node>2</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <pci-dev>hostdev0</pci-dev> + <numa-node>3</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <pci-dev>hostdev0</pci-dev> + <numa-node>4</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <pci-dev>hostdev0</pci-dev> + <numa-node>5</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <pci-dev>hostdev0</pci-dev> + <numa-node>6</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <pci-dev>hostdev0</pci-dev> + <numa-node>7</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <pci-dev>hostdev0</pci-dev> + <numa-node>8</numa-node> + </acpi-generic-initiator> + </devices> +</domain> diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c index 0d1804f101..fc906824e2 100644 --- a/tests/qemuxmlconftest.c +++ b/tests/qemuxmlconftest.c @@ -2796,6 +2796,7 @@ mymain(void) DO_TEST_CAPS_LATEST_PARSE_ERROR("virtio-iommu-invalid-address-type"); DO_TEST_CAPS_LATEST_PARSE_ERROR("virtio-iommu-invalid-address"); DO_TEST_CAPS_LATEST_PARSE_ERROR("virtio-iommu-dma-translation"); + DO_TEST_CAPS_LATEST("acpi-generic-initiator"); DO_TEST_CAPS_LATEST("cpu-hotplug-startup"); DO_TEST_CAPS_ARCH_LATEST_PARSE_ERROR("cpu-hotplug-granularity", "ppc64"); -- 2.50.1