summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/tegra/drm.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2019-10-28 13:37:08 +0100
committerThierry Reding <treding@nvidia.com>2019-10-29 15:04:34 +0100
commit7edd7961e58d531d19758134919de13dac47bcbe (patch)
tree9bedf33b332b683e71b3810b10914613cfd21259 /drivers/gpu/drm/tegra/drm.c
parenta7303f7735717c95bf5f65c18c901c72e91dc55b (diff)
drm/tegra: Simplify IOMMU group selection
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>
Diffstat (limited to 'drivers/gpu/drm/tegra/drm.c')
-rw-r--r--drivers/gpu/drm/tegra/drm.c34
1 files changed, 20 insertions, 14 deletions
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 7480f575188d..9a1c1694604a 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -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);
}