[PATCH] drm/etnaviv: optionally set gpu linear window to cma area

Sven Van Asbroeck thesven73 at gmail.com
Wed Jun 19 18:38:56 UTC 2019


On Vivante GPUs with an iommu-v1, the gpu linear window's
position must be determined at probe time, and cannot change
during the driver's lifetime.

The existing code attempts to guess a suitable window position
using the dma mask, but this does not always work [1].

According to a recent thread [2], Lucas Stach mentions that
on MC2.0 GPUs, one may simply point the window to the start
of the global cma area.

This patch provides an optional method to set the window
to the cma area, by adding a phandle to the etnaviv driver's
devicetree node, pointing to the global cma area.

Note that on iommu-v2 GPUs, this setting has no effect:
they do not depend on a fixed window position.

<Example>

/ {
	reserved-memory {
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;

		cma_area: linux,cma {
			compatible = "shared-dma-pool";
			reusable;
			size = <0x10000000>;
			linux,cma-default;
		};
	};
};

/* Tell the Vivante GPUS where the CMA area is */

&gpu_3d {
	default-cma-region = <&cma_area>;
};

&gpu_2d {
	default-cma-region = <&cma_area>;
};

</Example>

[1] iMX6Q 2G ram, 256M cma, v5.2-rc4 kernel:
    cma area @ 0x30000000 (auto-assigned by kernel)
    dma mask is 0xffffffff
    driver sets gpu window to 0x80000000
    result: gpu iommu-v1 cannot access cma area

[2] https://lkml.org/lkml/2017/11/15/599

To: Lucas Stach <l.stach at pengutronix.de>
Cc: Russell King <linux+etnaviv at armlinux.org.uk>
Cc: Christian Gmeiner <christian.gmeiner at gmail.com>
Cc: David Airlie <airlied at linux.ie>
Cc: Daniel Vetter <daniel at ffwll.ch>
Cc: etnaviv at lists.freedesktop.org
Cc: dri-devel at lists.freedesktop.org
Cc: linux-kernel at vger.kernel.org
Cc: Alexey Brodkin <Alexey.Brodkin at synopsys.com>
Cc: Gaƫl PORTAY <gael.portay at collabora.com>
Signed-off-by: Sven Van Asbroeck <TheSven73 at gmail.com>
---

devicetree documentation patch to follow, depending on how this patch
is received.

 drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 48 +++++++++++++++++++++------
 drivers/gpu/drm/etnaviv/etnaviv_gpu.h |  2 ++
 2 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 72d01e873160..7ed8705744d0 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -8,6 +8,7 @@
 #include <linux/dma-fence.h>
 #include <linux/moduleparam.h>
 #include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
 #include <linux/regulator/consumer.h>
 #include <linux/thermal.h>
 
@@ -687,6 +688,12 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
 			     prefetch);
 }
 
+static bool gpu_is_3d_mc10(const struct etnaviv_chip_identity *id)
+{
+	return (id->features & chipFeatures_PIPE_3D) &&
+		!(id->minor_features0 & chipMinorFeatures0_MC20);
+}
+
 int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
 {
 	int ret, i;
@@ -713,23 +720,33 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
 		goto fail;
 	}
 
-	/*
-	 * Set the GPU linear window to be at the end of the DMA window, where
-	 * the CMA area is likely to reside. This ensures that we are able to
-	 * map the command buffers while having the linear window overlap as
-	 * much RAM as possible, so we can optimize mappings for other buffers.
-	 *
-	 * For 3D cores only do this if MC2.0 is present, as with MC1.0 it leads
-	 * to different views of the memory on the individual engines.
-	 */
-	if (!(gpu->identity.features & chipFeatures_PIPE_3D) ||
-	    (gpu->identity.minor_features0 & chipMinorFeatures0_MC20)) {
+	if (!gpu_is_3d_mc10(&gpu->identity) && gpu->cma_base) {
+		/*
+		 * If we know the location of the CMA area, point the
+		 * GPU linear window to it. This ensures that we are able to
+		 * map the command buffers while having the linear window
+		 * overlap as much RAM as possible, so we can optimize mappings
+		 * for other buffers.
+		 */
+		gpu->memory_base = (u32)gpu->cma_base;
+	} else if (!gpu_is_3d_mc10(&gpu->identity)) {
+		/*
+		 * Set the GPU linear window to be at the end of the DMA window,
+		 * where the CMA area is likely to reside. In most cases, this
+		 * ensures that we are able to map the command buffers while
+		 * having the linear window overlap as much RAM as possible, so
+		 * we can optimize mappings for other buffers.
+		 */
 		u32 dma_mask = (u32)dma_get_required_mask(gpu->dev);
 		if (dma_mask < PHYS_OFFSET + SZ_2G)
 			gpu->memory_base = PHYS_OFFSET;
 		else
 			gpu->memory_base = dma_mask - SZ_2G + 1;
 	} else if (PHYS_OFFSET >= SZ_2G) {
+		/*
+		 * For MC1.0 3D cores, moving the linear window leads to
+		 * different views of the memory on the individual engines.
+		 */
 		dev_info(gpu->dev, "Need to move linear window on MC1.0, disabling TS\n");
 		gpu->memory_base = PHYS_OFFSET;
 		gpu->identity.features &= ~chipFeatures_FAST_CLEAR;
@@ -1709,7 +1726,9 @@ MODULE_DEVICE_TABLE(of, etnaviv_gpu_match);
 
 static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
 {
+	struct reserved_mem *rmem = NULL;
 	struct device *dev = &pdev->dev;
+	struct device_node *node;
 	struct etnaviv_gpu *gpu;
 	struct resource *res;
 	int err;
@@ -1718,6 +1737,13 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
 	if (!gpu)
 		return -ENOMEM;
 
+	node = of_parse_phandle(dev->of_node, "default-cma-region", 0);
+	if (node)
+		rmem = of_reserved_mem_lookup(node);
+	of_node_put(node);
+	if (rmem)
+		gpu->cma_base = rmem->base;
+
 	gpu->dev = &pdev->dev;
 	mutex_init(&gpu->lock);
 	mutex_init(&gpu->fence_lock);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 9bcf151f706b..3e968b395a72 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -106,6 +106,8 @@ struct etnaviv_gpu {
 
 	/* bus base address of memory  */
 	u32 memory_base;
+	/* base of the cma area */
+	phys_addr_t cma_base;
 
 	/* event management: */
 	DECLARE_BITMAP(event_bitmap, ETNA_NR_EVENTS);
-- 
2.17.1



More information about the dri-devel mailing list