[PATCH v3 0/6] qemu: acpi-generic-initiator support

= Overview = This patch set introduces support for acpi-generic-initiator devices, supported by QEMU [1]. The acpi-generic-initiator object is required to support Multi-Instance GPU (MIG) configurations on NVIDIA GPUs [2]. MIG enables partitioning of GPU resources into multiple isolated instances, each requiring a dedicated NUMA node definition. = Implementation = This patch set implements the libvirt counterpart to the QEMU feature, enabling users to configure acpi-generic-initiator objects within libvirt domain XML. This includes: - adding XML syntax to define acpi-generic-initiator objects, - resolving the acpi-generic-initiator definitions into the proper QEMU command-line arguments, - ensuring compatibility with existing NUMA configuration. = Example = - Domain XML: ``` ... <cpu mode='host-passthrough' check='none'> <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> ... <devices> ... <hostdev mode='subsystem' type='pci' managed='no'> <source> <address domain='0x0009' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> </hostdev> <acpi-generic-initiator> <alias name="gi1"/> <pci-dev>hostdev0</pci-dev> <numa-node>1</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi2"/> <pci-dev>hostdev0</pci-dev> <numa-node>2</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi3"/> <pci-dev>hostdev0</pci-dev> <numa-node>3</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi4"/> <pci-dev>hostdev0</pci-dev> <numa-node>4</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi5"/> <pci-dev>hostdev0</pci-dev> <numa-node>5</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi6"/> <pci-dev>hostdev0</pci-dev> <numa-node>6</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi7"/> <pci-dev>hostdev0</pci-dev> <numa-node>7</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi8"/> <pci-dev>hostdev0</pci-dev> <numa-node>8</numa-node> </acpi-generic-initiator> </devices> ``` - Generated QEMU command line options: ``` ... /usr/bin/qemu-system-aarch64 \ ... -object '{"qom-type":"memory-backend-ram","id":"ram-node0","size":8589934592}' \ -numa node,nodeid=0,cpus=0-15,memdev=ram-node0 \ -numa node,nodeid=1 \ -numa node,nodeid=2 \ -numa node,nodeid=3 \ -numa node,nodeid=4 \ -numa node,nodeid=5 \ -numa node,nodeid=6 \ -numa node,nodeid=7 \ -numa node,nodeid=8 \ ... -device '{"driver":"vfio-pci","host":"0009:01:00.0","id":"hostdev0","bus":"pci.3","addr":"0x0"}' ... -object acpi-generic-initiator,id=gi1,pci-dev=hostdev0,node=1 \ -object acpi-generic-initiator,id=gi2,pci-dev=hostdev0,node=2 \ -object acpi-generic-initiator,id=gi3,pci-dev=hostdev0,node=3 \ -object acpi-generic-initiator,id=gi4,pci-dev=hostdev0,node=4 \ -object acpi-generic-initiator,id=gi5,pci-dev=hostdev0,node=5 \ -object acpi-generic-initiator,id=gi6,pci-dev=hostdev0,node=6 \ -object acpi-generic-initiator,id=gi7,pci-dev=hostdev0,node=7 \ -object acpi-generic-initiator,id=gi8,pci-dev=hostdev0,node=8 ``` = References = [1] https://lore.kernel.org/all/20231225045603.7654-2-ankita@nvidia.com/ [2] https://www.nvidia.com/en-in/technologies/multi-instance-gpu/ ChangeLog v2 -> v3: - replaced <text/> with proper types in the XML schema - avoid mixing g_free() and VIR_FREE() - use virXMLPropString() instead of looping all XML nodes - report proper errors with virReportError() - use virBufferEscapeString() to process strings passed by the user - fix broken formatting of function headers - misc coding style fixes ChangeLog v1 -> v2: - split parser and driver changes in separate patches - introduce a new qemu capability flag - introduce test in qemuxmlconftest Andrea Righi (6): schema: Introduce acpi-generic-initiator definition conf: Introduce acpi-generic-initiator device qemu: Allow to define NUMA nodes without memory or CPUs assigned qemu: capabilies: Introduce QEMU_CAPS_ACPI_GENERIC_INITIATOR qemu: support acpi-generic-initiator qemu: Add test case for acpi-generic-initiator src/ch/ch_domain.c | 1 + src/conf/domain_conf.c | 159 +++++++++++++++++++++ src/conf/domain_conf.h | 14 ++ src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 37 +++++ src/conf/numa_conf.c | 3 + src/conf/schemas/domaincommon.rng | 19 +++ src/conf/virconftypes.h | 2 + src/libxl/libxl_driver.c | 6 + src/lxc/lxc_driver.c | 6 + src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 49 ++++++- 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 + .../caps_10.0.0_x86_64+amdsev.xml | 1 + tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.1.0_riscv64.xml | 1 + tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml | 1 + .../caps_9.2.0_aarch64+hvf.xml | 1 + .../caps_9.2.0_x86_64+amdsev.xml | 1 + tests/qemucapabilitiesdata/caps_9.2.0_x86_64.xml | 1 + .../acpi-generic-initiator.x86_64-latest.args | 55 +++++++ .../acpi-generic-initiator.x86_64-latest.xml | 102 +++++++++++++ tests/qemuxmlconfdata/acpi-generic-initiator.xml | 102 +++++++++++++ tests/qemuxmlconftest.c | 1 + 32 files changed, 581 insertions(+), 7 deletions(-) create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.xml

Introduce the definition of a new acpi-generic-initiator object that can be used to link a PCI device with multiple NUMA nodes. Link: https://mail.gnu.org/archive/html/qemu-arm/2024-03/msg00358.html Signed-off-by: Andrea Righi <arighi@nvidia.com> --- src/conf/domain_conf.c | 26 ++++++++++++++++++++++++++ src/conf/domain_conf.h | 13 +++++++++++++ src/conf/schemas/domaincommon.rng | 19 +++++++++++++++++++ src/conf/virconftypes.h | 2 ++ 4 files changed, 60 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c724638180..405f0207e9 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3479,6 +3479,19 @@ virDomainHostdevDefNew(void) } +virDomainAcpiInitiatorDef * +virDomainAcpiInitiatorDefNew(void) +{ + virDomainAcpiInitiatorDef *def; + + def = g_new0(virDomainAcpiInitiatorDef, 1); + + def->info = g_new0(virDomainDeviceInfo, 1); + + return def; +} + + static virDomainTPMDef * virDomainTPMDefNew(virDomainXMLOption *xmlopt) { @@ -3539,6 +3552,19 @@ void virDomainHostdevDefFree(virDomainHostdevDef *def) g_free(def); } +void +virDomainAcpiInitiatorDefFree(virDomainAcpiInitiatorDef *def) +{ + if (!def) + return; + + g_free(def->name); + g_free(def->pciDev); + + virDomainDeviceInfoFree(def->info); + g_free(def); +} + void virDomainHubDefFree(virDomainHubDef *def) { if (!def) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8dfadbb98d..9ee7ecfc4d 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -122,6 +122,7 @@ struct _virDomainDeviceDef { virDomainAudioDef *audio; virDomainCryptoDef *crypto; virDomainPstoreDef *pstore; + virDomainAcpiInitiatorDef *acpiinitiator; } data; }; @@ -353,6 +354,13 @@ typedef enum { VIR_DOMAIN_STARTUP_POLICY_LAST } virDomainStartupPolicy; +struct _virDomainAcpiInitiatorDef { + char *name; + char *pciDev; + int numaNode; + virDomainDeviceInfo *info; /* Guest address */ +}; + /* basic device for direct passthrough */ struct _virDomainHostdevDef { /* If 'parentnet' is non-NULL it means this host dev was @@ -3262,6 +3270,9 @@ struct _virDomainDef { size_t ntpms; virDomainTPMDef **tpms; + size_t nacpiinitiator; + virDomainAcpiInitiatorDef **acpiinitiator; + /* Only 1 */ virDomainMemballoonDef *memballoon; virDomainNVRAMDef *nvram; @@ -3744,6 +3755,8 @@ 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); virDomainHostdevDef *virDomainHostdevDefNew(void); void virDomainHostdevDefFree(virDomainHostdevDef *def); void virDomainHubDefFree(virDomainHubDef *def); diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 5597d5a66b..d3ffc2865c 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -6853,6 +6853,7 @@ <ref name="shmem"/> <ref name="memorydev"/> <ref name="crypto"/> + <ref name="acpi-generic-initiator"/> </choice> </zeroOrMore> <zeroOrMore> @@ -7708,6 +7709,24 @@ </element> </define> + <define name="acpi-generic-initiator"> + <element name="acpi-generic-initiator"> + <interleave> + <element name="alias"> + <attribute name="name"> + <ref name="objectName"/> + </attribute> + </element> + <element name="pci-dev"> + <ref name="alias"/> + </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 c70437bc05..776a804cd3 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; -- 2.49.0

On 4/2/25 10:25, Andrea Righi via Devel wrote:
Introduce the definition of a new acpi-generic-initiator object that can be used to link a PCI device with multiple NUMA nodes.
Link: https://mail.gnu.org/archive/html/qemu-arm/2024-03/msg00358.html
Signed-off-by: Andrea Righi <arighi@nvidia.com> --- src/conf/domain_conf.c | 26 ++++++++++++++++++++++++++ src/conf/domain_conf.h | 13 +++++++++++++ src/conf/schemas/domaincommon.rng | 19 +++++++++++++++++++ src/conf/virconftypes.h | 2 ++ 4 files changed, 60 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c724638180..405f0207e9 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3479,6 +3479,19 @@ virDomainHostdevDefNew(void) }
+virDomainAcpiInitiatorDef * +virDomainAcpiInitiatorDefNew(void) +{ + virDomainAcpiInitiatorDef *def; + + def = g_new0(virDomainAcpiInitiatorDef, 1); + + def->info = g_new0(virDomainDeviceInfo, 1); + + return def; +} + + static virDomainTPMDef * virDomainTPMDefNew(virDomainXMLOption *xmlopt) { @@ -3539,6 +3552,19 @@ void virDomainHostdevDefFree(virDomainHostdevDef *def) g_free(def); }
+void +virDomainAcpiInitiatorDefFree(virDomainAcpiInitiatorDef *def) +{ + if (!def) + return; + + g_free(def->name); + g_free(def->pciDev); + + virDomainDeviceInfoFree(def->info); + g_free(def); +} + void virDomainHubDefFree(virDomainHubDef *def) { if (!def) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8dfadbb98d..9ee7ecfc4d 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -122,6 +122,7 @@ struct _virDomainDeviceDef { virDomainAudioDef *audio; virDomainCryptoDef *crypto; virDomainPstoreDef *pstore; + virDomainAcpiInitiatorDef *acpiinitiator; } data; };
@@ -353,6 +354,13 @@ typedef enum { VIR_DOMAIN_STARTUP_POLICY_LAST } virDomainStartupPolicy;
+struct _virDomainAcpiInitiatorDef { + char *name; + char *pciDev; + int numaNode; + virDomainDeviceInfo *info; /* Guest address */
Firstly, this is always allocated (in virDomainAcpiInitiatorDefNew()) and thus doesn't need to be a pointer. Other devices live happily with device info being a direct member of their structs. Secondly, I'm not sure what "guest address" means, as this member is never formatted onto the cmd line. And finally, the virDomainDeviceInfo struct already has 'char *alias' member which serves the same purpose as your 'char *name'. No need to reinvent it. What we could do, is to have this struct look like this: struct _virDomainAcpiInitiatorDef { char *pciDev; int numaNode; virDomainDeviceInfo info; }; And then: 1) virDomainAcpiInitiatorDefParseXML() would call virDomainDeviceInfoParseXML() unconditionally, 2) virDomainAcpiInitiatorDefFormat would call virDomainDeviceInfoFormat(), 3) virDomainAcpiInitiatorDefValidate() would check that acpiinitiator->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE, Oh, and we do not really want users to provide object IDs that appear on the cmd line (except for one specific case). Libvirt usually invents device/object aliases on its own. You'll need to addjust qemuAssignDeviceAliases() to generate aliases for this too. Obviously, RNG shcema would need to be changed to follow this new approach. Speaking of which, we generally try to avoid using dashes in element name and prefer camelCase. Though, there is some prior art: suspend-to-mem or suspend-to-disk or tb-cache.
+}; + /* basic device for direct passthrough */ struct _virDomainHostdevDef { /* If 'parentnet' is non-NULL it means this host dev was @@ -3262,6 +3270,9 @@ struct _virDomainDef { size_t ntpms; virDomainTPMDef **tpms;
+ size_t nacpiinitiator; + virDomainAcpiInitiatorDef **acpiinitiator; + /* Only 1 */ virDomainMemballoonDef *memballoon; virDomainNVRAMDef *nvram; @@ -3744,6 +3755,8 @@ 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);
Here, you probably want to declare a cleanup function too: G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainAcpiInitiatorDef, virDomainAcpiInitiatorDefFree); Michal

Introduce apci-generic-initiator device to the domain XML. Example definition: <acpi-generic-initiator> <alias name="gi1" /> <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. Signed-off-by: Andrea Righi <arighi@nvidia.com> --- src/ch/ch_domain.c | 1 + src/conf/domain_conf.c | 133 ++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 1 + src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 37 +++++++++ src/conf/schemas/domaincommon.rng | 2 +- src/libxl/libxl_driver.c | 6 ++ src/lxc/lxc_driver.c | 6 ++ 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 + 16 files changed, 207 insertions(+), 1 deletion(-) diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index a08b18c5b9..f88ce32803 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -162,6 +162,7 @@ chValidateDomainDeviceDef(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_CONTROLLER: case VIR_DOMAIN_DEVICE_CHR: case VIR_DOMAIN_DEVICE_HOSTDEV: + 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 405f0207e9..2294ad42bf 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, @@ -3727,6 +3728,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; @@ -4705,6 +4709,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: @@ -4813,6 +4819,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; @@ -5038,6 +5047,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; @@ -5098,6 +5114,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 @@ -13685,6 +13702,65 @@ virDomainHostdevDefParseXML(virDomainXMLOption *xmlopt, } +static virDomainAcpiInitiatorDef * +virDomainAcpiInitiatorDefParseXML(virDomainXMLOption *xmlopt, + xmlNodePtr node, + xmlXPathContextPtr ctxt, + unsigned int flags) +{ + virDomainAcpiInitiatorDef *def; + g_autofree char *tmp = NULL; + + VIR_XPATH_NODE_AUTORESTORE(ctxt) + + ctxt->node = node; + + def = virDomainAcpiInitiatorDefNew(); + + def->name = virXPathString("string(./alias/@name)", ctxt); + if (!def->name) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing initiator name")); + goto error; + } + + def->pciDev = virXPathString("string(./pci-dev)", ctxt); + if (!def->pciDev) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing initiator pci-dev")); + goto error; + } + + tmp = virXPathString("string(./numa-node)", ctxt); + if (tmp) { + if (virStrToLong_i((const char *)tmp, NULL, 10, &def->numaNode) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("invalid value for numa-node: '%1$s'"), tmp); + goto error; + } + } else { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing initiator numa-node")); + goto error; + } + + if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, def->info, + flags) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to parse device information")); + goto error; + } + } + + return def; + + error: + virDomainAcpiInitiatorDefFree(def); + return NULL; +} + + static virDomainRedirdevDef * virDomainRedirdevDefParseXML(virDomainXMLOption *xmlopt, xmlNodePtr node, @@ -14686,6 +14762,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; @@ -20095,6 +20177,23 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt, } VIR_FREE(nodes); + /* analysis of the acpi generic initiator */ + if ((n = virXPathNodeSet("./devices/acpi-generic-initiator", ctxt, &nodes)) < 0) + return NULL; + + 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; @@ -21024,6 +21123,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) @@ -22372,6 +22482,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, @@ -22542,6 +22658,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 @@ -28762,6 +28879,18 @@ virDomainPstoreDefFormat(virBuffer *buf, return 0; } +static void +virDomainAcpiInitiatorDefFormat(virBuffer *buf, + virDomainAcpiInitiatorDef *acpiinitiator) +{ + g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + + virBufferEscapeString(&childBuf, "<alias name=\"%s\"/>\n", acpiinitiator->name); + 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, @@ -29246,6 +29375,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"); @@ -29406,6 +29538,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 9ee7ecfc4d..5061d39662 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; diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c index bf33f29638..acdfbdc679 100644 --- a/src/conf/domain_postparse.c +++ b/src/conf/domain_postparse.c @@ -757,6 +757,7 @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_CRYPTO: + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: case VIR_DOMAIN_DEVICE_PSTORE: ret = 0; break; diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index d0d4bc0bf4..0d40092e9f 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -2375,6 +2375,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->name[0] == '\0') { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("acpi-generic-initiator must have a name")); + return -1; + } + + if (acpiinitiator->pciDev[0] == '\0') { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("acpi-generic-initiator must have a PCI device assigned")); + return -1; + } + + return 0; +} + /** * virDomainMemoryGetMappedSize: * @mem: memory device definition @@ -3293,6 +3327,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 d3ffc2865c..0352f12028 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -7718,7 +7718,7 @@ </attribute> </element> <element name="pci-dev"> - <ref name="alias"/> + <ref name="aliasName"/> </element> <element name="numa-node"> <ref name="unsignedInt"/> diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 0fb256e5c0..bc3f25b3cb 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_command.c b/src/qemu/qemu_command.c index 86eb52f197..f5e6e25956 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -985,6 +985,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 e45eef4787..da61dcc37a 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -8768,6 +8768,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; } @@ -10700,6 +10701,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 e89cdee487..573bbc282c 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: @@ -819,6 +820,9 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev, return pciFlags; } + case VIR_DOMAIN_DEVICE_ACPI_INITIATOR: + return pciFlags; + 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 6ce949dd07..8a5cb6c5fe 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6899,6 +6899,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"), @@ -7118,6 +7119,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"), @@ -7244,6 +7246,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 9977662a2c..f7fa65084d 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -3538,6 +3538,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"), @@ -5508,6 +5509,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; @@ -5613,6 +5615,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"), @@ -6508,6 +6511,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"), @@ -7499,6 +7503,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 ed4af9ca8e..a6f610265e 100644 --- a/src/qemu/qemu_postparse.c +++ b/src/qemu/qemu_postparse.c @@ -906,6 +906,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 b2c3c9e2f6..bfd3115a63 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -5605,6 +5605,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 6f18b2b2c8..5c706a1035 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -10459,6 +10459,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"), @@ -10602,6 +10603,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"), @@ -10973,6 +10975,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"), @@ -11044,6 +11047,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"), -- 2.49.0

On 4/2/25 10:25, Andrea Righi via Devel wrote:
Introduce apci-generic-initiator device to the domain XML.
Example definition:
<acpi-generic-initiator> <alias name="gi1" /> <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.
Signed-off-by: Andrea Righi <arighi@nvidia.com> --- src/ch/ch_domain.c | 1 + src/conf/domain_conf.c | 133 ++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 1 + src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 37 +++++++++ src/conf/schemas/domaincommon.rng | 2 +- src/libxl/libxl_driver.c | 6 ++ src/lxc/lxc_driver.c | 6 ++ 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 + 16 files changed, 207 insertions(+), 1 deletion(-)
There's another switch() in hypervDomainAttachDeviceFlags() in src/hyperv/hyperv_driver.c that wants this new enum addition covered too.
diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index a08b18c5b9..f88ce32803 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -162,6 +162,7 @@ chValidateDomainDeviceDef(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_CONTROLLER: case VIR_DOMAIN_DEVICE_CHR: case VIR_DOMAIN_DEVICE_HOSTDEV: + 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 405f0207e9..2294ad42bf 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, @@ -3727,6 +3728,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; @@ -4705,6 +4709,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: @@ -4813,6 +4819,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; @@ -5038,6 +5047,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; @@ -5098,6 +5114,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 @@ -13685,6 +13702,65 @@ virDomainHostdevDefParseXML(virDomainXMLOption *xmlopt, }
+static virDomainAcpiInitiatorDef * +virDomainAcpiInitiatorDefParseXML(virDomainXMLOption *xmlopt, + xmlNodePtr node, + xmlXPathContextPtr ctxt, + unsigned int flags) +{ + virDomainAcpiInitiatorDef *def;
This could be: g_autoptr(virDomainAcpiInitiatorDef) def = NULL;
+ g_autofree char *tmp = NULL; + + VIR_XPATH_NODE_AUTORESTORE(ctxt) + + ctxt->node = node; + + def = virDomainAcpiInitiatorDefNew(); + + def->name = virXPathString("string(./alias/@name)", ctxt); + if (!def->name) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing initiator name")); + goto error;
and then all these 'goto error' could be plain 'return NULL'.
+ } + + def->pciDev = virXPathString("string(./pci-dev)", ctxt); + if (!def->pciDev) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing initiator pci-dev")); + goto error; + } + + tmp = virXPathString("string(./numa-node)", ctxt); + if (tmp) { + if (virStrToLong_i((const char *)tmp, NULL, 10, &def->numaNode) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("invalid value for numa-node: '%1$s'"), tmp); + goto error; + } + } else { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing initiator numa-node")); + goto error; + } + + if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, def->info, + flags) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to parse device information")); + goto error; + } + } + + return def; + + error: + virDomainAcpiInitiatorDefFree(def); + return NULL; +} + + static virDomainRedirdevDef * virDomainRedirdevDefParseXML(virDomainXMLOption *xmlopt, xmlNodePtr node, @@ -14686,6 +14762,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; @@ -20095,6 +20177,23 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt, } VIR_FREE(nodes);
+ /* analysis of the acpi generic initiator */ + if ((n = virXPathNodeSet("./devices/acpi-generic-initiator", ctxt, &nodes)) < 0) + return NULL; +
Missing: if (n)
+ def->acpiinitiator = g_new0(virDomainAcpiInitiatorDef *, n);
We probably don't need to allocate any memory if n==0. Not even a dummy pointer.
+ + 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); +
Michal

Allow to define NUMA nodes without memory or CPUs assigned to properly support the new acpi-generic-initiator device. This is required because the NUMA nodes passed to the acpi-generic-initiator object must be independent and not be shared with other resources, such as CPU or memory. Signed-off-by: Andrea Righi <arighi@nvidia.com> --- src/conf/numa_conf.c | 3 +++ src/qemu/qemu_command.c | 20 +++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/conf/numa_conf.c b/src/conf/numa_conf.c index 00f0c605ee..5b50f3e3f5 100644 --- a/src/conf/numa_conf.c +++ b/src/conf/numa_conf.c @@ -1492,6 +1492,9 @@ virDomainNumaFillCPUsInNode(virDomainNuma *numa, if (node >= virDomainNumaGetNodeCount(numa)) return -1; + if (virDomainNumaGetNodeMemorySize(numa, node) == 0) + return 0; + virBitmapSetAll(maxCPUsBitmap); for (i = 0; i < numa->nmem_nodes; i++) { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index f5e6e25956..9f5fa98de1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7651,7 +7651,10 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, } } - if (masterInitiator < 0) { + /* HMAT requires a master initiator, so when it's enabled, ensure that + * at least one NUMA node has CPUs assigned. + */ + if (hmat && masterInitiator < 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("At least one NUMA node has to have CPUs")); goto cleanup; @@ -7659,8 +7662,9 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, for (i = 0; i < ncells; i++) { ssize_t initiator = virDomainNumaGetNodeInitiator(def->numa, i); + unsigned long long memSize = virDomainNumaGetNodeMemorySize(def->numa, i); - if (needBackend) { + if (needBackend && memSize > 0) { g_autoptr(virJSONValue) tcProps = NULL; if (qemuBuildThreadContextProps(&tcProps, &nodeBackends[i], @@ -7688,11 +7692,13 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, virBufferAsprintf(&buf, ",initiator=%zd", initiator); } - if (needBackend) - virBufferAsprintf(&buf, ",memdev=ram-node%zu", i); - else - virBufferAsprintf(&buf, ",mem=%llu", - virDomainNumaGetNodeMemorySize(def->numa, i) / 1024); + if (memSize > 0) { + if (needBackend) { + virBufferAsprintf(&buf, ",memdev=ram-node%zu", i); + } else { + virBufferAsprintf(&buf, ",mem=%llu", memSize / 1024); + } + } virCommandAddArgBuffer(cmd, &buf); } -- 2.49.0

This capability tracks whether QEMU supports the acpi-generic-initiator object type. This object has been introduced in QEMU with the commit: b64b7ed8bb ("qom: new object to associate device to NUMA node"). Signed-off-by: Andrea Righi <arighi@nvidia.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_10.0.0_x86_64+amdsev.xml | 1 + tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.1.0_riscv64.xml | 1 + tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.2.0_aarch64+hvf.xml | 1 + tests/qemucapabilitiesdata/caps_9.2.0_x86_64+amdsev.xml | 1 + tests/qemucapabilitiesdata/caps_9.2.0_x86_64.xml | 1 + 10 files changed, 11 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 67350f2300..66216d66d5 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -732,6 +732,7 @@ VIR_ENUM_IMPL(virQEMUCaps, /* 475 */ "virtio-scsi.iothread-mapping", /* QEMU_CAPS_VIRTIO_SCSI_IOTHREAD_MAPPING */ + "acpi-generic-initiator", /* QEMU_CAPS_ACPI_GENERIC_INITIATOR */ ); @@ -1421,6 +1422,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "sev-snp-guest", QEMU_CAPS_SEV_SNP_GUEST }, { "acpi-erst", QEMU_CAPS_DEVICE_ACPI_ERST }, { "virtio-mem-ccw", QEMU_CAPS_DEVICE_VIRTIO_MEM_CCW }, + { "acpi-generic-initiator", QEMU_CAPS_ACPI_GENERIC_INITIATOR }, }; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 2c2433580c..b09a92bd8e 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -713,6 +713,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 475 */ QEMU_CAPS_VIRTIO_SCSI_IOTHREAD_MAPPING, /* virtio-scsi supports per-virtqueue iothread mapping */ + QEMU_CAPS_ACPI_GENERIC_INITIATOR, /* -object acpi-generic-initiator ccommand supported */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_10.0.0_x86_64+amdsev.xml b/tests/qemucapabilitiesdata/caps_10.0.0_x86_64+amdsev.xml index ad7bb7ebc8..08abe4a0e8 100644 --- a/tests/qemucapabilitiesdata/caps_10.0.0_x86_64+amdsev.xml +++ b/tests/qemucapabilitiesdata/caps_10.0.0_x86_64+amdsev.xml @@ -207,6 +207,7 @@ <flag name='migrate-incoming.exit-on-error'/> <flag name='blockdev-set-active'/> <flag name='shim'/> + <flag name='acpi-generic-initiator'/> <version>9002050</version> <microcodeVersion>43100285</microcodeVersion> <package>v9.2.0-2369-g98c7362b1e</package> diff --git a/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml index 529ec7fbe2..dec1c6a289 100644 --- a/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml @@ -207,6 +207,7 @@ <flag name='blockdev-set-active'/> <flag name='shim'/> <flag name='virtio-scsi.iothread-mapping'/> + <flag name='acpi-generic-initiator'/> <version>9002050</version> <microcodeVersion>43100285</microcodeVersion> <package>v9.2.0-2799-g0462a32b4f</package> diff --git a/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml index b273193d35..1bf3adf89b 100644 --- a/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml @@ -203,6 +203,7 @@ <flag name='intel-iommu.dma-translation'/> <flag name='machine-i8042-opt'/> <flag name='snapshot-internal-qmp'/> + <flag name='acpi-generic-initiator'/> <version>9000000</version> <microcodeVersion>43100245</microcodeVersion> <package>v9.0.0</package> diff --git a/tests/qemucapabilitiesdata/caps_9.1.0_riscv64.xml b/tests/qemucapabilitiesdata/caps_9.1.0_riscv64.xml index 60eeb04fe7..163f9e3574 100644 --- a/tests/qemucapabilitiesdata/caps_9.1.0_riscv64.xml +++ b/tests/qemucapabilitiesdata/caps_9.1.0_riscv64.xml @@ -163,6 +163,7 @@ <flag name='snapshot-internal-qmp'/> <flag name='migrate-incoming.exit-on-error'/> <flag name='machine.virt.aia'/> + <flag name='acpi-generic-initiator'/> <version>9001000</version> <microcodeVersion>0</microcodeVersion> <package>v9.1.0</package> diff --git a/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml index 6b995c2f26..4d301a764d 100644 --- a/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml @@ -202,6 +202,7 @@ <flag name='machine-i8042-opt'/> <flag name='snapshot-internal-qmp'/> <flag name='migrate-incoming.exit-on-error'/> + <flag name='acpi-generic-initiator'/> <version>9001000</version> <microcodeVersion>43100246</microcodeVersion> <package>v9.1.0</package> diff --git a/tests/qemucapabilitiesdata/caps_9.2.0_aarch64+hvf.xml b/tests/qemucapabilitiesdata/caps_9.2.0_aarch64+hvf.xml index a7bfc10168..892c8b31f2 100644 --- a/tests/qemucapabilitiesdata/caps_9.2.0_aarch64+hvf.xml +++ b/tests/qemucapabilitiesdata/caps_9.2.0_aarch64+hvf.xml @@ -136,6 +136,7 @@ <flag name='chardev-reconnect-miliseconds'/> <flag name='netdev-stream-reconnect-miliseconds'/> <flag name='migrate-incoming.exit-on-error'/> + <flag name='acpi-generic-initiator'/> <version>9002002</version> <microcodeVersion>61700247</microcodeVersion> <package></package> diff --git a/tests/qemucapabilitiesdata/caps_9.2.0_x86_64+amdsev.xml b/tests/qemucapabilitiesdata/caps_9.2.0_x86_64+amdsev.xml index 2181b9432a..85b36c4315 100644 --- a/tests/qemucapabilitiesdata/caps_9.2.0_x86_64+amdsev.xml +++ b/tests/qemucapabilitiesdata/caps_9.2.0_x86_64+amdsev.xml @@ -206,6 +206,7 @@ <flag name='chardev-reconnect-miliseconds'/> <flag name='netdev-stream-reconnect-miliseconds'/> <flag name='migrate-incoming.exit-on-error'/> + <flag name='acpi-generic-initiator'/> <version>9002000</version> <microcodeVersion>43100247</microcodeVersion> <package>v9.2.0</package> diff --git a/tests/qemucapabilitiesdata/caps_9.2.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_9.2.0_x86_64.xml index 924f56d010..d5cc6e3bea 100644 --- a/tests/qemucapabilitiesdata/caps_9.2.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_9.2.0_x86_64.xml @@ -204,6 +204,7 @@ <flag name='chardev-reconnect-miliseconds'/> <flag name='netdev-stream-reconnect-miliseconds'/> <flag name='migrate-incoming.exit-on-error'/> + <flag name='acpi-generic-initiator'/> <version>9002000</version> <microcodeVersion>43100247</microcodeVersion> <package>v9.2.0</package> -- 2.49.0

Add support to the qemu driver to generate the proper command line for the acpi-generic-initiator definitions. Signed-off-by: Andrea Righi <arighi@nvidia.com> --- src/qemu/qemu_command.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 9f5fa98de1..b50e21465e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -10371,6 +10371,29 @@ qemuBuildPstoreCommandLine(virCommand *cmd, return 0; } +static int +qemuBuildAcpiInitiatorCommandLine(virCommand *cmd, + const virDomainAcpiInitiatorDef *acpiinitiator, + virQEMUCaps *qemuCaps) +{ + g_autoptr(virJSONValue) props = NULL; + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_ACPI_GENERIC_INITIATOR)) + return -1; + + if (virJSONValueObjectAdd(&props, + "s:qom-type", "acpi-generic-initiator", + "s:id", acpiinitiator->name, + "s:pci-dev", acpiinitiator->pciDev, + "i:node", acpiinitiator->numaNode, + NULL) < 0) + return -1; + + if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0) + return -1; + + return 0; +} static int qemuBuildAsyncTeardownCommandLine(virCommand *cmd, @@ -10732,6 +10755,11 @@ qemuBuildCommandLine(virDomainObj *vm, qemuBuildPstoreCommandLine(cmd, def, def->pstore, qemuCaps) < 0) return NULL; + for (i = 0; i < def->nacpiinitiator; i++) { + if (qemuBuildAcpiInitiatorCommandLine(cmd, def->acpiinitiator[i], qemuCaps) < 0) + return NULL; + } + if (qemuBuildAsyncTeardownCommandLine(cmd, def, qemuCaps) < 0) return NULL; -- 2.49.0

Implement a sub-test in qemuxmlconftest that uses acpi-generic-initiator to link a PCI device with multiple NUMA node definitions (without any memory/cpu resource assigned). Then translate the VM definition to the corresponding qemu command line that associates the hostdev with the NUMA nodes. Signed-off-by: Andrea Righi <arighi@nvidia.com> --- .../acpi-generic-initiator.x86_64-latest.args | 55 ++++++++++ .../acpi-generic-initiator.x86_64-latest.xml | 102 ++++++++++++++++++ .../acpi-generic-initiator.xml | 102 ++++++++++++++++++ tests/qemuxmlconftest.c | 1 + 4 files changed, 260 insertions(+) create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.xml 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..ae2de56975 --- /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 \ +-numa node,nodeid=1 \ +-numa node,nodeid=2 \ +-numa node,nodeid=3 \ +-numa node,nodeid=4 \ +-numa node,nodeid=5 \ +-numa node,nodeid=6 \ +-numa node,nodeid=7 \ +-numa node,nodeid=8 \ +-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 \ +-object '{"qom-type":"acpi-generic-initiator","id":"gi1","pci-dev":"hostdev0","node":1}' \ +-object '{"qom-type":"acpi-generic-initiator","id":"gi2","pci-dev":"hostdev0","node":2}' \ +-object '{"qom-type":"acpi-generic-initiator","id":"gi3","pci-dev":"hostdev0","node":3}' \ +-object '{"qom-type":"acpi-generic-initiator","id":"gi4","pci-dev":"hostdev0","node":4}' \ +-object '{"qom-type":"acpi-generic-initiator","id":"gi5","pci-dev":"hostdev0","node":5}' \ +-object '{"qom-type":"acpi-generic-initiator","id":"gi6","pci-dev":"hostdev0","node":6}' \ +-object '{"qom-type":"acpi-generic-initiator","id":"gi7","pci-dev":"hostdev0","node":7}' \ +-object '{"qom-type":"acpi-generic-initiator","id":"gi8","pci-dev":"hostdev0","node":8}' \ +-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 100644 index 0000000000..bf2df513a4 --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.xml @@ -0,0 +1,102 @@ +<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> + <alias name="gi1"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>1</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi2"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>2</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi3"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>3</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi4"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>4</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi5"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>5</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi6"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>6</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi7"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>7</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi8"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>8</numa-node> + </acpi-generic-initiator> + </devices> +</domain> diff --git a/tests/qemuxmlconfdata/acpi-generic-initiator.xml b/tests/qemuxmlconfdata/acpi-generic-initiator.xml new file mode 100644 index 0000000000..bf2df513a4 --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-generic-initiator.xml @@ -0,0 +1,102 @@ +<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> + <alias name="gi1"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>1</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi2"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>2</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi3"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>3</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi4"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>4</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi5"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>5</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi6"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>6</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi7"/> + <pci-dev>hostdev0</pci-dev> + <numa-node>7</numa-node> + </acpi-generic-initiator> + <acpi-generic-initiator> + <alias name="gi8"/> + <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 be2fba9e4d..96af7a5bac 100644 --- a/tests/qemuxmlconftest.c +++ b/tests/qemuxmlconftest.c @@ -2765,6 +2765,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.49.0

On 4/2/25 10:25, Andrea Righi via Devel wrote:
= Overview =
This patch set introduces support for acpi-generic-initiator devices, supported by QEMU [1].
The acpi-generic-initiator object is required to support Multi-Instance GPU (MIG) configurations on NVIDIA GPUs [2]. MIG enables partitioning of GPU resources into multiple isolated instances, each requiring a dedicated NUMA node definition.
= Implementation =
This patch set implements the libvirt counterpart to the QEMU feature, enabling users to configure acpi-generic-initiator objects within libvirt domain XML.
This includes: - adding XML syntax to define acpi-generic-initiator objects, - resolving the acpi-generic-initiator definitions into the proper QEMU command-line arguments, - ensuring compatibility with existing NUMA configuration.
= Example =
- Domain XML: ``` ... <cpu mode='host-passthrough' check='none'> <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> ... <devices> ... <hostdev mode='subsystem' type='pci' managed='no'> <source> <address domain='0x0009' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> </hostdev> <acpi-generic-initiator> <alias name="gi1"/> <pci-dev>hostdev0</pci-dev> <numa-node>1</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi2"/> <pci-dev>hostdev0</pci-dev> <numa-node>2</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi3"/> <pci-dev>hostdev0</pci-dev> <numa-node>3</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi4"/> <pci-dev>hostdev0</pci-dev> <numa-node>4</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi5"/> <pci-dev>hostdev0</pci-dev> <numa-node>5</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi6"/> <pci-dev>hostdev0</pci-dev> <numa-node>6</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi7"/> <pci-dev>hostdev0</pci-dev> <numa-node>7</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi8"/> <pci-dev>hostdev0</pci-dev> <numa-node>8</numa-node> </acpi-generic-initiator> </devices> ```
- Generated QEMU command line options: ``` ... /usr/bin/qemu-system-aarch64 \ ... -object '{"qom-type":"memory-backend-ram","id":"ram-node0","size":8589934592}' \ -numa node,nodeid=0,cpus=0-15,memdev=ram-node0 \ -numa node,nodeid=1 \ -numa node,nodeid=2 \ -numa node,nodeid=3 \ -numa node,nodeid=4 \ -numa node,nodeid=5 \ -numa node,nodeid=6 \ -numa node,nodeid=7 \ -numa node,nodeid=8 \ ... -device '{"driver":"vfio-pci","host":"0009:01:00.0","id":"hostdev0","bus":"pci.3","addr":"0x0"}' ... -object acpi-generic-initiator,id=gi1,pci-dev=hostdev0,node=1 \ -object acpi-generic-initiator,id=gi2,pci-dev=hostdev0,node=2 \ -object acpi-generic-initiator,id=gi3,pci-dev=hostdev0,node=3 \ -object acpi-generic-initiator,id=gi4,pci-dev=hostdev0,node=4 \ -object acpi-generic-initiator,id=gi5,pci-dev=hostdev0,node=5 \ -object acpi-generic-initiator,id=gi6,pci-dev=hostdev0,node=6 \ -object acpi-generic-initiator,id=gi7,pci-dev=hostdev0,node=7 \ -object acpi-generic-initiator,id=gi8,pci-dev=hostdev0,node=8 ```
= References =
[1] https://lore.kernel.org/all/20231225045603.7654-2-ankita@nvidia.com/ [2] https://www.nvidia.com/en-in/technologies/multi-instance-gpu/
ChangeLog v2 -> v3: - replaced <text/> with proper types in the XML schema - avoid mixing g_free() and VIR_FREE() - use virXMLPropString() instead of looping all XML nodes - report proper errors with virReportError() - use virBufferEscapeString() to process strings passed by the user - fix broken formatting of function headers - misc coding style fixes
ChangeLog v1 -> v2: - split parser and driver changes in separate patches - introduce a new qemu capability flag - introduce test in qemuxmlconftest
Andrea Righi (6): schema: Introduce acpi-generic-initiator definition conf: Introduce acpi-generic-initiator device qemu: Allow to define NUMA nodes without memory or CPUs assigned qemu: capabilies: Introduce QEMU_CAPS_ACPI_GENERIC_INITIATOR qemu: support acpi-generic-initiator qemu: Add test case for acpi-generic-initiator
src/ch/ch_domain.c | 1 + src/conf/domain_conf.c | 159 +++++++++++++++++++++ src/conf/domain_conf.h | 14 ++ src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 37 +++++ src/conf/numa_conf.c | 3 + src/conf/schemas/domaincommon.rng | 19 +++ src/conf/virconftypes.h | 2 + src/libxl/libxl_driver.c | 6 + src/lxc/lxc_driver.c | 6 + src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 49 ++++++- 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 + .../caps_10.0.0_x86_64+amdsev.xml | 1 + tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.1.0_riscv64.xml | 1 + tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml | 1 + .../caps_9.2.0_aarch64+hvf.xml | 1 + .../caps_9.2.0_x86_64+amdsev.xml | 1 + tests/qemucapabilitiesdata/caps_9.2.0_x86_64.xml | 1 + .../acpi-generic-initiator.x86_64-latest.args | 55 +++++++ .../acpi-generic-initiator.x86_64-latest.xml | 102 +++++++++++++ tests/qemuxmlconfdata/acpi-generic-initiator.xml | 102 +++++++++++++ tests/qemuxmlconftest.c | 1 + 32 files changed, 581 insertions(+), 7 deletions(-) create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.xml
Sorry for late review. Normally, to make it up to you I'd fix all the small nits and merge, but this is introducing new feature and yet not updating documentation and that's a show stopper. Also, don't forget to add a NEWS.rst entry ;-) Michal

Hi Michal, On Fri, May 09, 2025 at 03:30:21PM +0200, Michal Prívozník wrote:
On 4/2/25 10:25, Andrea Righi via Devel wrote:
= Overview =
This patch set introduces support for acpi-generic-initiator devices, supported by QEMU [1].
The acpi-generic-initiator object is required to support Multi-Instance GPU (MIG) configurations on NVIDIA GPUs [2]. MIG enables partitioning of GPU resources into multiple isolated instances, each requiring a dedicated NUMA node definition.
= Implementation =
This patch set implements the libvirt counterpart to the QEMU feature, enabling users to configure acpi-generic-initiator objects within libvirt domain XML.
This includes: - adding XML syntax to define acpi-generic-initiator objects, - resolving the acpi-generic-initiator definitions into the proper QEMU command-line arguments, - ensuring compatibility with existing NUMA configuration.
= Example =
- Domain XML: ``` ... <cpu mode='host-passthrough' check='none'> <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> ... <devices> ... <hostdev mode='subsystem' type='pci' managed='no'> <source> <address domain='0x0009' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> </hostdev> <acpi-generic-initiator> <alias name="gi1"/> <pci-dev>hostdev0</pci-dev> <numa-node>1</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi2"/> <pci-dev>hostdev0</pci-dev> <numa-node>2</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi3"/> <pci-dev>hostdev0</pci-dev> <numa-node>3</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi4"/> <pci-dev>hostdev0</pci-dev> <numa-node>4</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi5"/> <pci-dev>hostdev0</pci-dev> <numa-node>5</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi6"/> <pci-dev>hostdev0</pci-dev> <numa-node>6</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi7"/> <pci-dev>hostdev0</pci-dev> <numa-node>7</numa-node> </acpi-generic-initiator> <acpi-generic-initiator> <alias name="gi8"/> <pci-dev>hostdev0</pci-dev> <numa-node>8</numa-node> </acpi-generic-initiator> </devices> ```
- Generated QEMU command line options: ``` ... /usr/bin/qemu-system-aarch64 \ ... -object '{"qom-type":"memory-backend-ram","id":"ram-node0","size":8589934592}' \ -numa node,nodeid=0,cpus=0-15,memdev=ram-node0 \ -numa node,nodeid=1 \ -numa node,nodeid=2 \ -numa node,nodeid=3 \ -numa node,nodeid=4 \ -numa node,nodeid=5 \ -numa node,nodeid=6 \ -numa node,nodeid=7 \ -numa node,nodeid=8 \ ... -device '{"driver":"vfio-pci","host":"0009:01:00.0","id":"hostdev0","bus":"pci.3","addr":"0x0"}' ... -object acpi-generic-initiator,id=gi1,pci-dev=hostdev0,node=1 \ -object acpi-generic-initiator,id=gi2,pci-dev=hostdev0,node=2 \ -object acpi-generic-initiator,id=gi3,pci-dev=hostdev0,node=3 \ -object acpi-generic-initiator,id=gi4,pci-dev=hostdev0,node=4 \ -object acpi-generic-initiator,id=gi5,pci-dev=hostdev0,node=5 \ -object acpi-generic-initiator,id=gi6,pci-dev=hostdev0,node=6 \ -object acpi-generic-initiator,id=gi7,pci-dev=hostdev0,node=7 \ -object acpi-generic-initiator,id=gi8,pci-dev=hostdev0,node=8 ```
= References =
[1] https://lore.kernel.org/all/20231225045603.7654-2-ankita@nvidia.com/ [2] https://www.nvidia.com/en-in/technologies/multi-instance-gpu/
ChangeLog v2 -> v3: - replaced <text/> with proper types in the XML schema - avoid mixing g_free() and VIR_FREE() - use virXMLPropString() instead of looping all XML nodes - report proper errors with virReportError() - use virBufferEscapeString() to process strings passed by the user - fix broken formatting of function headers - misc coding style fixes
ChangeLog v1 -> v2: - split parser and driver changes in separate patches - introduce a new qemu capability flag - introduce test in qemuxmlconftest
Andrea Righi (6): schema: Introduce acpi-generic-initiator definition conf: Introduce acpi-generic-initiator device qemu: Allow to define NUMA nodes without memory or CPUs assigned qemu: capabilies: Introduce QEMU_CAPS_ACPI_GENERIC_INITIATOR qemu: support acpi-generic-initiator qemu: Add test case for acpi-generic-initiator
src/ch/ch_domain.c | 1 + src/conf/domain_conf.c | 159 +++++++++++++++++++++ src/conf/domain_conf.h | 14 ++ src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 37 +++++ src/conf/numa_conf.c | 3 + src/conf/schemas/domaincommon.rng | 19 +++ src/conf/virconftypes.h | 2 + src/libxl/libxl_driver.c | 6 + src/lxc/lxc_driver.c | 6 + src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 49 ++++++- 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 + .../caps_10.0.0_x86_64+amdsev.xml | 1 + tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_9.1.0_riscv64.xml | 1 + tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml | 1 + .../caps_9.2.0_aarch64+hvf.xml | 1 + .../caps_9.2.0_x86_64+amdsev.xml | 1 + tests/qemucapabilitiesdata/caps_9.2.0_x86_64.xml | 1 + .../acpi-generic-initiator.x86_64-latest.args | 55 +++++++ .../acpi-generic-initiator.x86_64-latest.xml | 102 +++++++++++++ tests/qemuxmlconfdata/acpi-generic-initiator.xml | 102 +++++++++++++ tests/qemuxmlconftest.c | 1 + 32 files changed, 581 insertions(+), 7 deletions(-) create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/acpi-generic-initiator.xml
Sorry for late review. Normally, to make it up to you I'd fix all the small nits and merge, but this is introducing new feature and yet not updating documentation and that's a show stopper. Also, don't forget to add a NEWS.rst entry ;-)
Thanks for taking a look at this. Do you think docs/formatdomain.rst is the appropriate place to document the new acpi-generic-initiator? I'll also make sure to add a proper entry in NEWS.rst. -Andrea

On 5/15/25 16:35, Andrea Righi wrote:
Hi Michal,
Sorry for late review. Normally, to make it up to you I'd fix all the small nits and merge, but this is introducing new feature and yet not updating documentation and that's a show stopper. Also, don't forget to add a NEWS.rst entry ;-)
Thanks for taking a look at this. Do you think docs/formatdomain.rst is the appropriate place to document the new acpi-generic-initiator?
Yes, that's where we document our XML schema.
I'll also make sure to add a proper entry in NEWS.rst.
Thanks!
-Andrea
Michal
participants (3)
-
Andrea Righi
-
arighi@nvidia.com
-
Michal Prívozník