diff options
author | Thierry Reding <treding@nvidia.com> | 2018-05-04 15:02:24 +0200 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2018-05-17 14:08:40 +0200 |
commit | 0c407de5ed1a329468122cbf4f3e727e0c1e3f36 (patch) | |
tree | 3f96f17886dcfc453e117f3820fb3c24f80133f1 /drivers/gpu/drm/tegra/drm.c | |
parent | 230630bd3834af0ea6ec75354ec21819de148ee1 (diff) | |
download | lwn-0c407de5ed1a329468122cbf4f3e727e0c1e3f36.tar.gz lwn-0c407de5ed1a329468122cbf4f3e727e0c1e3f36.zip |
drm/tegra: Refactor IOMMU attach/detach
Attaching to and detaching from an IOMMU uses the same code sequence in
every driver, so factor it out into separate helpers.
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/drm/tegra/drm.c')
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 7afe2f635f74..181e82c58a4f 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1114,6 +1114,52 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra, return 0; } +struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client, + bool shared) +{ + struct drm_device *drm = dev_get_drvdata(client->parent); + struct tegra_drm *tegra = drm->dev_private; + struct iommu_group *group = NULL; + int err; + + if (tegra->domain) { + group = iommu_group_get(client->dev); + if (!group) { + dev_err(client->dev, "failed to get IOMMU group\n"); + return ERR_PTR(-ENODEV); + } + + if (!shared || (shared && (group != tegra->group))) { + err = iommu_attach_group(tegra->domain, group); + if (err < 0) { + iommu_group_put(group); + return ERR_PTR(err); + } + + if (shared && !tegra->group) + tegra->group = group; + } + } + + return group; +} + +void host1x_client_iommu_detach(struct host1x_client *client, + struct iommu_group *group) +{ + struct drm_device *drm = dev_get_drvdata(client->parent); + struct tegra_drm *tegra = drm->dev_private; + + if (group) { + if (group == tegra->group) { + iommu_detach_group(tegra->domain, group); + tegra->group = NULL; + } + + iommu_group_put(group); + } +} + void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *dma) { struct iova *alloc; |