On 16.05.2023 02:00, Jason Gunthorpe wrote:
> 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.
>
> Signed-off-by: Jason Gunthorpe <j...@nvidia.com>

Acked-by: Marek Szyprowski

> ---
>   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,

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

Reply via email to