The ``iommu`` element can be used to add an IOMMU device. :since:`Since 2.1.0`
-Example:
+Examples:
::
</devices>
...
+
+ ...
+ <devices>
+ <iommu model='virtio'>
+ <driver aw_bits='48'>
+ <granule size='64' unit='KiB'/>
+ </driver>
+ </iommu>
+ </devices>
+ ...
+
``model``
Supported values are ``intel`` (for Q35 guests) ``smmuv3``
(:since:`since 5.5.0`, for ARM virt guests), ``virtio``
The ``pciBus`` attribute notes the index of the controller that an
IOMMU device is attached to. (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
+than the host. :since:`Since 12.1.0` (QEMU/KVM and ``virtio`` model only).
+There are two possible options:
+
+::
+
+ <iommu model='virtio'>
+ <driver>
+ <granule mode='host'/>
+ </driver>
+ </iommu>
+
+ <iommu model='virtio'>
+ <driver>
+ <granule size='64' unit='KiB'/>
+ </driver>
+ </iommu>
+
+The ``mode='host'`` case matches the host page size, the other sets desired
+granule size. Please note that hypervisor might support only some selected
+values. For instance, QEMU supports only 4KiB, 8KiB, 16KiB and 64KiB large
+granules.
+
The ``virtio`` IOMMU devices can further have ``address`` element as described
in `Device addresses`_ (address has to by type of ``pci``).
);
+/*virDomainIOMMUGranuleModeTypeToString:
+ * @val: value to format
+ *
+ * Reuturns: an allocated string. Caller must free it.
+ */
+static char *
+virDomainIOMMUGranuleModeTypeToString(int val)
+{
+ if (val == -1)
+ return g_strdup("host");
+
+ return g_strdup_printf("%dKiB", val);
+}
+
+
static virClass *virDomainObjClass;
static virClass *virDomainXMLOptionClass;
static void virDomainObjDispose(void *obj);
return NULL;
if ((driver = virXPathNode("./driver", ctxt))) {
+ xmlNodePtr granule;
+
if (virXMLPropTristateSwitch(driver, "intremap", VIR_XML_PROP_NONE,
&iommu->intremap) < 0)
return NULL;
if (virXMLPropInt(driver, "pciBus", 10, VIR_XML_PROP_NONE,
&iommu->pci_bus, -1) < 0)
return NULL;
+
+ if ((granule = virXPathNode("./driver/granule", ctxt))) {
+ g_autofree char *mode = virXMLPropString(granule, "mode");
+ unsigned long long size;
+ int rc;
+
+ rc = virDomainParseMemory("./driver/granule/@size",
+ "./driver/granule/@unit",
+ ctxt, &size, false, false);
+ if (rc < 0) {
+ return NULL;
+ } else if (rc > 0) {
+ if (mode) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("'mode' and 'size' can't be specified at the same time for 'granule'"));
+ return NULL;
+ }
+
+ if (VIR_ASSIGN_IS_OVERFLOW(iommu->granule, size)) {
+ virReportError(VIR_ERR_OVERFLOW, "%s", _("size value too large"));
+ return NULL;
+ }
+ } else {
+ if (STREQ_NULLABLE(mode, "host")) {
+ iommu->granule = -1;
+ } else if (mode) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid value for attribute '%1$s' in element '%2$s': '%3$s'."),
+ "mode", "granule", mode);
+ return NULL;
+ }
+ }
+ }
}
if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt,
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 != b->granule)
return false;
if (a->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
virTristateSwitchTypeToString(src->xtsup));
return false;
}
+ if (src->granule != dst->granule) {
+ g_autofree char *src_granule = virDomainIOMMUGranuleModeTypeToString(src->granule);
+ g_autofree char *dst_granule = virDomainIOMMUGranuleModeTypeToString(dst->granule);
+
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain IOMMU device granule '%1$s' does not match source '%2$s'"),
+ dst_granule,
+ src_granule);
+ return false;
+ }
return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info);
}
g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) driverChildBuf = VIR_BUFFER_INIT_CHILD(&childBuf);
if (iommu->intremap != VIR_TRISTATE_SWITCH_ABSENT) {
virBufferAsprintf(&driverAttrBuf, " intremap='%s'",
virBufferAsprintf(&driverAttrBuf, " pciBus='%d'",
iommu->pci_bus);
}
+ if (iommu->granule != 0) {
+ if (iommu->granule == -1) {
+ virBufferAddLit(&driverChildBuf, "<granule mode='host'/>\n");
+ } else {
+ virBufferAsprintf(&driverChildBuf,
+ "<granule size='%d' unit='KiB'/>\n",
+ iommu->granule);
+ }
+ }
- virXMLFormatElement(&childBuf, "driver", &driverAttrBuf, NULL);
+ virXMLFormatElement(&childBuf, "driver", &driverAttrBuf, &driverChildBuf);
virDomainDeviceInfoFormat(&childBuf, &iommu->info, 0);
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 != 0) {
virReportError(VIR_ERR_XML_ERROR,
_("iommu model '%1$s' doesn't support some additional attributes"),
virDomainIOMMUModelTypeToString(iommu->model));
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 != 0) {
virReportError(VIR_ERR_XML_ERROR,
_("iommu model '%1$s' doesn't support some additional attributes"),
virDomainIOMMUModelTypeToString(iommu->model));
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 != 0) {
virReportError(VIR_ERR_XML_ERROR,
_("iommu model '%1$s' doesn't support some additional attributes"),
virDomainIOMMUModelTypeToString(iommu->model));