* [PATCH 0/4] drm/amdkfd: Enable device private memory THP support in kfd svm driver
@ 2026-08-31 14:24 Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 1/4] drm/amdkfd: Add awareness of THP of device and system RAM " Xiaogang.Chen
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Xiaogang.Chen @ 2026-08-31 14:24 UTC (permalink / raw)
To: amd-gfx; +Cc: Xiaogang Chen
From: Xiaogang Chen <xiaogang.chen@amd.com>
Use following work for device-private THP support in kfd driver to add
2MB/THP support in migration. The implementation enables efficient migration
of large folios between system memory and device-private memory.
https://lore.kernel.org/linux-mm/20251001065707.920170-1-balbirs@nvidia.com/
Xiaogang Chen (4):
drm/amdkfd: Add awareness of THP of device and system RAM in kfd svm
driver
drm/amdkfd: Change migration size in CPU/GPU page fault handler to THP
size
drm/amdkfd: Apply HMM THP zone device-private memory migration in kfd
driver
drm/amdkfd: Apply AMDGPU_PTE_FRAG to pte of gart page table for THP
mapping
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 290 ++++++++++++++++++-----
drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 17 +-
drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 12 +
3 files changed, 256 insertions(+), 63 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] drm/amdkfd: Add awareness of THP of device and system RAM in kfd svm driver
2026-08-31 14:24 [PATCH 0/4] drm/amdkfd: Enable device private memory THP support in kfd svm driver Xiaogang.Chen
@ 2026-08-31 14:24 ` Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 2/4] drm/amdkfd: Change migration size in CPU/GPU page fault handler to THP size Xiaogang.Chen
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Xiaogang.Chen @ 2026-08-31 14:24 UTC (permalink / raw)
To: amd-gfx; +Cc: Xiaogang Chen
From: Xiaogang Chen <xiaogang.chen@amd.com>
Extend kfd/svm function to allocate HPAGE_PMD_SIZE based device memory by buddy
allocator, each drm_buddy_block is HPAGE_PMD_SIZE aligned and to allocate THP
system ram by vma_alloc_folio.
It is preparation for following support for (THP) migration in zone
device-private memory.
Signed-off-by: Xiaogang Chen <xiaogang.chen@amd.com>
---
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 22 ++++++++++++++++------
drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 4 ++--
2 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index 253365a8257e..49a231e60dfa 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -217,14 +217,18 @@ svm_migrate_addr_to_pfn(struct amdgpu_device *adev, unsigned long addr)
}
static void
-svm_migrate_get_vram_page(struct svm_range *prange, unsigned long pfn)
+svm_migrate_get_vram_page(struct svm_range *prange, unsigned long pfn,
+ int order)
{
struct page *page;
+ struct folio *folio;
page = pfn_to_page(pfn);
svm_range_bo_ref(prange->svm_bo);
page->zone_device_data = prange->svm_bo;
- zone_device_page_init(page, page_pgmap(page), 0);
+
+ folio = page_folio(page);
+ zone_device_folio_init(folio, folio->pgmap, order);
}
static void
@@ -247,11 +251,17 @@ svm_migrate_addr(struct amdgpu_device *adev, struct page *page)
}
static struct page *
-svm_migrate_get_sys_page(struct vm_area_struct *vma, unsigned long addr)
+svm_migrate_get_sys_page(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long order)
{
struct page *page;
- page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
+ if (order)
+ page = folio_page(vma_alloc_folio(GFP_HIGHUSER,
+ order, vma, addr), 0);
+ else
+ page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
+
if (page)
lock_page(page);
@@ -300,7 +310,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
if (migrate->src[i] & MIGRATE_PFN_MIGRATE) {
dst[i] = cursor.start + (j << PAGE_SHIFT);
migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]);
- svm_migrate_get_vram_page(prange, migrate->dst[i]);
+ svm_migrate_get_vram_page(prange, migrate->dst[i], 0);
migrate->dst[i] = migrate_pfn(migrate->dst[i]);
mpages++;
}
@@ -630,7 +640,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
j = 0;
}
- dpage = svm_migrate_get_sys_page(migrate->vma, addr);
+ dpage = svm_migrate_get_sys_page(migrate->vma, addr, 0);
if (!dpage) {
pr_debug("failed get page svms 0x%p [0x%lx 0x%lx]\n",
prange->svms, prange->start, prange->last);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index fa4054d51f60..280c38932217 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -578,10 +578,10 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange,
}
memset(&bp, 0, sizeof(bp));
- bp.size = prange->npages * PAGE_SIZE;
+ bp.size = ALIGN(prange->npages * PAGE_SIZE, HPAGE_PMD_SIZE);
bp.bo_ptr_size = sizeof(struct svm_range_bo);
bp.destroy = svm_range_bo_destroy;
- bp.byte_align = PAGE_SIZE;
+ bp.byte_align = HPAGE_PMD_SIZE;
bp.domain = AMDGPU_GEM_DOMAIN_VRAM;
bp.flags = AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
bp.flags |= clear ? AMDGPU_GEM_CREATE_VRAM_CLEARED : 0;
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/4] drm/amdkfd: Change migration size in CPU/GPU page fault handler to THP size
2026-08-31 14:24 [PATCH 0/4] drm/amdkfd: Enable device private memory THP support in kfd svm driver Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 1/4] drm/amdkfd: Add awareness of THP of device and system RAM " Xiaogang.Chen
@ 2026-08-31 14:24 ` Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 3/4] drm/amdkfd: Apply HMM THP zone device-private memory migration in kfd driver Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 4/4] drm/amdkfd: Apply AMDGPU_PTE_FRAG to pte of gart page table for THP mapping Xiaogang.Chen
3 siblings, 0 replies; 5+ messages in thread
From: Xiaogang.Chen @ 2026-08-31 14:24 UTC (permalink / raw)
To: amd-gfx; +Cc: Xiaogang Chen
From: Xiaogang Chen <xiaogang.chen@amd.com>
When use HPAGE_PMD_SIZE based device private pages during migration core HMM
treats device private memory in HPAGE_PMD_SIZE compound folio if possible.
Current kfd driver uses prange->granularity that can be changed by user. Need
have migration size in CPU and GPU page fault handler in HPAGE_PMD_SIZE based.
For AMD GPU that exposes private device memory choose HPAGE_PMD_SIZE as
minimums migration size in CPU and GPU page fault handler. For x86 it is
same as default prange->granularity.
Signed-off-by: Xiaogang Chen <xiaogang.chen@amd.com>
---
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 6 ++++--
drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 13 +++++++++++--
drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 12 ++++++++++++
3 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index 49a231e60dfa..f1399dd90d2f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -1020,8 +1020,10 @@ static vm_fault_t svm_migrate_to_ram(struct vm_fault *vmf)
if (!prange->actual_loc)
goto out_unlock_prange;
- /* Align migration range start and size to granularity size */
- size = 1UL << prange->granularity;
+ /* Align migration range start and size to max of
+ * THP with HPAGE_PMD_ORDER and granularity size
+ */
+ size = 1UL << max(prange->granularity, HPAGE_PMD_ORDER);
start = max(ALIGN_DOWN(addr, size), prange->start);
last = min(ALIGN(addr + 1, size) - 1, prange->last);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 280c38932217..c66f83abedd0 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -3062,6 +3062,7 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
struct kfd_node *node;
int32_t best_loc;
int32_t gpuid, gpuidx = MAX_GPU_INSTANCE;
+ bool is_private_device = false;
bool write_locked = false;
struct vm_area_struct *vma;
bool migration = false;
@@ -3078,6 +3079,7 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
return 0;
}
svms = &p->svms;
+ is_private_device = svm_is_private_zone(adev);
pr_debug("restoring svms 0x%p fault address 0x%llx\n", svms, addr);
@@ -3215,8 +3217,15 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
kfd_smi_event_page_fault_start(node, p->lead_thread, addr,
write_fault, timestamp);
- /* Align migration range start and size to granularity size */
- size = 1UL << prange->granularity;
+ if (is_private_device)
+ /* Align migration range start and size to max of
+ * THP and granularity size
+ */
+ size = 1UL << max(prange->granularity, HPAGE_PMD_ORDER);
+ else
+ /* Align migration range start and size to granularity size */
+ size = 1UL << prange->granularity;
+
start = max_t(unsigned long, ALIGN_DOWN(addr, size), prange->start);
last = min_t(unsigned long, ALIGN(addr + 1, size) - 1, prange->last);
if (prange->actual_loc != 0 || best_loc != 0) {
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
index c7d7adae4476..0c9bb9cfd0b5 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
@@ -214,6 +214,13 @@ void svm_range_bo_unref_async(struct svm_range_bo *svm_bo);
void svm_range_set_max_pages(struct amdgpu_device *adev);
int svm_range_switch_xnack_reserve_mem(struct kfd_process *p, bool xnack_enabled);
+/* check adev has device private zone memory */
+static inline bool svm_is_private_zone(struct amdgpu_device *adev)
+{
+ struct amdgpu_kfd_dev *kfddev = &adev->kfd;
+ return (kfddev->pgmap.type == MEMORY_DEVICE_PRIVATE);
+}
+
#else
struct kfd_process;
@@ -276,6 +283,11 @@ static inline void svm_range_set_max_pages(struct amdgpu_device *adev)
{
}
+static inline bool svm_is_private_zone(struct amdgpu_device *adev)
+{
+ return false;
+}
+
#define KFD_IS_SVM_API_SUPPORTED(dev) false
#endif /* IS_ENABLED(CONFIG_HSA_AMD_SVM) */
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/4] drm/amdkfd: Apply HMM THP zone device-private memory migration in kfd driver
2026-08-31 14:24 [PATCH 0/4] drm/amdkfd: Enable device private memory THP support in kfd svm driver Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 1/4] drm/amdkfd: Add awareness of THP of device and system RAM " Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 2/4] drm/amdkfd: Change migration size in CPU/GPU page fault handler to THP size Xiaogang.Chen
@ 2026-08-31 14:24 ` Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 4/4] drm/amdkfd: Apply AMDGPU_PTE_FRAG to pte of gart page table for THP mapping Xiaogang.Chen
3 siblings, 0 replies; 5+ messages in thread
From: Xiaogang.Chen @ 2026-08-31 14:24 UTC (permalink / raw)
To: amd-gfx; +Cc: Xiaogang Chen
From: Xiaogang Chen <xiaogang.chen@amd.com>
Update kfd svm driver to migrate device-private THP introduced from HMM core
migration function. Select this function by flag MIGRATE_VMA_SELECT_COMPOUND
when call migrate_vma_setup. kfd migration procedure is updated according to
collected page type that can be either compound folio(physical continuous) or
normal size page.
Signed-off-by: Xiaogang Chen <xiaogang.chen@amd.com>
---
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 237 +++++++++++++++++++----
1 file changed, 194 insertions(+), 43 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index f1399dd90d2f..30eac5fbcde5 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -293,7 +293,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
u64 mpages = 0;
dma_addr_t *src;
u64 *dst;
- u64 i, j;
+ u64 i, j, k, l, m;
int r = 0;
pr_debug("svms 0x%p [0x%lx 0x%lx 0x%llx]\n", prange->svms, prange->start,
@@ -304,59 +304,147 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
amdgpu_res_first(prange->ttm_res, ttm_res_offset,
npages << PAGE_SHIFT, &cursor);
- for (i = j = 0; (i < npages) && (mpages < migrate->cpages); i++) {
+ for (i = j = m = 0; (i < npages) && (mpages < migrate->cpages);) {
struct page *spage;
+ bool is_large = false;
- if (migrate->src[i] & MIGRATE_PFN_MIGRATE) {
- dst[i] = cursor.start + (j << PAGE_SHIFT);
- migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]);
+ dst[i] = cursor.start + (m << PAGE_SHIFT);
+ migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]);
+
+ /* when migrate->src[i] has MIGRATE_PFN_COMPOUND set the src page
+ * is compound THP; its vm address is HPAGE_PMD_SIZE aligned and
+ * its MIGRATE_PFN_MIGRATE is set
+ */
+ if ((m + HPAGE_PMD_NR) <= (cursor.size >> PAGE_SHIFT) &&
+ (i + HPAGE_PMD_NR) <= npages &&
+ (migrate->src[i] & MIGRATE_PFN_COMPOUND) &&
+ IS_ALIGNED(migrate->dst[i], HPAGE_PMD_NR)) {
+
+ is_large = true;
+ k = HPAGE_PMD_NR;
+ } else
+ k = 1;
+
+ /* for THP src[0] alwas MIGRATE_PFN_MIGRATE
+ * just the first migrate->dst need be setup, others are zero
+ */
+ if (is_large) {
+ svm_migrate_get_vram_page(prange, migrate->dst[i],
+ HPAGE_PMD_ORDER);
+
+ migrate->dst[i] = migrate_pfn(migrate->dst[i]);
+ migrate->dst[i] |= MIGRATE_PFN_COMPOUND;
+
+ for (l=1; l < k; l++)
+ migrate->dst[i+l] = 0;
+
+ mpages++;
+
+ } else if ((migrate->src[i] & MIGRATE_PFN_MIGRATE)) {
svm_migrate_get_vram_page(prange, migrate->dst[i], 0);
migrate->dst[i] = migrate_pfn(migrate->dst[i]);
mpages++;
}
- spage = migrate_pfn_to_page(migrate->src[i]);
- if (spage && !is_zone_device_page(spage)) {
- src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- r = dma_mapping_error(dev, src[i]);
- if (r) {
- src[i] = 0;
- dev_err(dev, "%s: fail %d dma_map_page\n",
- __func__, r);
- goto out_free_vram_pages;
+
+ if (is_large) {
+ if (j) {
+ /* migrate previous accumulated pages */
+ r = svm_migrate_copy_memory_gart(
+ adev, src + i - j,
+ dst + i - j, j,
+ FROM_RAM_TO_VRAM,
+ mfence);
+
+ if (r)
+ goto out_free_vram_pages;
+
+ j = 0;
+ }
+
+ /* for THP check if the first src page is valid
+ * if not valid skip following HPAGE_PMD_NR - 1 pages
+ */
+ spage = migrate_pfn_to_page(migrate->src[i]);
+ if (spage && !is_zone_device_page(spage)) {
+ /* dma_map continuous HPAGE_PMD_NR sys ram pages */
+ src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE*HPAGE_PMD_NR,
+ DMA_BIDIRECTIONAL);
+
+ r = dma_mapping_error(dev, src[i]);
+ if (r) {
+ dev_err(dev, "%s: fail %d dma_map_page\n",
+ __func__, r);
+ goto out_free_vram_pages;
+ }
+
+ /* get dma address for following HPAGE_PMD_NR-1 pages
+ * since src pages are continuous their dma addresses
+ * are continuous too.
+ */
+ for (l=1; l < k; l++)
+ src[i + l] = src[i] + l*PAGE_SIZE;
+
+ /* migrate the HPAGE_PMD_NR pages above */
+ r = svm_migrate_copy_memory_gart(
+ adev, src + i,
+ dst + i, HPAGE_PMD_NR,
+ FROM_RAM_TO_VRAM,
+ mfence);
+
+ if (r)
+ goto out_free_vram_pages;
+
+ j = 0;
}
} else {
- if (j) {
+ /* single normal page case */
+ spage = migrate_pfn_to_page(migrate->src[i]);
+ if (spage && !is_zone_device_page(spage)) {
+ src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+
+ r = dma_mapping_error(dev, src[i]);
+
+ if (r) {
+ dev_err(dev, "%s: fail %d dma_map_page\n",
+ __func__, r);
+ goto out_free_vram_pages;
+ }
+ j += 1;
+
+ } else if (j) {
r = svm_migrate_copy_memory_gart(
adev, src + i - j,
dst + i - j, j,
FROM_RAM_TO_VRAM,
mfence);
+
if (r)
goto out_free_vram_pages;
- amdgpu_res_next(&cursor, (j + 1) << PAGE_SHIFT);
+
j = 0;
- } else {
- amdgpu_res_next(&cursor, PAGE_SIZE);
}
- continue;
}
- pr_debug_ratelimited("dma mapping src to 0x%llx, pfn 0x%lx\n",
- src[i] >> PAGE_SHIFT, page_to_pfn(spage));
+ pr_debug_ratelimited("dma mapping %lld pages, src to 0x%llx, pfn 0x%lx\n",
+ k, src[i] >> PAGE_SHIFT, migrate->src[i] >> MIGRATE_PFN_SHIFT);
+ i += k;
+ m += k;
+
+ if (m >= (cursor.size >> PAGE_SHIFT)) {
+ if (j > 0) {
+ r = svm_migrate_copy_memory_gart(adev, src + i - j,
+ dst + i - j, j,
+ FROM_RAM_TO_VRAM,
+ mfence);
+ if (r)
+ goto out_free_vram_pages;
+ }
+
+ amdgpu_res_next(&cursor, m*PAGE_SIZE);
- /* accumulated j + 1 pages reach end of current drm_buddy_block */
- if (j + 1 >= (cursor.size >> PAGE_SHIFT)) {
- r = svm_migrate_copy_memory_gart(adev, src + i - j,
- dst + i - j, j + 1,
- FROM_RAM_TO_VRAM,
- mfence);
- if (r)
- goto out_free_vram_pages;
- amdgpu_res_next(&cursor, (j + 1) * PAGE_SIZE);
j = 0;
- } else {
- j++;
+ m = 0;
}
}
@@ -405,17 +493,24 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
struct kfd_process_device *pdd;
struct dma_fence *mfence = NULL;
struct migrate_vma migrate = { 0 };
+ bool is_private_device = false;
unsigned long cpages = 0;
unsigned long mpages = 0;
dma_addr_t *scratch;
void *buf;
int r = -ENOMEM;
+ is_private_device = svm_is_private_zone(adev);
+
memset(&migrate, 0, sizeof(migrate));
migrate.vma = vma;
migrate.start = start;
migrate.end = end;
migrate.flags = MIGRATE_VMA_SELECT_SYSTEM;
+
+ if (is_private_device && ((end - start) >> PAGE_SHIFT) >= HPAGE_PMD_NR)
+ migrate.flags = migrate.flags | MIGRATE_VMA_SELECT_COMPOUND;
+
migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev);
buf = kvcalloc(npages,
@@ -603,6 +698,9 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
u64 addr;
int r = 0;
+ u64 l, k;
+ bool is_large = false;
+
pr_debug("svms 0x%p [0x%lx 0x%lx]\n", prange->svms, prange->start,
prange->last);
@@ -610,8 +708,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
src = (u64 *)(scratch + npages);
dst = scratch;
-
- for (i = 0, j = 0; i < npages; i++, addr += PAGE_SIZE) {
+ for (i = 0, j = 0; i < npages;) {
struct page *spage;
spage = migrate_pfn_to_page(migrate->src[i]);
@@ -627,6 +724,9 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
goto out_oom;
j = 0;
}
+
+ addr += PAGE_SIZE;
+ i++;
continue;
}
src[i] = svm_migrate_addr(adev, spage);
@@ -640,7 +740,21 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
j = 0;
}
- dpage = svm_migrate_get_sys_page(migrate->vma, addr, 0);
+ if(IS_ALIGNED(page_to_pfn(spage), HPAGE_PMD_NR) &&
+ (addr + HPAGE_PMD_SIZE) <= migrate->end &&
+ IS_ALIGNED (addr, HPAGE_PMD_SIZE) &&
+ migrate->src[i] & MIGRATE_PFN_COMPOUND) {
+
+ is_large = true;
+ k = HPAGE_PMD_NR;
+
+ dpage = svm_migrate_get_sys_page(migrate->vma, addr,
+ HPAGE_PMD_ORDER);
+ } else {
+ k = 1;
+ dpage = svm_migrate_get_sys_page(migrate->vma, addr, 0);
+ }
+
if (!dpage) {
pr_debug("failed get page svms 0x%p [0x%lx 0x%lx]\n",
prange->svms, prange->start, prange->last);
@@ -648,21 +762,52 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
goto out_oom;
}
- dst[i] = dma_map_page(dev, dpage, 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
+ dst[i] = dma_map_page(dev, dpage, 0, PAGE_SIZE*k, DMA_BIDIRECTIONAL);
r = dma_mapping_error(dev, dst[i]);
if (r) {
dev_err(adev->dev, "%s: fail %d dma_map_page\n", __func__, r);
- dst[i] = 0;
goto out_oom;
}
- pr_debug_ratelimited("dma mapping dst to 0x%llx, pfn 0x%lx\n",
- dst[i] >> PAGE_SHIFT, page_to_pfn(dpage));
-
migrate->dst[i] = migrate_pfn(page_to_pfn(dpage));
+ if (is_large)
+ migrate->dst[i] |= MIGRATE_PFN_COMPOUND;
+
+ if (is_large) {
+ /* migrate previous accumulated pages */
+ if(j) {
+ r = svm_migrate_copy_memory_gart(adev, dst + i - j,
+ src + i - j, j, FROM_VRAM_TO_RAM, mfence);
+ if (r)
+ goto out_oom;
+ j = 0;
+ }
+
+ for (l = 1; l < k; l++) {
+
+ src[i + l] = src[i] + l*PAGE_SIZE;
+ dst[i + l] = dst[i] + l*PAGE_SIZE;
+ migrate->dst[i + l] = 0;
+ }
+
+ /* migrate the HPAGE_PMD_NR pages above */
+ /* svm_migrate_copy_memory_gart will add a paramter to indicate
+ * the migration is for 2MB THP
+ */
+ r = svm_migrate_copy_memory_gart(
+ adev, dst + i,
+ src + i, HPAGE_PMD_NR,
+ FROM_VRAM_TO_RAM,
+ mfence);
+
+ if (r)
+ goto out_oom;
+
+ } else
+ j++;
- dpage = NULL;
- j++;
+ addr += PAGE_SIZE*k;
+ i += k;
}
if (j > 0)
@@ -727,6 +872,7 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
unsigned long cpages = 0;
unsigned long mpages = 0;
struct amdgpu_device *adev = node->adev;
+ bool is_private_device = false;
struct kfd_process_device *pdd;
struct dma_fence *mfence = NULL;
struct migrate_vma migrate = { 0 };
@@ -734,6 +880,8 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
void *buf;
int r = -ENOMEM;
+ is_private_device = svm_is_private_zone(adev);
+
memset(&migrate, 0, sizeof(migrate));
migrate.vma = vma;
migrate.start = start;
@@ -744,6 +892,9 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
else
migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE;
+ if (is_private_device && ((end - start) >> PAGE_SHIFT) >= HPAGE_PMD_NR)
+ migrate.flags = migrate.flags | MIGRATE_VMA_SELECT_COMPOUND;
+
buf = kvcalloc(npages,
2 * sizeof(*migrate.src) + sizeof(u64) + sizeof(dma_addr_t),
GFP_KERNEL);
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 4/4] drm/amdkfd: Apply AMDGPU_PTE_FRAG to pte of gart page table for THP mapping
2026-08-31 14:24 [PATCH 0/4] drm/amdkfd: Enable device private memory THP support in kfd svm driver Xiaogang.Chen
` (2 preceding siblings ...)
2026-08-31 14:24 ` [PATCH 3/4] drm/amdkfd: Apply HMM THP zone device-private memory migration in kfd driver Xiaogang.Chen
@ 2026-08-31 14:24 ` Xiaogang.Chen
3 siblings, 0 replies; 5+ messages in thread
From: Xiaogang.Chen @ 2026-08-31 14:24 UTC (permalink / raw)
To: amd-gfx; +Cc: Xiaogang Chen
From: Xiaogang Chen <xiaogang.chen@amd.com>
When both sys ram and vram are physical continuous HPAGE_PMD_NR pages during
migration set AMDGPU_PTE_FRAG(HPAGE_PMD_ORDER) at pte in gart page table to
let hardware know the migrating pages are HPAGE_PMD_NR size THP. That will
reduce hardware TLB pressure or increase TLB hit ration.
Signed-off-by: Xiaogang Chen <xiaogang.chen@amd.com>
---
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 43 ++++++++++++++----------
1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index 30eac5fbcde5..6863be041ba5 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -48,7 +48,7 @@ static int
svm_migrate_gart_map(struct amdgpu_ring *ring,
struct amdgpu_ttm_buffer_entity *entity,
u64 npages,
- dma_addr_t *addr, u64 *gart_addr, u64 flags)
+ dma_addr_t *addr, u64 *gart_addr, u64 flags, bool is_thp)
{
struct amdgpu_device *adev = ring->adev;
struct amdgpu_job *job;
@@ -90,6 +90,9 @@ svm_migrate_gart_map(struct amdgpu_ring *ring,
pte_flags |= AMDGPU_PTE_WRITEABLE;
pte_flags |= adev->gart.gart_pte_flags;
+ if (is_thp)
+ pte_flags |= AMDGPU_PTE_FRAG(HPAGE_PMD_ORDER);
+
cpu_addr = &job->ibs[0].ptr[num_dw];
amdgpu_gart_map(adev, 0, npages, addr, pte_flags, cpu_addr);
@@ -108,6 +111,7 @@ svm_migrate_gart_map(struct amdgpu_ring *ring,
* @npages: number of pages to copy
* @direction: enum MIGRATION_COPY_DIR
* @mfence: output, sdma fence to signal after sdma is done
+ * @is_thp: both sys and vram are physical continuous HPAGE_PMD_NR pages
*
* ram address uses GART table continuous entries mapping to ram pages,
* vram address uses direct mapping of vram pages, which must have npages
@@ -126,7 +130,7 @@ static int
svm_migrate_copy_memory_gart(struct amdgpu_device *adev, dma_addr_t *sys,
u64 *vram, u64 npages,
enum MIGRATION_COPY_DIR direction,
- struct dma_fence **mfence)
+ struct dma_fence **mfence, bool is_thp)
{
const u64 GTT_MAX_PAGES = (AMDGPU_GTT_MAX_TRANSFER_SIZE >> PAGE_SHIFT);
struct amdgpu_ring *ring;
@@ -136,6 +140,12 @@ svm_migrate_copy_memory_gart(struct amdgpu_device *adev, dma_addr_t *sys,
u64 size;
int r = 0;
+ if (is_thp && npages != HPAGE_PMD_NR) {
+ dev_warn(adev->dev, "THP migration should have %d pages\n",
+ HPAGE_PMD_NR);
+ is_thp = false;
+ }
+
ring = to_amdgpu_ring(adev->mman.buffer_funcs_scheds[0]);
entity = &adev->mman.move_entities[0];
@@ -146,11 +156,12 @@ svm_migrate_copy_memory_gart(struct amdgpu_device *adev, dma_addr_t *sys,
if (direction == FROM_VRAM_TO_RAM) {
gart_s = svm_migrate_direct_mapping_addr(adev, *vram);
- r = svm_migrate_gart_map(ring, entity, size, sys, &gart_d, 0);
+ r = svm_migrate_gart_map(ring, entity, size, sys, &gart_d, 0,
+ is_thp);
} else if (direction == FROM_RAM_TO_VRAM) {
r = svm_migrate_gart_map(ring, entity, size, sys, &gart_s,
- KFD_IOCTL_SVM_FLAG_GPU_RO);
+ KFD_IOCTL_SVM_FLAG_GPU_RO, is_thp);
gart_d = svm_migrate_direct_mapping_addr(adev, *vram);
}
if (r) {
@@ -353,7 +364,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
adev, src + i - j,
dst + i - j, j,
FROM_RAM_TO_VRAM,
- mfence);
+ mfence, false);
if (r)
goto out_free_vram_pages;
@@ -389,7 +400,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
adev, src + i,
dst + i, HPAGE_PMD_NR,
FROM_RAM_TO_VRAM,
- mfence);
+ mfence, true);
if (r)
goto out_free_vram_pages;
@@ -417,7 +428,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
adev, src + i - j,
dst + i - j, j,
FROM_RAM_TO_VRAM,
- mfence);
+ mfence, false);
if (r)
goto out_free_vram_pages;
@@ -436,7 +447,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
r = svm_migrate_copy_memory_gart(adev, src + i - j,
dst + i - j, j,
FROM_RAM_TO_VRAM,
- mfence);
+ mfence, false);
if (r)
goto out_free_vram_pages;
}
@@ -450,7 +461,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
if (j > 0)
r = svm_migrate_copy_memory_gart(adev, src + i - j, dst + i - j, j,
- FROM_RAM_TO_VRAM, mfence);
+ FROM_RAM_TO_VRAM, mfence, false);
out_free_vram_pages:
if (r) {
@@ -719,7 +730,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
r = svm_migrate_copy_memory_gart(adev, dst + i - j,
src + i - j, j,
FROM_VRAM_TO_RAM,
- mfence);
+ mfence, false);
if (r)
goto out_oom;
j = 0;
@@ -734,7 +745,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
r = svm_migrate_copy_memory_gart(adev, dst + i - j,
src + i - j, j,
FROM_VRAM_TO_RAM,
- mfence);
+ mfence, false);
if (r)
goto out_oom;
j = 0;
@@ -777,7 +788,8 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
/* migrate previous accumulated pages */
if(j) {
r = svm_migrate_copy_memory_gart(adev, dst + i - j,
- src + i - j, j, FROM_VRAM_TO_RAM, mfence);
+ src + i - j, j, FROM_VRAM_TO_RAM,
+ mfence, false);
if (r)
goto out_oom;
j = 0;
@@ -791,14 +803,11 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
}
/* migrate the HPAGE_PMD_NR pages above */
- /* svm_migrate_copy_memory_gart will add a paramter to indicate
- * the migration is for 2MB THP
- */
r = svm_migrate_copy_memory_gart(
adev, dst + i,
src + i, HPAGE_PMD_NR,
FROM_VRAM_TO_RAM,
- mfence);
+ mfence, true);
if (r)
goto out_oom;
@@ -812,7 +821,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
if (j > 0)
r = svm_migrate_copy_memory_gart(adev, dst + i - j, src + i - j, j,
- FROM_VRAM_TO_RAM, mfence);
+ FROM_VRAM_TO_RAM, mfence, false);
out_oom:
if (r) {
pr_debug("failed %d copy to ram\n", r);
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-31 14:26 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-31 14:24 [PATCH 0/4] drm/amdkfd: Enable device private memory THP support in kfd svm driver Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 1/4] drm/amdkfd: Add awareness of THP of device and system RAM " Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 2/4] drm/amdkfd: Change migration size in CPU/GPU page fault handler to THP size Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 3/4] drm/amdkfd: Apply HMM THP zone device-private memory migration in kfd driver Xiaogang.Chen
2026-08-31 14:24 ` [PATCH 4/4] drm/amdkfd: Apply AMDGPU_PTE_FRAG to pte of gart page table for THP mapping Xiaogang.Chen
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.