Add support for SVA domain allocation and provide an SVA-specific
iommu_domain_ops.

Signed-off-by: Lu Baolu <[email protected]>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 14 ++++++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 45 +++++++++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 13 +++++-
 3 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index cd48590ada30..7631c00fdcbd 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -759,6 +759,10 @@ struct iommu_sva *arm_smmu_sva_bind(struct device *dev, 
struct mm_struct *mm,
 void arm_smmu_sva_unbind(struct iommu_sva *handle);
 u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle);
 void arm_smmu_sva_notifier_synchronize(void);
+int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
+                                 struct device *dev, ioasid_t id);
+void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
+                                  struct device *dev, ioasid_t id);
 #else /* CONFIG_ARM_SMMU_V3_SVA */
 static inline bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
 {
@@ -804,5 +808,15 @@ static inline u32 arm_smmu_sva_get_pasid(struct iommu_sva 
*handle)
 }
 
 static inline void arm_smmu_sva_notifier_synchronize(void) {}
+
+static inline int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
+                                               struct device *dev, ioasid_t id)
+{
+       return -ENODEV;
+}
+
+static inline void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
+                                                struct device *dev,
+                                                ioasid_t id) {}
 #endif /* CONFIG_ARM_SMMU_V3_SVA */
 #endif /* _ARM_SMMU_V3_H */
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 22ddd05bbdcd..1e114b9dc17f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -534,3 +534,48 @@ void arm_smmu_sva_notifier_synchronize(void)
         */
        mmu_notifier_synchronize();
 }
+
+int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
+                                 struct device *dev, ioasid_t id)
+{
+       int ret = 0;
+       struct iommu_sva *handle;
+       struct mm_struct *mm = domain->sva_cookie;
+       struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+
+       if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1 ||
+           domain->type != IOMMU_DOMAIN_SVA || !mm)
+               return -EINVAL;
+
+       mutex_lock(&sva_lock);
+       handle = __arm_smmu_sva_bind(dev, mm);
+       if (IS_ERR_OR_NULL(handle))
+               ret = PTR_ERR(handle);
+       mutex_unlock(&sva_lock);
+
+       return ret;
+}
+
+void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
+                                  struct device *dev, ioasid_t id)
+{
+       struct arm_smmu_bond *bond = NULL, *t;
+       struct mm_struct *mm = domain->sva_cookie;
+       struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+
+       mutex_lock(&sva_lock);
+       list_for_each_entry(t, &master->bonds, list) {
+               if (t->mm == mm) {
+                       bond = t;
+                       break;
+               }
+       }
+
+       if (!WARN_ON(!bond) && refcount_dec_and_test(&bond->refs)) {
+               list_del(&bond->list);
+               arm_smmu_mmu_notifier_put(bond->smmu_mn);
+               iommu_sva_free_pasid(bond->mm);
+               kfree(bond);
+       }
+       mutex_unlock(&sva_lock);
+}
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 8e262210b5ad..2e9d3cd30510 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -88,6 +88,8 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
        { 0, NULL},
 };
 
+static void arm_smmu_domain_free(struct iommu_domain *domain);
+
 static void parse_driver_options(struct arm_smmu_device *smmu)
 {
        int i = 0;
@@ -1995,6 +1997,12 @@ static bool arm_smmu_capable(enum iommu_cap cap)
        }
 }
 
+static const struct iommu_domain_ops arm_smmu_sva_domain_ops = {
+       .attach_dev_pasid       = arm_smmu_sva_attach_dev_pasid,
+       .detach_dev_pasid       = arm_smmu_sva_detach_dev_pasid,
+       .free                   = arm_smmu_domain_free,
+};
+
 static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 {
        struct arm_smmu_domain *smmu_domain;
@@ -2002,7 +2010,8 @@ static struct iommu_domain 
*arm_smmu_domain_alloc(unsigned type)
        if (type != IOMMU_DOMAIN_UNMANAGED &&
            type != IOMMU_DOMAIN_DMA &&
            type != IOMMU_DOMAIN_DMA_FQ &&
-           type != IOMMU_DOMAIN_IDENTITY)
+           type != IOMMU_DOMAIN_IDENTITY &&
+           type != IOMMU_DOMAIN_SVA)
                return NULL;
 
        /*
@@ -2018,6 +2027,8 @@ static struct iommu_domain 
*arm_smmu_domain_alloc(unsigned type)
        INIT_LIST_HEAD(&smmu_domain->devices);
        spin_lock_init(&smmu_domain->devices_lock);
        INIT_LIST_HEAD(&smmu_domain->mmu_notifiers);
+       if (type == IOMMU_DOMAIN_SVA)
+               smmu_domain->domain.ops = &arm_smmu_sva_domain_ops;
 
        return &smmu_domain->domain;
 }
-- 
2.25.1

_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to