There would be some masters sharing the same IOMMU device. Put them in
the same iommu group and share the same iommu domain.

Signed-off-by: Jeffy Chen <jeffy.c...@rock-chips.com>
---

Changes in v2: None

 drivers/iommu/rockchip-iommu.c | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index c8de1456a016..6c316dd0dd2d 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -100,11 +100,13 @@ struct rk_iommu {
        struct iommu_device iommu;
        struct list_head node; /* entry in rk_iommu_domain.iommus */
        struct iommu_domain *domain; /* domain to which iommu is attached */
+       struct iommu_group *group;
        struct mutex pm_mutex; /* serializes power transitions */
 };
 
 struct rk_iommudata {
        struct device_link *link; /* runtime PM link from IOMMU to master */
+       struct iommu_domain *domain; /* domain to which device is attached */
        struct rk_iommu *iommu;
 };
 
@@ -964,6 +966,7 @@ static void rk_iommu_detach_device(struct iommu_domain 
*domain,
 {
        struct rk_iommu *iommu;
        struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
+       struct rk_iommudata *data = dev->archdata.iommu;
        unsigned long flags;
 
        /* Allow 'virtual devices' (eg drm) to detach from domain */
@@ -971,6 +974,12 @@ static void rk_iommu_detach_device(struct iommu_domain 
*domain,
        if (!iommu)
                return;
 
+       /* device already detached */
+       if (data->domain != domain)
+               return;
+
+       data->domain = NULL;
+
        dev_dbg(dev, "Detaching from iommu domain\n");
 
        /* iommu already detached */
@@ -994,6 +1003,7 @@ static int rk_iommu_attach_device(struct iommu_domain 
*domain,
 {
        struct rk_iommu *iommu;
        struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
+       struct rk_iommudata *data = dev->archdata.iommu;
        unsigned long flags;
        int ret;
 
@@ -1005,15 +1015,21 @@ static int rk_iommu_attach_device(struct iommu_domain 
*domain,
        if (!iommu)
                return 0;
 
+       /* device already attached */
+       if (data->domain == domain)
+               return 0;
+
+       if (data->domain)
+               rk_iommu_detach_device(data->domain, dev);
+
+       data->domain = domain;
+
        dev_dbg(dev, "Attaching to iommu domain\n");
 
        /* iommu already attached */
        if (iommu->domain == domain)
                return 0;
 
-       if (iommu->domain)
-               rk_iommu_detach_device(iommu->domain, dev);
-
        iommu->domain = domain;
 
        spin_lock_irqsave(&rk_domain->iommus_lock, flags);
@@ -1150,13 +1166,11 @@ static void rk_iommu_remove_device(struct device *dev)
 
 static struct iommu_group *rk_iommu_device_group(struct device *dev)
 {
-       struct iommu_group *group;
+       struct rk_iommu *iommu;
 
-       group = iommu_group_get(dev);
-       if (!group)
-               group = iommu_group_alloc();
+       iommu = rk_iommu_from_dev(dev);
 
-       return group;
+       return iommu ? iommu->group : NULL;
 }
 
 static int rk_iommu_of_xlate(struct device *dev,
@@ -1263,6 +1277,12 @@ static int rk_iommu_probe(struct platform_device *pdev)
        if (err)
                goto err_remove_sysfs;
 
+       iommu->group = iommu_group_alloc();
+       if (IS_ERR(iommu->group)) {
+               err = PTR_ERR(iommu->group);
+               goto err_unreg_iommu;
+       }
+
        /*
         * Use the first registered IOMMU device for domain to use with DMA
         * API, since a domain might not physically correspond to a single
@@ -1276,6 +1296,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
        pm_runtime_enable(dev);
 
        return 0;
+err_unreg_iommu:
+       iommu_device_unregister(&iommu->iommu);
 err_remove_sysfs:
        iommu_device_sysfs_remove(&iommu->iommu);
 err_put_clocks:
@@ -1289,6 +1311,7 @@ static int rk_iommu_remove(struct platform_device *pdev)
 
        pm_runtime_disable(&pdev->dev);
 
+       iommu_group_put(iommu->group);
        iommu_device_unregister(&iommu->iommu);
        iommu_device_sysfs_remove(&iommu->iommu);
        rk_iommu_put_clocks(iommu);
-- 
2.11.0


Reply via email to