Add pasid_bits attribute to iommu to set pasid bit width or disable
pasid capability if 0 for intel-iommu.

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

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index f376cefc16..76ce8f88c3 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -9490,6 +9490,11 @@ Examples:
       Enable first stage translation.
       :since:`Since 12.8.0` (QEMU/KVM and ``intel`` model only)
 
+   ``pasid_bits``
+      The ``pasid_bits`` attribute can be used to set the pasid bit width.
+      Max supported value is 20 according to PCI spec, pasid is disabled if 0.
+      :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 9b8048f895..f442aed5a3 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -14786,6 +14786,10 @@ virDomainIOMMUDefParseXML(virDomainXMLOption *xmlopt,
                                      &iommu->fsts) < 0)
             return NULL;
 
+        if (virXMLPropUInt(driver, "pasid_bits", 10, VIR_XML_PROP_NONE,
+                           &iommu->pasid_bits) < 0)
+            return NULL;
+
         if ((granule = virXPathNode("./driver/granule", ctxt))) {
             g_autofree char *mode = virXMLPropString(granule, "mode");
             unsigned long long size;
@@ -16898,6 +16902,7 @@ virDomainIOMMUDefEquals(const virDomainIOMMUDef *a,
         a->oas != b->oas ||
         a->scalable_mode != b->scalable_mode ||
         a->fsts != b->fsts ||
+        a->pasid_bits != b->pasid_bits ||
         a->xtsup != b->xtsup ||
         a->pt != b->pt ||
         a->granule != b->granule)
@@ -22847,6 +22852,12 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDef 
*src,
                        virTristateSwitchTypeToString(src->fsts));
         return false;
     }
+    if (src->pasid_bits != dst->pasid_bits) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Target domain IOMMU device 'pasid_bits' '%1$u' does 
not match source '%2$u'"),
+                       dst->pasid_bits, src->pasid_bits);
+        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'"),
@@ -29310,6 +29321,10 @@ virDomainIOMMUDefFormat(virBuffer *buf,
         virBufferAsprintf(&driverAttrBuf, " fsts='%s'",
                           virTristateSwitchTypeToString(iommu->fsts));
     }
+    if (iommu->pasid_bits > 0) {
+        virBufferAsprintf(&driverAttrBuf, " pasid_bits='%u'",
+                          iommu->pasid_bits);
+    }
     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 d9ec2dc786..243254dedc 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -3106,6 +3106,7 @@ struct _virDomainIOMMUDef {
     virTristateSwitch dma_translation;
     virTristateSwitch scalable_mode;
     virTristateSwitch fsts;
+    unsigned int pasid_bits;
     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 c321d7ceaf..f44bc867f8 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -3204,6 +3204,7 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
             iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->scalable_mode != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->fsts != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->pasid_bits != 0 ||
             iommu->xtsup != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->pt != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->granule != 0) {
@@ -3232,6 +3233,7 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
             iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->scalable_mode != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->fsts != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->pasid_bits != 0 ||
             iommu->pci_bus >= 0 ||
             iommu->accel != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->cmdqv != VIR_TRISTATE_SWITCH_ABSENT ||
@@ -3262,6 +3264,7 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
             iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->scalable_mode != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->fsts != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->pasid_bits != 0 ||
             iommu->pci_bus >= 0 ||
             iommu->accel != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->cmdqv != VIR_TRISTATE_SWITCH_ABSENT ||
@@ -3294,12 +3297,20 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef 
*iommu)
             return -1;
         }
 
-        if (iommu->scalable_mode != VIR_TRISTATE_SWITCH_ON &&
-            iommu->fsts == VIR_TRISTATE_SWITCH_ON) {
-            virReportError(VIR_ERR_XML_ERROR,
-                           _("iommu model '%1$s' 'fsts' requires 
'scalable_mode' to be 'on'"),
-                           virDomainIOMMUModelTypeToString(iommu->model));
-            return -1;
+        if (iommu->scalable_mode != VIR_TRISTATE_SWITCH_ON) {
+            if (iommu->fsts == VIR_TRISTATE_SWITCH_ON) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("iommu model '%1$s' 'fsts' requires 
'scalable_mode' to be 'on'"),
+                               virDomainIOMMUModelTypeToString(iommu->model));
+                return -1;
+            }
+
+            if (iommu->pasid_bits > 0) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("iommu model '%1$s' 'pasid_bits' requires 
'scalable_mode' to be 'on'"),
+                               virDomainIOMMUModelTypeToString(iommu->model));
+                return -1;
+            }
         }
         break;
 
diff --git a/src/conf/schemas/domaincommon.rng 
b/src/conf/schemas/domaincommon.rng
index ff905c18c2..888d0db214 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -6434,6 +6434,11 @@
                 <ref name="virOnOff"/>
               </attribute>
             </optional>
+            <optional>
+              <attribute name="pasid_bits">
+                <ref name="uint8"/>
+              </attribute>
+            </optional>
             <optional>
               <attribute name="xtsup">
                 <ref name="virOnOff"/>
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 8c59ca4383..5ea8337602 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -6345,6 +6345,7 @@ qemuBuildIOMMUCommandLine(virCommand *cmd,
                                       "T:dma-translation", 
iommu->dma_translation,
                                       "T:scalable-mode", iommu->scalable_mode,
                                       "T:fsts", iommu->fsts,
+                                      "p:pasid-bits", iommu->pasid_bits,
                                       NULL) < 0)
                 return -1;
 
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index fb4d100be3..2225f1a76b 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -5859,6 +5859,17 @@ qemuValidateDomainDeviceDefIOMMU(const virDomainIOMMUDef 
*iommu,
                        _("iommu: 'fsts' is not supported with this QEMU 
binary"));
         return -1;
     }
+    if (iommu->pasid_bits > 0 &&
+        !virQEMUCapsGet(qemuCaps, QEMU_CAPS_INTEL_IOMMU_PASID_BITS)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("iommu: 'pasid_bits' is not supported with this QEMU 
binary"));
+        return -1;
+    }
+    if (iommu->pasid_bits > 20) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("iommu: 'pasid_bits' exceeds maximum allowed value 20 
in 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-pasid-bits.x86_64-latest.args 
b/tests/qemuxmlconfdata/intel-iommu-pasid-bits.x86_64-latest.args
new file mode 100644
index 0000000000..e2f5adfc93
--- /dev/null
+++ b/tests/qemuxmlconfdata/intel-iommu-pasid-bits.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,"fsts":true,"pasid-bits":6}'
 \
+-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-pasid-bits.x86_64-latest.xml 
b/tests/qemuxmlconfdata/intel-iommu-pasid-bits.x86_64-latest.xml
new file mode 100644
index 0000000000..cbf5cce48a
--- /dev/null
+++ b/tests/qemuxmlconfdata/intel-iommu-pasid-bits.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' fsts='on' pasid_bits='6'/>
+    </iommu>
+  </devices>
+</domain>
diff --git a/tests/qemuxmlconfdata/intel-iommu-pasid-bits.xml 
b/tests/qemuxmlconfdata/intel-iommu-pasid-bits.xml
new file mode 100644
index 0000000000..cbf5cce48a
--- /dev/null
+++ b/tests/qemuxmlconfdata/intel-iommu-pasid-bits.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' fsts='on' pasid_bits='6'/>
+    </iommu>
+  </devices>
+</domain>
diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c
index 837bea7b63..bc83367cd8 100644
--- a/tests/qemuxmlconftest.c
+++ b/tests/qemuxmlconftest.c
@@ -2991,6 +2991,7 @@ mymain(void)
     DO_TEST_CAPS_LATEST("intel-iommu-dma-translation");
     DO_TEST_CAPS_LATEST("intel-iommu-scalable-mode");
     DO_TEST_CAPS_LATEST("intel-iommu-fsts");
+    DO_TEST_CAPS_LATEST("intel-iommu-pasid-bits");
     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