Skip to content

Commit

Permalink
drm/tegra: Use the iommu dma_owner mechanism
Browse files Browse the repository at this point in the history
Tegra joins many platform devices onto the same iommu_domain and builds
sort-of a DMA API on top of it.

Given that iommu_attach/detatch_device_shared() has supported this usage
model. Each device that wants to use the special domain will use
suppress_auto_claim_dma_owner and call iommu_attach_device_shared() which
will use dma owner framework to lock out other usages of the group and
refcount the domain attachment.

When the last device calls detatch the domain will be disconnected.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Tested-by: Dmitry Osipenko <digetx@gmail.com> # Nexus7 T30
  • Loading branch information
jgunthorpe committed Jan 28, 2022
1 parent 7326ea1 commit ae38950
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 28 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/tegra/dc.c
Expand Up @@ -3275,4 +3275,5 @@ struct platform_driver tegra_dc_driver = {
},
.probe = tegra_dc_probe,
.remove = tegra_dc_remove,
.suppress_auto_claim_dma_owner = true,
};
55 changes: 27 additions & 28 deletions drivers/gpu/drm/tegra/drm.c
Expand Up @@ -941,12 +941,15 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra,
return 0;
}

/*
* Clients which use this function must set suppress_auto_claim_dma_owner in
* their platform_driver's device_driver struct.
*/
int host1x_client_iommu_attach(struct host1x_client *client)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(client->dev);
struct drm_device *drm = dev_get_drvdata(client->host);
struct tegra_drm *tegra = drm->dev_private;
struct iommu_group *group = NULL;
int err;

#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
Expand All @@ -965,48 +968,44 @@ int host1x_client_iommu_attach(struct host1x_client *client)
* not the shared IOMMU domain, don't try to attach it to a different
* domain. This allows using the IOMMU-backed DMA API.
*/
if (domain && domain != tegra->domain)
client->group = NULL;
if (!client->dev->iommu_group || (domain && domain != tegra->domain))
return iommu_device_set_dma_owner(client->dev,
DMA_OWNER_DMA_API, NULL);

if (!tegra->domain)
return 0;

if (tegra->domain) {
group = iommu_group_get(client->dev);
if (!group)
return -ENODEV;

if (domain != tegra->domain) {
err = iommu_attach_group(tegra->domain, group);
if (err < 0) {
iommu_group_put(group);
return err;
}
}
err = iommu_device_set_dma_owner(client->dev,
DMA_OWNER_PRIVATE_DOMAIN, NULL);
if (err)
return err;

tegra->use_explicit_iommu = true;
err = iommu_attach_device_shared(tegra->domain, client->dev);
if (err) {
iommu_device_release_dma_owner(client->dev,
DMA_OWNER_PRIVATE_DOMAIN);
return err;
}

client->group = group;

tegra->use_explicit_iommu = true;
client->group = client->dev->iommu_group;
return 0;
}

void host1x_client_iommu_detach(struct host1x_client *client)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(client->dev);
struct drm_device *drm = dev_get_drvdata(client->host);
struct tegra_drm *tegra = drm->dev_private;
struct iommu_domain *domain;

if (client->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);

iommu_group_put(client->group);
iommu_detach_device_shared(tegra->domain, client->dev);
iommu_device_release_dma_owner(client->dev,
DMA_OWNER_PRIVATE_DOMAIN);
client->group = NULL;
} else {
iommu_device_release_dma_owner(client->dev, DMA_OWNER_DMA_API);
}
}

Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/tegra/gr2d.c
Expand Up @@ -404,4 +404,5 @@ struct platform_driver tegra_gr2d_driver = {
},
.probe = gr2d_probe,
.remove = gr2d_remove,
.suppress_auto_claim_dma_owner = true,
};
1 change: 1 addition & 0 deletions drivers/gpu/drm/tegra/gr3d.c
Expand Up @@ -639,4 +639,5 @@ struct platform_driver tegra_gr3d_driver = {
},
.probe = gr3d_probe,
.remove = gr3d_remove,
.suppress_auto_claim_dma_owner = true,
};
1 change: 1 addition & 0 deletions drivers/gpu/drm/tegra/vic.c
Expand Up @@ -526,6 +526,7 @@ struct platform_driver tegra_vic_driver = {
},
.probe = vic_probe,
.remove = vic_remove,
.suppress_auto_claim_dma_owner = true,
};

#if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC)
Expand Down

0 comments on commit ae38950

Please sign in to comment.