Add scalable_mode attribute to iommu to enable/disable scalable mode
for intel-iommu.

Signed-off-by: Zhenzhong Duan <[email protected]>
---
 docs/formatdomain.rst                         |  4 ++
 src/conf/domain_conf.c                        | 16 ++++++++
 src/conf/domain_conf.h                        |  1 +
 src/conf/domain_validate.c                    |  3 ++
 src/conf/schemas/domaincommon.rng             |  5 +++
 src/qemu/qemu_command.c                       |  1 +
 src/qemu/qemu_validate.c                      |  6 +++
 ...tel-iommu-scalable-mode.x86_64-latest.args | 34 +++++++++++++++++
 ...ntel-iommu-scalable-mode.x86_64-latest.xml | 37 +++++++++++++++++++
 .../intel-iommu-scalable-mode.xml             | 37 +++++++++++++++++++
 tests/qemuxmlconftest.c                       |  1 +
 11 files changed, 145 insertions(+)
 create mode 100644 
tests/qemuxmlconfdata/intel-iommu-scalable-mode.x86_64-latest.args
 create mode 100644 
tests/qemuxmlconfdata/intel-iommu-scalable-mode.x86_64-latest.xml
 create mode 100644 tests/qemuxmlconfdata/intel-iommu-scalable-mode.xml

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 5a278f3717..761c5747ed 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -9482,6 +9482,10 @@ Examples:
       default value is used.
       :since:`Since 12.7.0` (QEMU/KVM and ``smmuv3`` model only)
 
+   ``scalable_mode``
+      Enable scalable mode DMA translation.
+      :since:`Since 12.8.0` (QEMU/KVM and ``intel`` model only)
+
 In case of ``virtio`` IOMMU device, the ``driver`` element can optionally
 contain ``granule`` subelement that allows to choose which granule will be
 used by default. It is useful when running guests with different page size
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 34d3b00079..c055395120 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -14778,6 +14778,10 @@ virDomainIOMMUDefParseXML(virDomainXMLOption *xmlopt,
                           &iommu->oas, -1) < 0)
             return NULL;
 
+        if (virXMLPropTristateSwitch(driver, "scalable_mode", 
VIR_XML_PROP_NONE,
+                                     &iommu->scalable_mode) < 0)
+            return NULL;
+
         if ((granule = virXPathNode("./driver/granule", ctxt))) {
             g_autofree char *mode = virXMLPropString(granule, "mode");
             unsigned long long size;
@@ -16888,6 +16892,7 @@ virDomainIOMMUDefEquals(const virDomainIOMMUDef *a,
         a->ril != b->ril ||
         a->ssid_size != b->ssid_size ||
         a->oas != b->oas ||
+        a->scalable_mode != b->scalable_mode ||
         a->xtsup != b->xtsup ||
         a->pt != b->pt ||
         a->granule != b->granule)
@@ -22823,6 +22828,13 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDef 
*src,
                        virTristateSwitchTypeToString(src->dma_translation));
         return false;
     }
+    if (src->scalable_mode != dst->scalable_mode) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Target domain IOMMU device 'scalable_mode' '%1$s' 
does not match source '%2$s'"),
+                       virTristateSwitchTypeToString(dst->scalable_mode),
+                       virTristateSwitchTypeToString(src->scalable_mode));
+        return false;
+    }
     if (src->pt != dst->pt) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("Target domain IOMMU device passthrough '%1$s' does 
not match source '%2$s'"),
@@ -29278,6 +29290,10 @@ virDomainIOMMUDefFormat(virBuffer *buf,
         virBufferAsprintf(&driverAttrBuf, " dma_translation='%s'",
                           
virTristateSwitchTypeToString(iommu->dma_translation));
     }
+    if (iommu->scalable_mode != VIR_TRISTATE_SWITCH_ABSENT) {
+        virBufferAsprintf(&driverAttrBuf, " scalable_mode='%s'",
+                          virTristateSwitchTypeToString(iommu->scalable_mode));
+    }
     if (iommu->pt != VIR_TRISTATE_SWITCH_ABSENT) {
         virBufferAsprintf(&driverAttrBuf, " passthrough='%s'",
                           virTristateSwitchTypeToString(iommu->pt));
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 3732525af4..2c23a3f65a 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -3104,6 +3104,7 @@ struct _virDomainIOMMUDef {
     int pci_bus;
     virDomainDeviceInfo info;
     virTristateSwitch dma_translation;
+    virTristateSwitch scalable_mode;
     virTristateSwitch xtsup;
     virTristateSwitch pt;
     int granule; /* -1 means 'host', 0 unset, page size in KiB otherwise */
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index 15e3bb29e6..10318d89ee 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -3202,6 +3202,7 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
             iommu->iotlb != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->aw_bits != 0 ||
             iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->scalable_mode != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->xtsup != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->pt != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->granule != 0) {
@@ -3228,6 +3229,7 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
             iommu->eim != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->iotlb != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->scalable_mode != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->pci_bus >= 0 ||
             iommu->accel != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->cmdqv != VIR_TRISTATE_SWITCH_ABSENT ||
@@ -3256,6 +3258,7 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
             iommu->eim != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->aw_bits != 0 ||
             iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->scalable_mode != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->pci_bus >= 0 ||
             iommu->accel != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->cmdqv != VIR_TRISTATE_SWITCH_ABSENT ||
diff --git a/src/conf/schemas/domaincommon.rng 
b/src/conf/schemas/domaincommon.rng
index 887fb8f808..01b1766150 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -6424,6 +6424,11 @@
                 <ref name="virOnOff"/>
               </attribute>
             </optional>
+            <optional>
+              <attribute name="scalable_mode">
+                <ref name="virOnOff"/>
+              </attribute>
+            </optional>
             <optional>
               <attribute name="xtsup">
                 <ref name="virOnOff"/>
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index bcddb9c922..d7afdb4ee4 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -6343,6 +6343,7 @@ qemuBuildIOMMUCommandLine(virCommand *cmd,
                                       "T:device-iotlb", iommu->iotlb,
                                       "p:aw-bits", iommu->aw_bits,
                                       "T:dma-translation", 
iommu->dma_translation,
+                                      "T:scalable-mode", iommu->scalable_mode,
                                       NULL) < 0)
                 return -1;
 
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index e946f55351..efe55f16fd 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -5843,6 +5843,12 @@ qemuValidateDomainDeviceDefIOMMU(const virDomainIOMMUDef 
*iommu,
                        _("iommu: updating dma translation is not supported 
with this QEMU binary"));
         return -1;
     }
+    if (iommu->scalable_mode != VIR_TRISTATE_SWITCH_ABSENT &&
+        !virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_SCALABLE_MODE))  {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("iommu: 'scalable_mode' is not supported with this 
QEMU binary"));
+        return -1;
+    }
 
     /* While QEMU_CAPS_ARM_SMMUV3_ACCEL tracks the .accel attribute of
      * arm-smmuv3 it is also a good indicator of .ats, .ril, .ssidsize, and
diff --git a/tests/qemuxmlconfdata/intel-iommu-scalable-mode.x86_64-latest.args 
b/tests/qemuxmlconfdata/intel-iommu-scalable-mode.x86_64-latest.args
new file mode 100644
index 0000000000..bda776f46a
--- /dev/null
+++ b/tests/qemuxmlconfdata/intel-iommu-scalable-mode.x86_64-latest.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 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=@mon-fd@,server=on,wait=off \
+-object '{"qom-type":"monitor-qmp","id":"monitor","chardev":"charmonitor"}' \
+-rtc base=utc \
+-no-shutdown \
+-boot strict=on \
+-device '{"driver":"intel-iommu","id":"iommu0","scalable-mode":true}' \
+-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-scalable-mode.x86_64-latest.xml 
b/tests/qemuxmlconfdata/intel-iommu-scalable-mode.x86_64-latest.xml
new file mode 100644
index 0000000000..a8f044ee12
--- /dev/null
+++ b/tests/qemuxmlconfdata/intel-iommu-scalable-mode.x86_64-latest.xml
@@ -0,0 +1,37 @@
+<domain type='kvm'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219100</memory>
+  <currentMemory unit='KiB'>219100</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='q35'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <features>
+    <ioapic driver='qemu'/>
+  </features>
+  <cpu mode='custom' match='exact' check='none'>
+    <model fallback='forbid'>qemu64</model>
+  </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='usb' index='0' model='none'/>
+    <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'/>
+    <watchdog model='itco' action='reset'/>
+    <memballoon model='none'/>
+    <iommu model='intel'>
+      <driver scalable_mode='on'/>
+    </iommu>
+  </devices>
+</domain>
diff --git a/tests/qemuxmlconfdata/intel-iommu-scalable-mode.xml 
b/tests/qemuxmlconfdata/intel-iommu-scalable-mode.xml
new file mode 100644
index 0000000000..a8f044ee12
--- /dev/null
+++ b/tests/qemuxmlconfdata/intel-iommu-scalable-mode.xml
@@ -0,0 +1,37 @@
+<domain type='kvm'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219100</memory>
+  <currentMemory unit='KiB'>219100</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='q35'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <features>
+    <ioapic driver='qemu'/>
+  </features>
+  <cpu mode='custom' match='exact' check='none'>
+    <model fallback='forbid'>qemu64</model>
+  </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='usb' index='0' model='none'/>
+    <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'/>
+    <watchdog model='itco' action='reset'/>
+    <memballoon model='none'/>
+    <iommu model='intel'>
+      <driver scalable_mode='on'/>
+    </iommu>
+  </devices>
+</domain>
diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c
index 555c029f58..e77702427f 100644
--- a/tests/qemuxmlconftest.c
+++ b/tests/qemuxmlconftest.c
@@ -2989,6 +2989,7 @@ mymain(void)
     DO_TEST_CAPS_LATEST("intel-iommu-device-iotlb");
     DO_TEST_CAPS_LATEST("intel-iommu-aw-bits");
     DO_TEST_CAPS_LATEST("intel-iommu-dma-translation");
+    DO_TEST_CAPS_LATEST("intel-iommu-scalable-mode");
     DO_TEST_CAPS_LATEST_PARSE_ERROR("intel-iommu-wrong-machine");
     DO_TEST_CAPS_LATEST_ABI_UPDATE("intel-iommu-eim-autoadd");
     DO_TEST_CAPS_LATEST_ABI_UPDATE("intel-iommu-eim-autoadd-v2");
-- 
2.52.0

Reply via email to