]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/tegra: Use IOMMU groups
authorThierry Reding <treding@nvidia.com>
Thu, 12 Oct 2017 15:43:33 +0000 (17:43 +0200)
committerThierry Reding <treding@nvidia.com>
Thu, 21 Dec 2017 13:52:36 +0000 (14:52 +0100)
In order to support IOMMUs more generically and transparently handle the
ARM SMMU on Tegra186, move to using groups instead of devices for domain
attachment. An IOMMU group is a set of devices that share the same IOMMU
domain and is therefore a good match to represent what Tegra DRM needs.

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

index d118094a96c1641536f67d22ff0c9334cd22acb9..dc91911094fc82bd2a93c353a3964a9c91032c6d 100644 (file)
@@ -1748,6 +1748,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
 static int tegra_dc_init(struct host1x_client *client)
 {
        struct drm_device *drm = dev_get_drvdata(client->parent);
+       struct iommu_group *group = iommu_group_get(client->dev);
        unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
        struct tegra_dc *dc = host1x_client_to_dc(client);
        struct tegra_drm *tegra = drm->dev_private;
@@ -1759,12 +1760,17 @@ static int tegra_dc_init(struct host1x_client *client)
        if (!dc->syncpt)
                dev_warn(dc->dev, "failed to allocate syncpoint\n");
 
-       if (tegra->domain) {
-               err = iommu_attach_device(tegra->domain, dc->dev);
-               if (err < 0) {
-                       dev_err(dc->dev, "failed to attach to domain: %d\n",
-                               err);
-                       return err;
+       if (group && tegra->domain) {
+               if (group != tegra->group) {
+                       err = iommu_attach_group(tegra->domain, group);
+                       if (err < 0) {
+                               dev_err(dc->dev,
+                                       "failed to attach to domain: %d\n",
+                                       err);
+                               return err;
+                       }
+
+                       tegra->group = group;
                }
 
                dc->domain = tegra->domain;
@@ -1825,8 +1831,8 @@ cleanup:
        if (!IS_ERR(primary))
                drm_plane_cleanup(primary);
 
-       if (tegra->domain) {
-               iommu_detach_device(tegra->domain, dc->dev);
+       if (group && tegra->domain) {
+               iommu_detach_group(tegra->domain, group);
                dc->domain = NULL;
        }
 
@@ -1835,6 +1841,7 @@ cleanup:
 
 static int tegra_dc_exit(struct host1x_client *client)
 {
+       struct iommu_group *group = iommu_group_get(client->dev);
        struct tegra_dc *dc = host1x_client_to_dc(client);
        int err;
 
@@ -1846,8 +1853,8 @@ static int tegra_dc_exit(struct host1x_client *client)
                return err;
        }
 
-       if (dc->domain) {
-               iommu_detach_device(dc->domain, dc->dev);
+       if (group && dc->domain) {
+               iommu_detach_group(dc->domain, group);
                dc->domain = NULL;
        }
 
index c52bc5978d1c3eea0167d2bd5ed9c97f1bb1b4dd..da3d8c141aeef3774e29aba9b6aa58275b4f9c6f 100644 (file)
@@ -60,6 +60,7 @@ struct tegra_drm {
        struct drm_device *drm;
 
        struct iommu_domain *domain;
+       struct iommu_group *group;
        struct mutex mm_lock;
        struct drm_mm mm;
 
index d9664a34fb43fa35af310b86d1f35bc6161d9d10..f5794dd49f3b0b344bd16fa9fffbd8a635818d9d 100644 (file)
@@ -138,13 +138,14 @@ static const struct falcon_ops vic_falcon_ops = {
 static int vic_init(struct host1x_client *client)
 {
        struct tegra_drm_client *drm = host1x_to_drm_client(client);
+       struct iommu_group *group = iommu_group_get(client->dev);
        struct drm_device *dev = dev_get_drvdata(client->parent);
        struct tegra_drm *tegra = dev->dev_private;
        struct vic *vic = to_vic(drm);
        int err;
 
-       if (tegra->domain) {
-               err = iommu_attach_device(tegra->domain, vic->dev);
+       if (group && tegra->domain) {
+               err = iommu_attach_group(tegra->domain, group);
                if (err < 0) {
                        dev_err(vic->dev, "failed to attach to domain: %d\n",
                                err);
@@ -158,13 +159,13 @@ static int vic_init(struct host1x_client *client)
                vic->falcon.data = tegra;
                err = falcon_load_firmware(&vic->falcon);
                if (err < 0)
-                       goto detach_device;
+                       goto detach;
        }
 
        vic->channel = host1x_channel_request(client->dev);
        if (!vic->channel) {
                err = -ENOMEM;
-               goto detach_device;
+               goto detach;
        }
 
        client->syncpts[0] = host1x_syncpt_request(client, 0);
@@ -183,9 +184,9 @@ free_syncpt:
        host1x_syncpt_free(client->syncpts[0]);
 free_channel:
        host1x_channel_put(vic->channel);
-detach_device:
-       if (tegra->domain)
-               iommu_detach_device(tegra->domain, vic->dev);
+detach:
+       if (group && tegra->domain)
+               iommu_detach_group(tegra->domain, group);
 
        return err;
 }
@@ -193,6 +194,7 @@ detach_device:
 static int vic_exit(struct host1x_client *client)
 {
        struct tegra_drm_client *drm = host1x_to_drm_client(client);
+       struct iommu_group *group = iommu_group_get(client->dev);
        struct drm_device *dev = dev_get_drvdata(client->parent);
        struct tegra_drm *tegra = dev->dev_private;
        struct vic *vic = to_vic(drm);
@@ -206,7 +208,7 @@ static int vic_exit(struct host1x_client *client)
        host1x_channel_put(vic->channel);
 
        if (vic->domain) {
-               iommu_detach_device(vic->domain, vic->dev);
+               iommu_detach_group(vic->domain, group);
                vic->domain = NULL;
        }