- Rebased to libvirt-12.5.0 (VOYAGER-1356) - The rebase also fixes the following bugs: VOYAGER-1351 - conf: Include check for pci_bus in virDomainIOMMUDefEquals() (VOYAGER-1043) - qemu: introduce QEMU_CAPS_DEVICE_ARM_SMMUV3 (VOYAGER-1043) - qemu: introduce QEMU_CAPS_ARM_SMMUV3_SMMU_PER_BUS (VOYAGER-1043) - qemu: introduce QEMU_CAPS_ARM_SMMUV3_ACCEL (VOYAGER-1043) - qemu: Add support for HW-accelerated nested SMMUv3 (VOYAGER-1043) - tests: qemuxmlconfdata: provide HW-accel smmuv3 sample XML and CLI args (VOYAGER-1043) - qemu: Support NVIDIA Tegra241 CMDQV for SMMUv3 (VOYAGER-1045) - tests: qemuxmlconfdata: provide cmdqv sample XML and CLI args (VOYAGER-1045) - conf: Support EGM memory device model (VOYAGER-1109) - qemu: Add cgroup, namespace, and seclabel setup for EGM memory device model (VOYAGER-1109) - qemu: Add qemu CLI support for EGM (VOYAGER-1109) - tests: Add qemuxmlconftest for ACPI EGM memory device (VOYAGER-1109) Resolves: VOYAGER-1043, VOYAGER-1045, VOYAGER-1109, VOYAGER-1351, VOYAGER-1356
374 lines
16 KiB
Diff
374 lines
16 KiB
Diff
From e99dacdae8ffa42463b7dc06eab8043d4ed2d829 Mon Sep 17 00:00:00 2001
|
|
Message-ID: <e99dacdae8ffa42463b7dc06eab8043d4ed2d829.1786096788.git.phrdina@redhat.com>
|
|
From: Pavel Hrdina <phrdina@redhat.com>
|
|
Date: Wed, 5 Aug 2026 15:13:00 -0700
|
|
Subject: [PATCH] qemu: Add support for HW-accelerated nested SMMUv3
|
|
|
|
From: Nathan Chen <nathanc@nvidia.com>
|
|
|
|
Add support for enabling HW-accelerated nested SMMUv3 via <accel>
|
|
attribute and its additional attributes for ATS, SSID, RIL, and OAS
|
|
configuration.
|
|
|
|
Validate the domain iommu accel attribute in qemu_validate.c when
|
|
QEMU lacks this capability. Checking accel is sufficient because ats,
|
|
ril, ssidsize, and oas were introduced in the same QEMU release, and
|
|
it only makes sense to backport accel, ats, ril, ssidsize, and oas
|
|
all together.
|
|
|
|
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
|
|
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
|
|
(cherry picked from commit d4605d8279d73bf8d2b8031d49f453529738ef34)
|
|
|
|
Resolves: https://redhat.atlassian.net/browse/VOYAGER-1043
|
|
---
|
|
docs/formatdomain.rst | 38 +++++++++++++++
|
|
src/conf/domain_conf.c | 79 +++++++++++++++++++++++++++++++
|
|
src/conf/domain_conf.h | 5 ++
|
|
src/conf/domain_validate.c | 27 ++++++++++-
|
|
src/conf/schemas/domaincommon.rng | 25 ++++++++++
|
|
src/qemu/qemu_command.c | 15 ++++++
|
|
src/qemu/qemu_validate.c | 12 +++++
|
|
7 files changed, 200 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
|
|
index a861f9f177..1e8c81c3a5 100644
|
|
--- a/docs/formatdomain.rst
|
|
+++ b/docs/formatdomain.rst
|
|
@@ -9426,6 +9426,44 @@ Examples:
|
|
The ``pciBus`` attribute notes the index of the controller that an
|
|
IOMMU device is attached to. (QEMU/KVM and ``smmuv3`` model only)
|
|
|
|
+ ``accel``
|
|
+ The ``accel`` attribute with possible values ``on`` and ``off`` can
|
|
+ be used to enable hardware acceleration support for smmuv3 IOMMU
|
|
+ devices.
|
|
+ :since:`Since 12.7.0` (QEMU/KVM and ``smmuv3`` model only)
|
|
+
|
|
+ ``ats``
|
|
+ The ``ats`` attribute with possible values ``on`` and ``off`` can be
|
|
+ used to enable reporting Address Translation Services capability to
|
|
+ the guest for smmuv3 IOMMU devices with ``accel`` set to ``on``, if
|
|
+ the host SMMUv3 supports ATS and the associated passthrough device
|
|
+ supports ATS. If ``accel`` is enabled and ``ats`` is not configured,
|
|
+ the hypervisor default value is used.
|
|
+ :since:`Since 12.7.0` (QEMU/KVM and ``smmuv3`` model only)
|
|
+
|
|
+ ``ril``
|
|
+ The ``ril`` attribute with possible values ``on`` and ``off`` can be
|
|
+ used to report whether Range Invalidation for IOMMU devices with
|
|
+ ``accel`` set to ``on`` is compatible with host SMMUv3 support. If
|
|
+ ``accel`` is enabled and ``ril`` is not configured, the hypervisor
|
|
+ default value is used.
|
|
+ :since:`Since 12.7.0` (QEMU/KVM and ``smmuv3`` model only)
|
|
+
|
|
+ ``ssidsize``
|
|
+ The ``ssidsize`` attribute sets the number of bits used to
|
|
+ represent SubstreamIDs. A value of N allows SSIDs in the range
|
|
+ [0 .. 2^N - 1]. The valid range is 0-20, and a value greater than 0
|
|
+ is required for enabling PASID support, as doing so advertises PASID
|
|
+ capability to the vIOMMU. If ``accel`` is enabled and ``ssidsize`` is
|
|
+ not configured, the hypervisor default value is used.
|
|
+ :since:`Since 12.7.0` (QEMU/KVM and ``smmuv3`` model only)
|
|
+
|
|
+ ``oas``
|
|
+ The ``oas`` attribute sets the output address size in units of bits.
|
|
+ If ``accel`` is enabled and ``oas`` is not configured, the hypervisor
|
|
+ default value is used.
|
|
+ :since:`Since 12.7.0` (QEMU/KVM and ``smmuv3`` 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 94cfb27c1d..db44ba9a72 100644
|
|
--- a/src/conf/domain_conf.c
|
|
+++ b/src/conf/domain_conf.c
|
|
@@ -2863,6 +2863,10 @@ virDomainIOMMUDefNew(void)
|
|
|
|
iommu->pci_bus = -1;
|
|
|
|
+ iommu->ssid_size = -1;
|
|
+
|
|
+ iommu->oas = -1;
|
|
+
|
|
return g_steal_pointer(&iommu);
|
|
}
|
|
|
|
@@ -14746,6 +14750,26 @@ virDomainIOMMUDefParseXML(virDomainXMLOption *xmlopt,
|
|
&iommu->pci_bus, -1) < 0)
|
|
return NULL;
|
|
|
|
+ if (virXMLPropTristateSwitch(driver, "accel", VIR_XML_PROP_NONE,
|
|
+ &iommu->accel) < 0)
|
|
+ return NULL;
|
|
+
|
|
+ if (virXMLPropTristateSwitch(driver, "ats", VIR_XML_PROP_NONE,
|
|
+ &iommu->ats) < 0)
|
|
+ return NULL;
|
|
+
|
|
+ if (virXMLPropTristateSwitch(driver, "ril", VIR_XML_PROP_NONE,
|
|
+ &iommu->ril) < 0)
|
|
+ return NULL;
|
|
+
|
|
+ if (virXMLPropInt(driver, "ssidsize", 10, VIR_XML_PROP_NONE,
|
|
+ &iommu->ssid_size, -1) < 0)
|
|
+ return NULL;
|
|
+
|
|
+ if (virXMLPropInt(driver, "oas", 10, VIR_XML_PROP_NONE,
|
|
+ &iommu->oas, -1) < 0)
|
|
+ return NULL;
|
|
+
|
|
if ((granule = virXPathNode("./driver/granule", ctxt))) {
|
|
g_autofree char *mode = virXMLPropString(granule, "mode");
|
|
unsigned long long size;
|
|
@@ -16850,6 +16874,11 @@ virDomainIOMMUDefEquals(const virDomainIOMMUDef *a,
|
|
a->aw_bits != b->aw_bits ||
|
|
a->dma_translation != b->dma_translation ||
|
|
a->pci_bus != b->pci_bus ||
|
|
+ a->accel != b->accel ||
|
|
+ a->ats != b->ats ||
|
|
+ a->ril != b->ril ||
|
|
+ a->ssid_size != b->ssid_size ||
|
|
+ a->oas != b->oas ||
|
|
a->xtsup != b->xtsup ||
|
|
a->pt != b->pt ||
|
|
a->granule != b->granule)
|
|
@@ -22734,6 +22763,36 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDef *src,
|
|
dst->pci_bus, src->pci_bus);
|
|
return false;
|
|
}
|
|
+ if (src->accel != dst->accel) {
|
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
+ _("Target domain IOMMU device accel value '%1$d' does not match source '%2$d'"),
|
|
+ dst->accel, src->accel);
|
|
+ return false;
|
|
+ }
|
|
+ if (src->ats != dst->ats) {
|
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
+ _("Target domain IOMMU device ATS value '%1$d' does not match source '%2$d'"),
|
|
+ dst->ats, src->ats);
|
|
+ return false;
|
|
+ }
|
|
+ if (src->ril != dst->ril) {
|
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
+ _("Target domain IOMMU device ril value '%1$d' does not match source '%2$d'"),
|
|
+ dst->ril, src->ril);
|
|
+ return false;
|
|
+ }
|
|
+ if (src->ssid_size != dst->ssid_size) {
|
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
+ _("Target domain IOMMU device ssid_size value '%1$d' does not match source '%2$d'"),
|
|
+ dst->ssid_size, src->ssid_size);
|
|
+ return false;
|
|
+ }
|
|
+ if (src->oas != dst->oas) {
|
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
+ _("Target domain IOMMU device oas value '%1$d' does not match source '%2$d'"),
|
|
+ dst->oas, src->oas);
|
|
+ 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'"),
|
|
@@ -29204,6 +29263,26 @@ virDomainIOMMUDefFormat(virBuffer *buf,
|
|
virBufferAsprintf(&driverAttrBuf, " pciBus='%d'",
|
|
iommu->pci_bus);
|
|
}
|
|
+ if (iommu->accel != VIR_TRISTATE_SWITCH_ABSENT) {
|
|
+ virBufferAsprintf(&driverAttrBuf, " accel='%s'",
|
|
+ virTristateSwitchTypeToString(iommu->accel));
|
|
+ }
|
|
+ if (iommu->ats != VIR_TRISTATE_SWITCH_ABSENT) {
|
|
+ virBufferAsprintf(&driverAttrBuf, " ats='%s'",
|
|
+ virTristateSwitchTypeToString(iommu->ats));
|
|
+ }
|
|
+ if (iommu->ril != VIR_TRISTATE_SWITCH_ABSENT) {
|
|
+ virBufferAsprintf(&driverAttrBuf, " ril='%s'",
|
|
+ virTristateSwitchTypeToString(iommu->ril));
|
|
+ }
|
|
+ if (iommu->ssid_size >= 0) {
|
|
+ virBufferAsprintf(&driverAttrBuf, " ssidsize='%d'",
|
|
+ iommu->ssid_size);
|
|
+ }
|
|
+ if (iommu->oas >= 0) {
|
|
+ virBufferAsprintf(&driverAttrBuf, " oas='%d'",
|
|
+ iommu->oas);
|
|
+ }
|
|
if (iommu->granule != 0) {
|
|
if (iommu->granule == -1) {
|
|
virBufferAddLit(&driverChildBuf, "<granule mode='host'/>\n");
|
|
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
|
|
index 0c6c79c413..40ea6090f8 100644
|
|
--- a/src/conf/domain_conf.h
|
|
+++ b/src/conf/domain_conf.h
|
|
@@ -3105,6 +3105,11 @@ struct _virDomainIOMMUDef {
|
|
virTristateSwitch xtsup;
|
|
virTristateSwitch pt;
|
|
int granule; /* -1 means 'host', 0 unset, page size in KiB otherwise */
|
|
+ virTristateSwitch accel;
|
|
+ virTristateSwitch ats;
|
|
+ virTristateSwitch ril;
|
|
+ int ssid_size;
|
|
+ int oas;
|
|
};
|
|
|
|
typedef enum {
|
|
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
|
|
index 3946f92182..710a891904 100644
|
|
--- a/src/conf/domain_validate.c
|
|
+++ b/src/conf/domain_validate.c
|
|
@@ -3203,6 +3203,16 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
|
|
virDomainIOMMUModelTypeToString(iommu->model));
|
|
return -1;
|
|
}
|
|
+ if (iommu->accel != VIR_TRISTATE_SWITCH_ON &&
|
|
+ (iommu->ats != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ril != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ssid_size >= 0 ||
|
|
+ iommu->oas >= 0)) {
|
|
+ virReportError(VIR_ERR_XML_ERROR,
|
|
+ _("accel must be enabled for iommu model '%1$s' when setting ats, ril, ssidsize, or oas"),
|
|
+ virDomainIOMMUModelTypeToString(iommu->model));
|
|
+ return -1;
|
|
+ }
|
|
break;
|
|
case VIR_DOMAIN_IOMMU_MODEL_VIRTIO:
|
|
if (iommu->intremap != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
@@ -3210,7 +3220,12 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
|
|
iommu->eim != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
iommu->iotlb != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
- iommu->pci_bus >= 0) {
|
|
+ iommu->pci_bus >= 0 ||
|
|
+ iommu->accel != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ats != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ril != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ssid_size >= 0 ||
|
|
+ iommu->oas >= 0) {
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
_("iommu model '%1$s' doesn't support some additional attributes"),
|
|
virDomainIOMMUModelTypeToString(iommu->model));
|
|
@@ -3233,6 +3248,11 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
|
|
iommu->aw_bits != 0 ||
|
|
iommu->dma_translation != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
iommu->pci_bus >= 0 ||
|
|
+ iommu->accel != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ats != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ril != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ssid_size >= 0 ||
|
|
+ iommu->oas >= 0 ||
|
|
iommu->granule != 0) {
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
_("iommu model '%1$s' doesn't support some additional attributes"),
|
|
@@ -3245,6 +3265,11 @@ virDomainIOMMUDefValidate(const virDomainIOMMUDef *iommu)
|
|
if (iommu->pt != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
iommu->xtsup != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
iommu->pci_bus >= 0 ||
|
|
+ iommu->accel != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ats != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ril != VIR_TRISTATE_SWITCH_ABSENT ||
|
|
+ iommu->ssid_size >= 0 ||
|
|
+ iommu->oas >= 0 ||
|
|
iommu->granule != 0) {
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
_("iommu model '%1$s' doesn't support some additional attributes"),
|
|
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
|
|
index 121e4e06a6..c7d7ebc876 100644
|
|
--- a/src/conf/schemas/domaincommon.rng
|
|
+++ b/src/conf/schemas/domaincommon.rng
|
|
@@ -6454,6 +6454,31 @@
|
|
<empty/>
|
|
</element>
|
|
</optional>
|
|
+ <optional>
|
|
+ <attribute name="accel">
|
|
+ <ref name="virOnOff"/>
|
|
+ </attribute>
|
|
+ </optional>
|
|
+ <optional>
|
|
+ <attribute name="ats">
|
|
+ <ref name="virOnOff"/>
|
|
+ </attribute>
|
|
+ </optional>
|
|
+ <optional>
|
|
+ <attribute name="ril">
|
|
+ <ref name="virOnOff"/>
|
|
+ </attribute>
|
|
+ </optional>
|
|
+ <optional>
|
|
+ <attribute name="ssidsize">
|
|
+ <data type="int"/>
|
|
+ </attribute>
|
|
+ </optional>
|
|
+ <optional>
|
|
+ <attribute name="oas">
|
|
+ <data type="int"/>
|
|
+ </attribute>
|
|
+ </optional>
|
|
</element>
|
|
</optional>
|
|
<optional>
|
|
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
|
|
index e726dc661c..2d5eaa1e80 100644
|
|
--- a/src/qemu/qemu_command.c
|
|
+++ b/src/qemu/qemu_command.c
|
|
@@ -6276,6 +6276,8 @@ qemuBuildPCINestedSmmuv3DevProps(const virDomainDef *def,
|
|
{
|
|
g_autoptr(virJSONValue) props = NULL;
|
|
g_autofree char *bus = NULL;
|
|
+ g_autofree char *ssidsizeStr = NULL;
|
|
+ g_autofree char *oasStr = NULL;
|
|
virPCIDeviceAddress addr = { .bus = iommu->pci_bus };
|
|
|
|
bus = qemuBuildDeviceAddressPCIGetBus(def, &addr);
|
|
@@ -6286,10 +6288,23 @@ qemuBuildPCINestedSmmuv3DevProps(const virDomainDef *def,
|
|
return NULL;
|
|
}
|
|
|
|
+ if (iommu->ssid_size >= 0) {
|
|
+ ssidsizeStr = g_strdup_printf("%u", iommu->ssid_size);
|
|
+ }
|
|
+
|
|
+ if (iommu->oas >= 0) {
|
|
+ oasStr = g_strdup_printf("%u", iommu->oas);
|
|
+ }
|
|
+
|
|
if (virJSONValueObjectAdd(&props,
|
|
"s:driver", "arm-smmuv3",
|
|
"s:primary-bus", bus,
|
|
"s:id", iommu->info.alias,
|
|
+ "T:accel", iommu->accel,
|
|
+ "S:ats", qemuOnOffAuto(iommu->ats),
|
|
+ "S:ril", qemuOnOffAuto(iommu->ril),
|
|
+ "S:ssidsize", ssidsizeStr,
|
|
+ "S:oas", oasStr,
|
|
NULL) < 0)
|
|
return NULL;
|
|
|
|
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
|
|
index 2da99329c5..1093eb8363 100644
|
|
--- a/src/qemu/qemu_validate.c
|
|
+++ b/src/qemu/qemu_validate.c
|
|
@@ -5827,6 +5827,18 @@ qemuValidateDomainDeviceDefIOMMU(const virDomainIOMMUDef *iommu,
|
|
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
|
|
+ * .oas attributes as all of them were introduced in the same release,
|
|
+ * and these features are meant to be backported all together. */
|
|
+ if (iommu->model == VIR_DOMAIN_IOMMU_MODEL_SMMUV3 &&
|
|
+ iommu->accel != VIR_TRISTATE_SWITCH_ABSENT &&
|
|
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_ARM_SMMUV3_ACCEL)) {
|
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
+ _("iommu: accel is not supported with this QEMU binary"));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
if (iommu->granule > 0) {
|
|
/* QEMU supports only 4KiB, 8KiB, 16KiB and 64KiB granule size */
|
|
if (!(iommu->granule == 4 ||
|
|
--
|
|
2.55.0
|