diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 07208eef89..fa0edd1582 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -7449,6 +7449,16 @@ qemu-kvm -net nic,model=? /dev/null
Since 3.4.0 (QEMU/KVM only)
+ iotlb
+
+
+ The iotlb
attribute with possible values
+ on
and off
can be used to
+ turn on the IOTLB used to cache address translation
+ requests from devices.
+ Since 3.5.0 (QEMU/KVM only)
+
+
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 4d9f8d1a25..5c542c782a 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3964,6 +3964,11 @@
+
+
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index d4ee92eec5..625449ad23 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -14222,6 +14222,14 @@ virDomainIOMMUDefParseXML(xmlNodePtr node,
}
iommu->caching_mode = val;
}
+ VIR_FREE(tmp);
+ if ((tmp = virXPathString("string(./driver/@iotlb)", ctxt))) {
+ if ((val = virTristateSwitchTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, _("unknown iotlb value: %s"), tmp);
+ goto cleanup;
+ }
+ iommu->iotlb = val;
+ }
VIR_FREE(tmp);
if ((tmp = virXPathString("string(./driver/@eim)", ctxt))) {
@@ -19950,6 +19958,14 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDefPtr src,
virTristateSwitchTypeToString(src->eim));
return false;
}
+ if (src->iotlb != dst->iotlb) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain IOMMU device iotlb value '%s' "
+ "does not match source '%s'"),
+ virTristateSwitchTypeToString(dst->iotlb),
+ virTristateSwitchTypeToString(src->iotlb));
+ return false;
+ }
return true;
}
@@ -24264,7 +24280,8 @@ virDomainIOMMUDefFormat(virBufferPtr buf,
virBufferAdjustIndent(&childBuf, virBufferGetIndent(buf, false) + 2);
if (iommu->intremap != VIR_TRISTATE_SWITCH_ABSENT ||
- iommu->caching_mode != VIR_TRISTATE_SWITCH_ABSENT) {
+ iommu->caching_mode != VIR_TRISTATE_SWITCH_ABSENT ||
+ iommu->iotlb != VIR_TRISTATE_SWITCH_ABSENT) {
virBufferAddLit(&childBuf, "intremap != VIR_TRISTATE_SWITCH_ABSENT) {
virBufferAsprintf(&childBuf, " intremap='%s'",
@@ -24278,6 +24295,10 @@ virDomainIOMMUDefFormat(virBufferPtr buf,
virBufferAsprintf(&childBuf, " eim='%s'",
virTristateSwitchTypeToString(iommu->eim));
}
+ if (iommu->iotlb != VIR_TRISTATE_SWITCH_ABSENT) {
+ virBufferAsprintf(&childBuf, " iotlb='%s'",
+ virTristateSwitchTypeToString(iommu->iotlb));
+ }
virBufferAddLit(&childBuf, "/>\n");
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 1231aeac68..597fb22cca 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2213,6 +2213,7 @@ struct _virDomainIOMMUDef {
virTristateSwitch intremap;
virTristateSwitch caching_mode;
virTristateSwitch eim;
+ virTristateSwitch iotlb;
};
/*
* Guest VM main configuration
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu-device-iotlb.xml b/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu-device-iotlb.xml
new file mode 100644
index 0000000000..3eb08ab9af
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu-device-iotlb.xml
@@ -0,0 +1,31 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219100
+ 219100
+ 1
+
+ hvm
+
+
+
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-x86_64
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu-device-iotlb.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu-device-iotlb.xml
new file mode 120000
index 0000000000..3120d9f677
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu-device-iotlb.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/qemuxml2argv-intel-iommu-device-iotlb.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 6aececb598..31c624b86a 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -1128,6 +1128,7 @@ mymain(void)
DO_TEST("intel-iommu-ioapic", NONE);
DO_TEST("intel-iommu-caching-mode", NONE);
DO_TEST("intel-iommu-eim", NONE);
+ DO_TEST("intel-iommu-device-iotlb", NONE);
DO_TEST("cpu-check-none", NONE);
DO_TEST("cpu-check-partial", NONE);