diff options
author | Mikko Perttunen <mperttunen@nvidia.com> | 2016-12-14 13:16:14 +0200 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2017-04-05 18:11:43 +0200 |
commit | 404bfb78daf3bedafb0bfab24947059575cbea3d (patch) | |
tree | 59b8ed6b140ce74ffeb94e1488ee7818f3b02c18 /drivers/gpu/host1x/dev.c | |
parent | 8cadb01d2c2f520a890d1bc78b45471f21b9b76d (diff) | |
download | linux-404bfb78daf3bedafb0bfab24947059575cbea3d.tar.bz2 |
gpu: host1x: Add IOMMU support
Add support for the Host1x unit to be located behind
an IOMMU. This is required when gather buffers may be
allocated non-contiguously in physical memory, as can
be the case when TegraDRM is also using the IOMMU.
Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/host1x/dev.c')
-rw-r--r-- | drivers/gpu/host1x/dev.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index a62317af76ad..b386a0bf828a 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -27,6 +27,7 @@ #define CREATE_TRACE_POINTS #include <trace/events/host1x.h> +#undef CREATE_TRACE_POINTS #include "bus.h" #include "dev.h" @@ -168,16 +169,37 @@ static int host1x_probe(struct platform_device *pdev) return err; } + if (iommu_present(&platform_bus_type)) { + struct iommu_domain_geometry *geometry; + unsigned long order; + + host->domain = iommu_domain_alloc(&platform_bus_type); + if (!host->domain) + return -ENOMEM; + + err = iommu_attach_device(host->domain, &pdev->dev); + if (err) + goto fail_free_domain; + + geometry = &host->domain->geometry; + + order = __ffs(host->domain->pgsize_bitmap); + init_iova_domain(&host->iova, 1UL << order, + geometry->aperture_start >> order, + geometry->aperture_end >> order); + host->iova_end = geometry->aperture_end; + } + err = host1x_channel_list_init(host); if (err) { dev_err(&pdev->dev, "failed to initialize channel list\n"); - return err; + goto fail_detach_device; } err = clk_prepare_enable(host->clk); if (err < 0) { dev_err(&pdev->dev, "failed to enable clock\n"); - return err; + goto fail_detach_device; } err = host1x_syncpt_init(host); @@ -206,6 +228,15 @@ fail_deinit_syncpt: host1x_syncpt_deinit(host); fail_unprepare_disable: clk_disable_unprepare(host->clk); +fail_detach_device: + if (host->domain) { + put_iova_domain(&host->iova); + iommu_detach_device(host->domain, &pdev->dev); + } +fail_free_domain: + if (host->domain) + iommu_domain_free(host->domain); + return err; } @@ -218,6 +249,12 @@ static int host1x_remove(struct platform_device *pdev) host1x_syncpt_deinit(host); clk_disable_unprepare(host->clk); + if (host->domain) { + put_iova_domain(&host->iova); + iommu_detach_device(host->domain, &pdev->dev); + iommu_domain_free(host->domain); + } + return 0; } |