What exynos calls exynos_iommu_detach_device is actually putting the iommu
into identity mode.

Move to the new core support for ARM_DMA_USE_IOMMU by defining
ops->identity_domain.

Tested-by: Marek Szyprowski <m.szyprow...@samsung.com>
Acked-by: Marek Szyprowski <m.szyprow...@samsung.com>
Reviewed-by: Jerry Snitselaar <jsnit...@redhat.com>
Signed-off-by: Jason Gunthorpe <j...@nvidia.com>
---
 drivers/iommu/exynos-iommu.c | 66 +++++++++++++++++-------------------
 1 file changed, 32 insertions(+), 34 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index c275fe71c4db32..5e12b85dfe8705 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -24,6 +24,7 @@
 
 typedef u32 sysmmu_iova_t;
 typedef u32 sysmmu_pte_t;
+static struct iommu_domain exynos_identity_domain;
 
 /* We do not consider super section mapping (16MB) */
 #define SECT_ORDER 20
@@ -829,7 +830,7 @@ static int __maybe_unused exynos_sysmmu_suspend(struct 
device *dev)
                struct exynos_iommu_owner *owner = dev_iommu_priv_get(master);
 
                mutex_lock(&owner->rpm_lock);
-               if (data->domain) {
+               if (&data->domain->domain != &exynos_identity_domain) {
                        dev_dbg(data->sysmmu, "saving state\n");
                        __sysmmu_disable(data);
                }
@@ -847,7 +848,7 @@ static int __maybe_unused exynos_sysmmu_resume(struct 
device *dev)
                struct exynos_iommu_owner *owner = dev_iommu_priv_get(master);
 
                mutex_lock(&owner->rpm_lock);
-               if (data->domain) {
+               if (&data->domain->domain != &exynos_identity_domain) {
                        dev_dbg(data->sysmmu, "restoring state\n");
                        __sysmmu_enable(data);
                }
@@ -980,17 +981,20 @@ static void exynos_iommu_domain_free(struct iommu_domain 
*iommu_domain)
        kfree(domain);
 }
 
-static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain,
-                                   struct device *dev)
+static int exynos_iommu_identity_attach(struct iommu_domain *identity_domain,
+                                       struct device *dev)
 {
-       struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain);
        struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev);
-       phys_addr_t pagetable = virt_to_phys(domain->pgtable);
+       struct exynos_iommu_domain *domain;
+       phys_addr_t pagetable;
        struct sysmmu_drvdata *data, *next;
        unsigned long flags;
 
-       if (!has_sysmmu(dev) || owner->domain != iommu_domain)
-               return;
+       if (owner->domain == identity_domain)
+               return 0;
+
+       domain = to_exynos_domain(owner->domain);
+       pagetable = virt_to_phys(domain->pgtable);
 
        mutex_lock(&owner->rpm_lock);
 
@@ -1009,15 +1013,25 @@ static void exynos_iommu_detach_device(struct 
iommu_domain *iommu_domain,
                list_del_init(&data->domain_node);
                spin_unlock(&data->lock);
        }
-       owner->domain = NULL;
+       owner->domain = identity_domain;
        spin_unlock_irqrestore(&domain->lock, flags);
 
        mutex_unlock(&owner->rpm_lock);
 
-       dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", __func__,
-               &pagetable);
+       dev_dbg(dev, "%s: Restored IOMMU to IDENTITY from pgtable %pa\n",
+               __func__, &pagetable);
+       return 0;
 }
 
+static struct iommu_domain_ops exynos_identity_ops = {
+       .attach_dev = exynos_iommu_identity_attach,
+};
+
+static struct iommu_domain exynos_identity_domain = {
+       .type = IOMMU_DOMAIN_IDENTITY,
+       .ops = &exynos_identity_ops,
+};
+
 static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain,
                                   struct device *dev)
 {
@@ -1026,12 +1040,11 @@ static int exynos_iommu_attach_device(struct 
iommu_domain *iommu_domain,
        struct sysmmu_drvdata *data;
        phys_addr_t pagetable = virt_to_phys(domain->pgtable);
        unsigned long flags;
+       int err;
 
-       if (!has_sysmmu(dev))
-               return -ENODEV;
-
-       if (owner->domain)
-               exynos_iommu_detach_device(owner->domain, dev);
+       err = exynos_iommu_identity_attach(&exynos_identity_domain, dev);
+       if (err)
+               return err;
 
        mutex_lock(&owner->rpm_lock);
 
@@ -1407,26 +1420,12 @@ static struct iommu_device 
*exynos_iommu_probe_device(struct device *dev)
        return &data->iommu;
 }
 
-static void exynos_iommu_set_platform_dma(struct device *dev)
-{
-       struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev);
-
-       if (owner->domain) {
-               struct iommu_group *group = iommu_group_get(dev);
-
-               if (group) {
-                       exynos_iommu_detach_device(owner->domain, dev);
-                       iommu_group_put(group);
-               }
-       }
-}
-
 static void exynos_iommu_release_device(struct device *dev)
 {
        struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev);
        struct sysmmu_drvdata *data;
 
-       exynos_iommu_set_platform_dma(dev);
+       WARN_ON(exynos_iommu_identity_attach(&exynos_identity_domain, dev));
 
        list_for_each_entry(data, &owner->controllers, owner_node)
                device_link_del(data->link);
@@ -1457,6 +1456,7 @@ static int exynos_iommu_of_xlate(struct device *dev,
 
                INIT_LIST_HEAD(&owner->controllers);
                mutex_init(&owner->rpm_lock);
+               owner->domain = &exynos_identity_domain;
                dev_iommu_priv_set(dev, owner);
        }
 
@@ -1471,11 +1471,9 @@ static int exynos_iommu_of_xlate(struct device *dev,
 }
 
 static const struct iommu_ops exynos_iommu_ops = {
+       .identity_domain = &exynos_identity_domain,
        .domain_alloc = exynos_iommu_domain_alloc,
        .device_group = generic_device_group,
-#ifdef CONFIG_ARM
-       .set_platform_dma_ops = exynos_iommu_set_platform_dma,
-#endif
        .probe_device = exynos_iommu_probe_device,
        .release_device = exynos_iommu_release_device,
        .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
-- 
2.42.0

Reply via email to