virtio-iommu has a mode where the IDENTITY domain is actually a paging
domain with an identity mapping covering some of the system address
space manually created.

To support this add a new domain_alloc_identity() op that accepts
the struct device so that virtio can allocate and fully finalize a
paging domain to return.

Signed-off-by: Jason Gunthorpe <j...@nvidia.com>
---
 drivers/iommu/iommu.c        | 20 ++++++++++++--------
 drivers/iommu/virtio-iommu.c | 11 ++---------
 include/linux/iommu.h        |  4 ++++
 3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 870c3cdbd0f622..ee33d26dfcd40d 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1595,15 +1595,19 @@ static struct iommu_domain 
*__iommu_alloc_identity_domain(struct device *dev)
        if (ops->identity_domain)
                return ops->identity_domain;
 
-       /* Older drivers create the identity domain via ops->domain_alloc() */
-       if (!ops->domain_alloc)
+       if (ops->domain_alloc_identity) {
+               domain = ops->domain_alloc_identity(dev);
+               if (IS_ERR(domain))
+                       return domain;
+       } else if (ops->domain_alloc) {
+               domain = ops->domain_alloc(IOMMU_DOMAIN_IDENTITY);
+               if (!domain)
+                       return ERR_PTR(-ENOMEM);
+               if (IS_ERR(domain))
+                       return domain;
+       } else {
                return ERR_PTR(-EOPNOTSUPP);
-
-       domain = ops->domain_alloc(IOMMU_DOMAIN_IDENTITY);
-       if (IS_ERR(domain))
-               return domain;
-       if (!domain)
-               return ERR_PTR(-ENOMEM);
+       }
 
        iommu_domain_init(domain, IOMMU_DOMAIN_IDENTITY, ops);
        return domain;
diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c
index 55a2188197c621..2287b89967067d 100644
--- a/drivers/iommu/virtio-iommu.c
+++ b/drivers/iommu/virtio-iommu.c
@@ -1007,7 +1007,7 @@ static void viommu_get_resv_regions(struct device *dev, 
struct list_head *head)
        iommu_dma_get_resv_regions(dev, head);
 }
 
-static struct iommu_ops viommu_ops;
+static const struct iommu_ops viommu_ops;
 static struct virtio_driver virtio_iommu_drv;
 
 static int viommu_match_node(struct device *dev, const void *data)
@@ -1095,8 +1095,7 @@ static bool viommu_capable(struct device *dev, enum 
iommu_cap cap)
        }
 }
 
-static struct iommu_ops viommu_ops = {
-       .identity_domain        = &viommu_identity_domain.domain,
+static const struct iommu_ops viommu_ops = {
        .capable                = viommu_capable,
        .domain_alloc           = viommu_domain_alloc,
        .probe_device           = viommu_probe_device,
@@ -1224,12 +1223,6 @@ static int viommu_probe(struct virtio_device *vdev)
        if (virtio_has_feature(viommu->vdev, VIRTIO_IOMMU_F_BYPASS_CONFIG)) {
                viommu->identity_domain_id = viommu->first_domain;
                viommu->first_domain++;
-       } else {
-               /*
-                * Assume the VMM is sensible and it either supports bypass on
-                * all instances or no instances.
-                */
-               viommu_ops.identity_domain = NULL;
        }
 
        viommu_ops.pgsize_bitmap = viommu->pgsize_bitmap;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 38c65e92ecd091..6389d59178ba3f 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -557,6 +557,9 @@ iommu_copy_struct_from_full_user_array(void *kdst, size_t 
kdst_entry_size,
  * @domain_alloc: allocate and return an iommu domain if success. Otherwise
  *                NULL is returned. The domain is not fully initialized until
  *                the caller iommu_domain_alloc() returns.
+ * @domain_alloc_identity: allocate an IDENTITY domain. Drivers should prefer 
to
+ *                         use identity_domain instead. This should only be 
used
+ *                         if dynamic logic is necessary.
  * @domain_alloc_paging_flags: Allocate an iommu domain corresponding to the
  *                     input parameters as defined in
  *                     include/uapi/linux/iommufd.h. The @user_data can be
@@ -615,6 +618,7 @@ struct iommu_ops {
 
        /* Domain allocation and freeing by the iommu driver */
        struct iommu_domain *(*domain_alloc)(unsigned iommu_domain_type);
+       struct iommu_domain *(*domain_alloc_identity)(struct device *dev);
        struct iommu_domain *(*domain_alloc_paging_flags)(
                struct device *dev, u32 flags,
                const struct iommu_user_data *user_data);
-- 
2.43.0


Reply via email to