]> git.baikalelectronics.ru Git - kernel.git/commitdiff
drm/tegra: Simplify IOMMU group selection
authorThierry Reding <treding@nvidia.com>
Mon, 28 Oct 2019 12:37:08 +0000 (13:37 +0100)
committerThierry Reding <treding@nvidia.com>
Tue, 29 Oct 2019 14:04:34 +0000 (15:04 +0100)
All the devices that make up the DRM device are now part of the same
IOMMU group. This simplifies the handling of the IOMMU attachment and
also avoids exhausting the number of IOMMUs available on early Tegra
SoC generations.

Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/gr2d.c
drivers/gpu/drm/tegra/gr3d.c
drivers/gpu/drm/tegra/vic.c

index 54966f5381415994cb4d56ea775028dd3a37ccfb..36c36b295ab1000560859f9f44b6dd4d52f3ea44 100644 (file)
@@ -2014,7 +2014,7 @@ static int tegra_dc_init(struct host1x_client *client)
        if (!dc->syncpt)
                dev_warn(dc->dev, "failed to allocate syncpoint\n");
 
-       err = host1x_client_iommu_attach(client, true);
+       err = host1x_client_iommu_attach(client);
        if (err < 0) {
                dev_err(client->dev, "failed to attach to domain: %d\n", err);
                return err;
index 7480f575188ddbac059138221475fffe64727221..9a1c1694604a5f78b3a83ab915ae5a8a2eb173b9 100644 (file)
@@ -904,7 +904,7 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra,
        return 0;
 }
 
-int host1x_client_iommu_attach(struct host1x_client *client, bool shared)
+int host1x_client_iommu_attach(struct host1x_client *client)
 {
        struct drm_device *drm = dev_get_drvdata(client->parent);
        struct tegra_drm *tegra = drm->dev_private;
@@ -912,29 +912,30 @@ int host1x_client_iommu_attach(struct host1x_client *client, bool shared)
        int err;
 
        if (tegra->domain) {
+               struct iommu_domain *domain;
+
                group = iommu_group_get(client->dev);
                if (!group) {
                        dev_err(client->dev, "failed to get IOMMU group\n");
                        return -ENODEV;
                }
 
-               if (!shared || (shared && (group != tegra->group))) {
 #if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
-                       if (client->dev->archdata.mapping) {
-                               struct dma_iommu_mapping *mapping =
-                                       to_dma_iommu_mapping(client->dev);
-                               arm_iommu_detach_device(client->dev);
-                               arm_iommu_release_mapping(mapping);
-                       }
+               if (client->dev->archdata.mapping) {
+                       struct dma_iommu_mapping *mapping =
+                               to_dma_iommu_mapping(client->dev);
+                       arm_iommu_detach_device(client->dev);
+                       arm_iommu_release_mapping(mapping);
+               }
 #endif
+
+               domain = iommu_get_domain_for_dev(client->dev);
+               if (domain != tegra->domain) {
                        err = iommu_attach_group(tegra->domain, group);
                        if (err < 0) {
                                iommu_group_put(group);
                                return err;
                        }
-
-                       if (shared && !tegra->group)
-                               tegra->group = group;
                }
        }
 
@@ -947,12 +948,17 @@ void host1x_client_iommu_detach(struct host1x_client *client)
 {
        struct drm_device *drm = dev_get_drvdata(client->parent);
        struct tegra_drm *tegra = drm->dev_private;
+       struct iommu_domain *domain;
 
        if (client->group) {
-               if (client->group == tegra->group) {
+               /*
+                * Devices that are part of the same group may no longer be
+                * attached to a domain at this point because their group may
+                * have been detached by an earlier client.
+                */
+               domain = iommu_get_domain_for_dev(client->dev);
+               if (domain)
                        iommu_detach_group(tegra->domain, client->group);
-                       tegra->group = NULL;
-               }
 
                iommu_group_put(client->group);
        }
index 8b812bb52e5b1f2832acc5d7a91ca4617e300e28..28f2820a73714a5c5c90906330dd09d74cd201f3 100644 (file)
@@ -36,7 +36,6 @@ struct tegra_drm {
        struct drm_device *drm;
 
        struct iommu_domain *domain;
-       struct iommu_group *group;
        struct mutex mm_lock;
        struct drm_mm mm;
 
@@ -100,7 +99,7 @@ int tegra_drm_register_client(struct tegra_drm *tegra,
                              struct tegra_drm_client *client);
 int tegra_drm_unregister_client(struct tegra_drm *tegra,
                                struct tegra_drm_client *client);
-int host1x_client_iommu_attach(struct host1x_client *client, bool shared);
+int host1x_client_iommu_attach(struct host1x_client *client);
 void host1x_client_iommu_detach(struct host1x_client *client);
 
 int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
index 5d5af9a05c180e01b2e4974619a24516fb50120d..1fc4e56c7cc5a15a75ee28a0074025ff929d1148 100644 (file)
@@ -50,7 +50,7 @@ static int gr2d_init(struct host1x_client *client)
                goto put;
        }
 
-       err = host1x_client_iommu_attach(client, false);
+       err = host1x_client_iommu_attach(client);
        if (err < 0) {
                dev_err(client->dev, "failed to attach to domain: %d\n", err);
                goto free;
index c249a6bd8d515a824333815c702dd36c37b851f0..24fae0f64032d9bef824ad141836069355a5f3f4 100644 (file)
@@ -59,7 +59,7 @@ static int gr3d_init(struct host1x_client *client)
                goto put;
        }
 
-       err = host1x_client_iommu_attach(client, false);
+       err = host1x_client_iommu_attach(client);
        if (err < 0) {
                dev_err(client->dev, "failed to attach to domain: %d\n", err);
                goto free;
index d34b1ada422c11c182d0923ae621a9efc2af96af..603f41ed4b81e9f5e679bee2e11e7d842ddee9e5 100644 (file)
@@ -187,7 +187,7 @@ static int vic_init(struct host1x_client *client)
        struct vic *vic = to_vic(drm);
        int err;
 
-       err = host1x_client_iommu_attach(client, false);
+       err = host1x_client_iommu_attach(client);
        if (err < 0) {
                dev_err(vic->dev, "failed to attach to domain: %d\n", err);
                return err;