mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-20 19:23:57 +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/of.h>
|
||||||
#include <linux/reset.h>
|
#include <linux/reset.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/iommu.h>
|
||||||
#include <soc/tegra/fuse.h>
|
#include <soc/tegra/fuse.h>
|
||||||
#include <soc/tegra/pmc.h>
|
#include <soc/tegra/pmc.h>
|
||||||
|
|
||||||
@ -91,6 +92,71 @@ static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu)
|
|||||||
return 0;
|
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)
|
static int nouveau_platform_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct nouveau_platform_gpu *gpu;
|
struct nouveau_platform_gpu *gpu;
|
||||||
@ -118,6 +184,8 @@ static int nouveau_platform_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(gpu->clk_pwr))
|
if (IS_ERR(gpu->clk_pwr))
|
||||||
return PTR_ERR(gpu->clk_pwr);
|
return PTR_ERR(gpu->clk_pwr);
|
||||||
|
|
||||||
|
nouveau_platform_probe_iommu(&pdev->dev, gpu);
|
||||||
|
|
||||||
err = nouveau_platform_power_up(gpu);
|
err = nouveau_platform_power_up(gpu);
|
||||||
if (err)
|
if (err)
|
||||||
return 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 nouveau_drm *drm = nouveau_drm(drm_dev);
|
||||||
struct nvkm_device *device = nvxx_device(&drm->device);
|
struct nvkm_device *device = nvxx_device(&drm->device);
|
||||||
struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu;
|
struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu;
|
||||||
|
int err;
|
||||||
|
|
||||||
nouveau_drm_device_remove(drm_dev);
|
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)
|
#if IS_ENABLED(CONFIG_OF)
|
||||||
|
@ -24,10 +24,12 @@
|
|||||||
#define __NOUVEAU_PLATFORM_H__
|
#define __NOUVEAU_PLATFORM_H__
|
||||||
|
|
||||||
#include "core/device.h"
|
#include "core/device.h"
|
||||||
|
#include "core/mm.h"
|
||||||
|
|
||||||
struct reset_control;
|
struct reset_control;
|
||||||
struct clk;
|
struct clk;
|
||||||
struct regulator;
|
struct regulator;
|
||||||
|
struct iommu_domain;
|
||||||
struct platform_driver;
|
struct platform_driver;
|
||||||
|
|
||||||
struct nouveau_platform_gpu {
|
struct nouveau_platform_gpu {
|
||||||
@ -36,6 +38,22 @@ struct nouveau_platform_gpu {
|
|||||||
struct clk *clk_pwr;
|
struct clk *clk_pwr;
|
||||||
|
|
||||||
struct regulator *vdd;
|
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 {
|
struct nouveau_platform_device {
|
||||||
|
Loading…
Reference in New Issue
Block a user