All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sui Jingfeng <sui.jingfeng@linux.dev>
To: Lucas Stach <l.stach@pengutronix.de>
Cc: Christian Gmeiner <christian.gmeiner@gmail.com>,
	Russell King <linux+etnaviv@armlinux.org.uk>,
	dri-devel@lists.freedesktop.org, etnaviv@lists.freedesktop.org,
	linux-kernel@vger.kernel.org,
	Sui Jingfeng <sui.jingfeng@linux.dev>
Subject: [PATCH v15 17/19] drm/etnaviv: Support to manage dedicated VRAM base on drm_mm
Date: Sun,  8 Sep 2024 17:43:55 +0800	[thread overview]
Message-ID: <20240908094357.291862-18-sui.jingfeng@linux.dev> (raw)
In-Reply-To: <20240908094357.291862-1-sui.jingfeng@linux.dev>

The dedicated VRAM is seen as a kind of device memory (IOMEM) at present,
we should use ioremap() to make device memory CPU accessible, we should
also need to implement mmap() driver for userspace. Therefore, we add a
simple drm-mm based range allocator for the upper (GEM object function)
layer.

Signed-off-by: Sui Jingfeng <sui.jingfeng@linux.dev>
---
 drivers/gpu/drm/etnaviv/Makefile           |   1 +
 drivers/gpu/drm/etnaviv/etnaviv_drv.c      |  12 +
 drivers/gpu/drm/etnaviv/etnaviv_drv.h      |  11 +
 drivers/gpu/drm/etnaviv/etnaviv_gem.h      |   5 +
 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c | 258 +++++++++++++++++++++
 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.h |  12 +
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c  |  13 ++
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h  |   6 +
 8 files changed, 318 insertions(+)
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.h

diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile
index 383f181bfc4c..aba2578966ff 100644
--- a/drivers/gpu/drm/etnaviv/Makefile
+++ b/drivers/gpu/drm/etnaviv/Makefile
@@ -6,6 +6,7 @@ etnaviv-y := \
 	etnaviv_drv.o \
 	etnaviv_dump.o \
 	etnaviv_gem_prime.o \
+	etnaviv_gem_vram.o \
 	etnaviv_gem_submit.o \
 	etnaviv_gem.o \
 	etnaviv_gpu.o \
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 7fc654f051a3..f10661fe079f 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -23,6 +23,7 @@
 #include "etnaviv_drv.h"
 #include "etnaviv_gpu.h"
 #include "etnaviv_gem.h"
+#include "etnaviv_gem_vram.h"
 #include "etnaviv_mmu.h"
 #include "etnaviv_pci_drv.h"
 #include "etnaviv_perfmon.h"
@@ -46,6 +47,8 @@ static struct device_node *etnaviv_of_first_available_node(void)
 static int etnaviv_private_init(struct device *dev,
 				struct etnaviv_drm_private *priv)
 {
+	int ret;
+
 	xa_init_flags(&priv->active_contexts, XA_FLAGS_ALLOC);
 
 	mutex_init(&priv->gem_lock);
@@ -61,6 +64,10 @@ static int etnaviv_private_init(struct device *dev,
 
 	priv->cached_coherent = dev_is_dma_coherent(dev);
 
+	ret = etnaviv_init_dedicated_vram(dev, priv);
+	if (ret)
+		dev_err(dev, "Failed to init dedicated vram\n");
+
 	return 0;
 }
 
@@ -74,6 +81,11 @@ static void etnaviv_private_fini(struct etnaviv_drm_private *priv)
 	xa_destroy(&priv->active_contexts);
 
 	mutex_destroy(&priv->gem_lock);
+
+	if (priv->dedicated_vram) {
+		drm_mm_takedown(&priv->vram.mm);
+		priv->dedicated_vram = false;
+	}
 }
 
 static void load_gpu(struct drm_device *dev)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 84f2e79f0a53..b093f832599f 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -58,6 +58,17 @@ struct etnaviv_drm_private {
 	 */
 	bool cached_coherent;
 
+	/*
+	 * dedicated VRAM (device memory) resource
+	 */
+	struct {
+		struct drm_mm mm;
+		u64 gpu_base;
+		u64 cpu_base;
+		u64 size;
+	} vram;
+	bool dedicated_vram;
+
 	/* list of GEM objects: */
 	struct mutex gem_lock;
 	struct list_head gem_list;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index 8d8fc5b3a541..60bbbbc2dd19 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -59,6 +59,9 @@ struct etnaviv_gem_object {
 	u32 last_cpu_prep_op;
 
 	struct etnaviv_gem_userptr userptr;
+
+	/* dedicated vram, which is physically contiguous */
+	struct drm_mm_node *vram_np;
 };
 
 static inline
@@ -129,4 +132,6 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(
 	u64 va);
 void etnaviv_gem_mapping_unreference(struct etnaviv_vram_mapping *mapping);
 
+u64 etnaviv_obj_gpu_phys_addr(struct etnaviv_gem_object *etnaviv_obj);
+
 #endif /* __ETNAVIV_GEM_H__ */
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c
new file mode 100644
index 000000000000..c2942317a64e
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/pci.h>
+
+#include "etnaviv_drv.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_pci_drv.h"
+
+static struct lock_class_key etnaviv_vram_lock_class;
+
+static u64 etnaviv_obj_cpu_phys_addr(struct etnaviv_gem_object *etnaviv_obj)
+{
+	struct drm_gem_object *obj = &etnaviv_obj->base;
+	struct etnaviv_drm_private *priv = to_etnaviv_priv(obj->dev);
+
+	if (!etnaviv_obj->vram_np) {
+		drm_err(obj->dev, "No backing vram node, please pin it\n");
+		return 0;
+	}
+
+	return priv->vram.cpu_base + etnaviv_obj->vram_np->start;
+}
+
+u64 etnaviv_obj_gpu_phys_addr(struct etnaviv_gem_object *etnaviv_obj)
+{
+	struct drm_gem_object *obj = &etnaviv_obj->base;
+	struct etnaviv_drm_private *priv = to_etnaviv_priv(obj->dev);
+
+	if (!etnaviv_obj->vram_np) {
+		drm_err(obj->dev, "No backing vram node, no gpu offset\n");
+		return 0;
+	}
+
+	return priv->vram.gpu_base + etnaviv_obj->vram_np->start;
+}
+
+/* Called with etnaviv_obj->lock held, allocate pages from dedicated VRAM */
+static int etnaviv_gem_vram_get_pages(struct etnaviv_gem_object *etnaviv_obj)
+{
+	struct drm_gem_object *obj = &etnaviv_obj->base;
+	struct drm_device *drm = obj->dev;
+	struct etnaviv_drm_private *priv = to_etnaviv_priv(drm);
+	unsigned int npages = obj->size >> PAGE_SHIFT;
+	struct drm_mm_node *vram_np;
+	struct page **ppages;
+	u64 gpu_paddr;
+	unsigned int i;
+	int ret;
+
+	lockdep_assert_held(&etnaviv_obj->lock);
+
+	vram_np = kzalloc(sizeof(*vram_np), GFP_KERNEL);
+	if (!vram_np)
+		return -ENOMEM;
+
+	ret = drm_mm_insert_node(&priv->vram.mm, vram_np, obj->size);
+	if (ret) {
+		drm_err(drm, "Failed to insert %zu KiB\n", obj->size >> 10);
+		goto fail_allocate_range;
+	}
+
+	ppages = kvmalloc_array(npages, sizeof(*ppages), GFP_KERNEL);
+	if (!ppages) {
+		ret = -ENOMEM;
+		goto fail_allocate_pages;
+	}
+
+	etnaviv_obj->vram_np = vram_np;
+
+	gpu_paddr = etnaviv_obj_gpu_phys_addr(etnaviv_obj);
+	for (i = 0; i < npages; ++i) {
+		ppages[i] = pfn_to_page(__phys_to_pfn(gpu_paddr));
+		gpu_paddr += PAGE_SIZE;
+	}
+
+	etnaviv_obj->pages = ppages;
+
+	return 0;
+
+fail_allocate_pages:
+	drm_mm_remove_node(vram_np);
+fail_allocate_range:
+	kfree(vram_np);
+
+	return ret;
+}
+
+static void *etnaviv_gem_vram_vmap(struct etnaviv_gem_object *etnaviv_obj)
+{
+	struct drm_device *drm = etnaviv_obj->base.dev;
+	u64 offset;
+	u64 size;
+	int ret;
+
+	lockdep_assert_held(&etnaviv_obj->lock);
+
+	/*
+	 * This is equivalent to pin, we need the dedicated vram node
+	 * inserted into the whole drm_mm, to get a valid offset.
+	 */
+	if (!etnaviv_obj->pages) {
+		ret = etnaviv_obj->ops->get_pages(etnaviv_obj);
+		if (ret) {
+			drm_err(drm, "Failed to pin %p\n", etnaviv_obj);
+			return NULL;
+		}
+	}
+
+	offset = etnaviv_obj_cpu_phys_addr(etnaviv_obj);
+	size = etnaviv_obj->base.size;
+
+	drm_dbg(drm, "offset : 0x%llx, %llu\n", offset, size >> 10);
+
+	if (etnaviv_obj->flags & ETNA_BO_WC)
+		return ioremap_wc(offset, size);
+
+	return ioremap(offset, size);
+}
+
+static void etnaviv_gem_vram_vunmap(struct etnaviv_gem_object *etnaviv_obj)
+{
+	lockdep_assert_held(&etnaviv_obj->lock);
+
+	iounmap(etnaviv_obj->vaddr);
+}
+
+static void etnaviv_gem_vram_release(struct etnaviv_gem_object *etnaviv_obj)
+{
+	if (etnaviv_obj->sgt) {
+		sg_free_table(etnaviv_obj->sgt);
+		kfree(etnaviv_obj->sgt);
+		etnaviv_obj->sgt = NULL;
+	}
+
+	if (etnaviv_obj->pages) {
+		kvfree(etnaviv_obj->pages);
+		etnaviv_obj->pages = NULL;
+	}
+
+	if (etnaviv_obj->vram_np) {
+		drm_mm_remove_node(etnaviv_obj->vram_np);
+		kfree(etnaviv_obj->vram_np);
+		etnaviv_obj->vram_np = NULL;
+	}
+}
+
+static int etnaviv_gem_vram_mmap(struct etnaviv_gem_object *etnaviv_obj,
+				 struct vm_area_struct *vma)
+{
+	pgprot_t vm_page_prot;
+
+	vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
+
+	vm_page_prot = vm_get_page_prot(vma->vm_flags);
+
+	if (etnaviv_obj->flags & ETNA_BO_WC)
+		vma->vm_page_prot = pgprot_writecombine(vm_page_prot);
+	else if (etnaviv_obj->flags & ETNA_BO_UNCACHED)
+		vma->vm_page_prot = pgprot_noncached(vm_page_prot);
+	else
+		vma->vm_page_prot = vm_page_prot;
+
+	return 0;
+}
+
+static const struct etnaviv_gem_ops etnaviv_gem_vram_ops = {
+	.get_pages = etnaviv_gem_vram_get_pages,
+	.release = etnaviv_gem_vram_release,
+	.vmap = etnaviv_gem_vram_vmap,
+	.vunmap = etnaviv_gem_vram_vunmap,
+	.mmap = etnaviv_gem_vram_mmap,
+};
+
+int etnaviv_gem_new_vram(struct drm_device *dev, struct drm_file *file,
+			 u32 size, u32 flags, u32 *handle)
+{
+	struct etnaviv_gem_object *etnaviv_obj;
+	struct drm_gem_object *obj;
+	int ret;
+
+	size = PAGE_ALIGN(size);
+
+	ret = etnaviv_gem_new_private(dev, size, flags, false,
+				      &etnaviv_gem_vram_ops, &etnaviv_obj);
+	if (ret)
+		return ret;
+
+	lockdep_set_class(&etnaviv_obj->lock, &etnaviv_vram_lock_class);
+
+	obj = &etnaviv_obj->base;
+
+	ret = drm_gem_handle_create(file, obj, handle);
+
+	/* drop reference from allocate - handle holds it now */
+	drm_gem_object_put(obj);
+
+	return ret;
+}
+
+static int etnaviv_pci_init_dedicated_vram(struct device *dev,
+					   struct etnaviv_drm_private *priv)
+{
+	struct pci_dev *gpu = to_pci_dev(dev);
+	static const struct etnaviv_pci_gpu_data *pdata;
+	resource_size_t base, size;
+	u32 bar;
+
+	pdata = etnaviv_pci_get_match_data(dev);
+	if (!pdata)
+		return -ENOENT;
+
+	if (pdata->num_vram <= 0) {
+		dev_err(dev, "Don't has a dedicated VRAM\n");
+		return -ENODEV;
+	}
+
+	/* Using the first vram bar */
+	bar = pdata->vram_bars[0];
+
+	base = pci_resource_start(gpu, bar);
+	size = pci_resource_len(gpu, bar);
+	if (!base || !size)
+		return -ENOSPC;
+
+	priv->vram.gpu_base = pci_bus_address(gpu, bar);
+	priv->vram.cpu_base = base;
+	priv->vram.size = size;
+	priv->dedicated_vram = true;
+
+	dev_info(dev, "GPU Bar %u contains dedicated VRAM\n", bar);
+
+	return 0;
+}
+
+int etnaviv_init_dedicated_vram(struct device *dev,
+				struct etnaviv_drm_private *priv)
+{
+	int ret;
+
+	if (dev->parent && dev_is_pci(dev->parent)) {
+		ret = etnaviv_pci_init_dedicated_vram(dev->parent, priv);
+		if (ret)
+			return ret;
+	}
+
+	if (!priv->vram.size)
+		return 0;
+
+	/* CPU physical address */
+	drm_mm_init(&priv->vram.mm, 0, priv->vram.size);
+
+	dev_info(dev, "VRAM device address range: %08llx-%08llx\n",
+		 priv->vram.gpu_base, priv->vram.gpu_base + priv->vram.size);
+	dev_info(dev, "VRAM CPU physical address range: %08llx~%08llx\n",
+		 priv->vram.cpu_base, priv->vram.cpu_base + priv->vram.size);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_vram.h b/drivers/gpu/drm/etnaviv/etnaviv_gem_vram.h
new file mode 100644
index 000000000000..bbce93f118a2
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_vram.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ETNAVIV_GEM_VRAM_H__
+#define __ETNAVIV_GEM_VRAM_H__
+
+int etnaviv_gem_new_vram(struct drm_device *dev, struct drm_file *file,
+			 u32 size, u32 flags, u32 *handle);
+
+int etnaviv_init_dedicated_vram(struct device *dev,
+				struct etnaviv_drm_private *priv);
+
+#endif
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
index 9911bfdc41a9..cbb7bc0947a7 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
@@ -191,6 +191,19 @@ static struct pci_driver etnaviv_pci_driver = {
 	.remove = etnaviv_pci_remove,
 };
 
+const struct etnaviv_pci_gpu_data *
+etnaviv_pci_get_match_data(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	const struct pci_device_id *entity;
+
+	entity = pci_match_id(etnaviv_pci_id_list, pdev);
+	if (!entity)
+		return NULL;
+
+	return etnaviv_pci_get_platform_data(entity);
+}
+
 int etnaviv_register_pci_driver(void)
 {
 	return pci_register_driver(&etnaviv_pci_driver);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
index 39eb2851355a..f5184fb35f50 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
@@ -42,6 +42,9 @@ struct etnaviv_pci_gpu_data {
 	char market_name[24];
 };
 
+const struct etnaviv_pci_gpu_data *
+etnaviv_pci_get_match_data(struct device *dev);
+
 int etnaviv_register_pci_driver(void);
 void etnaviv_unregister_pci_driver(void);
 
@@ -52,6 +55,9 @@ int jemo_pcie_init(struct pci_dev *pdev);
 static inline int etnaviv_register_pci_driver(void) { return 0; }
 static inline void etnaviv_unregister_pci_driver(void) { }
 
+static inline struct etnaviv_pci_gpu_data *
+etnaviv_pci_get_match_data(struct device *dev) { return NULL; }
+
 #endif
 
 #endif
-- 
2.43.0


  parent reply	other threads:[~2024-09-08  9:45 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-08  9:43 [PATCH v15 00/19] drm/etnaviv: Add driver wrapper for vivante GPUs attached on PCI(e) device Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 01/19] drm/etnaviv: Implement drm_gem_object_funcs::print_info() Sui Jingfeng
2024-10-01 13:04   ` Lucas Stach
2024-11-09  7:23     ` Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 02/19] drm/etnaviv: Export drm_gem_print_info() and use it Sui Jingfeng
2024-10-01 13:10   ` Lucas Stach
2024-09-08  9:43 ` [PATCH v15 03/19] drm/etnaviv: Implement drm_gem_object_funcs::vunmap() Sui Jingfeng
2024-10-01 13:34   ` Lucas Stach
2024-09-08  9:43 ` [PATCH v15 04/19] drm/etnaviv: Make etnaviv_gem_prime_vmap() a static function Sui Jingfeng
2024-10-01 13:40   ` Lucas Stach
2024-10-01 14:05     ` Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 05/19] drm/etnaviv: Add contructor and destructor for etnaviv_gem_get_mapping structure Sui Jingfeng
2024-10-01 13:51   ` Lucas Stach
2024-09-08  9:43 ` [PATCH v15 06/19] drm/etnaviv: Prefer drm_device based drm_WARN_ON() over regular WARN_ON() Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 07/19] drm/etnaviv: Add a dedicated helper function to get various clocks Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 08/19] drm/etnaviv: Fix wrong caching mode being used for non writecombine buffers Sui Jingfeng
2024-10-01 13:58   ` Lucas Stach
2024-09-08  9:43 ` [PATCH v15 09/19] drm/etnaviv: Add constructor and destructor for the etnaviv_drm_private structure Sui Jingfeng
2024-10-01 14:07   ` Lucas Stach
2024-09-08  9:43 ` [PATCH v15 10/19] drm/etnaviv: Embed struct drm_device into struct etnaviv_drm_private Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 11/19] drm/etnaviv: Add etnaviv_gem_obj_remove() helper Sui Jingfeng
2024-10-01 14:21   ` Lucas Stach
2024-10-01 18:22     ` Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 12/19] drm/etnaviv: Add support for cached coherent caching mode Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 13/19] drm/etnaviv: Add support for vivante GPU cores attached via PCIe device Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 14/19] drm/etnaviv: Add PCIe IP setup code Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 15/19] drm/etnaviv: Make more use of the etnaviv_gem_new_private() function Sui Jingfeng
2024-09-08  9:43 ` [PATCH v15 16/19] drm/etnaviv: Call etnaviv_gem_obj_add() in ernaviv_gem_new_private() Sui Jingfeng
2024-10-01 14:39   ` Lucas Stach
2024-10-01 18:52     ` Sui Jingfeng
2024-09-08  9:43 ` Sui Jingfeng [this message]
2024-09-08  9:43 ` [PATCH v15 18/19] drm/etnaviv: Allow userspace specify the domain of etnaviv GEM buffer object Sui Jingfeng
2024-10-01 14:51   ` Lucas Stach
2024-09-08  9:43 ` [PATCH v15 19/19] drm/etnaviv: Expose basic sanity tests via debugfs Sui Jingfeng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240908094357.291862-18-sui.jingfeng@linux.dev \
    --to=sui.jingfeng@linux.dev \
    --cc=christian.gmeiner@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=etnaviv@lists.freedesktop.org \
    --cc=l.stach@pengutronix.de \
    --cc=linux+etnaviv@armlinux.org.uk \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.