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>
This commit is contained in:
Mikko Perttunen
2016-12-14 13:16:14 +02:00
committed by Thierry Reding
parent 8cadb01d2c
commit 404bfb78da
7 changed files with 177 additions and 39 deletions

View File

@@ -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;
}