[PATCH v1 5/8] vfio/type1: Report 1st-level/stage-1 format to userspace

From: Liu, Yi L
Date: Sun Mar 22 2020 - 08:26:46 EST


From: Liu Yi L <yi.l.liu@xxxxxxxxx>

VFIO exposes IOMMU nesting translation (a.k.a dual stage translation)
capability to userspace. Thus applications like QEMU could support
vIOMMU with hardware's nesting translation capability for pass-through
devices. Before setting up nesting translation for pass-through devices,
QEMU and other applications need to learn the supported 1st-lvl/stage-1
translation structure format like page table format.

Take vSVA (virtual Shared Virtual Addressing) as an example, to support
vSVA for pass-through devices, QEMU setup nesting translation for pass-
through devices. The guest page table are configured to host as 1st-lvl/
stage-1 page table. Therefore, guest format should be compatible with
host side.

This patch reports the supported 1st-lvl/stage-1 page table format on the
current platform to userspace. QEMU and other alike applications should
use this format info when trying to setup IOMMU nesting translation on
host IOMMU.

Cc: Kevin Tian <kevin.tian@xxxxxxxxx>
CC: Jacob Pan <jacob.jun.pan@xxxxxxxxxxxxxxx>
Cc: Alex Williamson <alex.williamson@xxxxxxxxxx>
Cc: Eric Auger <eric.auger@xxxxxxxxxx>
Cc: Jean-Philippe Brucker <jean-philippe@xxxxxxxxxx>
Signed-off-by: Liu Yi L <yi.l.liu@xxxxxxxxx>
---
drivers/vfio/vfio_iommu_type1.c | 56 +++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/vfio.h | 1 +
2 files changed, 57 insertions(+)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 9aa2a67..82a9e0b 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -2234,11 +2234,66 @@ static int vfio_iommu_type1_pasid_free(struct vfio_iommu *iommu,
return ret;
}

+static int vfio_iommu_get_stage1_format(struct vfio_iommu *iommu,
+ u32 *stage1_format)
+{
+ struct vfio_domain *domain;
+ u32 format = 0, tmp_format = 0;
+ int ret;
+
+ mutex_lock(&iommu->lock);
+ if (list_empty(&iommu->domain_list)) {
+ mutex_unlock(&iommu->lock);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(domain, &iommu->domain_list, next) {
+ if (iommu_domain_get_attr(domain->domain,
+ DOMAIN_ATTR_PASID_FORMAT, &format)) {
+ ret = -EINVAL;
+ format = 0;
+ goto out_unlock;
+ }
+ /*
+ * format is always non-zero (the first format is
+ * IOMMU_PASID_FORMAT_INTEL_VTD which is 1). For
+ * the reason of potential different backed IOMMU
+ * formats, here we expect to have identical formats
+ * in the domain list, no mixed formats support.
+ * return -EINVAL to fail the attempt of setup
+ * VFIO_TYPE1_NESTING_IOMMU if non-identical formats
+ * are detected.
+ */
+ if (tmp_format && tmp_format != format) {
+ ret = -EINVAL;
+ format = 0;
+ goto out_unlock;
+ }
+
+ tmp_format = format;
+ }
+ ret = 0;
+
+out_unlock:
+ if (format)
+ *stage1_format = format;
+ mutex_unlock(&iommu->lock);
+ return ret;
+}
+
static int vfio_iommu_info_add_nesting_cap(struct vfio_iommu *iommu,
struct vfio_info_cap *caps)
{
struct vfio_info_cap_header *header;
struct vfio_iommu_type1_info_cap_nesting *nesting_cap;
+ u32 formats = 0;
+ int ret;
+
+ ret = vfio_iommu_get_stage1_format(iommu, &formats);
+ if (ret) {
+ pr_warn("Failed to get stage-1 format\n");
+ return ret;
+ }

header = vfio_info_cap_add(caps, sizeof(*nesting_cap),
VFIO_IOMMU_TYPE1_INFO_CAP_NESTING, 1);
@@ -2254,6 +2309,7 @@ static int vfio_iommu_info_add_nesting_cap(struct vfio_iommu *iommu,
/* nesting iommu type supports PASID requests (alloc/free) */
nesting_cap->nesting_capabilities |= VFIO_IOMMU_PASID_REQS;
}
+ nesting_cap->stage1_formats = formats;

return 0;
}
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index ed9881d..ebeaf3e 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -763,6 +763,7 @@ struct vfio_iommu_type1_info_cap_nesting {
struct vfio_info_cap_header header;
#define VFIO_IOMMU_PASID_REQS (1 << 0)
__u32 nesting_capabilities;
+ __u32 stage1_formats;
};

#define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12)
--
2.7.4