Jelajahi Sumber

drm/nouveau/platform: allow to specify the IOMMU bit

Current Tegra code taking advantage of the IOMMU assumes a hardcoded
value for the IOMMU bit. Make it a platform property instead for
flexibility.

v2 (Ben Skeggs): remove nvkm dependence on drm structures

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Alexandre Courbot 10 tahun lalu
induk
melakukan
e396ecd178

+ 1 - 0
drivers/gpu/drm/nouveau/include/nvif/os.h

@@ -27,6 +27,7 @@
 #include <linux/agp_backend.h>
 #include <linux/agp_backend.h>
 #include <linux/reset.h>
 #include <linux/reset.h>
 #include <linux/iommu.h>
 #include <linux/iommu.h>
+#include <linux/of_device.h>
 
 
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 
 

+ 12 - 1
drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h

@@ -4,6 +4,7 @@
 #include <core/mm.h>
 #include <core/mm.h>
 
 
 struct nvkm_device_tegra {
 struct nvkm_device_tegra {
+	const struct nvkm_device_tegra_func *func;
 	struct nvkm_device device;
 	struct nvkm_device device;
 	struct platform_device *pdev;
 	struct platform_device *pdev;
 	int irq;
 	int irq;
@@ -28,7 +29,17 @@ struct nvkm_device_tegra {
 	int gpu_speedo;
 	int gpu_speedo;
 };
 };
 
 
-int nvkm_device_tegra_new(struct platform_device *,
+struct nvkm_device_tegra_func {
+	/*
+	 * If an IOMMU is used, indicates which address bit will trigger a
+	 * IOMMU translation when set (when this bit is not set, IOMMU is
+	 * bypassed). A value of 0 means an IOMMU is never used.
+	 */
+	u8 iommu_bit;
+};
+
+int nvkm_device_tegra_new(const struct nvkm_device_tegra_func *,
+			  struct platform_device *,
 			  const char *cfg, const char *dbg,
 			  const char *cfg, const char *dbg,
 			  bool detect, bool mmio, u64 subdev_mask,
 			  bool detect, bool mmio, u64 subdev_mask,
 			  struct nvkm_device **);
 			  struct nvkm_device **);

+ 3 - 2
drivers/gpu/drm/nouveau/nouveau_drm.c

@@ -1028,13 +1028,14 @@ nouveau_drm_pci_driver = {
 };
 };
 
 
 struct drm_device *
 struct drm_device *
-nouveau_platform_device_create(struct platform_device *pdev,
+nouveau_platform_device_create(const struct nvkm_device_tegra_func *func,
+			       struct platform_device *pdev,
 			       struct nvkm_device **pdevice)
 			       struct nvkm_device **pdevice)
 {
 {
 	struct drm_device *drm;
 	struct drm_device *drm;
 	int err;
 	int err;
 
 
-	err = nvkm_device_tegra_new(pdev, nouveau_config, nouveau_debug,
+	err = nvkm_device_tegra_new(func, pdev, nouveau_config, nouveau_debug,
 				    true, true, ~0ULL, pdevice);
 				    true, true, ~0ULL, pdevice);
 	if (err)
 	if (err)
 		goto err_free;
 		goto err_free;

+ 4 - 1
drivers/gpu/drm/nouveau/nouveau_drm.h

@@ -178,8 +178,11 @@ nouveau_drm(struct drm_device *dev)
 int nouveau_pmops_suspend(struct device *);
 int nouveau_pmops_suspend(struct device *);
 int nouveau_pmops_resume(struct device *);
 int nouveau_pmops_resume(struct device *);
 
 
+#include <nvkm/core/tegra.h>
+
 struct drm_device *
 struct drm_device *
-nouveau_platform_device_create(struct platform_device *, struct nvkm_device **);
+nouveau_platform_device_create(const struct nvkm_device_tegra_func *,
+			       struct platform_device *, struct nvkm_device **);
 void nouveau_drm_device_remove(struct drm_device *dev);
 void nouveau_drm_device_remove(struct drm_device *dev);
 
 
 #define NV_PRINTK(l,c,f,a...) do {                                             \
 #define NV_PRINTK(l,c,f,a...) do {                                             \

+ 16 - 3
drivers/gpu/drm/nouveau/nouveau_platform.c

@@ -23,11 +23,14 @@
 
 
 static int nouveau_platform_probe(struct platform_device *pdev)
 static int nouveau_platform_probe(struct platform_device *pdev)
 {
 {
+	const struct nvkm_device_tegra_func *func;
 	struct nvkm_device *device;
 	struct nvkm_device *device;
 	struct drm_device *drm;
 	struct drm_device *drm;
 	int ret;
 	int ret;
 
 
-	drm = nouveau_platform_device_create(pdev, &device);
+	func = of_device_get_match_data(&pdev->dev);
+
+	drm = nouveau_platform_device_create(func, pdev, &device);
 	if (IS_ERR(drm))
 	if (IS_ERR(drm))
 		return PTR_ERR(drm);
 		return PTR_ERR(drm);
 
 
@@ -48,9 +51,19 @@ static int nouveau_platform_remove(struct platform_device *pdev)
 }
 }
 
 
 #if IS_ENABLED(CONFIG_OF)
 #if IS_ENABLED(CONFIG_OF)
+static const struct nvkm_device_tegra_func gk20a_platform_data = {
+	.iommu_bit = 34,
+};
+
 static const struct of_device_id nouveau_platform_match[] = {
 static const struct of_device_id nouveau_platform_match[] = {
-	{ .compatible = "nvidia,gk20a" },
-	{ .compatible = "nvidia,gm20b" },
+	{
+		.compatible = "nvidia,gk20a",
+		.data = &gk20a_platform_data,
+	},
+	{
+		.compatible = "nvidia,gm20b",
+		.data = &gk20a_platform_data,
+	},
 	{ }
 	{ }
 };
 };
 
 

+ 10 - 3
drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c

@@ -85,6 +85,9 @@ nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev)
 	unsigned long pgsize_bitmap;
 	unsigned long pgsize_bitmap;
 	int ret;
 	int ret;
 
 
+	if (!tdev->func->iommu_bit)
+		return;
+
 	mutex_init(&tdev->iommu.mutex);
 	mutex_init(&tdev->iommu.mutex);
 
 
 	if (iommu_present(&platform_bus_type)) {
 	if (iommu_present(&platform_bus_type)) {
@@ -114,7 +117,8 @@ nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev)
 			goto free_domain;
 			goto free_domain;
 
 
 		ret = nvkm_mm_init(&tdev->iommu.mm, 0,
 		ret = nvkm_mm_init(&tdev->iommu.mm, 0,
-				   (1ULL << 40) >> tdev->iommu.pgshift, 1);
+				   (1ULL << tdev->func->iommu_bit) >>
+				   tdev->iommu.pgshift, 1);
 		if (ret)
 		if (ret)
 			goto detach_device;
 			goto detach_device;
 	}
 	}
@@ -237,7 +241,8 @@ nvkm_device_tegra_func = {
 };
 };
 
 
 int
 int
-nvkm_device_tegra_new(struct platform_device *pdev,
+nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
+		      struct platform_device *pdev,
 		      const char *cfg, const char *dbg,
 		      const char *cfg, const char *dbg,
 		      bool detect, bool mmio, u64 subdev_mask,
 		      bool detect, bool mmio, u64 subdev_mask,
 		      struct nvkm_device **pdevice)
 		      struct nvkm_device **pdevice)
@@ -248,6 +253,7 @@ nvkm_device_tegra_new(struct platform_device *pdev,
 	if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL)))
 	if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL)))
 		return -ENOMEM;
 		return -ENOMEM;
 	*pdevice = &tdev->device;
 	*pdevice = &tdev->device;
+	tdev->func = func;
 	tdev->pdev = pdev;
 	tdev->pdev = pdev;
 	tdev->irq = -1;
 	tdev->irq = -1;
 
 
@@ -285,7 +291,8 @@ nvkm_device_tegra_new(struct platform_device *pdev,
 }
 }
 #else
 #else
 int
 int
-nvkm_device_tegra_new(struct platform_device *pdev,
+nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
+		      struct platform_device *pdev,
 		      const char *cfg, const char *dbg,
 		      const char *cfg, const char *dbg,
 		      bool detect, bool mmio, u64 subdev_mask,
 		      bool detect, bool mmio, u64 subdev_mask,
 		      struct nvkm_device **pdevice)
 		      struct nvkm_device **pdevice)