mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-20 11:13:58 +08:00
drm/nouveau/platform: probe IOMMU if present
Tegra SoCs have an IOMMU that can be used to present non-contiguous physical memory as contiguous to the GPU and maximize the use of large pages in the GPU MMU, leading to performance gains. This patch adds support for probing such a IOMMU if present and make its properties available in the nouveau_platform_gpu structure so subsystems can take advantage of it. Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
5dc240bcfe
commit
58fd9375c2
@ -27,6 +27,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <soc/tegra/fuse.h>
|
||||
#include <soc/tegra/pmc.h>
|
||||
|
||||
@ -91,6 +92,71 @@ static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nouveau_platform_probe_iommu(struct device *dev,
|
||||
struct nouveau_platform_gpu *gpu)
|
||||
{
|
||||
int err;
|
||||
unsigned long pgsize_bitmap;
|
||||
|
||||
mutex_init(&gpu->iommu.mutex);
|
||||
|
||||
if (iommu_present(&platform_bus_type)) {
|
||||
gpu->iommu.domain = iommu_domain_alloc(&platform_bus_type);
|
||||
if (IS_ERR(gpu->iommu.domain))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* A IOMMU is only usable if it supports page sizes smaller
|
||||
* or equal to the system's PAGE_SIZE, with a preference if
|
||||
* both are equal.
|
||||
*/
|
||||
pgsize_bitmap = gpu->iommu.domain->ops->pgsize_bitmap;
|
||||
if (pgsize_bitmap & PAGE_SIZE) {
|
||||
gpu->iommu.pgshift = PAGE_SHIFT;
|
||||
} else {
|
||||
gpu->iommu.pgshift = fls(pgsize_bitmap & ~PAGE_MASK);
|
||||
if (gpu->iommu.pgshift == 0) {
|
||||
dev_warn(dev, "unsupported IOMMU page size\n");
|
||||
goto free_domain;
|
||||
}
|
||||
gpu->iommu.pgshift -= 1;
|
||||
}
|
||||
|
||||
err = iommu_attach_device(gpu->iommu.domain, dev);
|
||||
if (err)
|
||||
goto free_domain;
|
||||
|
||||
err = nvkm_mm_init(&gpu->iommu._mm, 0,
|
||||
(1ULL << 40) >> gpu->iommu.pgshift, 1);
|
||||
if (err)
|
||||
goto detach_device;
|
||||
|
||||
gpu->iommu.mm = &gpu->iommu._mm;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
detach_device:
|
||||
iommu_detach_device(gpu->iommu.domain, dev);
|
||||
|
||||
free_domain:
|
||||
iommu_domain_free(gpu->iommu.domain);
|
||||
|
||||
error:
|
||||
gpu->iommu.domain = NULL;
|
||||
gpu->iommu.pgshift = 0;
|
||||
dev_err(dev, "cannot initialize IOMMU MM\n");
|
||||
}
|
||||
|
||||
static void nouveau_platform_remove_iommu(struct device *dev,
|
||||
struct nouveau_platform_gpu *gpu)
|
||||
{
|
||||
if (gpu->iommu.domain) {
|
||||
iommu_detach_device(gpu->iommu.domain, dev);
|
||||
iommu_domain_free(gpu->iommu.domain);
|
||||
}
|
||||
}
|
||||
|
||||
static int nouveau_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct nouveau_platform_gpu *gpu;
|
||||
@ -118,6 +184,8 @@ static int nouveau_platform_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(gpu->clk_pwr))
|
||||
return PTR_ERR(gpu->clk_pwr);
|
||||
|
||||
nouveau_platform_probe_iommu(&pdev->dev, gpu);
|
||||
|
||||
err = nouveau_platform_power_up(gpu);
|
||||
if (err)
|
||||
return err;
|
||||
@ -154,10 +222,15 @@ static int nouveau_platform_remove(struct platform_device *pdev)
|
||||
struct nouveau_drm *drm = nouveau_drm(drm_dev);
|
||||
struct nvkm_device *device = nvxx_device(&drm->device);
|
||||
struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu;
|
||||
int err;
|
||||
|
||||
nouveau_drm_device_remove(drm_dev);
|
||||
|
||||
return nouveau_platform_power_down(gpu);
|
||||
err = nouveau_platform_power_down(gpu);
|
||||
|
||||
nouveau_platform_remove_iommu(&pdev->dev, gpu);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
|
@ -24,10 +24,12 @@
|
||||
#define __NOUVEAU_PLATFORM_H__
|
||||
|
||||
#include "core/device.h"
|
||||
#include "core/mm.h"
|
||||
|
||||
struct reset_control;
|
||||
struct clk;
|
||||
struct regulator;
|
||||
struct iommu_domain;
|
||||
struct platform_driver;
|
||||
|
||||
struct nouveau_platform_gpu {
|
||||
@ -36,6 +38,22 @@ struct nouveau_platform_gpu {
|
||||
struct clk *clk_pwr;
|
||||
|
||||
struct regulator *vdd;
|
||||
|
||||
struct {
|
||||
/*
|
||||
* Protects accesses to mm from subsystems
|
||||
*/
|
||||
struct mutex mutex;
|
||||
|
||||
struct nvkm_mm _mm;
|
||||
/*
|
||||
* Just points to _mm. We need this to avoid embedding
|
||||
* struct nvkm_mm in os.h
|
||||
*/
|
||||
struct nvkm_mm *mm;
|
||||
struct iommu_domain *domain;
|
||||
unsigned long pgshift;
|
||||
} iommu;
|
||||
};
|
||||
|
||||
struct nouveau_platform_device {
|
||||
|
Loading…
Reference in New Issue
Block a user