From: Michal Privoznik <[email protected]>

In PCI assignment scenario the virtio-iommu needs to know the
guest page size also known as granule. Expose it as an attribute
to the <driver/> element of a virtio-iommu.

This is possibly interesting only for aarch64 since it supports
virtio-iommu and also supports running guests with different page
size than the host.

Signed-off-by: Michal Privoznik <[email protected]>
---
 docs/formatdomain.rst                         |  7 +++++
 src/conf/domain_conf.c                        | 30 ++++++++++++++++++-
 src/conf/domain_conf.h                        | 13 ++++++++
 src/conf/domain_validate.c                    |  9 ++++--
 src/conf/schemas/domaincommon.rng             | 11 +++++++
 src/libvirt_private.syms                      |  2 ++
 .../virtio-iommu-aarch64.aarch64-latest.xml   |  2 +-
 .../qemuxmlconfdata/virtio-iommu-aarch64.xml  |  2 +-
 8 files changed, 70 insertions(+), 6 deletions(-)

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 4b34a8a963..1dfe3915b5 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -9264,6 +9264,13 @@ Example:
       The ``pciBus`` attribute notes the index of the controller that an
       IOMMU device is attached to. (QEMU/KVM and ``smmuv3`` model only)
 
+   ``granule``
+      This allows to choose which granule will be used by default by the
+      virtio-iommu and is useful when running guests with different page size
+      than the host. Accepted values are: ``4K``, ``8K``, ``16K``, ``64K`` and
+      ``host`` (matches the host page size). :since:`Since 12.1.0` (QEMU/KVM
+      and ``virtio`` model only).
+
 The ``virtio`` IOMMU devices can further have ``address`` element as described
 in `Device addresses`_ (address has to by type of ``pci``).
 
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index d00a43e969..140333b1ec 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1356,6 +1356,16 @@ VIR_ENUM_IMPL(virDomainIOMMUModel,
               "amd",
 );
 
+VIR_ENUM_IMPL(virDomainIOMMUGranuleMode,
+              VIR_DOMAIN_IOMMU_GRANULE_MODE_LAST,
+              "none",
+              "4K",
+              "8K",
+              "16K",
+              "64K",
+              "host",
+);
+
 VIR_ENUM_IMPL(virDomainVsockModel,
               VIR_DOMAIN_VSOCK_MODEL_LAST,
               "default",
@@ -14514,6 +14524,12 @@ virDomainIOMMUDefParseXML(virDomainXMLOption *xmlopt,
         if (virXMLPropInt(driver, "pciBus", 10, VIR_XML_PROP_NONE,
                           &iommu->pci_bus, -1) < 0)
             return NULL;
+
+        if (virXMLPropEnum(driver, "granule",
+                           virDomainIOMMUGranuleModeTypeFromString,
+                           VIR_XML_PROP_NONZERO, &iommu->granule_mode) < 0) {
+            return NULL;
+        }
     }
 
     if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt,
@@ -16565,7 +16581,8 @@ virDomainIOMMUDefEquals(const virDomainIOMMUDef *a,
         a->eim != b->eim ||
         a->iotlb != b->iotlb ||
         a->aw_bits != b->aw_bits ||
-        a->dma_translation != b->dma_translation)
+        a->dma_translation != b->dma_translation ||
+        a->granule_mode != b->granule_mode)
         return false;
 
     if (a->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
@@ -22320,6 +22337,13 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDef 
*src,
                        virTristateSwitchTypeToString(src->xtsup));
         return false;
     }
+    if (src->granule_mode != dst->granule_mode) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Target domain IOMMU device granule '%1$s' does not 
match source '%2$s'"),
+                       
virDomainIOMMUGranuleModeTypeToString(dst->granule_mode),
+                       
virDomainIOMMUGranuleModeTypeToString(src->granule_mode));
+        return false;
+    }
 
     return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info);
 }
@@ -28645,6 +28669,10 @@ virDomainIOMMUDefFormat(virBuffer *buf,
         virBufferAsprintf(&driverAttrBuf, " pciBus='%d'",
                           iommu->pci_bus);
     }
+    if (iommu->granule_mode != VIR_DOMAIN_IOMMU_GRANULE_MODE_NONE) {
+        virBufferAsprintf(&driverAttrBuf, " granule='%s'",
+                          
virDomainIOMMUGranuleModeTypeToString(iommu->granule_mode));
+    }
 
     virXMLFormatElement(&childBuf, "driver", &driverAttrBuf, NULL);
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 83d49969d3..8ea620a738 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -3050,6 +3050,17 @@ typedef enum {
     VIR_DOMAIN_IOMMU_MODEL_LAST
 } virDomainIOMMUModel;
 
+typedef enum {
+    VIR_DOMAIN_IOMMU_GRANULE_MODE_NONE = 0,
+    VIR_DOMAIN_IOMMU_GRANULE_MODE_4K,
+    VIR_DOMAIN_IOMMU_GRANULE_MODE_8K,
+    VIR_DOMAIN_IOMMU_GRANULE_MODE_16K,
+    VIR_DOMAIN_IOMMU_GRANULE_MODE_64K,
+    VIR_DOMAIN_IOMMU_GRANULE_MODE_HOST,
+
+    VIR_DOMAIN_IOMMU_GRANULE_MODE_LAST
+} virDomainIOMMUGranuleMode;
+
 struct _virDomainIOMMUDef {
     virDomainIOMMUModel model;
     virTristateSwitch intremap;
@@ -3062,6 +3073,7 @@ struct _virDomainIOMMUDef {
     virTristateSwitch dma_translation;
     virTristateSwitch xtsup;
     virTristateSwitch pt;
+    virDomainIOMMUGranuleMode granule_mode;
 };
 
 typedef enum {
@@ -4443,6 +4455,7 @@ VIR_ENUM_DECL(virDomainMemoryBackingModel);
 VIR_ENUM_DECL(virDomainMemorySource);
 VIR_ENUM_DECL(virDomainMemoryAllocation);
 VIR_ENUM_DECL(virDomainIOMMUModel);
+VIR_ENUM_DECL(virDomainIOMMUGranuleMode);
 VIR_ENUM_DECL(virDomainVsockModel);
 VIR_ENUM_DECL(virDomainCryptoModel);
 VIR_ENUM_DECL(virDomainCryptoType);
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index 440f23d726..fd28526159 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -3194,7 +3194,8 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
             iommu->aw_bits != 0 ||
             iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->xtsup != VIR_TRISTATE_SWITCH_ABSENT ||
-            iommu->pt != VIR_TRISTATE_SWITCH_ABSENT) {
+            iommu->pt != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->granule_mode != VIR_DOMAIN_IOMMU_GRANULE_MODE_NONE) {
             virReportError(VIR_ERR_XML_ERROR,
                            _("iommu model '%1$s' doesn't support some 
additional attributes"),
                            virDomainIOMMUModelTypeToString(iommu->model));
@@ -3226,7 +3227,8 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
             iommu->eim != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->aw_bits != 0 ||
             iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
-            iommu->pci_bus >= 0) {
+            iommu->pci_bus >= 0 ||
+            iommu->granule_mode != VIR_DOMAIN_IOMMU_GRANULE_MODE_NONE) {
             virReportError(VIR_ERR_XML_ERROR,
                            _("iommu model '%1$s' doesn't support some 
additional attributes"),
                            virDomainIOMMUModelTypeToString(iommu->model));
@@ -3237,7 +3239,8 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
     case VIR_DOMAIN_IOMMU_MODEL_INTEL:
         if (iommu->pt != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->xtsup != VIR_TRISTATE_SWITCH_ABSENT ||
-            iommu->pci_bus >= 0) {
+            iommu->pci_bus >= 0 ||
+            iommu->granule_mode != VIR_DOMAIN_IOMMU_GRANULE_MODE_NONE) {
             virReportError(VIR_ERR_XML_ERROR,
                            _("iommu model '%1$s' doesn't support some 
additional attributes"),
                            virDomainIOMMUModelTypeToString(iommu->model));
diff --git a/src/conf/schemas/domaincommon.rng 
b/src/conf/schemas/domaincommon.rng
index 114dd3f96f..175e735a99 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -6329,6 +6329,17 @@
                 <data type="unsignedInt"/>
               </attribute>
             </optional>
+            <optional>
+              <attribute name="granule">
+                <choice>
+                  <value>4K</value>
+                  <value>8K</value>
+                  <value>16K</value>
+                  <value>64K</value>
+                  <value>host</value>
+                </choice>
+              </attribute>
+            </optional>
           </element>
         </optional>
         <optional>
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 6bffd2eb6d..d34b65a415 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -499,6 +499,8 @@ virDomainIOMMUDefEquals;
 virDomainIOMMUDefFind;
 virDomainIOMMUDefFree;
 virDomainIOMMUDefNew;
+virDomainIOMMUGranuleModeTypeFromString;
+virDomainIOMMUGranuleModeTypeToString;
 virDomainIOMMUModelTypeFromString;
 virDomainIOMMUModelTypeToString;
 virDomainIOThreadIDAdd;
diff --git a/tests/qemuxmlconfdata/virtio-iommu-aarch64.aarch64-latest.xml 
b/tests/qemuxmlconfdata/virtio-iommu-aarch64.aarch64-latest.xml
index 4ae628ab5a..709a24f796 100644
--- a/tests/qemuxmlconfdata/virtio-iommu-aarch64.aarch64-latest.xml
+++ b/tests/qemuxmlconfdata/virtio-iommu-aarch64.aarch64-latest.xml
@@ -29,7 +29,7 @@
     <audio id='1' type='none'/>
     <memballoon model='none'/>
     <iommu model='virtio'>
-      <driver aw_bits='48'/>
+      <driver aw_bits='48' granule='64K'/>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x01' 
function='0x0'/>
     </iommu>
   </devices>
diff --git a/tests/qemuxmlconfdata/virtio-iommu-aarch64.xml 
b/tests/qemuxmlconfdata/virtio-iommu-aarch64.xml
index 96e5ea05ae..bf8bc58211 100644
--- a/tests/qemuxmlconfdata/virtio-iommu-aarch64.xml
+++ b/tests/qemuxmlconfdata/virtio-iommu-aarch64.xml
@@ -14,7 +14,7 @@
     <controller type='usb' model='none'/>
     <memballoon model='none'/>
     <iommu model='virtio'>
-      <driver aw_bits='48'/>
+      <driver aw_bits='48' granule='64K'/>
     </iommu>
   </devices>
 </domain>
-- 
2.52.0

Reply via email to