linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/13] drm: Reduce page tables overhead with THP
@ 2025-10-15 15:30 Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 01/13] drm/shmem-helper: Simplify page offset calculation in fault handler Loïc Molinari
                   ` (12 more replies)
  0 siblings, 13 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

This series aims to reduce the page tables overhead of DRM drivers for
builds with CONFIG_TRANSPARENT_HUGEPAGE enabled and either the sysfs
knob '/sys/kernel/mm/transparent_hugepage/shmem_enabled' appropriately
set or drivers using a dedicated huge tmpfs mount point.

It starts by implementing a map_pages handler for GEM objects to map
pages around a faulty address in a single batch. It also checks in
both the fault and fault-around handlers whether a faulty address is
part of a huge page in order to attempt a PMD sized PFN insertion into
the VMA. It then introduces a dedicated get_unmapped_area file
operation on the DRM file descriptor for GEM objects to get the best
virtual address alignment for the underlying shmem buffers.

The remaining commits propose shmem helpers to create and release huge
tmpfs mount points and adapt the i915 and V3D drivers. The helpers are
then used to optionally enable Transparent Hugepage for Panfrost and
Panthor.

For Panthor on a Rock 5B, this series makes the first memcpy() to an
entire BO object mapped in userspace about twice as fast with
Transparent Hugepage enabled.

Loïc Molinari (13):
  drm/shmem-helper: Simplify page offset calculation in fault handler
  drm/shmem-helper: Implement map_pages fault-around handler
  drm/shmem-helper: Map huge pages in fault handlers
  drm/gem: Introduce drm_gem_get_unmapped_area() fop
  drm/gem: Add huge tmpfs mount point helper
  drm/i915: Use huge tmpfs mount point helper
  drm/v3d: Use huge tmpfs mount point helper
  drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n
  drm/gem: Get rid of *_with_mnt helpers
  drm/panthor: Introduce huge tmpfs mount point option
  drm/panthor: Improve IOMMU map/unmap debugging logs
  drm/panfrost: Introduce huge tmpfs mount point option
  Documentation/gpu/drm-mm: Add THP paragraph to GEM mapping section

 Documentation/gpu/drm-mm.rst                  |  25 ++-
 drivers/gpu/drm/drm_gem.c                     | 199 +++++++++++++-----
 drivers/gpu/drm/drm_gem_shmem_helper.c        | 138 ++++++++----
 drivers/gpu/drm/i915/Makefile                 |   3 +-
 drivers/gpu/drm/i915/gem/i915_gem_shmem.c     |  47 +++--
 drivers/gpu/drm/i915/gem/i915_gemfs.c         |  69 ------
 drivers/gpu/drm/i915/gem/i915_gemfs.h         |  14 --
 .../gpu/drm/i915/gem/selftests/huge_pages.c   |  10 +-
 drivers/gpu/drm/i915/i915_drv.h               |   5 -
 drivers/gpu/drm/panfrost/panfrost_device.c    |   3 +
 drivers/gpu/drm/panfrost/panfrost_drv.c       |   6 +
 drivers/gpu/drm/panfrost/panfrost_drv.h       |  11 +
 drivers/gpu/drm/panfrost/panfrost_gem.c       |  19 ++
 drivers/gpu/drm/panfrost/panfrost_gem.h       |   2 +
 drivers/gpu/drm/panthor/panthor_device.c      |   3 +
 drivers/gpu/drm/panthor/panthor_drv.c         |   7 +
 drivers/gpu/drm/panthor/panthor_drv.h         |  11 +
 drivers/gpu/drm/panthor/panthor_gem.c         |  19 ++
 drivers/gpu/drm/panthor/panthor_gem.h         |   2 +
 drivers/gpu/drm/panthor/panthor_mmu.c         |  19 +-
 drivers/gpu/drm/v3d/Makefile                  |   3 +-
 drivers/gpu/drm/v3d/v3d_bo.c                  |   6 +-
 drivers/gpu/drm/v3d/v3d_drv.c                 |   2 +-
 drivers/gpu/drm/v3d/v3d_drv.h                 |  13 +-
 drivers/gpu/drm/v3d/v3d_gem.c                 |  29 ++-
 drivers/gpu/drm/v3d/v3d_gemfs.c               |  60 ------
 include/drm/drm_device.h                      |  11 +
 include/drm/drm_gem.h                         |   8 +-
 include/drm/drm_gem_shmem_helper.h            |   3 -
 mm/shmem.c                                    |   1 +
 30 files changed, 456 insertions(+), 292 deletions(-)
 delete mode 100644 drivers/gpu/drm/i915/gem/i915_gemfs.c
 delete mode 100644 drivers/gpu/drm/i915/gem/i915_gemfs.h
 create mode 100644 drivers/gpu/drm/panfrost/panfrost_drv.h
 create mode 100644 drivers/gpu/drm/panthor/panthor_drv.h
 delete mode 100644 drivers/gpu/drm/v3d/v3d_gemfs.c

-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 01/13] drm/shmem-helper: Simplify page offset calculation in fault handler
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 02/13] drm/shmem-helper: Implement map_pages fault-around handler Loïc Molinari
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

For a fault at address addr, the page offset is
  page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT
              = ((addr & PAGE_MASK) - vma->vm_start) >> PAGE_SHIFT
	      = (addr - vma->vm_start) >> PAGE_SHIFT

Since the faulty logical page offset based on VMA is
  vmf->pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT)

We can slightly simplify the calculation using
  page_offset = vmf->pgoff - vma->vm_pgoff

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index dc94a27710e5..be89be1c804c 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -577,8 +577,8 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
 	struct page *page;
 	pgoff_t page_offset;
 
-	/* We don't use vmf->pgoff since that has the fake offset */
-	page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+	/* Offset to faulty address in the VMA (without the fake offset). */
+	page_offset = vmf->pgoff - vma->vm_pgoff;
 
 	dma_resv_lock(shmem->base.resv, NULL);
 
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 02/13] drm/shmem-helper: Implement map_pages fault-around handler
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 01/13] drm/shmem-helper: Simplify page offset calculation in fault handler Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 03/13] drm/shmem-helper: Map huge pages in fault handlers Loïc Molinari
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

This gives the mm subsystem the ability to increase fault handling
performance by proposing the insertion of a range of pages around the
faulty address in a single batch.

v4:
- Implement map_pages instead of huge_fault

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 53 +++++++++++++++++++++++---
 1 file changed, 48 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index be89be1c804c..e151262332f9 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -567,24 +567,66 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
 
-static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
+static bool drm_gem_shmem_fault_is_valid(struct drm_gem_object *obj,
+					 pgoff_t pgoff)
+{
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+	if (drm_WARN_ON_ONCE(obj->dev, !shmem->pages) ||
+	    pgoff >= (obj->size >> PAGE_SHIFT) ||
+	    shmem->madv < 0)
+		return false;
+
+	return true;
+}
+
+static vm_fault_t drm_gem_shmem_map_pages(struct vm_fault *vmf,
+					  pgoff_t start_pgoff,
+					  pgoff_t end_pgoff)
 {
 	struct vm_area_struct *vma = vmf->vma;
 	struct drm_gem_object *obj = vma->vm_private_data;
 	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
-	loff_t num_pages = obj->size >> PAGE_SHIFT;
+	unsigned long addr, pfn;
 	vm_fault_t ret;
+
+	start_pgoff -= vma->vm_pgoff;
+	end_pgoff -= vma->vm_pgoff;
+	addr = vma->vm_start + (start_pgoff << PAGE_SHIFT);
+
+	dma_resv_lock(shmem->base.resv, NULL);
+
+	if (unlikely(!drm_gem_shmem_fault_is_valid(obj, start_pgoff))) {
+		ret = VM_FAULT_SIGBUS;
+	} else {
+		/* Map a range of pages around the faulty address. */
+		do {
+			pfn = page_to_pfn(shmem->pages[start_pgoff]);
+			ret = vmf_insert_pfn(vma, addr, pfn);
+			addr += PAGE_SIZE;
+		} while (++start_pgoff <= end_pgoff && ret == VM_FAULT_NOPAGE);
+	}
+
+	dma_resv_unlock(shmem->base.resv);
+
+	return ret;
+}
+
+static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
+{
+	struct vm_area_struct *vma = vmf->vma;
+	struct drm_gem_object *obj = vma->vm_private_data;
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
 	struct page *page;
 	pgoff_t page_offset;
+	vm_fault_t ret;
 
 	/* Offset to faulty address in the VMA (without the fake offset). */
 	page_offset = vmf->pgoff - vma->vm_pgoff;
 
 	dma_resv_lock(shmem->base.resv, NULL);
 
-	if (page_offset >= num_pages ||
-	    drm_WARN_ON_ONCE(obj->dev, !shmem->pages) ||
-	    shmem->madv < 0) {
+	if (unlikely(!drm_gem_shmem_fault_is_valid(obj, page_offset))) {
 		ret = VM_FAULT_SIGBUS;
 	} else {
 		page = shmem->pages[page_offset];
@@ -632,6 +674,7 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
 }
 
 const struct vm_operations_struct drm_gem_shmem_vm_ops = {
+	.map_pages = drm_gem_shmem_map_pages,
 	.fault = drm_gem_shmem_fault,
 	.open = drm_gem_shmem_vm_open,
 	.close = drm_gem_shmem_vm_close,
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 03/13] drm/shmem-helper: Map huge pages in fault handlers
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 01/13] drm/shmem-helper: Simplify page offset calculation in fault handler Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 02/13] drm/shmem-helper: Implement map_pages fault-around handler Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-15 17:27   ` Matthew Wilcox
  2025-10-15 15:30 ` [PATCH v4 04/13] drm/gem: Introduce drm_gem_get_unmapped_area() fop Loïc Molinari
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Check whether the starting address in the fault-around handler or the
faulty address in the fault handler is part of a huge page in order to
attempt a PMD sized PFN insertion into the VMA.

On builds with CONFIG_TRANSPARENT_HUGEPAGE enabled, if the mmap() user
address is PMD size aligned, if the GEM object is backed by shmem
buffers on mount points setting the 'huge=' option and if the shmem
backing store manages to allocate a huge folio, CPU mapping would then
benefit from significantly increased memcpy() performance. When these
conditions are met on a system with 2 MiB huge pages, an aligned copy
of 2 MiB would raise a single page fault instead of 4096.

v4:
- Implement map_pages instead of huge_fault

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 57 +++++++++++++++++++++-----
 1 file changed, 46 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index e151262332f9..5d11bea573fe 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -580,6 +580,26 @@ static bool drm_gem_shmem_fault_is_valid(struct drm_gem_object *obj,
 	return true;
 }
 
+static bool drm_gem_shmem_map_pmd(struct vm_fault *vmf, unsigned long addr,
+				  struct page *page)
+{
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
+	unsigned long pfn = page_to_pfn(page);
+	unsigned long paddr = pfn << PAGE_SHIFT;
+	bool aligned = (addr & ~PMD_MASK) == (paddr & ~PMD_MASK);
+
+	if (aligned &&
+	    pmd_none(*vmf->pmd) &&
+	    folio_test_pmd_mappable(page_folio(page))) {
+		pfn &= PMD_MASK >> PAGE_SHIFT;
+		if (vmf_insert_pfn_pmd(vmf, pfn, false) == VM_FAULT_NOPAGE)
+			return true;
+	}
+#endif
+
+	return false;
+}
+
 static vm_fault_t drm_gem_shmem_map_pages(struct vm_fault *vmf,
 					  pgoff_t start_pgoff,
 					  pgoff_t end_pgoff)
@@ -587,6 +607,7 @@ static vm_fault_t drm_gem_shmem_map_pages(struct vm_fault *vmf,
 	struct vm_area_struct *vma = vmf->vma;
 	struct drm_gem_object *obj = vma->vm_private_data;
 	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+	struct page **pages = shmem->pages;
 	unsigned long addr, pfn;
 	vm_fault_t ret;
 
@@ -598,15 +619,22 @@ static vm_fault_t drm_gem_shmem_map_pages(struct vm_fault *vmf,
 
 	if (unlikely(!drm_gem_shmem_fault_is_valid(obj, start_pgoff))) {
 		ret = VM_FAULT_SIGBUS;
-	} else {
-		/* Map a range of pages around the faulty address. */
-		do {
-			pfn = page_to_pfn(shmem->pages[start_pgoff]);
-			ret = vmf_insert_pfn(vma, addr, pfn);
-			addr += PAGE_SIZE;
-		} while (++start_pgoff <= end_pgoff && ret == VM_FAULT_NOPAGE);
+		goto out;
 	}
 
+	if (drm_gem_shmem_map_pmd(vmf, addr, pages[start_pgoff])) {
+		ret = VM_FAULT_NOPAGE;
+		goto out;
+	}
+
+	/* Map a range of pages around the faulty address. */
+	do {
+		pfn = page_to_pfn(pages[start_pgoff]);
+		ret = vmf_insert_pfn(vma, addr, pfn);
+		addr += PAGE_SIZE;
+	} while (++start_pgoff <= end_pgoff && ret == VM_FAULT_NOPAGE);
+
+ out:
 	dma_resv_unlock(shmem->base.resv);
 
 	return ret;
@@ -617,8 +645,9 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
 	struct vm_area_struct *vma = vmf->vma;
 	struct drm_gem_object *obj = vma->vm_private_data;
 	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
-	struct page *page;
+	struct page **pages = shmem->pages;
 	pgoff_t page_offset;
+	unsigned long pfn;
 	vm_fault_t ret;
 
 	/* Offset to faulty address in the VMA (without the fake offset). */
@@ -628,12 +657,18 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
 
 	if (unlikely(!drm_gem_shmem_fault_is_valid(obj, page_offset))) {
 		ret = VM_FAULT_SIGBUS;
-	} else {
-		page = shmem->pages[page_offset];
+		goto out;
+	}
 
-		ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page));
+	if (drm_gem_shmem_map_pmd(vmf, vmf->address, pages[page_offset])) {
+		ret = VM_FAULT_NOPAGE;
+		goto out;
 	}
 
+	pfn = page_to_pfn(pages[page_offset]);
+	ret = vmf_insert_pfn(vma, vmf->address, pfn);
+
+ out:
 	dma_resv_unlock(shmem->base.resv);
 
 	return ret;
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 04/13] drm/gem: Introduce drm_gem_get_unmapped_area() fop
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
                   ` (2 preceding siblings ...)
  2025-10-15 15:30 ` [PATCH v4 03/13] drm/shmem-helper: Map huge pages in fault handlers Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 05/13] drm/gem: Add huge tmpfs mount point helper Loïc Molinari
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

mmap() calls on the DRM file pointer currently always end up using
mm_get_unmapped_area() to get a free mapping region. On builds with
CONFIG_TRANSPARENT_HUGEPAGE enabled, this isn't ideal for GEM objects
backed by shmem buffers on mount points setting the 'huge=' option
because it can't correctly figure out the potentially huge address
alignment required.

This commit introduces the drm_gem_get_unmapped_area() function which
is meant to be used as a get_unmapped_area file operation on the DRM
file pointer to lookup GEM objects based on their fake offsets and get
a properly aligned region by calling shmem_get_unmapped_area() with
the right file pointer. If a GEM object isn't available at the given
offset or if the caller isn't granted access to it, the function falls
back to mm_get_unmapped_area().

This also makes drm_gem_get_unmapped_area() part of the default GEM
file operations so that all the DRM drivers can benefit from more
efficient mappings thanks to the huge page fault handler introduced in
previous commit 'drm/shmem-helper: Add huge page fault handler'.

The shmem_get_unmapped_area() function needs to be exported so that
it can be used from the DRM subsystem.

v3:
- add missing include: 'linux/sched/mm.h'
- forward to shmem layer in builds with CONFIG_TRANSPARENT_HUGEPAGE=n

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
---
 drivers/gpu/drm/drm_gem.c | 107 ++++++++++++++++++++++++++++++--------
 include/drm/drm_gem.h     |   4 ++
 mm/shmem.c                |   1 +
 3 files changed, 90 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index a1a9c828938b..a98d5744cc6c 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -36,6 +36,7 @@
 #include <linux/module.h>
 #include <linux/pagemap.h>
 #include <linux/pagevec.h>
+#include <linux/sched/mm.h>
 #include <linux/shmem_fs.h>
 #include <linux/slab.h>
 #include <linux/string_helpers.h>
@@ -1187,36 +1188,27 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
 }
 EXPORT_SYMBOL(drm_gem_mmap_obj);
 
-/**
- * drm_gem_mmap - memory map routine for GEM objects
- * @filp: DRM file pointer
- * @vma: VMA for the area to be mapped
- *
- * If a driver supports GEM object mapping, mmap calls on the DRM file
- * descriptor will end up here.
- *
- * Look up the GEM object based on the offset passed in (vma->vm_pgoff will
- * contain the fake offset we created when the GTT map ioctl was called on
- * the object) and map it with a call to drm_gem_mmap_obj().
- *
- * If the caller is not granted access to the buffer object, the mmap will fail
- * with EACCES. Please see the vma manager for more information.
+/*
+ * Look up a GEM object in offset space based on the exact start address. The
+ * caller must be granted access to the object. Returns a GEM object on success
+ * or a negative error code on failure. The returned GEM object needs to be
+ * released with drm_gem_object_put().
  */
-int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+static struct drm_gem_object *
+drm_gem_object_lookup_from_offset(struct file *filp, unsigned long start,
+				  unsigned long pages)
 {
 	struct drm_file *priv = filp->private_data;
 	struct drm_device *dev = priv->minor->dev;
 	struct drm_gem_object *obj = NULL;
 	struct drm_vma_offset_node *node;
-	int ret;
 
 	if (drm_dev_is_unplugged(dev))
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 
 	drm_vma_offset_lock_lookup(dev->vma_offset_manager);
 	node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager,
-						  vma->vm_pgoff,
-						  vma_pages(vma));
+						  start, pages);
 	if (likely(node)) {
 		obj = container_of(node, struct drm_gem_object, vma_node);
 		/*
@@ -1235,14 +1227,85 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 	drm_vma_offset_unlock_lookup(dev->vma_offset_manager);
 
 	if (!obj)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	if (!drm_vma_node_is_allowed(node, priv)) {
 		drm_gem_object_put(obj);
-		return -EACCES;
+		return ERR_PTR(-EACCES);
 	}
 
-	ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node) << PAGE_SHIFT,
+	return obj;
+}
+
+/**
+ * drm_gem_get_unmapped_area - get memory mapping region routine for GEM objects
+ * @filp: DRM file pointer
+ * @uaddr: User address hint
+ * @len: Mapping length
+ * @pgoff: Offset (in pages)
+ * @flags: Mapping flags
+ *
+ * If a driver supports GEM object mapping, before ending up in drm_gem_mmap(),
+ * mmap calls on the DRM file descriptor will first try to find a free linear
+ * address space large enough for a mapping. Since GEM objects are backed by
+ * shmem buffers, this should preferably be handled by the shmem virtual memory
+ * filesystem which can appropriately align addresses to huge page sizes when
+ * needed.
+ *
+ * Look up the GEM object based on the offset passed in (vma->vm_pgoff will
+ * contain the fake offset we created) and call shmem_get_unmapped_area() with
+ * the right file pointer.
+ *
+ * If a GEM object is not available at the given offset or if the caller is not
+ * granted access to it, fall back to mm_get_unmapped_area().
+ */
+unsigned long drm_gem_get_unmapped_area(struct file *filp, unsigned long uaddr,
+					unsigned long len, unsigned long pgoff,
+					unsigned long flags)
+{
+	struct drm_gem_object *obj;
+	unsigned long ret;
+
+	obj = drm_gem_object_lookup_from_offset(filp, pgoff, len >> PAGE_SHIFT);
+	if (IS_ERR(obj))
+		return mm_get_unmapped_area(current->mm, filp, uaddr, len, 0,
+					    flags);
+
+	ret = shmem_get_unmapped_area(obj->filp, uaddr, len, 0, flags);
+
+	drm_gem_object_put(obj);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_gem_get_unmapped_area);
+
+/**
+ * drm_gem_mmap - memory map routine for GEM objects
+ * @filp: DRM file pointer
+ * @vma: VMA for the area to be mapped
+ *
+ * If a driver supports GEM object mapping, mmap calls on the DRM file
+ * descriptor will end up here.
+ *
+ * Look up the GEM object based on the offset passed in (vma->vm_pgoff will
+ * contain the fake offset we created) and map it with a call to
+ * drm_gem_mmap_obj().
+ *
+ * If the caller is not granted access to the buffer object, the mmap will fail
+ * with EACCES. Please see the vma manager for more information.
+ */
+int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_gem_object *obj;
+	int ret;
+
+	obj = drm_gem_object_lookup_from_offset(filp, vma->vm_pgoff,
+						vma_pages(vma));
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	ret = drm_gem_mmap_obj(obj,
+			       drm_vma_node_size(&obj->vma_node) << PAGE_SHIFT,
 			       vma);
 
 	drm_gem_object_put(obj);
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index 8d48d2af2649..7c8bd67d087c 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -469,6 +469,7 @@ struct drm_gem_object {
 	.poll		= drm_poll,\
 	.read		= drm_read,\
 	.llseek		= noop_llseek,\
+	.get_unmapped_area	= drm_gem_get_unmapped_area,\
 	.mmap		= drm_gem_mmap, \
 	.fop_flags	= FOP_UNSIGNED_OFFSET
 
@@ -506,6 +507,9 @@ void drm_gem_vm_close(struct vm_area_struct *vma);
 int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
 		     struct vm_area_struct *vma);
 int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+unsigned long drm_gem_get_unmapped_area(struct file *filp, unsigned long uaddr,
+					unsigned long len, unsigned long pgoff,
+					unsigned long flags);
 
 /**
  * drm_gem_object_get - acquire a GEM buffer object reference
diff --git a/mm/shmem.c b/mm/shmem.c
index b9081b817d28..612218fc95cb 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2851,6 +2851,7 @@ unsigned long shmem_get_unmapped_area(struct file *file,
 		return addr;
 	return inflated_addr;
 }
+EXPORT_SYMBOL_GPL(shmem_get_unmapped_area);
 
 #ifdef CONFIG_NUMA
 static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol)
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 05/13] drm/gem: Add huge tmpfs mount point helper
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
                   ` (3 preceding siblings ...)
  2025-10-15 15:30 ` [PATCH v4 04/13] drm/gem: Introduce drm_gem_get_unmapped_area() fop Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-20  9:10   ` Tvrtko Ursulin
  2025-10-15 15:30 ` [PATCH v4 06/13] drm/i915: Use " Loïc Molinari
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Add the drm_gem_huge_mnt_create() helper to avoid code duplication in
the i915, V3D, Panfrost and Panthor drivers. It creates and mounts a
dedicated huge tmpfs mountpoint, for the lifetime of a DRM device,
used at GEM object initialization.

The next commits will port drivers to this helper.

v3:
- store huge tmpfs mountpoint in drm_device

v4:
- return 0 in builds with CONFIG_TRANSPARENT_HUGEPAGE=n
- return 0 when huge_mnt already exists

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
---
 drivers/gpu/drm/drm_gem.c | 58 +++++++++++++++++++++++++++++++++++++++
 include/drm/drm_device.h  | 11 ++++++++
 include/drm/drm_gem.h     |  1 +
 3 files changed, 70 insertions(+)

diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index a98d5744cc6c..db8c0a217add 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -29,6 +29,7 @@
 #include <linux/export.h>
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/iosys-map.h>
 #include <linux/mem_encrypt.h>
 #include <linux/mm.h>
@@ -82,6 +83,63 @@
  * up at a later date, and as our interface with shmfs for memory allocation.
  */
 
+static void drm_gem_huge_mnt_free(struct drm_device *dev, void *data)
+{
+	drm_WARN_ON(dev, dev->huge_mnt == NULL);
+
+	kern_unmount(dev->huge_mnt);
+	dev->huge_mnt = NULL;
+}
+
+/**
+ * drm_gem_huge_mnt_create - Create, mount and use a huge tmpfs mountpoint
+ * @dev: drm_device a huge tmpfs mountpoint should be used with
+ * @value: huge tmpfs mount option value
+ *
+ * This function creates and mounts a dedicated huge tmpfs mountpoint for the
+ * lifetime of the drm device @dev which is used at GEM object initialization
+ * with drm_gem_object_init().
+ *
+ * The most common option value @value is "within_size" which only allocates
+ * huge pages if the page will be fully within the GEM object size. "always",
+ * "advise" and "never" are supported too but the latter would just create a
+ * mountpoint similar to the default one (`shm_mnt`). See shmemfs and
+ * Transparent Hugepage for more information.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_gem_huge_mnt_create(struct drm_device *dev, const char *value)
+{
+	struct file_system_type *type;
+	struct fs_context *fc;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
+		return 0;
+	if (unlikely(dev->huge_mnt))
+		return 0;
+
+	type = get_fs_type("tmpfs");
+	if (unlikely(!type))
+		return -EOPNOTSUPP;
+	fc = fs_context_for_mount(type, SB_KERNMOUNT);
+	if (IS_ERR(fc))
+		return PTR_ERR(fc);
+	ret = vfs_parse_fs_string(fc, "source", "tmpfs");
+	if (unlikely(ret))
+		return -ENOPARAM;
+	ret = vfs_parse_fs_string(fc, "huge", value);
+	if (unlikely(ret))
+		return -ENOPARAM;
+
+	dev->huge_mnt = fc_mount_longterm(fc);
+	put_fs_context(fc);
+
+	return drmm_add_action_or_reset(dev, drm_gem_huge_mnt_free, NULL);
+}
+EXPORT_SYMBOL_GPL(drm_gem_huge_mnt_create);
+
 static void
 drm_gem_init_release(struct drm_device *dev, void *ptr)
 {
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
index 778b2cca6c49..352e3db402d7 100644
--- a/include/drm/drm_device.h
+++ b/include/drm/drm_device.h
@@ -3,6 +3,7 @@
 
 #include <linux/list.h>
 #include <linux/kref.h>
+#include <linux/mount.h>
 #include <linux/mutex.h>
 #include <linux/idr.h>
 #include <linux/sched.h>
@@ -168,6 +169,16 @@ struct drm_device {
 	 */
 	struct drm_master *master;
 
+	/**
+	 * @huge_mnt:
+	 *
+	 * Huge tmpfs mountpoint used at GEM object initialization
+	 * drm_gem_object_init(). Drivers can call drm_gem_huge_mnt_create() to
+	 * create a huge tmfps mountpoint. The default tmpfs mountpoint
+	 * (`shm_mnt`) is used if NULL.
+	 */
+	struct vfsmount *huge_mnt;
+
 	/**
 	 * @driver_features: per-device driver features
 	 *
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index 7c8bd67d087c..7285a62d9afc 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -492,6 +492,7 @@ struct drm_gem_object {
 		DRM_GEM_FOPS,\
 	}
 
+int drm_gem_huge_mnt_create(struct drm_device *dev, const char *value);
 void drm_gem_object_release(struct drm_gem_object *obj);
 void drm_gem_object_free(struct kref *kref);
 int drm_gem_object_init(struct drm_device *dev,
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 06/13] drm/i915: Use huge tmpfs mount point helper
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
                   ` (4 preceding siblings ...)
  2025-10-15 15:30 ` [PATCH v4 05/13] drm/gem: Add huge tmpfs mount point helper Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 07/13] drm/v3d: " Loïc Molinari
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Make use of the new drm_gem_huge_mnt_create() helper to avoid code
duplication. Now that it's just a few lines long, the single function
in i915_gemfs.c is moved into v3d_gem_shmem.c.

v3:
- use huge tmpfs mountpoint in drm_device
- move i915_gemfs.c into i915_gem_shmem.c

v4:
- clean up mountpoint creation error handling

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
---
 drivers/gpu/drm/i915/Makefile                 |  3 +-
 drivers/gpu/drm/i915/gem/i915_gem_shmem.c     | 47 +++++++++----
 drivers/gpu/drm/i915/gem/i915_gemfs.c         | 69 -------------------
 drivers/gpu/drm/i915/gem/i915_gemfs.h         | 14 ----
 .../gpu/drm/i915/gem/selftests/huge_pages.c   | 10 +--
 drivers/gpu/drm/i915/i915_drv.h               |  5 --
 6 files changed, 40 insertions(+), 108 deletions(-)
 delete mode 100644 drivers/gpu/drm/i915/gem/i915_gemfs.c
 delete mode 100644 drivers/gpu/drm/i915/gem/i915_gemfs.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index e58c0c158b3a..e22393a7cf6f 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -163,8 +163,7 @@ gem-y += \
 	gem/i915_gem_ttm_move.o \
 	gem/i915_gem_ttm_pm.o \
 	gem/i915_gem_userptr.o \
-	gem/i915_gem_wait.o \
-	gem/i915_gemfs.o
+	gem/i915_gem_wait.o
 i915-y += \
 	$(gem-y) \
 	i915_active.o \
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index b9dae15c1d16..a72d98f1202f 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -9,14 +9,15 @@
 #include <linux/uio.h>
 
 #include <drm/drm_cache.h>
+#include <drm/drm_gem.h>
 
 #include "gem/i915_gem_region.h"
 #include "i915_drv.h"
 #include "i915_gem_object.h"
 #include "i915_gem_tiling.h"
-#include "i915_gemfs.h"
 #include "i915_scatterlist.h"
 #include "i915_trace.h"
+#include "i915_utils.h"
 
 /*
  * Move folios to appropriate lru and release the batch, decrementing the
@@ -506,9 +507,9 @@ static int __create_shmem(struct drm_i915_private *i915,
 	if (BITS_PER_LONG == 64 && size > MAX_LFS_FILESIZE)
 		return -E2BIG;
 
-	if (i915->mm.gemfs)
-		filp = shmem_file_setup_with_mnt(i915->mm.gemfs, "i915", size,
-						 flags);
+	if (i915->drm.huge_mnt)
+		filp = shmem_file_setup_with_mnt(i915->drm.huge_mnt, "i915",
+						 size, flags);
 	else
 		filp = shmem_file_setup("i915", size, flags);
 	if (IS_ERR(filp))
@@ -635,21 +636,41 @@ i915_gem_object_create_shmem_from_data(struct drm_i915_private *i915,
 
 static int init_shmem(struct intel_memory_region *mem)
 {
-	i915_gemfs_init(mem->i915);
-	intel_memory_region_set_name(mem, "system");
+	struct drm_i915_private *i915 = mem->i915;
+	int err;
 
-	return 0; /* We have fallback to the kernel mnt if gemfs init failed. */
-}
+	/*
+	 * By creating our own shmemfs mountpoint, we can pass in
+	 * mount flags that better match our usecase.
+	 *
+	 * One example, although it is probably better with a per-file
+	 * control, is selecting huge page allocations ("huge=within_size").
+	 * However, we only do so on platforms which benefit from it, or to
+	 * offset the overhead of iommu lookups, where with latter it is a net
+	 * win even on platforms which would otherwise see some performance
+	 * regressions such a slow reads issue on Broadwell and Skylake.
+	 */
 
-static int release_shmem(struct intel_memory_region *mem)
-{
-	i915_gemfs_fini(mem->i915);
-	return 0;
+	if (GRAPHICS_VER(i915) < 11 && !i915_vtd_active(i915))
+		goto no_thp;
+
+	err = drm_gem_huge_mnt_create(&i915->drm, "within_size");
+	if (i915->drm.huge_mnt)
+		drm_info(&i915->drm, "Using Transparent Hugepages\n");
+	else if (err)
+		drm_notice(&i915->drm,
+			   "Transparent Hugepage support is recommended for optimal performance%s\n",
+			   GRAPHICS_VER(i915) >= 11 ? " on this platform!" :
+						      " when IOMMU is enabled!");
+
+ no_thp:
+	intel_memory_region_set_name(mem, "system");
+
+	return 0; /* We have fallback to the kernel mnt if huge mnt failed. */
 }
 
 static const struct intel_memory_region_ops shmem_region_ops = {
 	.init = init_shmem,
-	.release = release_shmem,
 	.init_object = shmem_object_init,
 };
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gemfs.c b/drivers/gpu/drm/i915/gem/i915_gemfs.c
deleted file mode 100644
index 8f13ec4ff0d0..000000000000
--- a/drivers/gpu/drm/i915/gem/i915_gemfs.c
+++ /dev/null
@@ -1,69 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2017 Intel Corporation
- */
-
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/fs_context.h>
-
-#include "i915_drv.h"
-#include "i915_gemfs.h"
-#include "i915_utils.h"
-
-void i915_gemfs_init(struct drm_i915_private *i915)
-{
-	struct file_system_type *type;
-	struct fs_context *fc;
-	struct vfsmount *gemfs;
-	int ret;
-
-	/*
-	 * By creating our own shmemfs mountpoint, we can pass in
-	 * mount flags that better match our usecase.
-	 *
-	 * One example, although it is probably better with a per-file
-	 * control, is selecting huge page allocations ("huge=within_size").
-	 * However, we only do so on platforms which benefit from it, or to
-	 * offset the overhead of iommu lookups, where with latter it is a net
-	 * win even on platforms which would otherwise see some performance
-	 * regressions such a slow reads issue on Broadwell and Skylake.
-	 */
-
-	if (GRAPHICS_VER(i915) < 11 && !i915_vtd_active(i915))
-		return;
-
-	if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
-		goto err;
-
-	type = get_fs_type("tmpfs");
-	if (!type)
-		goto err;
-
-	fc = fs_context_for_mount(type, SB_KERNMOUNT);
-	if (IS_ERR(fc))
-		goto err;
-	ret = vfs_parse_fs_string(fc, "source", "tmpfs");
-	if (!ret)
-		ret = vfs_parse_fs_string(fc, "huge", "within_size");
-	if (!ret)
-		gemfs = fc_mount_longterm(fc);
-	put_fs_context(fc);
-	if (ret)
-		goto err;
-
-	i915->mm.gemfs = gemfs;
-	drm_info(&i915->drm, "Using Transparent Hugepages\n");
-	return;
-
-err:
-	drm_notice(&i915->drm,
-		   "Transparent Hugepage support is recommended for optimal performance%s\n",
-		   GRAPHICS_VER(i915) >= 11 ? " on this platform!" :
-					      " when IOMMU is enabled!");
-}
-
-void i915_gemfs_fini(struct drm_i915_private *i915)
-{
-	kern_unmount(i915->mm.gemfs);
-}
diff --git a/drivers/gpu/drm/i915/gem/i915_gemfs.h b/drivers/gpu/drm/i915/gem/i915_gemfs.h
deleted file mode 100644
index 16d4333c9a4e..000000000000
--- a/drivers/gpu/drm/i915/gem/i915_gemfs.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2017 Intel Corporation
- */
-
-#ifndef __I915_GEMFS_H__
-#define __I915_GEMFS_H__
-
-struct drm_i915_private;
-
-void i915_gemfs_init(struct drm_i915_private *i915);
-void i915_gemfs_fini(struct drm_i915_private *i915);
-
-#endif
diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
index bd08605a1611..b41a38af63fd 100644
--- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
+++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
@@ -1316,7 +1316,7 @@ typedef struct drm_i915_gem_object *
 
 static inline bool igt_can_allocate_thp(struct drm_i915_private *i915)
 {
-	return i915->mm.gemfs && has_transparent_hugepage();
+	return i915->drm.huge_mnt && has_transparent_hugepage();
 }
 
 static struct drm_i915_gem_object *
@@ -1761,7 +1761,7 @@ static int igt_tmpfs_fallback(void *arg)
 	struct drm_i915_private *i915 = arg;
 	struct i915_address_space *vm;
 	struct i915_gem_context *ctx;
-	struct vfsmount *gemfs = i915->mm.gemfs;
+	struct vfsmount *huge_mnt = i915->drm.huge_mnt;
 	struct drm_i915_gem_object *obj;
 	struct i915_vma *vma;
 	struct file *file;
@@ -1782,10 +1782,10 @@ static int igt_tmpfs_fallback(void *arg)
 	/*
 	 * Make sure that we don't burst into a ball of flames upon falling back
 	 * to tmpfs, which we rely on if on the off-chance we encounter a failure
-	 * when setting up gemfs.
+	 * when setting up a huge mountpoint.
 	 */
 
-	i915->mm.gemfs = NULL;
+	i915->drm.huge_mnt = NULL;
 
 	obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
 	if (IS_ERR(obj)) {
@@ -1819,7 +1819,7 @@ static int igt_tmpfs_fallback(void *arg)
 out_put:
 	i915_gem_object_put(obj);
 out_restore:
-	i915->mm.gemfs = gemfs;
+	i915->drm.huge_mnt = huge_mnt;
 
 	i915_vm_put(vm);
 out:
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 6a768aad8edd..1bfee23e64a3 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -141,11 +141,6 @@ struct i915_gem_mm {
 	 */
 	atomic_t free_count;
 
-	/**
-	 * tmpfs instance used for shmem backed objects
-	 */
-	struct vfsmount *gemfs;
-
 	struct intel_memory_region *regions[INTEL_REGION_UNKNOWN];
 
 	struct notifier_block oom_notifier;
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 07/13] drm/v3d: Use huge tmpfs mount point helper
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
                   ` (5 preceding siblings ...)
  2025-10-15 15:30 ` [PATCH v4 06/13] drm/i915: Use " Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-20  9:33   ` Tvrtko Ursulin
  2025-10-15 15:30 ` [PATCH v4 08/13] drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n Loïc Molinari
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Make use of the new drm_gem_huge_mnt_create() helper to avoid code
duplication. Now that it's just a few lines long, the single function
in v3d_gemfs.c is moved into v3d_gem.c.

v3:
- use huge tmpfs mountpoint in drm_device
- move v3d_gemfs.c into v3d_gem.c

v4:
- clean up mountpoint creation error handling

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
---
 drivers/gpu/drm/v3d/Makefile    |  3 +-
 drivers/gpu/drm/v3d/v3d_bo.c    |  5 ++-
 drivers/gpu/drm/v3d/v3d_drv.c   |  2 +-
 drivers/gpu/drm/v3d/v3d_drv.h   | 11 +-----
 drivers/gpu/drm/v3d/v3d_gem.c   | 27 +++++++++++++--
 drivers/gpu/drm/v3d/v3d_gemfs.c | 60 ---------------------------------
 6 files changed, 30 insertions(+), 78 deletions(-)
 delete mode 100644 drivers/gpu/drm/v3d/v3d_gemfs.c

diff --git a/drivers/gpu/drm/v3d/Makefile b/drivers/gpu/drm/v3d/Makefile
index fcf710926057..b7d673f1153b 100644
--- a/drivers/gpu/drm/v3d/Makefile
+++ b/drivers/gpu/drm/v3d/Makefile
@@ -13,8 +13,7 @@ v3d-y := \
 	v3d_trace_points.o \
 	v3d_sched.o \
 	v3d_sysfs.o \
-	v3d_submit.o \
-	v3d_gemfs.o
+	v3d_submit.o
 
 v3d-$(CONFIG_DEBUG_FS) += v3d_debugfs.o
 
diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
index c41476ddde68..6b9909bfce82 100644
--- a/drivers/gpu/drm/v3d/v3d_bo.c
+++ b/drivers/gpu/drm/v3d/v3d_bo.c
@@ -112,7 +112,7 @@ v3d_bo_create_finish(struct drm_gem_object *obj)
 	if (IS_ERR(sgt))
 		return PTR_ERR(sgt);
 
-	if (!v3d->gemfs)
+	if (!obj->dev->huge_mnt)
 		align = SZ_4K;
 	else if (obj->size >= SZ_1M)
 		align = SZ_1M;
@@ -148,12 +148,11 @@ struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv,
 			     size_t unaligned_size)
 {
 	struct drm_gem_shmem_object *shmem_obj;
-	struct v3d_dev *v3d = to_v3d_dev(dev);
 	struct v3d_bo *bo;
 	int ret;
 
 	shmem_obj = drm_gem_shmem_create_with_mnt(dev, unaligned_size,
-						  v3d->gemfs);
+						  dev->huge_mnt);
 	if (IS_ERR(shmem_obj))
 		return ERR_CAST(shmem_obj);
 	bo = to_v3d_bo(&shmem_obj->base);
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
index c5a3bbbc74c5..19ec0ea7f38e 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
@@ -106,7 +106,7 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
 		args->value = v3d->perfmon_info.max_counters;
 		return 0;
 	case DRM_V3D_PARAM_SUPPORTS_SUPER_PAGES:
-		args->value = !!v3d->gemfs;
+		args->value = !!dev->huge_mnt;
 		return 0;
 	case DRM_V3D_PARAM_GLOBAL_RESET_COUNTER:
 		mutex_lock(&v3d->reset_lock);
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
index 1884686985b8..99a39329bb85 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.h
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
@@ -158,11 +158,6 @@ struct v3d_dev {
 	struct drm_mm mm;
 	spinlock_t mm_lock;
 
-	/*
-	 * tmpfs instance used for shmem backed objects
-	 */
-	struct vfsmount *gemfs;
-
 	struct work_struct overflow_mem_work;
 
 	struct v3d_queue_state queue[V3D_MAX_QUEUES];
@@ -569,6 +564,7 @@ extern const struct dma_fence_ops v3d_fence_ops;
 struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q);
 
 /* v3d_gem.c */
+extern bool super_pages;
 int v3d_gem_init(struct drm_device *dev);
 void v3d_gem_destroy(struct drm_device *dev);
 void v3d_reset_sms(struct v3d_dev *v3d);
@@ -576,11 +572,6 @@ void v3d_reset(struct v3d_dev *v3d);
 void v3d_invalidate_caches(struct v3d_dev *v3d);
 void v3d_clean_caches(struct v3d_dev *v3d);
 
-/* v3d_gemfs.c */
-extern bool super_pages;
-void v3d_gemfs_init(struct v3d_dev *v3d);
-void v3d_gemfs_fini(struct v3d_dev *v3d);
-
 /* v3d_submit.c */
 void v3d_job_cleanup(struct v3d_job *job);
 void v3d_job_put(struct v3d_job *job);
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index bb110d35f749..635ff0fabe7e 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -258,6 +258,30 @@ v3d_invalidate_caches(struct v3d_dev *v3d)
 	v3d_invalidate_slices(v3d, 0);
 }
 
+static void
+v3d_huge_mnt_init(struct v3d_dev *v3d)
+{
+	int err = 0;
+
+	/*
+	 * By using a huge shmemfs mountpoint when the user wants to
+	 * enable Super Pages, we can pass in mount flags that better
+	 * match our usecase.
+	 */
+
+	if (super_pages)
+		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
+
+	if (v3d->drm.huge_mnt)
+		drm_info(&v3d->drm, "Using Transparent Hugepages\n");
+	else if (err)
+		drm_warn(&v3d->drm, "Can't use Transparent Hugepages (%d)\n",
+			 err);
+	else
+		drm_notice(&v3d->drm,
+			   "Transparent Hugepage support is recommended for optimal performance on this platform!\n");
+}
+
 int
 v3d_gem_init(struct drm_device *dev)
 {
@@ -309,7 +333,7 @@ v3d_gem_init(struct drm_device *dev)
 	v3d_init_hw_state(v3d);
 	v3d_mmu_set_page_table(v3d);
 
-	v3d_gemfs_init(v3d);
+	v3d_huge_mnt_init(v3d);
 
 	ret = v3d_sched_init(v3d);
 	if (ret) {
@@ -329,7 +353,6 @@ v3d_gem_destroy(struct drm_device *dev)
 	enum v3d_queue q;
 
 	v3d_sched_fini(v3d);
-	v3d_gemfs_fini(v3d);
 
 	/* Waiting for jobs to finish would need to be done before
 	 * unregistering V3D.
diff --git a/drivers/gpu/drm/v3d/v3d_gemfs.c b/drivers/gpu/drm/v3d/v3d_gemfs.c
deleted file mode 100644
index c1a30166c099..000000000000
--- a/drivers/gpu/drm/v3d/v3d_gemfs.c
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/* Copyright (C) 2024 Raspberry Pi */
-
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/fs_context.h>
-
-#include "v3d_drv.h"
-
-void v3d_gemfs_init(struct v3d_dev *v3d)
-{
-	struct file_system_type *type;
-	struct fs_context *fc;
-	struct vfsmount *gemfs;
-	int ret;
-
-	/*
-	 * By creating our own shmemfs mountpoint, we can pass in
-	 * mount flags that better match our usecase. However, we
-	 * only do so on platforms which benefit from it.
-	 */
-	if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
-		goto err;
-
-	/* The user doesn't want to enable Super Pages */
-	if (!super_pages)
-		goto err;
-
-	type = get_fs_type("tmpfs");
-	if (!type)
-		goto err;
-
-	fc = fs_context_for_mount(type, SB_KERNMOUNT);
-	if (IS_ERR(fc))
-		goto err;
-	ret = vfs_parse_fs_string(fc, "source", "tmpfs");
-	if (!ret)
-		ret = vfs_parse_fs_string(fc, "huge", "within_size");
-	if (!ret)
-		gemfs = fc_mount_longterm(fc);
-	put_fs_context(fc);
-	if (ret)
-		goto err;
-
-	v3d->gemfs = gemfs;
-	drm_info(&v3d->drm, "Using Transparent Hugepages\n");
-
-	return;
-
-err:
-	v3d->gemfs = NULL;
-	drm_notice(&v3d->drm,
-		   "Transparent Hugepage support is recommended for optimal performance on this platform!\n");
-}
-
-void v3d_gemfs_fini(struct v3d_dev *v3d)
-{
-	if (v3d->gemfs)
-		kern_unmount(v3d->gemfs);
-}
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 08/13] drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
                   ` (6 preceding siblings ...)
  2025-10-15 15:30 ` [PATCH v4 07/13] drm/v3d: " Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-15 18:17   ` Boris Brezillon
  2025-10-15 15:30 ` [PATCH v4 09/13] drm/gem: Get rid of *_with_mnt helpers Loïc Molinari
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Don't declare "super_pages" on builds with CONFIG_TRANSPARENT_HUGEPAGE
disabled to prevent build error:

ERROR: modpost: "super_pages" [drivers/gpu/drm/v3d/v3d.ko] undefined!

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
---
 drivers/gpu/drm/v3d/v3d_drv.h | 2 ++
 drivers/gpu/drm/v3d/v3d_gem.c | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
index 99a39329bb85..481502104391 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.h
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
@@ -564,7 +564,9 @@ extern const struct dma_fence_ops v3d_fence_ops;
 struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q);
 
 /* v3d_gem.c */
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 extern bool super_pages;
+#endif
 int v3d_gem_init(struct drm_device *dev);
 void v3d_gem_destroy(struct drm_device *dev);
 void v3d_reset_sms(struct v3d_dev *v3d);
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index 635ff0fabe7e..0039063eb8b2 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -269,7 +269,9 @@ v3d_huge_mnt_init(struct v3d_dev *v3d)
 	 * match our usecase.
 	 */
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	if (super_pages)
+#endif
 		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
 
 	if (v3d->drm.huge_mnt)
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 09/13] drm/gem: Get rid of *_with_mnt helpers
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
                   ` (7 preceding siblings ...)
  2025-10-15 15:30 ` [PATCH v4 08/13] drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 10/13] drm/panthor: Introduce huge tmpfs mount point option Loïc Molinari
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

drm_gem_object_init_with_mnt() and drm_gem_shmem_create_with_mnt() can
be removed now that the drivers use drm_gem_huge_mnt_create().

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/drm_gem.c              | 34 ++++++-----------------
 drivers/gpu/drm/drm_gem_shmem_helper.c | 38 ++++++--------------------
 drivers/gpu/drm/v3d/v3d_bo.c           |  3 +-
 include/drm/drm_gem.h                  |  3 --
 include/drm/drm_gem_shmem_helper.h     |  3 --
 5 files changed, 17 insertions(+), 64 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index db8c0a217add..d8fa789cf330 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -172,28 +172,26 @@ drm_gem_init(struct drm_device *dev)
 }
 
 /**
- * drm_gem_object_init_with_mnt - initialize an allocated shmem-backed GEM
- * object in a given shmfs mountpoint
+ * drm_gem_object_init - initialize an allocated shmem-backed GEM object
  *
  * @dev: drm_device the object should be initialized for
  * @obj: drm_gem_object to initialize
  * @size: object size
- * @gemfs: tmpfs mount where the GEM object will be created. If NULL, use
- * the usual tmpfs mountpoint (`shm_mnt`).
  *
  * Initialize an already allocated GEM object of the specified size with
- * shmfs backing store.
+ * shmfs backing store. A huge mountpoint can be used by calling
+ * drm_gem_huge_mnt_create() beforehand.
  */
-int drm_gem_object_init_with_mnt(struct drm_device *dev,
-				 struct drm_gem_object *obj, size_t size,
-				 struct vfsmount *gemfs)
+int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj,
+			size_t size)
 {
 	struct file *filp;
 
 	drm_gem_private_object_init(dev, obj, size);
 
-	if (gemfs)
-		filp = shmem_file_setup_with_mnt(gemfs, "drm mm object", size,
+	if (dev->huge_mnt)
+		filp = shmem_file_setup_with_mnt(dev->huge_mnt,
+						 "drm mm object", size,
 						 VM_NORESERVE);
 	else
 		filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
@@ -205,22 +203,6 @@ int drm_gem_object_init_with_mnt(struct drm_device *dev,
 
 	return 0;
 }
-EXPORT_SYMBOL(drm_gem_object_init_with_mnt);
-
-/**
- * drm_gem_object_init - initialize an allocated shmem-backed GEM object
- * @dev: drm_device the object should be initialized for
- * @obj: drm_gem_object to initialize
- * @size: object size
- *
- * Initialize an already allocated GEM object of the specified size with
- * shmfs backing store.
- */
-int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj,
-			size_t size)
-{
-	return drm_gem_object_init_with_mnt(dev, obj, size, NULL);
-}
 EXPORT_SYMBOL(drm_gem_object_init);
 
 /**
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 5d11bea573fe..33f2ecc5f31f 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -50,7 +50,7 @@ static const struct drm_gem_object_funcs drm_gem_shmem_funcs = {
 };
 
 static int __drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem,
-				size_t size, bool private, struct vfsmount *gemfs)
+				size_t size, bool private)
 {
 	struct drm_gem_object *obj = &shmem->base;
 	int ret = 0;
@@ -62,7 +62,7 @@ static int __drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_obj
 		drm_gem_private_object_init(dev, obj, size);
 		shmem->map_wc = false; /* dma-buf mappings use always writecombine */
 	} else {
-		ret = drm_gem_object_init_with_mnt(dev, obj, size, gemfs);
+		ret = drm_gem_object_init(dev, obj, size);
 	}
 	if (ret) {
 		drm_gem_private_object_fini(obj);
@@ -103,13 +103,12 @@ static int __drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_obj
  */
 int drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, size_t size)
 {
-	return __drm_gem_shmem_init(dev, shmem, size, false, NULL);
+	return __drm_gem_shmem_init(dev, shmem, size, false);
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_init);
 
 static struct drm_gem_shmem_object *
-__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private,
-		       struct vfsmount *gemfs)
+__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private)
 {
 	struct drm_gem_shmem_object *shmem;
 	struct drm_gem_object *obj;
@@ -129,7 +128,7 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private,
 		obj = &shmem->base;
 	}
 
-	ret = __drm_gem_shmem_init(dev, shmem, size, private, gemfs);
+	ret = __drm_gem_shmem_init(dev, shmem, size, private);
 	if (ret) {
 		kfree(obj);
 		return ERR_PTR(ret);
@@ -150,31 +149,10 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private,
  */
 struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size)
 {
-	return __drm_gem_shmem_create(dev, size, false, NULL);
+	return __drm_gem_shmem_create(dev, size, false);
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
 
-/**
- * drm_gem_shmem_create_with_mnt - Allocate an object with the given size in a
- * given mountpoint
- * @dev: DRM device
- * @size: Size of the object to allocate
- * @gemfs: tmpfs mount where the GEM object will be created
- *
- * This function creates a shmem GEM object in a given tmpfs mountpoint.
- *
- * Returns:
- * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative
- * error code on failure.
- */
-struct drm_gem_shmem_object *drm_gem_shmem_create_with_mnt(struct drm_device *dev,
-							   size_t size,
-							   struct vfsmount *gemfs)
-{
-	return __drm_gem_shmem_create(dev, size, false, gemfs);
-}
-EXPORT_SYMBOL_GPL(drm_gem_shmem_create_with_mnt);
-
 /**
  * drm_gem_shmem_release - Release resources associated with a shmem GEM object.
  * @shmem: shmem GEM object
@@ -902,7 +880,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
 	size_t size = PAGE_ALIGN(attach->dmabuf->size);
 	struct drm_gem_shmem_object *shmem;
 
-	shmem = __drm_gem_shmem_create(dev, size, true, NULL);
+	shmem = __drm_gem_shmem_create(dev, size, true);
 	if (IS_ERR(shmem))
 		return ERR_CAST(shmem);
 
@@ -950,7 +928,7 @@ struct drm_gem_object *drm_gem_shmem_prime_import_no_map(struct drm_device *dev,
 
 	size = PAGE_ALIGN(attach->dmabuf->size);
 
-	shmem = __drm_gem_shmem_create(dev, size, true, NULL);
+	shmem = __drm_gem_shmem_create(dev, size, true);
 	if (IS_ERR(shmem)) {
 		ret = PTR_ERR(shmem);
 		goto fail_detach;
diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
index 6b9909bfce82..ef9e9c15da3c 100644
--- a/drivers/gpu/drm/v3d/v3d_bo.c
+++ b/drivers/gpu/drm/v3d/v3d_bo.c
@@ -151,8 +151,7 @@ struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv,
 	struct v3d_bo *bo;
 	int ret;
 
-	shmem_obj = drm_gem_shmem_create_with_mnt(dev, unaligned_size,
-						  dev->huge_mnt);
+	shmem_obj = drm_gem_shmem_create(dev, unaligned_size);
 	if (IS_ERR(shmem_obj))
 		return ERR_CAST(shmem_obj);
 	bo = to_v3d_bo(&shmem_obj->base);
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index 7285a62d9afc..42d9066b1785 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -497,9 +497,6 @@ void drm_gem_object_release(struct drm_gem_object *obj);
 void drm_gem_object_free(struct kref *kref);
 int drm_gem_object_init(struct drm_device *dev,
 			struct drm_gem_object *obj, size_t size);
-int drm_gem_object_init_with_mnt(struct drm_device *dev,
-				 struct drm_gem_object *obj, size_t size,
-				 struct vfsmount *gemfs);
 void drm_gem_private_object_init(struct drm_device *dev,
 				 struct drm_gem_object *obj, size_t size);
 void drm_gem_private_object_fini(struct drm_gem_object *obj);
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index 589f7bfe7506..6b6478f5ca24 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -109,9 +109,6 @@ struct drm_gem_shmem_object {
 
 int drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, size_t size);
 struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size);
-struct drm_gem_shmem_object *drm_gem_shmem_create_with_mnt(struct drm_device *dev,
-							   size_t size,
-							   struct vfsmount *gemfs);
 void drm_gem_shmem_release(struct drm_gem_shmem_object *shmem);
 void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem);
 
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 10/13] drm/panthor: Introduce huge tmpfs mount point option
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
                   ` (8 preceding siblings ...)
  2025-10-15 15:30 ` [PATCH v4 09/13] drm/gem: Get rid of *_with_mnt helpers Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 11/13] drm/panthor: Improve IOMMU map/unmap debugging logs Loïc Molinari
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Introduce the 'panthor.transparent_hugepage' boolean module parameter
(false by default). When the parameter is set to true, a new tmpfs
mount point is created and mounted using the 'huge=within_size'
option. It's then used at GEM object creation instead of the default
'shm_mnt' mount point in order to enable Transparent Hugepage (THP)
for the object (without having to rely on a system wide parameter).

v3:
- use huge tmpfs mountpoint in drm_device

v4:
- fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n
- clean up mountpoint creation error handling
- print negative error value

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/panthor/panthor_device.c |  3 +++
 drivers/gpu/drm/panthor/panthor_drv.c    |  7 +++++++
 drivers/gpu/drm/panthor/panthor_drv.h    | 11 +++++++++++
 drivers/gpu/drm/panthor/panthor_gem.c    | 19 +++++++++++++++++++
 drivers/gpu/drm/panthor/panthor_gem.h    |  2 ++
 5 files changed, 42 insertions(+)
 create mode 100644 drivers/gpu/drm/panthor/panthor_drv.h

diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
index c7033d82cef5..4ced0bef22e8 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -17,6 +17,7 @@
 #include "panthor_devfreq.h"
 #include "panthor_device.h"
 #include "panthor_fw.h"
+#include "panthor_gem.h"
 #include "panthor_gpu.h"
 #include "panthor_hw.h"
 #include "panthor_mmu.h"
@@ -271,6 +272,8 @@ int panthor_device_init(struct panthor_device *ptdev)
 	if (ret)
 		goto err_unplug_fw;
 
+	panthor_gem_init(ptdev);
+
 	/* ~3 frames */
 	pm_runtime_set_autosuspend_delay(ptdev->base.dev, 50);
 	pm_runtime_use_autosuspend(ptdev->base.dev);
diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c
index fb4b293f17f0..9e49af1d0959 100644
--- a/drivers/gpu/drm/panthor/panthor_drv.c
+++ b/drivers/gpu/drm/panthor/panthor_drv.c
@@ -1556,6 +1556,7 @@ static const struct file_operations panthor_drm_driver_fops = {
 	.read = drm_read,
 	.llseek = noop_llseek,
 	.mmap = panthor_mmap,
+	.get_unmapped_area = drm_gem_get_unmapped_area,
 	.show_fdinfo = drm_show_fdinfo,
 	.fop_flags = FOP_UNSIGNED_OFFSET,
 };
@@ -1623,6 +1624,12 @@ static const struct drm_driver panthor_drm_driver = {
 #endif
 };
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+bool panthor_transparent_hugepage;
+module_param_named(transparent_hugepage, panthor_transparent_hugepage, bool, 0400);
+MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (false = default)");
+#endif
+
 static int panthor_probe(struct platform_device *pdev)
 {
 	struct panthor_device *ptdev;
diff --git a/drivers/gpu/drm/panthor/panthor_drv.h b/drivers/gpu/drm/panthor/panthor_drv.h
new file mode 100644
index 000000000000..27fe9b6f77bd
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_drv.h
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+/* Copyright 2025 Amazon.com, Inc. or its affiliates */
+
+#ifndef __PANTHOR_DRV_H__
+#define __PANTHOR_DRV_H__
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+extern bool panthor_transparent_hugepage;
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c
index 156c7a0b62a2..1a176e7e35ea 100644
--- a/drivers/gpu/drm/panthor/panthor_gem.c
+++ b/drivers/gpu/drm/panthor/panthor_gem.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 or MIT
 /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
 /* Copyright 2023 Collabora ltd. */
+/* Copyright 2025 Amazon.com, Inc. or its affiliates */
 
 #include <linux/cleanup.h>
 #include <linux/dma-buf.h>
@@ -11,10 +12,28 @@
 #include <drm/panthor_drm.h>
 
 #include "panthor_device.h"
+#include "panthor_drv.h"
 #include "panthor_fw.h"
 #include "panthor_gem.h"
 #include "panthor_mmu.h"
 
+void panthor_gem_init(struct panthor_device *ptdev)
+{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+	int err;
+
+	if (!panthor_transparent_hugepage)
+		return;
+
+	err = drm_gem_huge_mnt_create(&ptdev->base, "within_size");
+	if (ptdev->base.huge_mnt)
+		drm_info(&ptdev->base, "Using Transparent Hugepage\n");
+	else if (err)
+		drm_warn(&ptdev->base, "Can't use Transparent Hugepage (%d)\n",
+			 err);
+#endif
+}
+
 #ifdef CONFIG_DEBUG_FS
 static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo)
 {
diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h
index 80c6e24112d0..2eefe9104e5e 100644
--- a/drivers/gpu/drm/panthor/panthor_gem.h
+++ b/drivers/gpu/drm/panthor/panthor_gem.h
@@ -136,6 +136,8 @@ struct panthor_gem_object *to_panthor_bo(struct drm_gem_object *obj)
 	return container_of(to_drm_gem_shmem_obj(obj), struct panthor_gem_object, base);
 }
 
+void panthor_gem_init(struct panthor_device *ptdev);
+
 struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size);
 
 int
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 11/13] drm/panthor: Improve IOMMU map/unmap debugging logs
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
                   ` (9 preceding siblings ...)
  2025-10-15 15:30 ` [PATCH v4 10/13] drm/panthor: Introduce huge tmpfs mount point option Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 12/13] drm/panfrost: Introduce huge tmpfs mount point option Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 13/13] Documentation/gpu/drm-mm: Add THP paragraph to GEM mapping section Loïc Molinari
  12 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Log the number of pages and their sizes actually mapped/unmapped by
the IOMMU page table driver. Since a map/unmap op is often split in
several ops depending on the underlying scatter/gather table, add the
start address and the total size to the debugging logs in order to
help understand which batch an op is part of.

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/panthor/panthor_mmu.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index 6dec4354e378..aefbd83d1a75 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -917,10 +917,9 @@ static int panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size)
 {
 	struct panthor_device *ptdev = vm->ptdev;
 	struct io_pgtable_ops *ops = vm->pgtbl_ops;
+	u64 start_iova = iova;
 	u64 offset = 0;
 
-	drm_dbg(&ptdev->base, "unmap: as=%d, iova=%llx, len=%llx", vm->as.id, iova, size);
-
 	while (offset < size) {
 		size_t unmapped_sz = 0, pgcount;
 		size_t pgsize = get_pgsize(iova + offset, size - offset, &pgcount);
@@ -935,6 +934,12 @@ static int panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size)
 			panthor_vm_flush_range(vm, iova, offset + unmapped_sz);
 			return  -EINVAL;
 		}
+
+		drm_dbg(&ptdev->base,
+			"unmap: as=%d, iova=0x%llx, sz=%llu, va=0x%llx, pgcnt=%zu, pgsz=%zu",
+			vm->as.id, start_iova, size, iova + offset,
+			unmapped_sz / pgsize, pgsize);
+
 		offset += unmapped_sz;
 	}
 
@@ -950,6 +955,7 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, int prot,
 	struct scatterlist *sgl;
 	struct io_pgtable_ops *ops = vm->pgtbl_ops;
 	u64 start_iova = iova;
+	u64 start_size = size;
 	int ret;
 
 	if (!size)
@@ -969,15 +975,18 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, int prot,
 		len = min_t(size_t, len, size);
 		size -= len;
 
-		drm_dbg(&ptdev->base, "map: as=%d, iova=%llx, paddr=%pad, len=%zx",
-			vm->as.id, iova, &paddr, len);
-
 		while (len) {
 			size_t pgcount, mapped = 0;
 			size_t pgsize = get_pgsize(iova | paddr, len, &pgcount);
 
 			ret = ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot,
 					     GFP_KERNEL, &mapped);
+
+			drm_dbg(&ptdev->base,
+				"map: as=%d, iova=0x%llx, sz=%llu, va=0x%llx, pa=%pad, pgcnt=%zu, pgsz=%zu",
+				vm->as.id, start_iova, start_size, iova, &paddr,
+				mapped / pgsize, pgsize);
+
 			iova += mapped;
 			paddr += mapped;
 			len -= mapped;
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 12/13] drm/panfrost: Introduce huge tmpfs mount point option
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
                   ` (10 preceding siblings ...)
  2025-10-15 15:30 ` [PATCH v4 11/13] drm/panthor: Improve IOMMU map/unmap debugging logs Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  2025-10-15 15:30 ` [PATCH v4 13/13] Documentation/gpu/drm-mm: Add THP paragraph to GEM mapping section Loïc Molinari
  12 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Introduce the 'panfrost.transparent_hugepage' boolean module parameter
(false by default). When the parameter is set to true, a new tmpfs
mount point is created and mounted using the 'huge=within_size'
option. It's then used at GEM object creation instead of the default
'shm_mnt' mount point in order to enable Transparent Hugepage (THP)
for the object (without having to rely on a system wide parameter).

v3:
- use huge tmpfs mountpoint in drm_device

v4:
- fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n
- clean up mountpoint creation error handling
- print negative error value

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/panfrost/panfrost_device.c |  3 +++
 drivers/gpu/drm/panfrost/panfrost_drv.c    |  6 ++++++
 drivers/gpu/drm/panfrost/panfrost_drv.h    | 11 +++++++++++
 drivers/gpu/drm/panfrost/panfrost_gem.c    | 19 +++++++++++++++++++
 drivers/gpu/drm/panfrost/panfrost_gem.h    |  2 ++
 5 files changed, 41 insertions(+)
 create mode 100644 drivers/gpu/drm/panfrost/panfrost_drv.h

diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index 04bec27449cb..a189bfaac959 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -12,6 +12,7 @@
 #include "panfrost_device.h"
 #include "panfrost_devfreq.h"
 #include "panfrost_features.h"
+#include "panfrost_gem.h"
 #include "panfrost_issues.h"
 #include "panfrost_gpu.h"
 #include "panfrost_job.h"
@@ -266,6 +267,8 @@ int panfrost_device_init(struct panfrost_device *pfdev)
 	if (err)
 		goto out_job;
 
+	panfrost_gem_init(pfdev);
+
 	return 0;
 out_job:
 	panfrost_job_fini(pfdev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 607a5b8448d0..dfeb6a633fa1 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -858,6 +858,12 @@ static const struct drm_driver panfrost_drm_driver = {
 #endif
 };
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+bool panfrost_transparent_hugepage;
+module_param_named(transparent_hugepage, panfrost_transparent_hugepage, bool, 0400);
+MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (false = default)");
+#endif
+
 static int panfrost_probe(struct platform_device *pdev)
 {
 	struct panfrost_device *pfdev;
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.h b/drivers/gpu/drm/panfrost/panfrost_drv.h
new file mode 100644
index 000000000000..60454611b6a6
--- /dev/null
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.h
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+/* Copyright 2025 Amazon.com, Inc. or its affiliates */
+
+#ifndef __PANFROST_DRV_H__
+#define __PANFROST_DRV_H__
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+extern bool panfrost_transparent_hugepage;
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
index 85d6289a6eda..9b059a8b0f9f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
+/* Copyright 2025 Amazon.com, Inc. or its affiliates */
 
 #include <linux/cleanup.h>
 #include <linux/err.h>
@@ -9,9 +10,27 @@
 
 #include <drm/panfrost_drm.h>
 #include "panfrost_device.h"
+#include "panfrost_drv.h"
 #include "panfrost_gem.h"
 #include "panfrost_mmu.h"
 
+void panfrost_gem_init(struct panfrost_device *pfdev)
+{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+	int err;
+
+	if (!panfrost_transparent_hugepage)
+		return;
+
+	err = drm_gem_huge_mnt_create(pfdev->ddev, "within_size");
+	if (pfdev->ddev->huge_mnt)
+		drm_info(pfdev->ddev, "Using Transparent Hugepage\n");
+	else if (err)
+		drm_warn(pfdev->ddev, "Can't use Transparent Hugepage (%d)\n",
+			 err);
+#endif
+}
+
 #ifdef CONFIG_DEBUG_FS
 static void panfrost_gem_debugfs_bo_add(struct panfrost_device *pfdev,
 					struct panfrost_gem_object *bo)
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h
index 8de3e76f2717..1a62529ff06f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.h
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.h
@@ -124,6 +124,8 @@ drm_mm_node_to_panfrost_mapping(struct drm_mm_node *node)
 	return container_of(node, struct panfrost_gem_mapping, mmnode);
 }
 
+void panfrost_gem_init(struct panfrost_device *pfdev);
+
 struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size);
 
 struct drm_gem_object *
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v4 13/13] Documentation/gpu/drm-mm: Add THP paragraph to GEM mapping section
  2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
                   ` (11 preceding siblings ...)
  2025-10-15 15:30 ` [PATCH v4 12/13] drm/panfrost: Introduce huge tmpfs mount point option Loïc Molinari
@ 2025-10-15 15:30 ` Loïc Molinari
  12 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 15:30 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Loïc Molinari,
	Al Viro, Mikołaj Wasiak, Christian Brauner, Nitin Gote,
	Andi Shyti, Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Add a paragraph to the GEM objects mapping section explaining how
transparent huge pages are handled by GEM.

v4:
- fix wording after huge_pages handler removal

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
Reviewed-by: Bagas Sanjaya <bagasdotme@gmail.com>
---
 Documentation/gpu/drm-mm.rst | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst
index d55751cad67c..3d6176adc7ca 100644
--- a/Documentation/gpu/drm-mm.rst
+++ b/Documentation/gpu/drm-mm.rst
@@ -283,6 +283,9 @@ made up of several fields, the more interesting ones being:
 		void (*open)(struct vm_area_struct * area);
 		void (*close)(struct vm_area_struct * area);
 		vm_fault_t (*fault)(struct vm_fault *vmf);
+		vm_fault_t (*map_pages)(struct vm_fault *vmf,
+					pgoff_t start_pgoff,
+					pgoff_t end_pgoff);
 	};
 
 
@@ -290,15 +293,27 @@ The open and close operations must update the GEM object reference
 count. Drivers can use the drm_gem_vm_open() and drm_gem_vm_close() helper
 functions directly as open and close handlers.
 
-The fault operation handler is responsible for mapping individual pages
-to userspace when a page fault occurs. Depending on the memory
-allocation scheme, drivers can allocate pages at fault time, or can
-decide to allocate memory for the GEM object at the time the object is
-created.
+The fault and map_pages operations are responsible for mapping pages to
+userspace when a page fault occurs. Depending on the memory allocation
+scheme, drivers can allocate pages at fault time, or can decide to
+allocate memory for the GEM object at the time the object is created.
 
 Drivers that want to map the GEM object upfront instead of handling page
 faults can implement their own mmap file operation handler.
 
+In order to reduce page table overhead, if the internal shmem mountpoint
+"shm_mnt" is configured to use transparent huge pages (for builds with
+CONFIG_TRANSPARENT_HUGEPAGE enabled) and if the shmem backing store
+managed to allocate a huge page for a faulty address, the fault and
+map_pages handlers will first attempt to insert that huge page into the
+VMA before falling back to individual page insertion. mmap() user
+address alignment for GEM objects is handled by providing a custom
+get_unmapped_area file operation which forwards to the shmem backing
+store. For most drivers, which don't create a huge mountpoint by default
+or through a module parameter, transparent huge pages can be enabled by
+either setting the "transparent_hugepage_shmem" kernel parameter or the
+"/sys/kernel/mm/transparent_hugepage/shmem_enabled" sysfs knob.
+
 For platforms without MMU the GEM core provides a helper method
 drm_gem_dma_get_unmapped_area(). The mmap() routines will call this to get a
 proposed address for the mapping.
-- 
2.47.3



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 03/13] drm/shmem-helper: Map huge pages in fault handlers
  2025-10-15 15:30 ` [PATCH v4 03/13] drm/shmem-helper: Map huge pages in fault handlers Loïc Molinari
@ 2025-10-15 17:27   ` Matthew Wilcox
  2025-10-16 11:17     ` Loïc Molinari
  0 siblings, 1 reply; 27+ messages in thread
From: Matthew Wilcox @ 2025-10-15 17:27 UTC (permalink / raw)
  To: Loïc Molinari
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Al Viro,
	Mikołaj Wasiak, Christian Brauner, Nitin Gote, Andi Shyti,
	Jonathan Corbet, Christopher Healy, Bagas Sanjaya, linux-kernel,
	dri-devel, intel-gfx, linux-mm, linux-doc, kernel

On Wed, Oct 15, 2025 at 05:30:07PM +0200, Loïc Molinari wrote:

This looks fine, no need to resend to fix this, but if you'd written
the previous patch slightly differently, you'd've reduced the amount of
code you moved around in this patch, which would have made it easier to
review.

> +	/* Map a range of pages around the faulty address. */
> +	do {
> +		pfn = page_to_pfn(pages[start_pgoff]);
> +		ret = vmf_insert_pfn(vma, addr, pfn);
> +		addr += PAGE_SIZE;
> +	} while (++start_pgoff <= end_pgoff && ret == VM_FAULT_NOPAGE);

It looks to me like we have an opportunity to do better here by
adding a vmf_insert_pfns() interface.  I don't think we should delay
your patch series to add it, but let's not forget to do that; it can
have very good performnce effects on ARM to use contptes.

> @@ -617,8 +645,9 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
[...]
>  
> -		ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page));
> +	if (drm_gem_shmem_map_pmd(vmf, vmf->address, pages[page_offset])) {
> +		ret = VM_FAULT_NOPAGE;
> +		goto out;
>  	}

Does this actually work?


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 08/13] drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n
  2025-10-15 15:30 ` [PATCH v4 08/13] drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n Loïc Molinari
@ 2025-10-15 18:17   ` Boris Brezillon
  2025-10-15 20:41     ` Loïc Molinari
  0 siblings, 1 reply; 27+ messages in thread
From: Boris Brezillon @ 2025-10-15 18:17 UTC (permalink / raw)
  To: Loïc Molinari
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Rob Herring, Steven Price,
	Liviu Dudau, Melissa Wen, Maíra Canal, Hugh Dickins,
	Baolin Wang, Andrew Morton, Al Viro, Mikołaj Wasiak,
	Christian Brauner, Nitin Gote, Andi Shyti, Jonathan Corbet,
	Christopher Healy, Matthew Wilcox, Bagas Sanjaya, linux-kernel,
	dri-devel, intel-gfx, linux-mm, linux-doc, kernel

On Wed, 15 Oct 2025 17:30:12 +0200
Loïc Molinari <loic.molinari@collabora.com> wrote:

> Don't declare "super_pages" on builds with CONFIG_TRANSPARENT_HUGEPAGE
> disabled to prevent build error:
> 
> ERROR: modpost: "super_pages" [drivers/gpu/drm/v3d/v3d.ko] undefined!

I believe this is a bug introduced by the previous commit: the
compiler probably drops any code between the
IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) check and the err label
because IS_ENABLED() evaluates to false at compile time. So I'd squash
those changes in the previous commit.

> 
> Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
> ---
>  drivers/gpu/drm/v3d/v3d_drv.h | 2 ++
>  drivers/gpu/drm/v3d/v3d_gem.c | 2 ++
>  2 files changed, 4 insertions(+)
> 
> diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
> index 99a39329bb85..481502104391 100644
> --- a/drivers/gpu/drm/v3d/v3d_drv.h
> +++ b/drivers/gpu/drm/v3d/v3d_drv.h
> @@ -564,7 +564,9 @@ extern const struct dma_fence_ops v3d_fence_ops;
>  struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q);
>  
>  /* v3d_gem.c */
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>  extern bool super_pages;
> +#endif
>  int v3d_gem_init(struct drm_device *dev);
>  void v3d_gem_destroy(struct drm_device *dev);
>  void v3d_reset_sms(struct v3d_dev *v3d);
> diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
> index 635ff0fabe7e..0039063eb8b2 100644
> --- a/drivers/gpu/drm/v3d/v3d_gem.c
> +++ b/drivers/gpu/drm/v3d/v3d_gem.c
> @@ -269,7 +269,9 @@ v3d_huge_mnt_init(struct v3d_dev *v3d)
>  	 * match our usecase.
>  	 */
>  
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>  	if (super_pages)
> +#endif
>  		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");

Why not

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
  	if (super_pages)
  		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
#endif

I guess

	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && super_pages)
		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");

would also do, since it's likely to rely on the same optimization the
previous v3d_gemfs_init() implementation was relying on, but it's
fragile (not sure what happens when compiled with -O0).

>  
>  	if (v3d->drm.huge_mnt)



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 08/13] drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n
  2025-10-15 18:17   ` Boris Brezillon
@ 2025-10-15 20:41     ` Loïc Molinari
  2025-10-16  5:56       ` Boris Brezillon
  0 siblings, 1 reply; 27+ messages in thread
From: Loïc Molinari @ 2025-10-15 20:41 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Rob Herring, Steven Price,
	Liviu Dudau, Melissa Wen, Maíra Canal, Hugh Dickins,
	Baolin Wang, Andrew Morton, Al Viro, Mikołaj Wasiak,
	Christian Brauner, Nitin Gote, Andi Shyti, Jonathan Corbet,
	Christopher Healy, Matthew Wilcox, Bagas Sanjaya, linux-kernel,
	dri-devel, intel-gfx, linux-mm, linux-doc, kernel

On 15/10/2025 20:17, Boris Brezillon wrote:
> On Wed, 15 Oct 2025 17:30:12 +0200
> Loïc Molinari <loic.molinari@collabora.com> wrote:
> 
>> Don't declare "super_pages" on builds with CONFIG_TRANSPARENT_HUGEPAGE
>> disabled to prevent build error:
>>
>> ERROR: modpost: "super_pages" [drivers/gpu/drm/v3d/v3d.ko] undefined!
> 
> I believe this is a bug introduced by the previous commit: the
> compiler probably drops any code between the
> IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) check and the err label
> because IS_ENABLED() evaluates to false at compile time. So I'd squash
> those changes in the previous commit.

Right, it's been introduced in previous commit.

>
>>
>> Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
>> ---
>>   drivers/gpu/drm/v3d/v3d_drv.h | 2 ++
>>   drivers/gpu/drm/v3d/v3d_gem.c | 2 ++
>>   2 files changed, 4 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
>> index 99a39329bb85..481502104391 100644
>> --- a/drivers/gpu/drm/v3d/v3d_drv.h
>> +++ b/drivers/gpu/drm/v3d/v3d_drv.h
>> @@ -564,7 +564,9 @@ extern const struct dma_fence_ops v3d_fence_ops;
>>   struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q);
>>   
>>   /* v3d_gem.c */
>> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>>   extern bool super_pages;
>> +#endif
>>   int v3d_gem_init(struct drm_device *dev);
>>   void v3d_gem_destroy(struct drm_device *dev);
>>   void v3d_reset_sms(struct v3d_dev *v3d);
>> diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
>> index 635ff0fabe7e..0039063eb8b2 100644
>> --- a/drivers/gpu/drm/v3d/v3d_gem.c
>> +++ b/drivers/gpu/drm/v3d/v3d_gem.c
>> @@ -269,7 +269,9 @@ v3d_huge_mnt_init(struct v3d_dev *v3d)
>>   	 * match our usecase.
>>   	 */
>>   
>> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>>   	if (super_pages)
>> +#endif
>>   		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> 
> Why not
> 
> #ifdef CONFIG_TRANSPARENT_HUGEPAGE
>    	if (super_pages)
>    		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> #endif
> 
> I guess
> 
> 	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && super_pages)
> 		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> 
> would also do, since it's likely to rely on the same optimization the
> previous v3d_gemfs_init() implementation was relying on, but it's
> fragile (not sure what happens when compiled with -O0).

I'll remove the #ifdef/#endif around the super_pages declaration in 
v3d_drv.h because it isn't necessary if super_pages is compiled out in 
v3d_huge_mnt_init().

In v3d_huge_mnt_init(), I'd add the #ifdef before the ret variable 
declaration and the #endif right after the last else so that it's clear 
drm_notice("THP is recommended...") is called unconditionally when 
CONFIG_TRANSPARENT_HUGEPAGE=n, whatever the optim level. What do you think?

> 
>>   
>>   	if (v3d->drm.huge_mnt)
> 



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 08/13] drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n
  2025-10-15 20:41     ` Loïc Molinari
@ 2025-10-16  5:56       ` Boris Brezillon
  2025-10-16  7:09         ` Loïc Molinari
  0 siblings, 1 reply; 27+ messages in thread
From: Boris Brezillon @ 2025-10-16  5:56 UTC (permalink / raw)
  To: Loïc Molinari
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Rob Herring, Steven Price,
	Liviu Dudau, Melissa Wen, Maíra Canal, Hugh Dickins,
	Baolin Wang, Andrew Morton, Al Viro, Mikołaj Wasiak,
	Christian Brauner, Nitin Gote, Andi Shyti, Jonathan Corbet,
	Christopher Healy, Matthew Wilcox, Bagas Sanjaya, linux-kernel,
	dri-devel, intel-gfx, linux-mm, linux-doc, kernel

On Wed, 15 Oct 2025 22:41:59 +0200
Loïc Molinari <loic.molinari@collabora.com> wrote:

> On 15/10/2025 20:17, Boris Brezillon wrote:
> > On Wed, 15 Oct 2025 17:30:12 +0200
> > Loïc Molinari <loic.molinari@collabora.com> wrote:
> >   
> >> Don't declare "super_pages" on builds with CONFIG_TRANSPARENT_HUGEPAGE
> >> disabled to prevent build error:
> >>
> >> ERROR: modpost: "super_pages" [drivers/gpu/drm/v3d/v3d.ko] undefined!  
> > 
> > I believe this is a bug introduced by the previous commit: the
> > compiler probably drops any code between the
> > IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) check and the err label
> > because IS_ENABLED() evaluates to false at compile time. So I'd squash
> > those changes in the previous commit.  
> 
> Right, it's been introduced in previous commit.
> 
> >  
> >>
> >> Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
> >> ---
> >>   drivers/gpu/drm/v3d/v3d_drv.h | 2 ++
> >>   drivers/gpu/drm/v3d/v3d_gem.c | 2 ++
> >>   2 files changed, 4 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
> >> index 99a39329bb85..481502104391 100644
> >> --- a/drivers/gpu/drm/v3d/v3d_drv.h
> >> +++ b/drivers/gpu/drm/v3d/v3d_drv.h
> >> @@ -564,7 +564,9 @@ extern const struct dma_fence_ops v3d_fence_ops;
> >>   struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q);
> >>   
> >>   /* v3d_gem.c */
> >> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> >>   extern bool super_pages;
> >> +#endif
> >>   int v3d_gem_init(struct drm_device *dev);
> >>   void v3d_gem_destroy(struct drm_device *dev);
> >>   void v3d_reset_sms(struct v3d_dev *v3d);
> >> diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
> >> index 635ff0fabe7e..0039063eb8b2 100644
> >> --- a/drivers/gpu/drm/v3d/v3d_gem.c
> >> +++ b/drivers/gpu/drm/v3d/v3d_gem.c
> >> @@ -269,7 +269,9 @@ v3d_huge_mnt_init(struct v3d_dev *v3d)
> >>   	 * match our usecase.
> >>   	 */
> >>   
> >> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> >>   	if (super_pages)
> >> +#endif
> >>   		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");  
> > 
> > Why not
> > 
> > #ifdef CONFIG_TRANSPARENT_HUGEPAGE
> >    	if (super_pages)
> >    		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> > #endif
> > 
> > I guess
> > 
> > 	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && super_pages)
> > 		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> > 
> > would also do, since it's likely to rely on the same optimization the
> > previous v3d_gemfs_init() implementation was relying on, but it's
> > fragile (not sure what happens when compiled with -O0).  
> 
> I'll remove the #ifdef/#endif around the super_pages declaration in 
> v3d_drv.h because it isn't necessary if super_pages is compiled out in 
> v3d_huge_mnt_init().
> 
> In v3d_huge_mnt_init(), I'd add the #ifdef before the ret variable 
> declaration and the #endif right after the last else so that it's clear 
> drm_notice("THP is recommended...") is called unconditionally when 
> CONFIG_TRANSPARENT_HUGEPAGE=n, whatever the optim level. What do you think?

First off, I'm not a huge fan of the following pattern

#if foo
	if (xxxx)
#endif
		do_something

which also applies to

#if foo
	if (xxxx)
		do_xxx
	else if (yyy)
		do_yyy
	else
#endif
		do_something

I'd rather have do_something duplicated in an #else section
like that:

#if foo
	if (xxxx)
		do_xxx
	else if (yyy)
		do_yyy
	else
		do_something
#else
	do_something
#endif

But I'm not even seeing what the problem is here. If you do:

	int err = 0;

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
    	if (super_pages)
    		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
#endif

	if (v3d->drm.huge_mnt)
		drm_info(&v3d->drm, "Using Transparent Hugepages\n");
	else if (err)
		drm_warn(&v3d->drm, "Can't use Transparent Hugepages (%d)\n", err);
	else
		drm_notice(&v3d->drm,
			   "Transparent Hugepage support is recommended for optimal performance on this platform!\n");

You're guaranteed that err=0 and v3d->drm.huge_mnt=NULL when
CONFIG_TRANSPARENT_HUGEPAGE=n, so the "THP recommended"
message should be displayed unconditionally. Am I missing
something?


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 08/13] drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n
  2025-10-16  5:56       ` Boris Brezillon
@ 2025-10-16  7:09         ` Loïc Molinari
  2025-10-16  7:22           ` Boris Brezillon
  0 siblings, 1 reply; 27+ messages in thread
From: Loïc Molinari @ 2025-10-16  7:09 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Rob Herring, Steven Price,
	Liviu Dudau, Melissa Wen, Maíra Canal, Hugh Dickins,
	Baolin Wang, Andrew Morton, Al Viro, Mikołaj Wasiak,
	Christian Brauner, Nitin Gote, Andi Shyti, Jonathan Corbet,
	Christopher Healy, Matthew Wilcox, Bagas Sanjaya, linux-kernel,
	dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Hi Boris,

On 16/10/2025 07:56, Boris Brezillon wrote:
> On Wed, 15 Oct 2025 22:41:59 +0200
> Loïc Molinari <loic.molinari@collabora.com> wrote:
> 
>> On 15/10/2025 20:17, Boris Brezillon wrote:
>>> On Wed, 15 Oct 2025 17:30:12 +0200
>>> Loïc Molinari <loic.molinari@collabora.com> wrote:
>>>    
>>>> Don't declare "super_pages" on builds with CONFIG_TRANSPARENT_HUGEPAGE
>>>> disabled to prevent build error:
>>>>
>>>> ERROR: modpost: "super_pages" [drivers/gpu/drm/v3d/v3d.ko] undefined!
>>>
>>> I believe this is a bug introduced by the previous commit: the
>>> compiler probably drops any code between the
>>> IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) check and the err label
>>> because IS_ENABLED() evaluates to false at compile time. So I'd squash
>>> those changes in the previous commit.
>>
>> Right, it's been introduced in previous commit.
>>
>>>   
>>>>
>>>> Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
>>>> ---
>>>>    drivers/gpu/drm/v3d/v3d_drv.h | 2 ++
>>>>    drivers/gpu/drm/v3d/v3d_gem.c | 2 ++
>>>>    2 files changed, 4 insertions(+)
>>>>
>>>> diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
>>>> index 99a39329bb85..481502104391 100644
>>>> --- a/drivers/gpu/drm/v3d/v3d_drv.h
>>>> +++ b/drivers/gpu/drm/v3d/v3d_drv.h
>>>> @@ -564,7 +564,9 @@ extern const struct dma_fence_ops v3d_fence_ops;
>>>>    struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q);
>>>>    
>>>>    /* v3d_gem.c */
>>>> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>>>>    extern bool super_pages;
>>>> +#endif
>>>>    int v3d_gem_init(struct drm_device *dev);
>>>>    void v3d_gem_destroy(struct drm_device *dev);
>>>>    void v3d_reset_sms(struct v3d_dev *v3d);
>>>> diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
>>>> index 635ff0fabe7e..0039063eb8b2 100644
>>>> --- a/drivers/gpu/drm/v3d/v3d_gem.c
>>>> +++ b/drivers/gpu/drm/v3d/v3d_gem.c
>>>> @@ -269,7 +269,9 @@ v3d_huge_mnt_init(struct v3d_dev *v3d)
>>>>    	 * match our usecase.
>>>>    	 */
>>>>    
>>>> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>>>>    	if (super_pages)
>>>> +#endif
>>>>    		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
>>>
>>> Why not
>>>
>>> #ifdef CONFIG_TRANSPARENT_HUGEPAGE
>>>     	if (super_pages)
>>>     		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
>>> #endif
>>>
>>> I guess
>>>
>>> 	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && super_pages)
>>> 		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
>>>
>>> would also do, since it's likely to rely on the same optimization the
>>> previous v3d_gemfs_init() implementation was relying on, but it's
>>> fragile (not sure what happens when compiled with -O0).
>>
>> I'll remove the #ifdef/#endif around the super_pages declaration in
>> v3d_drv.h because it isn't necessary if super_pages is compiled out in
>> v3d_huge_mnt_init().
>>
>> In v3d_huge_mnt_init(), I'd add the #ifdef before the ret variable
>> declaration and the #endif right after the last else so that it's clear
>> drm_notice("THP is recommended...") is called unconditionally when
>> CONFIG_TRANSPARENT_HUGEPAGE=n, whatever the optim level. What do you think?
> 
> First off, I'm not a huge fan of the following pattern
> 
> #if foo
> 	if (xxxx)
> #endif
> 		do_something
> 
> which also applies to
> 
> #if foo
> 	if (xxxx)
> 		do_xxx
> 	else if (yyy)
> 		do_yyy
> 	else
> #endif
> 		do_something
> 
> I'd rather have do_something duplicated in an #else section
> like that:
> 
> #if foo
> 	if (xxxx)
> 		do_xxx
> 	else if (yyy)
> 		do_yyy
> 	else
> 		do_something
> #else
> 	do_something
> #endif
> 
> But I'm not even seeing what the problem is here. If you do:
> 
> 	int err = 0;
> 
> #ifdef CONFIG_TRANSPARENT_HUGEPAGE
>      	if (super_pages)
>      		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> #endif
> 
> 	if (v3d->drm.huge_mnt)
> 		drm_info(&v3d->drm, "Using Transparent Hugepages\n");
> 	else if (err)
> 		drm_warn(&v3d->drm, "Can't use Transparent Hugepages (%d)\n", err);
> 	else
> 		drm_notice(&v3d->drm,
> 			   "Transparent Hugepage support is recommended for optimal performance on this platform!\n");
> 
> You're guaranteed that err=0 and v3d->drm.huge_mnt=NULL when
> CONFIG_TRANSPARENT_HUGEPAGE=n, so the "THP recommended"
> message should be displayed unconditionally. Am I missing
> something?

It doesn't really matter here but I just thought it would be cleaner to 
explicitly let just the drm_notice() because the compiler doesn't know 
v3d->drm.huge_mnt is always NULL here and would emit a branch in 
CONFIG_TRANSPARENT_HUGEPAGE=n builds. I know your dislike for this 
pattern now, so I will stick to the suggestion :)

Loïc


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 08/13] drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n
  2025-10-16  7:09         ` Loïc Molinari
@ 2025-10-16  7:22           ` Boris Brezillon
  0 siblings, 0 replies; 27+ messages in thread
From: Boris Brezillon @ 2025-10-16  7:22 UTC (permalink / raw)
  To: Loïc Molinari
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Rob Herring, Steven Price,
	Liviu Dudau, Melissa Wen, Maíra Canal, Hugh Dickins,
	Baolin Wang, Andrew Morton, Al Viro, Mikołaj Wasiak,
	Christian Brauner, Nitin Gote, Andi Shyti, Jonathan Corbet,
	Christopher Healy, Matthew Wilcox, Bagas Sanjaya, linux-kernel,
	dri-devel, intel-gfx, linux-mm, linux-doc, kernel

On Thu, 16 Oct 2025 09:09:26 +0200
Loïc Molinari <loic.molinari@collabora.com> wrote:

> Hi Boris,
> 
> On 16/10/2025 07:56, Boris Brezillon wrote:
> > On Wed, 15 Oct 2025 22:41:59 +0200
> > Loïc Molinari <loic.molinari@collabora.com> wrote:
> >   
> >> On 15/10/2025 20:17, Boris Brezillon wrote:  
> >>> On Wed, 15 Oct 2025 17:30:12 +0200
> >>> Loïc Molinari <loic.molinari@collabora.com> wrote:
> >>>      
> >>>> Don't declare "super_pages" on builds with CONFIG_TRANSPARENT_HUGEPAGE
> >>>> disabled to prevent build error:
> >>>>
> >>>> ERROR: modpost: "super_pages" [drivers/gpu/drm/v3d/v3d.ko] undefined!  
> >>>
> >>> I believe this is a bug introduced by the previous commit: the
> >>> compiler probably drops any code between the
> >>> IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) check and the err label
> >>> because IS_ENABLED() evaluates to false at compile time. So I'd squash
> >>> those changes in the previous commit.  
> >>
> >> Right, it's been introduced in previous commit.
> >>  
> >>>     
> >>>>
> >>>> Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
> >>>> ---
> >>>>    drivers/gpu/drm/v3d/v3d_drv.h | 2 ++
> >>>>    drivers/gpu/drm/v3d/v3d_gem.c | 2 ++
> >>>>    2 files changed, 4 insertions(+)
> >>>>
> >>>> diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
> >>>> index 99a39329bb85..481502104391 100644
> >>>> --- a/drivers/gpu/drm/v3d/v3d_drv.h
> >>>> +++ b/drivers/gpu/drm/v3d/v3d_drv.h
> >>>> @@ -564,7 +564,9 @@ extern const struct dma_fence_ops v3d_fence_ops;
> >>>>    struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q);
> >>>>    
> >>>>    /* v3d_gem.c */
> >>>> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> >>>>    extern bool super_pages;
> >>>> +#endif
> >>>>    int v3d_gem_init(struct drm_device *dev);
> >>>>    void v3d_gem_destroy(struct drm_device *dev);
> >>>>    void v3d_reset_sms(struct v3d_dev *v3d);
> >>>> diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
> >>>> index 635ff0fabe7e..0039063eb8b2 100644
> >>>> --- a/drivers/gpu/drm/v3d/v3d_gem.c
> >>>> +++ b/drivers/gpu/drm/v3d/v3d_gem.c
> >>>> @@ -269,7 +269,9 @@ v3d_huge_mnt_init(struct v3d_dev *v3d)
> >>>>    	 * match our usecase.
> >>>>    	 */
> >>>>    
> >>>> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> >>>>    	if (super_pages)
> >>>> +#endif
> >>>>    		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");  
> >>>
> >>> Why not
> >>>
> >>> #ifdef CONFIG_TRANSPARENT_HUGEPAGE
> >>>     	if (super_pages)
> >>>     		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> >>> #endif
> >>>
> >>> I guess
> >>>
> >>> 	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && super_pages)
> >>> 		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> >>>
> >>> would also do, since it's likely to rely on the same optimization the
> >>> previous v3d_gemfs_init() implementation was relying on, but it's
> >>> fragile (not sure what happens when compiled with -O0).  
> >>
> >> I'll remove the #ifdef/#endif around the super_pages declaration in
> >> v3d_drv.h because it isn't necessary if super_pages is compiled out in
> >> v3d_huge_mnt_init().
> >>
> >> In v3d_huge_mnt_init(), I'd add the #ifdef before the ret variable
> >> declaration and the #endif right after the last else so that it's clear
> >> drm_notice("THP is recommended...") is called unconditionally when
> >> CONFIG_TRANSPARENT_HUGEPAGE=n, whatever the optim level. What do you think?  
> > 
> > First off, I'm not a huge fan of the following pattern
> > 
> > #if foo
> > 	if (xxxx)
> > #endif
> > 		do_something
> > 
> > which also applies to
> > 
> > #if foo
> > 	if (xxxx)
> > 		do_xxx
> > 	else if (yyy)
> > 		do_yyy
> > 	else
> > #endif
> > 		do_something
> > 
> > I'd rather have do_something duplicated in an #else section
> > like that:
> > 
> > #if foo
> > 	if (xxxx)
> > 		do_xxx
> > 	else if (yyy)
> > 		do_yyy
> > 	else
> > 		do_something
> > #else
> > 	do_something
> > #endif
> > 
> > But I'm not even seeing what the problem is here. If you do:
> > 
> > 	int err = 0;
> > 
> > #ifdef CONFIG_TRANSPARENT_HUGEPAGE
> >      if (super_pages)
> >      	err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> > #endif
> > 
> > 	if (v3d->drm.huge_mnt)
> > 		drm_info(&v3d->drm, "Using Transparent Hugepages\n");
> > 	else if (err)
> > 		drm_warn(&v3d->drm, "Can't use Transparent Hugepages (%d)\n", err);
> > 	else
> > 		drm_notice(&v3d->drm,
> > 			   "Transparent Hugepage support is recommended for optimal performance on this platform!\n");
> > 
> > You're guaranteed that err=0 and v3d->drm.huge_mnt=NULL when
> > CONFIG_TRANSPARENT_HUGEPAGE=n, so the "THP recommended"
> > message should be displayed unconditionally. Am I missing
> > something?  
> 
> It doesn't really matter here but I just thought it would be cleaner to 
> explicitly let just the drm_notice() because the compiler doesn't know 
> v3d->drm.huge_mnt is always NULL here and would emit a branch in 
> CONFIG_TRANSPARENT_HUGEPAGE=n builds.

Okay, well. I think it would matter if this was a hot-path, maybe? But
that's clearly not the case, this code is called once at probe time.

> I know your dislike for this 
> pattern now, so I will stick to the suggestion :)

Actually, I would probably stick to the original

	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && super_pages)
		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");

pattern since it worked so far. If -O0 is really a problem (didn't
check if it is), and v3d maintainers care about it (I doubt anyone
forces -O0 to be honest), they'll fix that in a follow-up patchset.


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 03/13] drm/shmem-helper: Map huge pages in fault handlers
  2025-10-15 17:27   ` Matthew Wilcox
@ 2025-10-16 11:17     ` Loïc Molinari
  2025-10-17 21:42       ` Matthew Wilcox
  0 siblings, 1 reply; 27+ messages in thread
From: Loïc Molinari @ 2025-10-16 11:17 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Al Viro,
	Mikołaj Wasiak, Christian Brauner, Nitin Gote, Andi Shyti,
	Jonathan Corbet, Christopher Healy, Bagas Sanjaya, linux-kernel,
	dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Hi Matthew,

On 15/10/2025 19:27, Matthew Wilcox wrote:
> On Wed, Oct 15, 2025 at 05:30:07PM +0200, Loïc Molinari wrote:
> 
> This looks fine, no need to resend to fix this, but if you'd written
> the previous patch slightly differently, you'd've reduced the amount of
> code you moved around in this patch, which would have made it easier to
> review.
> 
>> +	/* Map a range of pages around the faulty address. */
>> +	do {
>> +		pfn = page_to_pfn(pages[start_pgoff]);
>> +		ret = vmf_insert_pfn(vma, addr, pfn);
>> +		addr += PAGE_SIZE;
>> +	} while (++start_pgoff <= end_pgoff && ret == VM_FAULT_NOPAGE);
> 
> It looks to me like we have an opportunity to do better here by
> adding a vmf_insert_pfns() interface.  I don't think we should delay
> your patch series to add it, but let's not forget to do that; it can
> have very good performnce effects on ARM to use contptes.

Agreed. I initially wanted to provide such an interface based on 
set_ptes() to benefit from arm64 contptes but thought it'd better be a 
distinct patch series.

> 
>> @@ -617,8 +645,9 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
> [...]
>>   
>> -		ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page));
>> +	if (drm_gem_shmem_map_pmd(vmf, vmf->address, pages[page_offset])) {
>> +		ret = VM_FAULT_NOPAGE;
>> +		goto out;
>>   	}
> 
> Does this actually work?

Yes, it does. Huge pages are successfully mapped from both map_pages and 
fault handlers. Anything wrong with it?


There seems to be an another issue thought. There are failures [1], all 
looking like that one [2]. I think it's because map_pages is called with 
the RCU read lock taken and the DRM GEM map_pages handler must lock the 
GEM object before accessing pages with dma_resv_lock(). The locking doc 
says: "If it's not possible to reach a page without blocking, filesystem 
should skip it.". Unlocking the RCU read lock in the handler seems wrong 
and doing without a map_pages implementation would be unfortunate. What 
would you recommend here?

Loïc

[1] https://patchwork.freedesktop.org/series/156001/
[2] 
https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_156001v1/bat-dg1-7/igt@vgem_basic@dmabuf-mmap.html


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 03/13] drm/shmem-helper: Map huge pages in fault handlers
  2025-10-16 11:17     ` Loïc Molinari
@ 2025-10-17 21:42       ` Matthew Wilcox
  2025-11-10 14:39         ` Loïc Molinari
  0 siblings, 1 reply; 27+ messages in thread
From: Matthew Wilcox @ 2025-10-17 21:42 UTC (permalink / raw)
  To: Loïc Molinari
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Al Viro,
	Mikołaj Wasiak, Christian Brauner, Nitin Gote, Andi Shyti,
	Jonathan Corbet, Christopher Healy, Bagas Sanjaya, linux-kernel,
	dri-devel, intel-gfx, linux-mm, linux-doc, kernel

On Thu, Oct 16, 2025 at 01:17:07PM +0200, Loïc Molinari wrote:
> > It looks to me like we have an opportunity to do better here by
> > adding a vmf_insert_pfns() interface.  I don't think we should delay
> > your patch series to add it, but let's not forget to do that; it can
> > have very good performnce effects on ARM to use contptes.
> 
> Agreed. I initially wanted to provide such an interface based on set_ptes()
> to benefit from arm64 contptes but thought it'd better be a distinct patch
> series.

Agreed.

> > 
> > > @@ -617,8 +645,9 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
> > [...]
> > > -		ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page));
> > > +	if (drm_gem_shmem_map_pmd(vmf, vmf->address, pages[page_offset])) {
> > > +		ret = VM_FAULT_NOPAGE;
> > > +		goto out;
> > >   	}
> > 
> > Does this actually work?
> 
> Yes, it does. Huge pages are successfully mapped from both map_pages and
> fault handlers. Anything wrong with it?

No, I just wasn't sure that this would work correctly.

> There seems to be an another issue thought. There are failures [1], all
> looking like that one [2]. I think it's because map_pages is called with the
> RCU read lock taken and the DRM GEM map_pages handler must lock the GEM
> object before accessing pages with dma_resv_lock(). The locking doc says:
> "If it's not possible to reach a page without blocking, filesystem should
> skip it.". Unlocking the RCU read lock in the handler seems wrong and doing
> without a map_pages implementation would be unfortunate. What would you
> recommend here?

I'm not familiar with GEM locking, so let me describe briefly how
pagecache locking works.

Calling mmap bumps the refcount on the inode.  That keeps the inode
around while the page fault handler runs.  For each folio, we
get a refcount on it, then we trylock it.  Then we map each page in the
folio.

So maybe you can trylock the GEM object?  It isn't clear to me whether
you want finer grained locking than that.  If the trylock fails, no big
deal, you just fall through to the fault path (with the slightly more
heavy-weight locking that allows you to sleep).


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 05/13] drm/gem: Add huge tmpfs mount point helper
  2025-10-15 15:30 ` [PATCH v4 05/13] drm/gem: Add huge tmpfs mount point helper Loïc Molinari
@ 2025-10-20  9:10   ` Tvrtko Ursulin
  2025-10-20 14:13     ` Loïc Molinari
  0 siblings, 1 reply; 27+ messages in thread
From: Tvrtko Ursulin @ 2025-10-20  9:10 UTC (permalink / raw)
  To: Loïc Molinari, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Al Viro,
	Mikołaj Wasiak, Christian Brauner, Nitin Gote, Andi Shyti,
	Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel


On 15/10/2025 16:30, Loïc Molinari wrote:
> Add the drm_gem_huge_mnt_create() helper to avoid code duplication in
> the i915, V3D, Panfrost and Panthor drivers. It creates and mounts a
> dedicated huge tmpfs mountpoint, for the lifetime of a DRM device,
> used at GEM object initialization.
> 
> The next commits will port drivers to this helper.
> 
> v3:
> - store huge tmpfs mountpoint in drm_device
> 
> v4:
> - return 0 in builds with CONFIG_TRANSPARENT_HUGEPAGE=n
> - return 0 when huge_mnt already exists
> 
> Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
> ---
>   drivers/gpu/drm/drm_gem.c | 58 +++++++++++++++++++++++++++++++++++++++
>   include/drm/drm_device.h  | 11 ++++++++
>   include/drm/drm_gem.h     |  1 +
>   3 files changed, 70 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index a98d5744cc6c..db8c0a217add 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -29,6 +29,7 @@
>   #include <linux/export.h>
>   #include <linux/file.h>
>   #include <linux/fs.h>
> +#include <linux/fs_context.h>
>   #include <linux/iosys-map.h>
>   #include <linux/mem_encrypt.h>
>   #include <linux/mm.h>
> @@ -82,6 +83,63 @@
>    * up at a later date, and as our interface with shmfs for memory allocation.
>    */
>   
> +static void drm_gem_huge_mnt_free(struct drm_device *dev, void *data)
> +{
> +	drm_WARN_ON(dev, dev->huge_mnt == NULL);

I don't see a benefit of adding this check but maybe I am missing something.

> +
> +	kern_unmount(dev->huge_mnt);
> +	dev->huge_mnt = NULL;

Ditto - device is going away, no? So why bother clearing the pointer?

Also, is the compiler smart enough to not compile or complain this 
function is unused in the !CONFIG_TRANSPARENT_HUGEPAGE case?

> +}
> +
> +/**
> + * drm_gem_huge_mnt_create - Create, mount and use a huge tmpfs mountpoint
> + * @dev: drm_device a huge tmpfs mountpoint should be used with
> + * @value: huge tmpfs mount option value
> + *
> + * This function creates and mounts a dedicated huge tmpfs mountpoint for the
> + * lifetime of the drm device @dev which is used at GEM object initialization
> + * with drm_gem_object_init().
> + *
> + * The most common option value @value is "within_size" which only allocates
> + * huge pages if the page will be fully within the GEM object size. "always",
> + * "advise" and "never" are supported too but the latter would just create a
> + * mountpoint similar to the default one (`shm_mnt`). See shmemfs and
> + * Transparent Hugepage for more information.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */
> +int drm_gem_huge_mnt_create(struct drm_device *dev, const char *value)
> +{
> +	struct file_system_type *type;
> +	struct fs_context *fc;
> +	int ret;
> +
> +	if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
> +		return 0;

Is there a specific reason why the !CONFIG_TRANSPARENT_HUGEPAGE path is 
not implemented in the header as a static inline? That would enable 
those builds to avoid the pointless function in text and function call 
in the drivers.

> +	if (unlikely(dev->huge_mnt))
> +		return 0;

Any special reason why it is allowed to call it multiple times with success?

> +
> +	type = get_fs_type("tmpfs");
> +	if (unlikely(!type))
> +		return -EOPNOTSUPP;
> +	fc = fs_context_for_mount(type, SB_KERNMOUNT);
> +	if (IS_ERR(fc))
> +		return PTR_ERR(fc);
> +	ret = vfs_parse_fs_string(fc, "source", "tmpfs");
> +	if (unlikely(ret))
> +		return -ENOPARAM;
> +	ret = vfs_parse_fs_string(fc, "huge", value);
> +	if (unlikely(ret))
> +		return -ENOPARAM;
> +
> +	dev->huge_mnt = fc_mount_longterm(fc);
> +	put_fs_context(fc);
> +
> +	return drmm_add_action_or_reset(dev, drm_gem_huge_mnt_free, NULL);
> +}
> +EXPORT_SYMBOL_GPL(drm_gem_huge_mnt_create);
> +
>   static void
>   drm_gem_init_release(struct drm_device *dev, void *ptr)
>   {
> diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
> index 778b2cca6c49..352e3db402d7 100644
> --- a/include/drm/drm_device.h
> +++ b/include/drm/drm_device.h
> @@ -3,6 +3,7 @@
>   
>   #include <linux/list.h>
>   #include <linux/kref.h>
> +#include <linux/mount.h>
>   #include <linux/mutex.h>
>   #include <linux/idr.h>
>   #include <linux/sched.h>
> @@ -168,6 +169,16 @@ struct drm_device {
>   	 */
>   	struct drm_master *master;
>   
> +	/**
> +	 * @huge_mnt:
> +	 *
> +	 * Huge tmpfs mountpoint used at GEM object initialization
> +	 * drm_gem_object_init(). Drivers can call drm_gem_huge_mnt_create() to
> +	 * create a huge tmfps mountpoint. The default tmpfs mountpoint
> +	 * (`shm_mnt`) is used if NULL.
> +	 */
> +	struct vfsmount *huge_mnt;

Maybe it would be nice to hide this in the !CONFIG_TRANSPARENT_HUGEPAGE 
case? A bit ugly to add an ifdef but it is also a bit questionable to 
force the member on everyone.

Regards,

Tvrtko

> +
>   	/**
>   	 * @driver_features: per-device driver features
>   	 *
> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> index 7c8bd67d087c..7285a62d9afc 100644
> --- a/include/drm/drm_gem.h
> +++ b/include/drm/drm_gem.h
> @@ -492,6 +492,7 @@ struct drm_gem_object {
>   		DRM_GEM_FOPS,\
>   	}
>   
> +int drm_gem_huge_mnt_create(struct drm_device *dev, const char *value);
>   void drm_gem_object_release(struct drm_gem_object *obj);
>   void drm_gem_object_free(struct kref *kref);
>   int drm_gem_object_init(struct drm_device *dev,



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 07/13] drm/v3d: Use huge tmpfs mount point helper
  2025-10-15 15:30 ` [PATCH v4 07/13] drm/v3d: " Loïc Molinari
@ 2025-10-20  9:33   ` Tvrtko Ursulin
  2025-10-20 14:27     ` Loïc Molinari
  0 siblings, 1 reply; 27+ messages in thread
From: Tvrtko Ursulin @ 2025-10-20  9:33 UTC (permalink / raw)
  To: Loïc Molinari, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Al Viro,
	Mikołaj Wasiak, Christian Brauner, Nitin Gote, Andi Shyti,
	Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel


On 15/10/2025 16:30, Loïc Molinari wrote:
> Make use of the new drm_gem_huge_mnt_create() helper to avoid code
> duplication. Now that it's just a few lines long, the single function
> in v3d_gemfs.c is moved into v3d_gem.c.
> 
> v3:
> - use huge tmpfs mountpoint in drm_device
> - move v3d_gemfs.c into v3d_gem.c
> 
> v4:
> - clean up mountpoint creation error handling
> 
> Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
> ---
>   drivers/gpu/drm/v3d/Makefile    |  3 +-
>   drivers/gpu/drm/v3d/v3d_bo.c    |  5 ++-
>   drivers/gpu/drm/v3d/v3d_drv.c   |  2 +-
>   drivers/gpu/drm/v3d/v3d_drv.h   | 11 +-----
>   drivers/gpu/drm/v3d/v3d_gem.c   | 27 +++++++++++++--
>   drivers/gpu/drm/v3d/v3d_gemfs.c | 60 ---------------------------------
>   6 files changed, 30 insertions(+), 78 deletions(-)
>   delete mode 100644 drivers/gpu/drm/v3d/v3d_gemfs.c
> 
> diff --git a/drivers/gpu/drm/v3d/Makefile b/drivers/gpu/drm/v3d/Makefile
> index fcf710926057..b7d673f1153b 100644
> --- a/drivers/gpu/drm/v3d/Makefile
> +++ b/drivers/gpu/drm/v3d/Makefile
> @@ -13,8 +13,7 @@ v3d-y := \
>   	v3d_trace_points.o \
>   	v3d_sched.o \
>   	v3d_sysfs.o \
> -	v3d_submit.o \
> -	v3d_gemfs.o
> +	v3d_submit.o
>   
>   v3d-$(CONFIG_DEBUG_FS) += v3d_debugfs.o
>   
> diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
> index c41476ddde68..6b9909bfce82 100644
> --- a/drivers/gpu/drm/v3d/v3d_bo.c
> +++ b/drivers/gpu/drm/v3d/v3d_bo.c
> @@ -112,7 +112,7 @@ v3d_bo_create_finish(struct drm_gem_object *obj)
>   	if (IS_ERR(sgt))
>   		return PTR_ERR(sgt);
>   
> -	if (!v3d->gemfs)
> +	if (!obj->dev->huge_mnt)

Maybe it would be a good idea to add a helper for this check. Keeping 
aligned with drm_gem_huge_mnt_create() something like 
drm_gem_has_huge_mnt()? That would then hide the optional drm_device 
struct member if you decide to go for that.

>   		align = SZ_4K;
>   	else if (obj->size >= SZ_1M)
>   		align = SZ_1M;
> @@ -148,12 +148,11 @@ struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv,
>   			     size_t unaligned_size)
>   {
>   	struct drm_gem_shmem_object *shmem_obj;
> -	struct v3d_dev *v3d = to_v3d_dev(dev);
>   	struct v3d_bo *bo;
>   	int ret;
>   
>   	shmem_obj = drm_gem_shmem_create_with_mnt(dev, unaligned_size,
> -						  v3d->gemfs);
> +						  dev->huge_mnt);

Okay this one goes away by the end of the series.

>   	if (IS_ERR(shmem_obj))
>   		return ERR_CAST(shmem_obj);
>   	bo = to_v3d_bo(&shmem_obj->base);
> diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
> index c5a3bbbc74c5..19ec0ea7f38e 100644
> --- a/drivers/gpu/drm/v3d/v3d_drv.c
> +++ b/drivers/gpu/drm/v3d/v3d_drv.c
> @@ -106,7 +106,7 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
>   		args->value = v3d->perfmon_info.max_counters;
>   		return 0;
>   	case DRM_V3D_PARAM_SUPPORTS_SUPER_PAGES:
> -		args->value = !!v3d->gemfs;
> +		args->value = !!dev->huge_mnt;
>   		return 0;
>   	case DRM_V3D_PARAM_GLOBAL_RESET_COUNTER:
>   		mutex_lock(&v3d->reset_lock);
> diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
> index 1884686985b8..99a39329bb85 100644
> --- a/drivers/gpu/drm/v3d/v3d_drv.h
> +++ b/drivers/gpu/drm/v3d/v3d_drv.h
> @@ -158,11 +158,6 @@ struct v3d_dev {
>   	struct drm_mm mm;
>   	spinlock_t mm_lock;
>   
> -	/*
> -	 * tmpfs instance used for shmem backed objects
> -	 */
> -	struct vfsmount *gemfs;
> -
>   	struct work_struct overflow_mem_work;
>   
>   	struct v3d_queue_state queue[V3D_MAX_QUEUES];
> @@ -569,6 +564,7 @@ extern const struct dma_fence_ops v3d_fence_ops;
>   struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q);
>   
>   /* v3d_gem.c */
> +extern bool super_pages;
>   int v3d_gem_init(struct drm_device *dev);
>   void v3d_gem_destroy(struct drm_device *dev);
>   void v3d_reset_sms(struct v3d_dev *v3d);
> @@ -576,11 +572,6 @@ void v3d_reset(struct v3d_dev *v3d);
>   void v3d_invalidate_caches(struct v3d_dev *v3d);
>   void v3d_clean_caches(struct v3d_dev *v3d);
>   
> -/* v3d_gemfs.c */
> -extern bool super_pages;
> -void v3d_gemfs_init(struct v3d_dev *v3d);
> -void v3d_gemfs_fini(struct v3d_dev *v3d);
> -
>   /* v3d_submit.c */
>   void v3d_job_cleanup(struct v3d_job *job);
>   void v3d_job_put(struct v3d_job *job);
> diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
> index bb110d35f749..635ff0fabe7e 100644
> --- a/drivers/gpu/drm/v3d/v3d_gem.c
> +++ b/drivers/gpu/drm/v3d/v3d_gem.c
> @@ -258,6 +258,30 @@ v3d_invalidate_caches(struct v3d_dev *v3d)
>   	v3d_invalidate_slices(v3d, 0);
>   }
>   
> +static void
> +v3d_huge_mnt_init(struct v3d_dev *v3d)
> +{
> +	int err = 0;
> +
> +	/*
> +	 * By using a huge shmemfs mountpoint when the user wants to
> +	 * enable Super Pages, we can pass in mount flags that better
> +	 * match our usecase.
> +	 */
> +
> +	if (super_pages)
> +		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");

If it is this patch that is creating the build failure then the two 
should be squashed.

Then in "drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n" this 
ends up a bit ugly:

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
  	if (super_pages)
#endif
  		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");

Does this not work:

  	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && super_pages)
  		err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");

?

Regards,

Tvrtko

> +
> +	if (v3d->drm.huge_mnt)
> +		drm_info(&v3d->drm, "Using Transparent Hugepages\n");
> +	else if (err)
> +		drm_warn(&v3d->drm, "Can't use Transparent Hugepages (%d)\n",
> +			 err);
> +	else
> +		drm_notice(&v3d->drm,
> +			   "Transparent Hugepage support is recommended for optimal performance on this platform!\n");
> +}
> +
>   int
>   v3d_gem_init(struct drm_device *dev)
>   {
> @@ -309,7 +333,7 @@ v3d_gem_init(struct drm_device *dev)
>   	v3d_init_hw_state(v3d);
>   	v3d_mmu_set_page_table(v3d);
>   
> -	v3d_gemfs_init(v3d);
> +	v3d_huge_mnt_init(v3d);
>   
>   	ret = v3d_sched_init(v3d);
>   	if (ret) {
> @@ -329,7 +353,6 @@ v3d_gem_destroy(struct drm_device *dev)
>   	enum v3d_queue q;
>   
>   	v3d_sched_fini(v3d);
> -	v3d_gemfs_fini(v3d);
>   
>   	/* Waiting for jobs to finish would need to be done before
>   	 * unregistering V3D.
> diff --git a/drivers/gpu/drm/v3d/v3d_gemfs.c b/drivers/gpu/drm/v3d/v3d_gemfs.c
> deleted file mode 100644
> index c1a30166c099..000000000000
> --- a/drivers/gpu/drm/v3d/v3d_gemfs.c
> +++ /dev/null
> @@ -1,60 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0+
> -/* Copyright (C) 2024 Raspberry Pi */
> -
> -#include <linux/fs.h>
> -#include <linux/mount.h>
> -#include <linux/fs_context.h>
> -
> -#include "v3d_drv.h"
> -
> -void v3d_gemfs_init(struct v3d_dev *v3d)
> -{
> -	struct file_system_type *type;
> -	struct fs_context *fc;
> -	struct vfsmount *gemfs;
> -	int ret;
> -
> -	/*
> -	 * By creating our own shmemfs mountpoint, we can pass in
> -	 * mount flags that better match our usecase. However, we
> -	 * only do so on platforms which benefit from it.
> -	 */
> -	if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
> -		goto err;
> -
> -	/* The user doesn't want to enable Super Pages */
> -	if (!super_pages)
> -		goto err;
> -
> -	type = get_fs_type("tmpfs");
> -	if (!type)
> -		goto err;
> -
> -	fc = fs_context_for_mount(type, SB_KERNMOUNT);
> -	if (IS_ERR(fc))
> -		goto err;
> -	ret = vfs_parse_fs_string(fc, "source", "tmpfs");
> -	if (!ret)
> -		ret = vfs_parse_fs_string(fc, "huge", "within_size");
> -	if (!ret)
> -		gemfs = fc_mount_longterm(fc);
> -	put_fs_context(fc);
> -	if (ret)
> -		goto err;
> -
> -	v3d->gemfs = gemfs;
> -	drm_info(&v3d->drm, "Using Transparent Hugepages\n");
> -
> -	return;
> -
> -err:
> -	v3d->gemfs = NULL;
> -	drm_notice(&v3d->drm,
> -		   "Transparent Hugepage support is recommended for optimal performance on this platform!\n");
> -}
> -
> -void v3d_gemfs_fini(struct v3d_dev *v3d)
> -{
> -	if (v3d->gemfs)
> -		kern_unmount(v3d->gemfs);
> -}



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 05/13] drm/gem: Add huge tmpfs mount point helper
  2025-10-20  9:10   ` Tvrtko Ursulin
@ 2025-10-20 14:13     ` Loïc Molinari
  0 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-20 14:13 UTC (permalink / raw)
  To: Tvrtko Ursulin, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Al Viro,
	Mikołaj Wasiak, Christian Brauner, Nitin Gote, Andi Shyti,
	Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

On 20/10/2025 11:10, Tvrtko Ursulin wrote:
> 
> On 15/10/2025 16:30, Loïc Molinari wrote:
>> Add the drm_gem_huge_mnt_create() helper to avoid code duplication in
>> the i915, V3D, Panfrost and Panthor drivers. It creates and mounts a
>> dedicated huge tmpfs mountpoint, for the lifetime of a DRM device,
>> used at GEM object initialization.
>>
>> The next commits will port drivers to this helper.
>>
>> v3:
>> - store huge tmpfs mountpoint in drm_device
>>
>> v4:
>> - return 0 in builds with CONFIG_TRANSPARENT_HUGEPAGE=n
>> - return 0 when huge_mnt already exists
>>
>> Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
>> ---
>>   drivers/gpu/drm/drm_gem.c | 58 +++++++++++++++++++++++++++++++++++++++
>>   include/drm/drm_device.h  | 11 ++++++++
>>   include/drm/drm_gem.h     |  1 +
>>   3 files changed, 70 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
>> index a98d5744cc6c..db8c0a217add 100644
>> --- a/drivers/gpu/drm/drm_gem.c
>> +++ b/drivers/gpu/drm/drm_gem.c
>> @@ -29,6 +29,7 @@
>>   #include <linux/export.h>
>>   #include <linux/file.h>
>>   #include <linux/fs.h>
>> +#include <linux/fs_context.h>
>>   #include <linux/iosys-map.h>
>>   #include <linux/mem_encrypt.h>
>>   #include <linux/mm.h>
>> @@ -82,6 +83,63 @@
>>    * up at a later date, and as our interface with shmfs for memory 
>> allocation.
>>    */
>> +static void drm_gem_huge_mnt_free(struct drm_device *dev, void *data)
>> +{
>> +    drm_WARN_ON(dev, dev->huge_mnt == NULL);
> 
> I don't see a benefit of adding this check but maybe I am missing 
> something.

That was mostly to detect and warn drivers setting the drm_device's 
huge_mnt pointer directly. I can remove that.

>> +
>> +    kern_unmount(dev->huge_mnt);
>> +    dev->huge_mnt = NULL;
> 
> Ditto - device is going away, no? So why bother clearing the pointer?

This one is necessary to let drivers tear down and reload. 
drm_gem_huge_mnt_create() returns if the pointer isn't NULL.

> Also, is the compiler smart enough to not compile or complain this 
> function is unused in the !CONFIG_TRANSPARENT_HUGEPAGE case?

No compiler warnings, but this might not be the case with different 
compilers/versions so I'll ifdef it out.

>> +}
>> +
>> +/**
>> + * drm_gem_huge_mnt_create - Create, mount and use a huge tmpfs 
>> mountpoint
>> + * @dev: drm_device a huge tmpfs mountpoint should be used with
>> + * @value: huge tmpfs mount option value
>> + *
>> + * This function creates and mounts a dedicated huge tmpfs mountpoint 
>> for the
>> + * lifetime of the drm device @dev which is used at GEM object 
>> initialization
>> + * with drm_gem_object_init().
>> + *
>> + * The most common option value @value is "within_size" which only 
>> allocates
>> + * huge pages if the page will be fully within the GEM object size. 
>> "always",
>> + * "advise" and "never" are supported too but the latter would just 
>> create a
>> + * mountpoint similar to the default one (`shm_mnt`). See shmemfs and
>> + * Transparent Hugepage for more information.
>> + *
>> + * Returns:
>> + * 0 on success or a negative error code on failure.
>> + */
>> +int drm_gem_huge_mnt_create(struct drm_device *dev, const char *value)
>> +{
>> +    struct file_system_type *type;
>> +    struct fs_context *fc;
>> +    int ret;
>> +
>> +    if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
>> +        return 0;
> 
> Is there a specific reason why the !CONFIG_TRANSPARENT_HUGEPAGE path is 
> not implemented in the header as a static inline? That would enable 
> those builds to avoid the pointless function in text and function call 
> in the drivers.

Good point. I'll propose a new version with drm_gem_huge_mnt_create() 
implemented as a static inline function that calls into 
__drm_gem_huge_mnt_create() only for builds with 
CONFIG_TRANSPARENT_HUGEPAGE=y.

>  
>> +    if (unlikely(dev->huge_mnt))
>> +        return 0;
> 
> Any special reason why it is allowed to call it multiple times with 
> success?

That was initially returning -EEXIST in v3 but got changed after review 
to simplify call sites.

> 
>> +
>> +    type = get_fs_type("tmpfs");
>> +    if (unlikely(!type))
>> +        return -EOPNOTSUPP;
>> +    fc = fs_context_for_mount(type, SB_KERNMOUNT);
>> +    if (IS_ERR(fc))
>> +        return PTR_ERR(fc);
>> +    ret = vfs_parse_fs_string(fc, "source", "tmpfs");
>> +    if (unlikely(ret))
>> +        return -ENOPARAM;
>> +    ret = vfs_parse_fs_string(fc, "huge", value);
>> +    if (unlikely(ret))
>> +        return -ENOPARAM;
>> +
>> +    dev->huge_mnt = fc_mount_longterm(fc);
>> +    put_fs_context(fc);
>> +
>> +    return drmm_add_action_or_reset(dev, drm_gem_huge_mnt_free, NULL);
>> +}
>> +EXPORT_SYMBOL_GPL(drm_gem_huge_mnt_create);
>> +
>>   static void
>>   drm_gem_init_release(struct drm_device *dev, void *ptr)
>>   {
>> diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
>> index 778b2cca6c49..352e3db402d7 100644
>> --- a/include/drm/drm_device.h
>> +++ b/include/drm/drm_device.h
>> @@ -3,6 +3,7 @@
>>   #include <linux/list.h>
>>   #include <linux/kref.h>
>> +#include <linux/mount.h>
>>   #include <linux/mutex.h>
>>   #include <linux/idr.h>
>>   #include <linux/sched.h>
>> @@ -168,6 +169,16 @@ struct drm_device {
>>        */
>>       struct drm_master *master;
>> +    /**
>> +     * @huge_mnt:
>> +     *
>> +     * Huge tmpfs mountpoint used at GEM object initialization
>> +     * drm_gem_object_init(). Drivers can call 
>> drm_gem_huge_mnt_create() to
>> +     * create a huge tmfps mountpoint. The default tmpfs mountpoint
>> +     * (`shm_mnt`) is used if NULL.
>> +     */
>> +    struct vfsmount *huge_mnt;
> 
> Maybe it would be nice to hide this in the !CONFIG_TRANSPARENT_HUGEPAGE 
> case? A bit ugly to add an ifdef but it is also a bit questionable to 
> force the member on everyone.

It was initially stored in drivers' data structures but, as mentioned 
above for v3, got put in drm_device to simplify call sites.

Both V3D and i915 are testing for that pointer in a few places and that 
would require adding ifdefs there too. This would also be the same for 
any drivers adding support for huge pages. Is that really worth it?

> 
> Regards,
> 
> Tvrtko
> 
>> +
>>       /**
>>        * @driver_features: per-device driver features
>>        *
>> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
>> index 7c8bd67d087c..7285a62d9afc 100644
>> --- a/include/drm/drm_gem.h
>> +++ b/include/drm/drm_gem.h
>> @@ -492,6 +492,7 @@ struct drm_gem_object {
>>           DRM_GEM_FOPS,\
>>       }
>> +int drm_gem_huge_mnt_create(struct drm_device *dev, const char *value);
>>   void drm_gem_object_release(struct drm_gem_object *obj);
>>   void drm_gem_object_free(struct kref *kref);
>>   int drm_gem_object_init(struct drm_device *dev,
> 



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 07/13] drm/v3d: Use huge tmpfs mount point helper
  2025-10-20  9:33   ` Tvrtko Ursulin
@ 2025-10-20 14:27     ` Loïc Molinari
  0 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-10-20 14:27 UTC (permalink / raw)
  To: Tvrtko Ursulin, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Al Viro,
	Mikołaj Wasiak, Christian Brauner, Nitin Gote, Andi Shyti,
	Jonathan Corbet, Christopher Healy, Matthew Wilcox,
	Bagas Sanjaya
  Cc: linux-kernel, dri-devel, intel-gfx, linux-mm, linux-doc, kernel

On 20/10/2025 11:33, Tvrtko Ursulin wrote:
> 
> On 15/10/2025 16:30, Loïc Molinari wrote:
>> Make use of the new drm_gem_huge_mnt_create() helper to avoid code
>> duplication. Now that it's just a few lines long, the single function
>> in v3d_gemfs.c is moved into v3d_gem.c.
>>
>> v3:
>> - use huge tmpfs mountpoint in drm_device
>> - move v3d_gemfs.c into v3d_gem.c
>>
>> v4:
>> - clean up mountpoint creation error handling
>>
>> Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
>> ---
>>   drivers/gpu/drm/v3d/Makefile    |  3 +-
>>   drivers/gpu/drm/v3d/v3d_bo.c    |  5 ++-
>>   drivers/gpu/drm/v3d/v3d_drv.c   |  2 +-
>>   drivers/gpu/drm/v3d/v3d_drv.h   | 11 +-----
>>   drivers/gpu/drm/v3d/v3d_gem.c   | 27 +++++++++++++--
>>   drivers/gpu/drm/v3d/v3d_gemfs.c | 60 ---------------------------------
>>   6 files changed, 30 insertions(+), 78 deletions(-)
>>   delete mode 100644 drivers/gpu/drm/v3d/v3d_gemfs.c
>>
>> diff --git a/drivers/gpu/drm/v3d/Makefile b/drivers/gpu/drm/v3d/Makefile
>> index fcf710926057..b7d673f1153b 100644
>> --- a/drivers/gpu/drm/v3d/Makefile
>> +++ b/drivers/gpu/drm/v3d/Makefile
>> @@ -13,8 +13,7 @@ v3d-y := \
>>       v3d_trace_points.o \
>>       v3d_sched.o \
>>       v3d_sysfs.o \
>> -    v3d_submit.o \
>> -    v3d_gemfs.o
>> +    v3d_submit.o
>>   v3d-$(CONFIG_DEBUG_FS) += v3d_debugfs.o
>> diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
>> index c41476ddde68..6b9909bfce82 100644
>> --- a/drivers/gpu/drm/v3d/v3d_bo.c
>> +++ b/drivers/gpu/drm/v3d/v3d_bo.c
>> @@ -112,7 +112,7 @@ v3d_bo_create_finish(struct drm_gem_object *obj)
>>       if (IS_ERR(sgt))
>>           return PTR_ERR(sgt);
>> -    if (!v3d->gemfs)
>> +    if (!obj->dev->huge_mnt)
> 
> Maybe it would be a good idea to add a helper for this check. Keeping 
> aligned with drm_gem_huge_mnt_create() something like 
> drm_gem_has_huge_mnt()? That would then hide the optional drm_device 
> struct member if you decide to go for that.

Sounds good. This would prevent cluttering code with ifdefs in drivers 
while still removing the huge_mnt field in drm_device in builds with 
CONFIG_TRANSPARENT_HUGEPAGE=n. I'll propose a new version doing so.

> 
>>           align = SZ_4K;
>>       else if (obj->size >= SZ_1M)
>>           align = SZ_1M;
>> @@ -148,12 +148,11 @@ struct v3d_bo *v3d_bo_create(struct drm_device 
>> *dev, struct drm_file *file_priv,
>>                    size_t unaligned_size)
>>   {
>>       struct drm_gem_shmem_object *shmem_obj;
>> -    struct v3d_dev *v3d = to_v3d_dev(dev);
>>       struct v3d_bo *bo;
>>       int ret;
>>       shmem_obj = drm_gem_shmem_create_with_mnt(dev, unaligned_size,
>> -                          v3d->gemfs);
>> +                          dev->huge_mnt);
> 
> Okay this one goes away by the end of the series.
> 
>>       if (IS_ERR(shmem_obj))
>>           return ERR_CAST(shmem_obj);
>>       bo = to_v3d_bo(&shmem_obj->base);
>> diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/ 
>> v3d_drv.c
>> index c5a3bbbc74c5..19ec0ea7f38e 100644
>> --- a/drivers/gpu/drm/v3d/v3d_drv.c
>> +++ b/drivers/gpu/drm/v3d/v3d_drv.c
>> @@ -106,7 +106,7 @@ static int v3d_get_param_ioctl(struct drm_device 
>> *dev, void *data,
>>           args->value = v3d->perfmon_info.max_counters;
>>           return 0;
>>       case DRM_V3D_PARAM_SUPPORTS_SUPER_PAGES:
>> -        args->value = !!v3d->gemfs;
>> +        args->value = !!dev->huge_mnt;
>>           return 0;
>>       case DRM_V3D_PARAM_GLOBAL_RESET_COUNTER:
>>           mutex_lock(&v3d->reset_lock);
>> diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/ 
>> v3d_drv.h
>> index 1884686985b8..99a39329bb85 100644
>> --- a/drivers/gpu/drm/v3d/v3d_drv.h
>> +++ b/drivers/gpu/drm/v3d/v3d_drv.h
>> @@ -158,11 +158,6 @@ struct v3d_dev {
>>       struct drm_mm mm;
>>       spinlock_t mm_lock;
>> -    /*
>> -     * tmpfs instance used for shmem backed objects
>> -     */
>> -    struct vfsmount *gemfs;
>> -
>>       struct work_struct overflow_mem_work;
>>       struct v3d_queue_state queue[V3D_MAX_QUEUES];
>> @@ -569,6 +564,7 @@ extern const struct dma_fence_ops v3d_fence_ops;
>>   struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum 
>> v3d_queue q);
>>   /* v3d_gem.c */
>> +extern bool super_pages;
>>   int v3d_gem_init(struct drm_device *dev);
>>   void v3d_gem_destroy(struct drm_device *dev);
>>   void v3d_reset_sms(struct v3d_dev *v3d);
>> @@ -576,11 +572,6 @@ void v3d_reset(struct v3d_dev *v3d);
>>   void v3d_invalidate_caches(struct v3d_dev *v3d);
>>   void v3d_clean_caches(struct v3d_dev *v3d);
>> -/* v3d_gemfs.c */
>> -extern bool super_pages;
>> -void v3d_gemfs_init(struct v3d_dev *v3d);
>> -void v3d_gemfs_fini(struct v3d_dev *v3d);
>> -
>>   /* v3d_submit.c */
>>   void v3d_job_cleanup(struct v3d_job *job);
>>   void v3d_job_put(struct v3d_job *job);
>> diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/ 
>> v3d_gem.c
>> index bb110d35f749..635ff0fabe7e 100644
>> --- a/drivers/gpu/drm/v3d/v3d_gem.c
>> +++ b/drivers/gpu/drm/v3d/v3d_gem.c
>> @@ -258,6 +258,30 @@ v3d_invalidate_caches(struct v3d_dev *v3d)
>>       v3d_invalidate_slices(v3d, 0);
>>   }
>> +static void
>> +v3d_huge_mnt_init(struct v3d_dev *v3d)
>> +{
>> +    int err = 0;
>> +
>> +    /*
>> +     * By using a huge shmemfs mountpoint when the user wants to
>> +     * enable Super Pages, we can pass in mount flags that better
>> +     * match our usecase.
>> +     */
>> +
>> +    if (super_pages)
>> +        err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> 
> If it is this patch that is creating the build failure then the two 
> should be squashed.
> 
> Then in "drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n" this 
> ends up a bit ugly:
> 
> #ifdef CONFIG_TRANSPARENT_HUGEPAGE
>       if (super_pages)
> #endif
>           err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> 
> Does this not work:
> 
>       if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && super_pages)
>           err = drm_gem_huge_mnt_create(&v3d->drm, "within_size");
> 
> ?

I've got a new version ready that does exactly that (after discussing 
with Boris).

> 
> Regards,
> 
> Tvrtko
> 
>> +
>> +    if (v3d->drm.huge_mnt)
>> +        drm_info(&v3d->drm, "Using Transparent Hugepages\n");
>> +    else if (err)
>> +        drm_warn(&v3d->drm, "Can't use Transparent Hugepages (%d)\n",
>> +             err);
>> +    else
>> +        drm_notice(&v3d->drm,
>> +               "Transparent Hugepage support is recommended for 
>> optimal performance on this platform!\n");
>> +}
>> +
>>   int
>>   v3d_gem_init(struct drm_device *dev)
>>   {
>> @@ -309,7 +333,7 @@ v3d_gem_init(struct drm_device *dev)
>>       v3d_init_hw_state(v3d);
>>       v3d_mmu_set_page_table(v3d);
>> -    v3d_gemfs_init(v3d);
>> +    v3d_huge_mnt_init(v3d);
>>       ret = v3d_sched_init(v3d);
>>       if (ret) {
>> @@ -329,7 +353,6 @@ v3d_gem_destroy(struct drm_device *dev)
>>       enum v3d_queue q;
>>       v3d_sched_fini(v3d);
>> -    v3d_gemfs_fini(v3d);
>>       /* Waiting for jobs to finish would need to be done before
>>        * unregistering V3D.
>> diff --git a/drivers/gpu/drm/v3d/v3d_gemfs.c b/drivers/gpu/drm/v3d/ 
>> v3d_gemfs.c
>> deleted file mode 100644
>> index c1a30166c099..000000000000
>> --- a/drivers/gpu/drm/v3d/v3d_gemfs.c
>> +++ /dev/null
>> @@ -1,60 +0,0 @@
>> -// SPDX-License-Identifier: GPL-2.0+
>> -/* Copyright (C) 2024 Raspberry Pi */
>> -
>> -#include <linux/fs.h>
>> -#include <linux/mount.h>
>> -#include <linux/fs_context.h>
>> -
>> -#include "v3d_drv.h"
>> -
>> -void v3d_gemfs_init(struct v3d_dev *v3d)
>> -{
>> -    struct file_system_type *type;
>> -    struct fs_context *fc;
>> -    struct vfsmount *gemfs;
>> -    int ret;
>> -
>> -    /*
>> -     * By creating our own shmemfs mountpoint, we can pass in
>> -     * mount flags that better match our usecase. However, we
>> -     * only do so on platforms which benefit from it.
>> -     */
>> -    if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
>> -        goto err;
>> -
>> -    /* The user doesn't want to enable Super Pages */
>> -    if (!super_pages)
>> -        goto err;
>> -
>> -    type = get_fs_type("tmpfs");
>> -    if (!type)
>> -        goto err;
>> -
>> -    fc = fs_context_for_mount(type, SB_KERNMOUNT);
>> -    if (IS_ERR(fc))
>> -        goto err;
>> -    ret = vfs_parse_fs_string(fc, "source", "tmpfs");
>> -    if (!ret)
>> -        ret = vfs_parse_fs_string(fc, "huge", "within_size");
>> -    if (!ret)
>> -        gemfs = fc_mount_longterm(fc);
>> -    put_fs_context(fc);
>> -    if (ret)
>> -        goto err;
>> -
>> -    v3d->gemfs = gemfs;
>> -    drm_info(&v3d->drm, "Using Transparent Hugepages\n");
>> -
>> -    return;
>> -
>> -err:
>> -    v3d->gemfs = NULL;
>> -    drm_notice(&v3d->drm,
>> -           "Transparent Hugepage support is recommended for optimal 
>> performance on this platform!\n");
>> -}
>> -
>> -void v3d_gemfs_fini(struct v3d_dev *v3d)
>> -{
>> -    if (v3d->gemfs)
>> -        kern_unmount(v3d->gemfs);
>> -}
> 



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v4 03/13] drm/shmem-helper: Map huge pages in fault handlers
  2025-10-17 21:42       ` Matthew Wilcox
@ 2025-11-10 14:39         ` Loïc Molinari
  0 siblings, 0 replies; 27+ messages in thread
From: Loïc Molinari @ 2025-11-10 14:39 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Boris Brezillon, Rob Herring,
	Steven Price, Liviu Dudau, Melissa Wen, Maíra Canal,
	Hugh Dickins, Baolin Wang, Andrew Morton, Al Viro,
	Mikołaj Wasiak, Christian Brauner, Nitin Gote, Andi Shyti,
	Jonathan Corbet, Christopher Healy, Bagas Sanjaya, linux-kernel,
	dri-devel, intel-gfx, linux-mm, linux-doc, kernel

Hi Matthew,

On 17/10/2025 23:42, Matthew Wilcox wrote:
> On Thu, Oct 16, 2025 at 01:17:07PM +0200, Loïc Molinari wrote:
>>> It looks to me like we have an opportunity to do better here by
>>> adding a vmf_insert_pfns() interface.  I don't think we should delay
>>> your patch series to add it, but let's not forget to do that; it can
>>> have very good performnce effects on ARM to use contptes.
>>
>> Agreed. I initially wanted to provide such an interface based on set_ptes()
>> to benefit from arm64 contptes but thought it'd better be a distinct patch
>> series.
> 
> Agreed.
> 
>>>
>>>> @@ -617,8 +645,9 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
>>> [...]
>>>> -		ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page));
>>>> +	if (drm_gem_shmem_map_pmd(vmf, vmf->address, pages[page_offset])) {
>>>> +		ret = VM_FAULT_NOPAGE;
>>>> +		goto out;
>>>>    	}
>>>
>>> Does this actually work?
>>
>> Yes, it does. Huge pages are successfully mapped from both map_pages and
>> fault handlers. Anything wrong with it?
> 
> No, I just wasn't sure that this would work correctly.
> 
>> There seems to be an another issue thought. There are failures [1], all
>> looking like that one [2]. I think it's because map_pages is called with the
>> RCU read lock taken and the DRM GEM map_pages handler must lock the GEM
>> object before accessing pages with dma_resv_lock(). The locking doc says:
>> "If it's not possible to reach a page without blocking, filesystem should
>> skip it.". Unlocking the RCU read lock in the handler seems wrong and doing
>> without a map_pages implementation would be unfortunate. What would you
>> recommend here?
> 
> I'm not familiar with GEM locking, so let me describe briefly how
> pagecache locking works.
> 
> Calling mmap bumps the refcount on the inode.  That keeps the inode
> around while the page fault handler runs.  For each folio, we
> get a refcount on it, then we trylock it.  Then we map each page in the
> folio.
> 
> So maybe you can trylock the GEM object?  It isn't clear to me whether
> you want finer grained locking than that.  If the trylock fails, no big
> deal, you just fall through to the fault path (with the slightly more
> heavy-weight locking that allows you to sleep).

I proposed a series v5 using dma_resv_trylock(). This actually fails 
later because the vmf_insert_pfn*() functions end up locking too. Not 
sure how to fix that yet so I proposed a v6 with no fault-around path 
and will get back to it (along with contptes) later.

Loïc



^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2025-11-10 14:39 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-15 15:30 [PATCH v4 00/13] drm: Reduce page tables overhead with THP Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 01/13] drm/shmem-helper: Simplify page offset calculation in fault handler Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 02/13] drm/shmem-helper: Implement map_pages fault-around handler Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 03/13] drm/shmem-helper: Map huge pages in fault handlers Loïc Molinari
2025-10-15 17:27   ` Matthew Wilcox
2025-10-16 11:17     ` Loïc Molinari
2025-10-17 21:42       ` Matthew Wilcox
2025-11-10 14:39         ` Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 04/13] drm/gem: Introduce drm_gem_get_unmapped_area() fop Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 05/13] drm/gem: Add huge tmpfs mount point helper Loïc Molinari
2025-10-20  9:10   ` Tvrtko Ursulin
2025-10-20 14:13     ` Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 06/13] drm/i915: Use " Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 07/13] drm/v3d: " Loïc Molinari
2025-10-20  9:33   ` Tvrtko Ursulin
2025-10-20 14:27     ` Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 08/13] drm/v3d: Fix builds with CONFIG_TRANSPARENT_HUGEPAGE=n Loïc Molinari
2025-10-15 18:17   ` Boris Brezillon
2025-10-15 20:41     ` Loïc Molinari
2025-10-16  5:56       ` Boris Brezillon
2025-10-16  7:09         ` Loïc Molinari
2025-10-16  7:22           ` Boris Brezillon
2025-10-15 15:30 ` [PATCH v4 09/13] drm/gem: Get rid of *_with_mnt helpers Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 10/13] drm/panthor: Introduce huge tmpfs mount point option Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 11/13] drm/panthor: Improve IOMMU map/unmap debugging logs Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 12/13] drm/panfrost: Introduce huge tmpfs mount point option Loïc Molinari
2025-10-15 15:30 ` [PATCH v4 13/13] Documentation/gpu/drm-mm: Add THP paragraph to GEM mapping section Loïc Molinari

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox