IOMMU device is attached to.
:since:`Since 11.10.0` (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
iommu->pci_bus = -1;
+ iommu->ssid_size = -1;
+
+ iommu->oas = -1;
+
return g_steal_pointer(&iommu);
}
&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;
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)
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'"),
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");
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 {
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 ||
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));
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"),
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"),
<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>
{
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);
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;
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 ||