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

Reply via email to