public inbox for drm-ai-reviews@public-inbox.freedesktop.org
 help / color / mirror / Atom feed
* [PATCH v9 0/4] Enable THP support in drm_pagemap
@ 2026-03-12 19:20 Francois Dugast
  2026-03-12 19:20 ` [PATCH v9 1/4] drm/pagemap: Unlock and put folios when possible Francois Dugast
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Francois Dugast @ 2026-03-12 19:20 UTC (permalink / raw)
  To: intel-xe; +Cc: dri-devel

Use Balbir Singh's series for device-private THP support [1] and previous
preparation work in drm_pagemap [2] to add 2MB/THP support in xe. This leads
to significant performance improvements when using SVM with 2MB pages.

[1] https://lore.kernel.org/linux-mm/20251001065707.920170-1-balbirs@nvidia.com/
[2] https://patchwork.freedesktop.org/series/151754/

v2:
- rebase on top of multi-device SVM
- add drm_pagemap_cpages() with temporary patch
- address other feedback from Matt Brost on v1

v3:
The major change is to remove the dependency to the mm/huge_memory
helper migrate_device_split_page() that was called explicitely when
a 2M buddy allocation backed by a large folio would be later reused
for a smaller allocation (4K or 64K). Instead, the first 3 patches
provided by Matthew Brost ensure large folios are split at the time
of freeing.

v4:
- add order argument to folio_free callback
- send complete series to linux-mm and MM folks as requested (Zi Yan
  and Andrew Morton) and cover letter to anyone receiving at least
  one of the patches (Liam R. Howlett)

v5:
- update zone_device_page_init() in patch #1 to reinitialize large
  zone device private folios

v6:
- fix drm_pagemap change in patch #1 to allow applying to 6.19 and
  add some comments

v7:
- now that patch #1 is merged, rebase and resend for CI

v8:
- rebase on 7.0.0-rc3

v9:
- fix build when CONFIG_ZONE_DEVICE is disabled

Francois Dugast (3):
  drm/pagemap: Unlock and put folios when possible
  drm/pagemap: Add helper to access zone_device_data
  drm/pagemap: Enable THP support for GPU memory migration

Matthew Brost (1):
  drm/pagemap: Correct cpages calculation for migrate_vma_setup

 drivers/gpu/drm/drm_gpusvm.c  |   7 +-
 drivers/gpu/drm/drm_pagemap.c | 157 +++++++++++++++++++++++++++-------
 include/drm/drm_pagemap.h     |  21 +++++
 3 files changed, 154 insertions(+), 31 deletions(-)

-- 
2.43.0


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

* [PATCH v9 1/4] drm/pagemap: Unlock and put folios when possible
  2026-03-12 19:20 [PATCH v9 0/4] Enable THP support in drm_pagemap Francois Dugast
@ 2026-03-12 19:20 ` Francois Dugast
  2026-03-13  3:55   ` Claude review: " Claude Code Review Bot
  2026-03-12 19:20 ` [PATCH v9 2/4] drm/pagemap: Add helper to access zone_device_data Francois Dugast
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Francois Dugast @ 2026-03-12 19:20 UTC (permalink / raw)
  To: intel-xe; +Cc: dri-devel

If the page is part of a folio, unlock and put the whole folio at once
instead of individual pages one after the other. This will reduce the
amount of operations once device THP are in use.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Liam R. Howlett <Liam.Howlett@oracle.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: linux-mm@kvack.org
Suggested-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Francois Dugast <francois.dugast@intel.com>
Reviewed-by: Balbir Singh <balbirs@nvidia.com>
---
 drivers/gpu/drm/drm_pagemap.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c
index 862675ac5bb2..f453a12b6a8e 100644
--- a/drivers/gpu/drm/drm_pagemap.c
+++ b/drivers/gpu/drm/drm_pagemap.c
@@ -154,15 +154,15 @@ static void drm_pagemap_zdd_put(struct drm_pagemap_zdd *zdd)
 }
 
 /**
- * drm_pagemap_migration_unlock_put_page() - Put a migration page
- * @page: Pointer to the page to put
+ * drm_pagemap_migration_unlock_put_folio() - Put a migration folio
+ * @folio: Pointer to the folio to put
  *
- * This function unlocks and puts a page.
+ * This function unlocks and puts a folio.
  */
-static void drm_pagemap_migration_unlock_put_page(struct page *page)
+static void drm_pagemap_migration_unlock_put_folio(struct folio *folio)
 {
-	unlock_page(page);
-	put_page(page);
+	folio_unlock(folio);
+	folio_put(folio);
 }
 
 /**
@@ -177,15 +177,23 @@ static void drm_pagemap_migration_unlock_put_pages(unsigned long npages,
 {
 	unsigned long i;
 
-	for (i = 0; i < npages; ++i) {
+	for (i = 0; i < npages;) {
 		struct page *page;
+		struct folio *folio;
+		unsigned int order = 0;
 
 		if (!migrate_pfn[i])
-			continue;
+			goto next;
 
 		page = migrate_pfn_to_page(migrate_pfn[i]);
-		drm_pagemap_migration_unlock_put_page(page);
+		folio = page_folio(page);
+		order = folio_order(folio);
+
+		drm_pagemap_migration_unlock_put_folio(folio);
 		migrate_pfn[i] = 0;
+
+next:
+		i += NR_PAGES(order);
 	}
 }
 
-- 
2.43.0


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

* [PATCH v9 2/4] drm/pagemap: Add helper to access zone_device_data
  2026-03-12 19:20 [PATCH v9 0/4] Enable THP support in drm_pagemap Francois Dugast
  2026-03-12 19:20 ` [PATCH v9 1/4] drm/pagemap: Unlock and put folios when possible Francois Dugast
@ 2026-03-12 19:20 ` Francois Dugast
  2026-03-13  3:55   ` Claude review: " Claude Code Review Bot
  2026-03-12 19:20 ` [PATCH v9 3/4] drm/pagemap: Correct cpages calculation for migrate_vma_setup Francois Dugast
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Francois Dugast @ 2026-03-12 19:20 UTC (permalink / raw)
  To: intel-xe; +Cc: dri-devel

This new helper helps ensure all accesses to zone_device_data use the
correct API whether the page is part of a folio or not.

v2:
- Move to drm_pagemap.h, stick to folio_zone_device_data (Matthew Brost)
- Return struct drm_pagemap_zdd * (Matthew Brost)

v3:
- Add stub for !CONFIG_ZONE_DEVICE (CI)

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Liam R. Howlett <Liam.Howlett@oracle.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: linux-mm@kvack.org
Suggested-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Francois Dugast <francois.dugast@intel.com>
---
 drivers/gpu/drm/drm_gpusvm.c  |  7 +++++--
 drivers/gpu/drm/drm_pagemap.c | 21 ++++++++++++---------
 include/drm/drm_pagemap.h     | 21 +++++++++++++++++++++
 3 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index 35dd07297dd0..4b928fda5b12 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -1488,12 +1488,15 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
 		order = drm_gpusvm_hmm_pfn_to_order(pfns[i], i, npages);
 		if (is_device_private_page(page) ||
 		    is_device_coherent_page(page)) {
+			struct drm_pagemap_zdd *__zdd =
+				drm_pagemap_page_zone_device_data(page);
+
 			if (!ctx->allow_mixed &&
-			    zdd != page->zone_device_data && i > 0) {
+			    zdd != __zdd && i > 0) {
 				err = -EOPNOTSUPP;
 				goto err_unmap;
 			}
-			zdd = page->zone_device_data;
+			zdd = __zdd;
 			if (pagemap != page_pgmap(page)) {
 				if (pagemap) {
 					err = -EOPNOTSUPP;
diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c
index f453a12b6a8e..733a3857947c 100644
--- a/drivers/gpu/drm/drm_pagemap.c
+++ b/drivers/gpu/drm/drm_pagemap.c
@@ -252,7 +252,7 @@ static int drm_pagemap_migrate_map_pages(struct device *dev,
 		order = folio_order(folio);
 
 		if (is_device_private_page(page)) {
-			struct drm_pagemap_zdd *zdd = page->zone_device_data;
+			struct drm_pagemap_zdd *zdd = drm_pagemap_page_zone_device_data(page);
 			struct drm_pagemap *dpagemap = zdd->dpagemap;
 			struct drm_pagemap_addr addr;
 
@@ -323,7 +323,7 @@ static void drm_pagemap_migrate_unmap_pages(struct device *dev,
 			goto next;
 
 		if (is_zone_device_page(page)) {
-			struct drm_pagemap_zdd *zdd = page->zone_device_data;
+			struct drm_pagemap_zdd *zdd = drm_pagemap_page_zone_device_data(page);
 			struct drm_pagemap *dpagemap = zdd->dpagemap;
 
 			dpagemap->ops->device_unmap(dpagemap, dev, &pagemap_addr[i]);
@@ -601,7 +601,8 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
 
 		pages[i] = NULL;
 		if (src_page && is_device_private_page(src_page)) {
-			struct drm_pagemap_zdd *src_zdd = src_page->zone_device_data;
+			struct drm_pagemap_zdd *src_zdd =
+				drm_pagemap_page_zone_device_data(src_page);
 
 			if (page_pgmap(src_page) == pagemap &&
 			    !mdetails->can_migrate_same_pagemap) {
@@ -723,8 +724,8 @@ static int drm_pagemap_migrate_populate_ram_pfn(struct vm_area_struct *vas,
 			goto next;
 
 		if (fault_page) {
-			if (src_page->zone_device_data !=
-			    fault_page->zone_device_data)
+			if (drm_pagemap_page_zone_device_data(src_page) !=
+			    drm_pagemap_page_zone_device_data(fault_page))
 				goto next;
 		}
 
@@ -1065,7 +1066,7 @@ static int __drm_pagemap_migrate_to_ram(struct vm_area_struct *vas,
 	void *buf;
 	int i, err = 0;
 
-	zdd = page->zone_device_data;
+	zdd = drm_pagemap_page_zone_device_data(page);
 	if (time_before64(get_jiffies_64(), zdd->devmem_allocation->timeslice_expiration))
 		return 0;
 
@@ -1148,7 +1149,9 @@ static int __drm_pagemap_migrate_to_ram(struct vm_area_struct *vas,
  */
 static void drm_pagemap_folio_free(struct folio *folio)
 {
-	drm_pagemap_zdd_put(folio->page.zone_device_data);
+	struct page *page = folio_page(folio, 0);
+
+	drm_pagemap_zdd_put(drm_pagemap_page_zone_device_data(page));
 }
 
 /**
@@ -1164,7 +1167,7 @@ static void drm_pagemap_folio_free(struct folio *folio)
  */
 static vm_fault_t drm_pagemap_migrate_to_ram(struct vm_fault *vmf)
 {
-	struct drm_pagemap_zdd *zdd = vmf->page->zone_device_data;
+	struct drm_pagemap_zdd *zdd = drm_pagemap_page_zone_device_data(vmf->page);
 	int err;
 
 	err = __drm_pagemap_migrate_to_ram(vmf->vma,
@@ -1230,7 +1233,7 @@ EXPORT_SYMBOL_GPL(drm_pagemap_devmem_init);
  */
 struct drm_pagemap *drm_pagemap_page_to_dpagemap(struct page *page)
 {
-	struct drm_pagemap_zdd *zdd = page->zone_device_data;
+	struct drm_pagemap_zdd *zdd = drm_pagemap_page_zone_device_data(page);
 
 	return zdd->devmem_allocation->dpagemap;
 }
diff --git a/include/drm/drm_pagemap.h b/include/drm/drm_pagemap.h
index c848f578e3da..75e6ca58922d 100644
--- a/include/drm/drm_pagemap.h
+++ b/include/drm/drm_pagemap.h
@@ -4,6 +4,7 @@
 
 #include <linux/dma-direction.h>
 #include <linux/hmm.h>
+#include <linux/memremap.h>
 #include <linux/types.h>
 
 #define NR_PAGES(order) (1U << (order))
@@ -367,6 +368,26 @@ void drm_pagemap_destroy(struct drm_pagemap *dpagemap, bool is_atomic_or_reclaim
 
 int drm_pagemap_reinit(struct drm_pagemap *dpagemap);
 
+/**
+ * drm_pagemap_page_zone_device_data() - Page to zone_device_data
+ * @page: Pointer to the page
+ *
+ * Return: Page's zone_device_data
+ */
+static inline struct drm_pagemap_zdd *drm_pagemap_page_zone_device_data(struct page *page)
+{
+	struct folio *folio = page_folio(page);
+
+	return folio_zone_device_data(folio);
+}
+
+#else
+
+static inline struct drm_pagemap_zdd *drm_pagemap_page_zone_device_data(struct page *page)
+{
+	return NULL;
+}
+
 #endif /* IS_ENABLED(CONFIG_ZONE_DEVICE) */
 
 #endif
-- 
2.43.0


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

* [PATCH v9 3/4] drm/pagemap: Correct cpages calculation for migrate_vma_setup
  2026-03-12 19:20 [PATCH v9 0/4] Enable THP support in drm_pagemap Francois Dugast
  2026-03-12 19:20 ` [PATCH v9 1/4] drm/pagemap: Unlock and put folios when possible Francois Dugast
  2026-03-12 19:20 ` [PATCH v9 2/4] drm/pagemap: Add helper to access zone_device_data Francois Dugast
@ 2026-03-12 19:20 ` Francois Dugast
  2026-03-13  3:55   ` Claude review: " Claude Code Review Bot
  2026-03-12 19:20 ` [PATCH v9 4/4] drm/pagemap: Enable THP support for GPU memory migration Francois Dugast
  2026-03-13  3:55 ` Claude review: Enable THP support in drm_pagemap Claude Code Review Bot
  4 siblings, 1 reply; 11+ messages in thread
From: Francois Dugast @ 2026-03-12 19:20 UTC (permalink / raw)
  To: intel-xe; +Cc: dri-devel

From: Matthew Brost <matthew.brost@intel.com>

cpages returned from migrate_vma_setup represents the total number of
individual pages found, not the number of 4K pages. The math in
drm_pagemap_migrate_to_devmem for npages is based on the number of 4K
pages, so cpages != npages can fail even if the entire memory range is
found in migrate_vma_setup (e.g., when a single 2M page is found).
Add drm_pagemap_cpages, which converts cpages to the number of 4K pages
found.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Liam R. Howlett <Liam.Howlett@oracle.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: linux-mm@kvack.org
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Francois Dugast <francois.dugast@intel.com>
Signed-off-by: Francois Dugast <francois.dugast@intel.com>
Reviewed-by: Balbir Singh <balbirs@nvidia.com>
---
 drivers/gpu/drm/drm_pagemap.c | 38 ++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c
index 733a3857947c..837b881883f9 100644
--- a/drivers/gpu/drm/drm_pagemap.c
+++ b/drivers/gpu/drm/drm_pagemap.c
@@ -452,6 +452,41 @@ static int drm_pagemap_migrate_range(struct drm_pagemap_devmem *devmem,
 	return ret;
 }
 
+/**
+ * drm_pagemap_cpages() - Count collected pages
+ * @migrate_pfn: Array of migrate_pfn entries to account
+ * @npages: Number of entries in @migrate_pfn
+ *
+ * Compute the total number of minimum-sized pages represented by the
+ * collected entries in @migrate_pfn. The total is derived from the
+ * order encoded in each entry.
+ *
+ * Return: Total number of minimum-sized pages.
+ */
+static int drm_pagemap_cpages(unsigned long *migrate_pfn, unsigned long npages)
+{
+	unsigned long i, cpages = 0;
+
+	for (i = 0; i < npages;) {
+		struct page *page = migrate_pfn_to_page(migrate_pfn[i]);
+		struct folio *folio;
+		unsigned int order = 0;
+
+		if (page) {
+			folio = page_folio(page);
+			order = folio_order(folio);
+			cpages += NR_PAGES(order);
+		} else if (migrate_pfn[i] & MIGRATE_PFN_COMPOUND) {
+			order = HPAGE_PMD_ORDER;
+			cpages += NR_PAGES(order);
+		}
+
+		i += NR_PAGES(order);
+	}
+
+	return cpages;
+}
+
 /**
  * drm_pagemap_migrate_to_devmem() - Migrate a struct mm_struct range to device memory
  * @devmem_allocation: The device memory allocation to migrate to.
@@ -554,7 +589,8 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
 		goto err_free;
 	}
 
-	if (migrate.cpages != npages) {
+	if (migrate.cpages != npages &&
+	    drm_pagemap_cpages(migrate.src, npages) != npages) {
 		/*
 		 * Some pages to migrate. But we want to migrate all or
 		 * nothing. Raced or unknown device pages.
-- 
2.43.0


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

* [PATCH v9 4/4] drm/pagemap: Enable THP support for GPU memory migration
  2026-03-12 19:20 [PATCH v9 0/4] Enable THP support in drm_pagemap Francois Dugast
                   ` (2 preceding siblings ...)
  2026-03-12 19:20 ` [PATCH v9 3/4] drm/pagemap: Correct cpages calculation for migrate_vma_setup Francois Dugast
@ 2026-03-12 19:20 ` Francois Dugast
  2026-03-13  3:55   ` Claude review: " Claude Code Review Bot
  2026-03-13  3:55 ` Claude review: Enable THP support in drm_pagemap Claude Code Review Bot
  4 siblings, 1 reply; 11+ messages in thread
From: Francois Dugast @ 2026-03-12 19:20 UTC (permalink / raw)
  To: intel-xe; +Cc: dri-devel

This enables support for Transparent Huge Pages (THP) for device pages by
using MIGRATE_VMA_SELECT_COMPOUND during migration. It removes the need to
split folios and loop multiple times over all pages to perform required
operations at page level. Instead, we rely on newly introduced support for
higher orders in drm_pagemap and folio-level API.

In Xe, this drastically improves performance when using SVM. The GT stats
below collected after a 2MB page fault show overall servicing is more than
7 times faster, and thanks to reduced CPU overhead the time spent on the
actual copy goes from 23% without THP to 80% with THP:

Without THP:

    svm_2M_pagefault_us: 966
    svm_2M_migrate_us: 942
    svm_2M_device_copy_us: 223
    svm_2M_get_pages_us: 9
    svm_2M_bind_us: 10

With THP:

    svm_2M_pagefault_us: 132
    svm_2M_migrate_us: 128
    svm_2M_device_copy_us: 106
    svm_2M_get_pages_us: 1
    svm_2M_bind_us: 2

v2:
- Fix one occurrence of drm_pagemap_get_devmem_page() (Matthew Brost)

v3:
- Remove migrate_device_split_page() and folio_split_lock, instead rely on
  free_zone_device_folio() to split folios before freeing (Matthew Brost)
- Assert folio order is HPAGE_PMD_ORDER (Matthew Brost)
- Always use folio_set_zone_device_data() in split (Matthew Brost)

v4:
- Warn on compound device page, s/continue/goto next/ (Matthew Brost)

v5:
- Revert warn on compound device page
- s/zone_device_page_init()/zone_device_folio_init() (Matthew Brost)

Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Michal Mrozek <michal.mrozek@intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Liam R. Howlett <Liam.Howlett@oracle.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: linux-mm@kvack.org
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Francois Dugast <francois.dugast@intel.com>
---
 drivers/gpu/drm/drm_pagemap.c | 72 ++++++++++++++++++++++++++++++-----
 1 file changed, 62 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c
index 837b881883f9..5002049e0198 100644
--- a/drivers/gpu/drm/drm_pagemap.c
+++ b/drivers/gpu/drm/drm_pagemap.c
@@ -200,16 +200,19 @@ static void drm_pagemap_migration_unlock_put_pages(unsigned long npages,
 /**
  * drm_pagemap_get_devmem_page() - Get a reference to a device memory page
  * @page: Pointer to the page
+ * @order: Order
  * @zdd: Pointer to the GPU SVM zone device data
  *
  * This function associates the given page with the specified GPU SVM zone
  * device data and initializes it for zone device usage.
  */
 static void drm_pagemap_get_devmem_page(struct page *page,
+					unsigned int order,
 					struct drm_pagemap_zdd *zdd)
 {
-	page->zone_device_data = drm_pagemap_zdd_get(zdd);
-	zone_device_page_init(page, page_pgmap(page), 0);
+	zone_device_folio_init((struct folio *)page, zdd->dpagemap->pagemap,
+			       order);
+	folio_set_zone_device_data(page_folio(page), drm_pagemap_zdd_get(zdd));
 }
 
 /**
@@ -524,7 +527,7 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
 		.end		= end,
 		.pgmap_owner	= pagemap->owner,
 		.flags		= MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT |
-		MIGRATE_VMA_SELECT_DEVICE_PRIVATE,
+		MIGRATE_VMA_SELECT_DEVICE_PRIVATE | MIGRATE_VMA_SELECT_COMPOUND,
 	};
 	unsigned long i, npages = npages_in_range(start, end);
 	unsigned long own_pages = 0, migrated_pages = 0;
@@ -630,11 +633,13 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
 
 	own_pages = 0;
 
-	for (i = 0; i < npages; ++i) {
+	for (i = 0; i < npages;) {
+		unsigned long j;
 		struct page *page = pfn_to_page(migrate.dst[i]);
 		struct page *src_page = migrate_pfn_to_page(migrate.src[i]);
-		cur.start = i;
+		unsigned int order = 0;
 
+		cur.start = i;
 		pages[i] = NULL;
 		if (src_page && is_device_private_page(src_page)) {
 			struct drm_pagemap_zdd *src_zdd =
@@ -644,7 +649,7 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
 			    !mdetails->can_migrate_same_pagemap) {
 				migrate.dst[i] = 0;
 				own_pages++;
-				continue;
+				goto next;
 			}
 			if (mdetails->source_peer_migrates) {
 				cur.dpagemap = src_zdd->dpagemap;
@@ -660,7 +665,20 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
 			pages[i] = page;
 		}
 		migrate.dst[i] = migrate_pfn(migrate.dst[i]);
-		drm_pagemap_get_devmem_page(page, zdd);
+
+		if (migrate.src[i] & MIGRATE_PFN_COMPOUND) {
+			drm_WARN_ONCE(dpagemap->drm, src_page &&
+				      folio_order(page_folio(src_page)) != HPAGE_PMD_ORDER,
+				      "Unexpected folio order\n");
+
+			order = HPAGE_PMD_ORDER;
+			migrate.dst[i] |= MIGRATE_PFN_COMPOUND;
+
+			for (j = 1; j < NR_PAGES(order) && i + j < npages; j++)
+				migrate.dst[i + j] = 0;
+		}
+
+		drm_pagemap_get_devmem_page(page, order, zdd);
 
 		/* If we switched the migrating drm_pagemap, migrate previous pages now */
 		err = drm_pagemap_migrate_range(devmem_allocation, migrate.src, migrate.dst,
@@ -670,7 +688,11 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
 			npages = i + 1;
 			goto err_finalize;
 		}
+
+next:
+		i += NR_PAGES(order);
 	}
+
 	cur.start = npages;
 	cur.ops = NULL; /* Force migration */
 	err = drm_pagemap_migrate_range(devmem_allocation, migrate.src, migrate.dst,
@@ -779,6 +801,8 @@ static int drm_pagemap_migrate_populate_ram_pfn(struct vm_area_struct *vas,
 		page = folio_page(folio, 0);
 		mpfn[i] = migrate_pfn(page_to_pfn(page));
 
+		if (order)
+			mpfn[i] |= MIGRATE_PFN_COMPOUND;
 next:
 		if (page)
 			addr += page_size(page);
@@ -1034,8 +1058,15 @@ int drm_pagemap_evict_to_ram(struct drm_pagemap_devmem *devmem_allocation)
 	if (err)
 		goto err_finalize;
 
-	for (i = 0; i < npages; ++i)
+	for (i = 0; i < npages;) {
+		unsigned int order = 0;
+
 		pages[i] = migrate_pfn_to_page(src[i]);
+		if (pages[i])
+			order = folio_order(page_folio(pages[i]));
+
+		i += NR_PAGES(order);
+	}
 
 	err = ops->copy_to_ram(pages, pagemap_addr, npages, NULL);
 	if (err)
@@ -1088,7 +1119,8 @@ static int __drm_pagemap_migrate_to_ram(struct vm_area_struct *vas,
 		.vma		= vas,
 		.pgmap_owner	= page_pgmap(page)->owner,
 		.flags		= MIGRATE_VMA_SELECT_DEVICE_PRIVATE |
-		MIGRATE_VMA_SELECT_DEVICE_COHERENT,
+				  MIGRATE_VMA_SELECT_DEVICE_COHERENT |
+				  MIGRATE_VMA_SELECT_COMPOUND,
 		.fault_page	= page,
 	};
 	struct drm_pagemap_migrate_details mdetails = {};
@@ -1154,8 +1186,15 @@ static int __drm_pagemap_migrate_to_ram(struct vm_area_struct *vas,
 	if (err)
 		goto err_finalize;
 
-	for (i = 0; i < npages; ++i)
+	for (i = 0; i < npages;) {
+		unsigned int order = 0;
+
 		pages[i] = migrate_pfn_to_page(migrate.src[i]);
+		if (pages[i])
+			order = folio_order(page_folio(pages[i]));
+
+		i += NR_PAGES(order);
+	}
 
 	err = ops->copy_to_ram(pages, pagemap_addr, npages, NULL);
 	if (err)
@@ -1213,9 +1252,22 @@ static vm_fault_t drm_pagemap_migrate_to_ram(struct vm_fault *vmf)
 	return err ? VM_FAULT_SIGBUS : 0;
 }
 
+static void drm_pagemap_folio_split(struct folio *orig_folio, struct folio *new_folio)
+{
+	struct drm_pagemap_zdd *zdd;
+
+	if (!new_folio)
+		return;
+
+	new_folio->pgmap = orig_folio->pgmap;
+	zdd = folio_zone_device_data(orig_folio);
+	folio_set_zone_device_data(new_folio, drm_pagemap_zdd_get(zdd));
+}
+
 static const struct dev_pagemap_ops drm_pagemap_pagemap_ops = {
 	.folio_free = drm_pagemap_folio_free,
 	.migrate_to_ram = drm_pagemap_migrate_to_ram,
+	.folio_split = drm_pagemap_folio_split,
 };
 
 /**
-- 
2.43.0


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

* Claude review: Enable THP support in drm_pagemap
  2026-03-12 19:20 [PATCH v9 0/4] Enable THP support in drm_pagemap Francois Dugast
                   ` (3 preceding siblings ...)
  2026-03-12 19:20 ` [PATCH v9 4/4] drm/pagemap: Enable THP support for GPU memory migration Francois Dugast
@ 2026-03-13  3:55 ` Claude Code Review Bot
  4 siblings, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-03-13  3:55 UTC (permalink / raw)
  To: dri-devel-reviews

Overall Series Review

Subject: Enable THP support in drm_pagemap
Author: Francois Dugast <francois.dugast@intel.com>
Patches: 5
Reviewed: 2026-03-13T13:55:13.872314

---

This is a well-structured 4-patch series (v9) that enables Transparent Huge Page (THP) support in the DRM pagemap layer for GPU memory migration. The series is logically ordered: first convert to folio-level unlock/put operations, then introduce a helper for zone_device_data access, fix cpages accounting, and finally enable compound page migration. The performance numbers are compelling (7x improvement on 2MB SVM page faults). The code has been through multiple review rounds and carries Reviewed-by tags from Matthew Brost and Balbir Singh.

Overall the series looks solid. I have a few observations, mostly minor, noted below.

---
Generated by Claude Code Patch Reviewer

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

* Claude review: drm/pagemap: Unlock and put folios when possible
  2026-03-12 19:20 ` [PATCH v9 1/4] drm/pagemap: Unlock and put folios when possible Francois Dugast
@ 2026-03-13  3:55   ` Claude Code Review Bot
  0 siblings, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-03-13  3:55 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

**Good:** Clean conversion from page-level to folio-level unlock/put. The loop change from `++i` to stepping by `NR_PAGES(order)` correctly skips tail pages of large folios.

**Concern — uninitialized `order` on zero migrate_pfn path:**

```c
for (i = 0; i < npages;) {
    struct page *page;
    struct folio *folio;
    unsigned int order = 0;

    if (!migrate_pfn[i])
        goto next;
    ...
next:
    i += NR_PAGES(order);
}
```

When `migrate_pfn[i]` is zero, `order` is 0 and `NR_PAGES(0)` is 1, so the loop advances by 1. This is correct. However, it means for null entries interleaved within a large folio's PFN slots, each null entry is iterated individually. This is fine for correctness — the null entries simply indicate pages that weren't migrated — but it's worth noting the semantics are consistent.

**Minor:** The `migrate_pfn[i] = 0` clear on line 273 only clears the head page's entry, not tail entries. This appears correct since `drm_pagemap_migration_unlock_put_pages` is cleaning up after errors and only the head PFN would have been set during setup.

Looks good.

---
Generated by Claude Code Patch Reviewer

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

* Claude review: drm/pagemap: Add helper to access zone_device_data
  2026-03-12 19:20 ` [PATCH v9 2/4] drm/pagemap: Add helper to access zone_device_data Francois Dugast
@ 2026-03-13  3:55   ` Claude Code Review Bot
  0 siblings, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-03-13  3:55 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

**Good:** Centralizes `zone_device_data` access through `drm_pagemap_page_zone_device_data()`, which correctly goes through the folio API (`page_folio()` → `folio_zone_device_data()`). This prepares for THP where only the head page's `zone_device_data` is meaningful.

**Concern — `folio_zone_device_data` only checks `folio_is_device_private`:**

Looking at the kernel's `folio_zone_device_data()`:
```c
static inline void *folio_zone_device_data(const struct folio *folio)
{
    VM_WARN_ON_FOLIO(!folio_is_device_private(folio), folio);
    return folio->page.zone_device_data;
}
```

This will trigger a `VM_WARN` if called on a device-coherent folio. The existing code in `drm_pagemap.c` accesses `zone_device_data` on both device-private and device-coherent pages (e.g., `drm_pagemap_migrate_unmap_pages` checks `is_zone_device_page` which covers both). In `drm_gpusvm.c` the call site at line 1493 also checks `is_device_coherent_page`. So the new helper will produce `VM_WARN` on coherent pages in debug builds. This seems like a pre-existing issue with the `folio_zone_device_data` API rather than this patch specifically, but it's worth noting — the callers in `drm_pagemap_migrate_unmap_pages` at line 325-326 use `is_zone_device_page` which includes coherent pages.

**Good:** The `#else` stub returning NULL for `!CONFIG_ZONE_DEVICE` is correctly placed (the v9 changelog notes this was a build fix).

**Minor:** In `drm_pagemap_folio_free`:
```c
struct page *page = folio_page(folio, 0);
drm_pagemap_zdd_put(drm_pagemap_page_zone_device_data(page));
```
This could simply use `folio_zone_device_data(folio)` directly without the extra `folio_page` + `page_folio` round-trip inside the helper. Not a bug, just a minor indirection.

---
Generated by Claude Code Patch Reviewer

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

* Claude review: drm/pagemap: Correct cpages calculation for migrate_vma_setup
  2026-03-12 19:20 ` [PATCH v9 3/4] drm/pagemap: Correct cpages calculation for migrate_vma_setup Francois Dugast
@ 2026-03-13  3:55   ` Claude Code Review Bot
  0 siblings, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-03-13  3:55 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

**Good:** The commit message clearly explains the problem: `migrate_vma_setup` returns cpages as the count of entries (folios/pages), not the count of base pages, so a single 2MB compound page returns cpages=1 but npages=512.

**Observation — MIGRATE_PFN_COMPOUND without a page:**

```c
} else if (migrate_pfn[i] & MIGRATE_PFN_COMPOUND) {
    order = HPAGE_PMD_ORDER;
    cpages += NR_PAGES(order);
}
```

This branch handles compound entries where `migrate_pfn_to_page()` returns NULL but the COMPOUND flag is set. This would be the case for PTE-mapped large folios that can't be directly referenced? It's a bit unusual — if there's no page, what does the compound flag mean? This seems like a defensive measure, but a comment explaining when this case occurs would help readability.

**Minor — return type:** The function returns `int` but `cpages` is `unsigned long`. This is fine in practice since npages won't overflow int, but for consistency with the `npages` parameter type (`unsigned long`), the return type could be `unsigned long`.

---
Generated by Claude Code Patch Reviewer

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

* Claude review: drm/pagemap: Enable THP support for GPU memory migration
  2026-03-12 19:20 ` [PATCH v9 4/4] drm/pagemap: Enable THP support for GPU memory migration Francois Dugast
@ 2026-03-13  3:55   ` Claude Code Review Bot
  0 siblings, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-03-13  3:55 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

This is the main patch. Several observations:

**Concern — unsafe cast in `drm_pagemap_get_devmem_page`:**

```c
zone_device_folio_init((struct folio *)page, zdd->dpagemap->pagemap, order);
folio_set_zone_device_data(page_folio(page), drm_pagemap_zdd_get(zdd));
```

The first line casts `struct page *` directly to `struct folio *`. When `order > 0`, this assumes `page` points to a compound page's head page. This should be safe given that `populate_devmem_pfn` returns fresh device memory pages and `pfn_to_page(migrate.dst[i])` at the call site gives the base page, but the second line then calls `page_folio(page)` which is the proper API. The inconsistency suggests the first line should also use `page_folio(page)` or an explicit comment explaining why the direct cast is needed (perhaps because the folio hasn't been initialized yet at that point, so `page_folio()` wouldn't work for order-0 → order-N transition).

**Concern — `pages[]` array population in evict/migrate-to-RAM loops:**

```c
for (i = 0; i < npages;) {
    unsigned int order = 0;

    pages[i] = migrate_pfn_to_page(src[i]);
    if (pages[i])
        order = folio_order(page_folio(pages[i]));

    i += NR_PAGES(order);
}
```

This sets `pages[i]` for the head page index only. The `copy_to_ram` callback receives the `pages` array with only head-page entries set and NULL/uninitialized for tail indices. The callback must be aware it needs to handle this sparsely-populated array — presumably it uses `npages` and the folio order to figure things out. This is an implicit contract that should ideally be documented.

**Good — `drm_pagemap_folio_split` implementation:**

```c
static void drm_pagemap_folio_split(struct folio *orig_folio, struct folio *new_folio)
{
    if (!new_folio)
        return;

    new_folio->pgmap = orig_folio->pgmap;
    zdd = folio_zone_device_data(orig_folio);
    folio_set_zone_device_data(new_folio, drm_pagemap_zdd_get(zdd));
}
```

Correctly handles the split by propagating pgmap and taking a reference on the zdd. The NULL check on `new_folio` matches the kernel convention for the `folio_split` callback.

**Observation — MIGRATE_PFN_COMPOUND in `drm_pagemap_migrate_populate_ram_pfn`:**

```c
if (order)
    mpfn[i] |= MIGRATE_PFN_COMPOUND;
```

This is set when populating RAM PFNs for the migrate-to-RAM path, correctly signaling to the migration framework that the destination should be a compound page.

**Minor — hardcoded HPAGE_PMD_ORDER assumption:**

```c
order = HPAGE_PMD_ORDER;
```

The series only supports PMD-level (2MB on x86) huge pages. This is fine for now but means any future support for other huge page sizes (e.g., PUD-level 1GB) would require rework. The `drm_WARN_ONCE` check correctly validates this assumption.

---
Generated by Claude Code Patch Reviewer

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

* Claude review: drm/pagemap: Enable THP support for GPU memory migration
  2026-03-12 15:16 ` [PATCH v8 4/4] drm/pagemap: Enable THP support for GPU memory migration Francois Dugast
@ 2026-03-13  4:02   ` Claude Code Review Bot
  0 siblings, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-03-13  4:02 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

This is the main enablement patch. Several observations:

**1. Ordering change in `drm_pagemap_get_devmem_page`:**

```c
+	zone_device_folio_init((struct folio *)page, zdd->dpagemap->pagemap,
+			       order);
+	folio_set_zone_device_data(page_folio(page), drm_pagemap_zdd_get(zdd));
```

The original code set `zone_device_data` *before* `zone_device_page_init`. The new code sets it *after* `zone_device_folio_init`. This is fine because `zone_device_page_init` doesn't read `zone_device_data`, but the `(struct folio *)page` cast is a raw cast that bypasses `page_folio()` checks. This is safe here because `page` is the head page from `pfn_to_page(migrate.dst[i])`, but it's worth noting this assumption.

Also, the original used `page_pgmap(page)` while the new code uses `zdd->dpagemap->pagemap`. These should be equivalent for destination pages in migrate-to-devmem, but it's a subtle semantic change.

**2. Eviction page array gaps:**

In both `drm_pagemap_evict_to_ram` and `__drm_pagemap_migrate_to_ram`, the loop that populates `pages[]` now skips tail page entries:

```c
+	for (i = 0; i < npages;) {
+		unsigned int order = 0;
+
 		pages[i] = migrate_pfn_to_page(src[i]);
+		if (pages[i])
+			order = folio_order(page_folio(pages[i]));
+
+		i += NR_PAGES(order);
+	}
```

Previously every `pages[i]` was populated. Now only head-page entries are set; tail entries remain NULL (from `kcalloc`). The `copy_to_ram` callback must be aware of this — it will see a non-NULL entry for the head page followed by NR_PAGES(order)-1 NULL entries. If `copy_to_ram` implementations iterate linearly and check `pages[i]` for NULL to skip, this works. But this is a behavioral contract change that should be documented or validated against all `copy_to_ram` implementations.

**3. `drm_pagemap_folio_split` callback:**

```c
+static void drm_pagemap_folio_split(struct folio *orig_folio, struct folio *new_folio)
+{
+	if (!new_folio)
+		return;
+
+	new_folio->pgmap = orig_folio->pgmap;
+	zdd = folio_zone_device_data(orig_folio);
+	folio_set_zone_device_data(new_folio, drm_pagemap_zdd_get(zdd));
+}
```

This correctly takes a new zdd reference for the split folio and copies `pgmap`. The `new_folio == NULL` early return is consistent with the default handler in `zone_device_private_split_cb`. This looks correct.

**4. Missing THP allocation fallback:**

The existing code in `drm_pagemap_migrate_populate_ram_pfn` already has:
```c
/* TODO: Support fallback to single pages if THP allocation fails */
```

With THP now enabled, a failed order-9 allocation will cause the entire migration to fail (`goto free_pages`). For production robustness, a fallback to base-page allocation would be important. This is a known limitation (marked TODO), not a bug introduced by this patch.

**Verdict: Correct overall. The `pages[]` sparse population contract with `copy_to_ram` callbacks should be verified/documented.**

---
Generated by Claude Code Patch Reviewer

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

end of thread, other threads:[~2026-03-13  4:02 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-12 19:20 [PATCH v9 0/4] Enable THP support in drm_pagemap Francois Dugast
2026-03-12 19:20 ` [PATCH v9 1/4] drm/pagemap: Unlock and put folios when possible Francois Dugast
2026-03-13  3:55   ` Claude review: " Claude Code Review Bot
2026-03-12 19:20 ` [PATCH v9 2/4] drm/pagemap: Add helper to access zone_device_data Francois Dugast
2026-03-13  3:55   ` Claude review: " Claude Code Review Bot
2026-03-12 19:20 ` [PATCH v9 3/4] drm/pagemap: Correct cpages calculation for migrate_vma_setup Francois Dugast
2026-03-13  3:55   ` Claude review: " Claude Code Review Bot
2026-03-12 19:20 ` [PATCH v9 4/4] drm/pagemap: Enable THP support for GPU memory migration Francois Dugast
2026-03-13  3:55   ` Claude review: " Claude Code Review Bot
2026-03-13  3:55 ` Claude review: Enable THP support in drm_pagemap Claude Code Review Bot
  -- strict thread matches above, loose matches on Subject: below --
2026-03-12 15:16 [PATCH v8 0/4] " Francois Dugast
2026-03-12 15:16 ` [PATCH v8 4/4] drm/pagemap: Enable THP support for GPU memory migration Francois Dugast
2026-03-13  4:02   ` Claude review: " Claude Code Review Bot

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