diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 7b702cfc6b..39f3e38351 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -6453,6 +6453,37 @@ qemuDomainPstoreDefPostParse(virDomainPstoreDef *pstore,
}
+static int
+qemuDomainIOMMUDefPostParse(virDomainIOMMUDef *iommu,
+ const virDomainDef *def,
+ virQEMUCaps *qemuCaps,
+ unsigned int parseFlags)
+{
+ /* In case domain has huge number of vCPUS and Extended Interrupt Mode
+ * (EIM) is not explicitly turned off, let's enable it. If we didn't then
+ * guest will have troubles with interrupts. */
+ if (parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE &&
+ ARCH_IS_X86(def->os.arch) &&
+ virDomainDefGetVcpusMax(def) > QEMU_MAX_VCPUS_WITHOUT_EIM &&
+ qemuDomainIsQ35(def) &&
+ iommu && iommu->model == VIR_DOMAIN_IOMMU_MODEL_INTEL) {
+
+ /* eim requires intremap. */
+ if (iommu->intremap == VIR_TRISTATE_SWITCH_ABSENT &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_INTREMAP)) {
+ iommu->intremap = VIR_TRISTATE_SWITCH_ON;
+ }
+
+ if (iommu->eim == VIR_TRISTATE_SWITCH_ABSENT &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_EIM)) {
+ iommu->eim = VIR_TRISTATE_SWITCH_ON;
+ }
+ }
+
+ return 0;
+}
+
+
static int
qemuDomainDeviceDefPostParse(virDomainDeviceDef *dev,
const virDomainDef *def,
@@ -6518,6 +6549,11 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDef *dev,
ret = qemuDomainPstoreDefPostParse(dev->data.pstore, def, driver);
break;
+ case VIR_DOMAIN_DEVICE_IOMMU:
+ ret = qemuDomainIOMMUDefPostParse(dev->data.iommu, def,
+ qemuCaps, parseFlags);
+ break;
+
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_FS:
case VIR_DOMAIN_DEVICE_INPUT:
@@ -6530,7 +6566,6 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDef *dev,
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_RNG:
- case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_AUDIO:
case VIR_DOMAIN_DEVICE_CRYPTO:
ret = 0;
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index fa23c5f973..aaa056379e 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -31,7 +31,6 @@
#include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
-#define QEMU_MAX_VCPUS_WITHOUT_EIM 255
VIR_LOG_INIT("qemu.qemu_validate");
diff --git a/src/qemu/qemu_validate.h b/src/qemu/qemu_validate.h
index e06a43b8e3..9315be73f5 100644
--- a/src/qemu/qemu_validate.h
+++ b/src/qemu/qemu_validate.h
@@ -22,6 +22,8 @@
#include "qemu_capabilities.h"
+#define QEMU_MAX_VCPUS_WITHOUT_EIM 255
+
int
qemuValidateDomainDef(const virDomainDef *def,
void *opaque,
diff --git a/tests/qemuxmlconfdata/intel-iommu-eim-autoadd.x86_64-latest.abi-update.args b/tests/qemuxmlconfdata/intel-iommu-eim-autoadd.x86_64-latest.abi-update.args
new file mode 100644
index 0000000000..07fa1191b7
--- /dev/null
+++ b/tests/qemuxmlconfdata/intel-iommu-eim-autoadd.x86_64-latest.abi-update.args
@@ -0,0 +1,34 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1 \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.local/share \
+XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.cache \
+XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
+/usr/bin/qemu-system-x86_64 \
+-name guest=QEMUGuest1,debug-threads=on \
+-S \
+-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-QEMUGuest1/master-key.aes"}' \
+-machine q35,usb=off,kernel_irqchip=split,dump-guest-core=off,memory-backend=pc.ram,acpi=off \
+-accel kvm \
+-cpu qemu64 \
+-m size=219136k \
+-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}' \
+-overcommit mem-lock=off \
+-smp 288,sockets=288,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-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":"intel-iommu","id":"iommu0","intremap":"on","eim":"on"}' \
+-audiodev '{"id":"audio1","driver":"none"}' \
+-global ICH9-LPC.noreboot=off \
+-watchdog-action reset \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxmlconfdata/intel-iommu-eim-autoadd.x86_64-latest.abi-update.xml b/tests/qemuxmlconfdata/intel-iommu-eim-autoadd.x86_64-latest.abi-update.xml
new file mode 100644
index 0000000000..1caa0ceb60
--- /dev/null
+++ b/tests/qemuxmlconfdata/intel-iommu-eim-autoadd.x86_64-latest.abi-update.xml
@@ -0,0 +1,37 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219100
+ 219100
+ 288
+
+ hvm
+
+
+
+
+
+
+ qemu64
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-x86_64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxmlconfdata/intel-iommu-eim-autoadd.xml b/tests/qemuxmlconfdata/intel-iommu-eim-autoadd.xml
new file mode 100644
index 0000000000..7c294fe2f9
--- /dev/null
+++ b/tests/qemuxmlconfdata/intel-iommu-eim-autoadd.xml
@@ -0,0 +1,35 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219100
+ 219100
+ 288
+
+ hvm
+
+
+
+
+
+
+ qemu64
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-x86_64
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c
index 9bcd937447..2b94d5dc63 100644
--- a/tests/qemuxmlconftest.c
+++ b/tests/qemuxmlconftest.c
@@ -2764,6 +2764,7 @@ mymain(void)
DO_TEST_CAPS_LATEST("intel-iommu-aw-bits");
DO_TEST_CAPS_LATEST("intel-iommu-dma-translation");
DO_TEST_CAPS_LATEST_PARSE_ERROR("intel-iommu-wrong-machine");
+ DO_TEST_CAPS_LATEST_ABI_UPDATE("intel-iommu-eim-autoadd");
DO_TEST_CAPS_ARCH_LATEST("iommu-smmuv3", "aarch64");
DO_TEST_CAPS_LATEST("virtio-iommu-x86_64");
DO_TEST_CAPS_VER_PARSE_ERROR("virtio-iommu-x86_64", "6.1.0");