]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: Implement pluggable-device smmuv3
authorNathan Chen <nathanc@nvidia.com>
Thu, 20 Nov 2025 01:42:41 +0000 (17:42 -0800)
committerJán Tomko <jtomko@redhat.com>
Thu, 20 Nov 2025 21:56:39 +0000 (22:56 +0100)
Introduce support for "pciBus" driver attribute for
"smmuv3" IOMMU model. The "pciBus" attribute indicates
the index of the controller that a smmuv3 IOMMU device
is attached to, and differentiates the device-pluggable
arm-smmuv3 model from the virt-machine-associated smmuv3
model.

Signed-off-by: Nathan Chen <nathanc@nvidia.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
docs/formatdomain.rst
src/conf/domain_conf.c
src/conf/domain_conf.h
src/conf/domain_validate.c
src/conf/schemas/domaincommon.rng
src/qemu/qemu_command.c

index c6d0b183d04bf5942e4a5718e982f2019b542800..160e7ad9c7a0ef5243d5e030f6e938ab8f915189 100644 (file)
@@ -9238,6 +9238,10 @@ Example:
       Enable x2APIC mode. Useful for higher number of guest CPUs.
       :since:`Since 11.5.0` (QEMU/KVM and ``amd`` model only)
 
+   ``pciBus``
+      The ``pciBus`` attribute notes the index of the controller that an
+      IOMMU device is attached to. (QEMU/KVM and ``smmuv3`` model only)
+
 The ``virtio`` IOMMU devices can further have ``address`` element as described
 in `Device addresses`_ (address has to by type of ``pci``).
 
index 90d7b8a355c85ddc614491bd86b5653b535c2474..6e47ccb23dfa89872ebe13095d8bb3bc74c1b1b7 100644 (file)
@@ -2815,6 +2815,8 @@ virDomainIOMMUDefNew(void)
 
     iommu = g_new0(virDomainIOMMUDef, 1);
 
+    iommu->pci_bus = -1;
+
     return g_steal_pointer(&iommu);
 }
 
@@ -14501,6 +14503,10 @@ virDomainIOMMUDefParseXML(virDomainXMLOption *xmlopt,
         if (virXMLPropTristateSwitch(driver, "passthrough", VIR_XML_PROP_NONE,
                                      &iommu->pt) < 0)
             return NULL;
+
+        if (virXMLPropInt(driver, "pciBus", 10, VIR_XML_PROP_NONE,
+                          &iommu->pci_bus, -1) < 0)
+            return NULL;
     }
 
     if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt,
@@ -22227,6 +22233,12 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDef *src,
                        dst->aw_bits, src->aw_bits);
         return false;
     }
+    if (src->pci_bus != dst->pci_bus) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Target domain IOMMU device pci_bus value '%1$d' does not match source '%2$d'"),
+                       dst->pci_bus, src->pci_bus);
+        return false;
+    }
     if (src->dma_translation != dst->dma_translation) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("Target domain IOMMU device dma translation '%1$s' does not match source '%2$s'"),
@@ -28562,6 +28574,10 @@ virDomainIOMMUDefFormat(virBuffer *buf,
         virBufferAsprintf(&driverAttrBuf, " xtsup='%s'",
                           virTristateSwitchTypeToString(iommu->xtsup));
     }
+    if (iommu->pci_bus >= 0) {
+        virBufferAsprintf(&driverAttrBuf, " pciBus='%d'",
+                          iommu->pci_bus);
+    }
 
     virXMLFormatElement(&childBuf, "driver", &driverAttrBuf, NULL);
 
index 1bd9586de1866287c0b1335cd2e1d6d3439f626a..4fd8342950ea2753138d970c638c91bc977e22f2 100644 (file)
@@ -3056,6 +3056,7 @@ struct _virDomainIOMMUDef {
     virTristateSwitch eim;
     virTristateSwitch iotlb;
     unsigned int aw_bits;
+    int pci_bus;
     virDomainDeviceInfo info;
     virTristateSwitch dma_translation;
     virTristateSwitch xtsup;
index 3339fc83e0de2b9699225ce497ba69b599b4e5ca..8bbea5f000a61108dbbaf4053dc3c2f36422181a 100644 (file)
@@ -1853,6 +1853,11 @@ virDomainDefIOMMUValidate(const virDomainDef *def)
                            _("IOMMU model smmuv3 must be specified for multiple IOMMU definitions"));
         }
 
+        if (def->niommus > 1 && iommu->pci_bus < 0) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("device-pluggable IOMMU with pciBus attribute must be specified for multiple IOMMU definitions"));
+        }
+
         if (iommu->intremap == VIR_TRISTATE_SWITCH_ON &&
             def->features[VIR_DOMAIN_FEATURE_IOAPIC] != VIR_DOMAIN_IOAPIC_QEMU) {
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -3107,13 +3112,28 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
 {
     switch (iommu->model) {
     case VIR_DOMAIN_IOMMU_MODEL_SMMUV3:
+        if (iommu->intremap != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->caching_mode != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->eim != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->iotlb != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->aw_bits != 0 ||
+            iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->xtsup != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->pt != VIR_TRISTATE_SWITCH_ABSENT) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("iommu model '%1$s' doesn't support some additional attributes"),
+                           virDomainIOMMUModelTypeToString(iommu->model));
+            return -1;
+        }
+        break;
     case VIR_DOMAIN_IOMMU_MODEL_VIRTIO:
         if (iommu->intremap != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->caching_mode != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->eim != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->iotlb != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->aw_bits != 0 ||
-            iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT) {
+            iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->pci_bus >= 0) {
             virReportError(VIR_ERR_XML_ERROR,
                            _("iommu model '%1$s' doesn't support additional attributes"),
                            virDomainIOMMUModelTypeToString(iommu->model));
@@ -3125,7 +3145,8 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
         if (iommu->caching_mode != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->eim != VIR_TRISTATE_SWITCH_ABSENT ||
             iommu->aw_bits != 0 ||
-            iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT) {
+            iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->pci_bus >= 0) {
             virReportError(VIR_ERR_XML_ERROR,
                            _("iommu model '%1$s' doesn't support some additional attributes"),
                            virDomainIOMMUModelTypeToString(iommu->model));
@@ -3135,7 +3156,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->xtsup != VIR_TRISTATE_SWITCH_ABSENT ||
+            iommu->pci_bus >= 0) {
             virReportError(VIR_ERR_XML_ERROR,
                            _("iommu model '%1$s' doesn't support some additional attributes"),
                            virDomainIOMMUModelTypeToString(iommu->model));
index 3cbe7d1aa0163022d9dd8cbf07feffdc4a0d7885..78cf0a08cf394fe4f24436b88395460bbecafb62 100644 (file)
                 <ref name="virOnOff"/>
               </attribute>
             </optional>
+            <optional>
+              <attribute name="pciBus">
+                <data type="unsignedInt"/>
+              </attribute>
+            </optional>
           </element>
         </optional>
         <optional>
index 17159db593f028b987ab8a6c147f21b942176271..5a834ef8425c10e8e17a5dac22749f58a9d1bdab 100644 (file)
@@ -6239,6 +6239,33 @@ qemuBuildBootCommandLine(virCommand *cmd,
 }
 
 
+static virJSONValue *
+qemuBuildPCINestedSmmuv3DevProps(const virDomainDef *def,
+                                 const virDomainIOMMUDef *iommu)
+{
+    g_autoptr(virJSONValue) props = NULL;
+    g_autofree char *bus = NULL;
+    virPCIDeviceAddress addr = { .bus = iommu->pci_bus };
+
+    bus = qemuBuildDeviceAddressPCIGetBus(def, &addr);
+
+    if (!bus) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Could not find a suitable controller for smmuv3"));
+        return NULL;
+    }
+
+    if (virJSONValueObjectAdd(&props,
+                              "s:driver", "arm-smmuv3",
+                              "s:primary-bus", bus,
+                              "s:id", iommu->info.alias,
+                              NULL) < 0)
+        return NULL;
+
+    return g_steal_pointer(&props);
+}
+
+
 static int
 qemuBuildIOMMUCommandLine(virCommand *cmd,
                           const virDomainDef *def,
@@ -6269,6 +6296,7 @@ qemuBuildIOMMUCommandLine(virCommand *cmd,
                 return -1;
 
             break;
+
         case VIR_DOMAIN_IOMMU_MODEL_VIRTIO:
             if (virJSONValueObjectAdd(&props,
                                       "s:driver", "virtio-iommu",
@@ -6284,9 +6312,6 @@ qemuBuildIOMMUCommandLine(virCommand *cmd,
                 return -1;
 
             break;
-        case VIR_DOMAIN_IOMMU_MODEL_SMMUV3:
-            /* There is no -device for SMMUv3, so nothing to be done here */
-            break;
 
         case VIR_DOMAIN_IOMMU_MODEL_AMD:
             if (virJSONValueObjectAdd(&wrapperProps,
@@ -6316,6 +6341,15 @@ qemuBuildIOMMUCommandLine(virCommand *cmd,
 
             break;
 
+        case VIR_DOMAIN_IOMMU_MODEL_SMMUV3:
+            if (iommu->pci_bus >= 0) {
+                if (!(props = qemuBuildPCINestedSmmuv3DevProps(def, iommu)))
+                    return -1;
+                if (qemuBuildDeviceCommandlineFromJSON(cmd, props, def, qemuCaps) < 0)
+                    return -1;
+            }
+            break;
+
         case VIR_DOMAIN_IOMMU_MODEL_LAST:
         default:
             virReportEnumRangeError(virDomainIOMMUModel, iommu->model);