* [PATCH v16 01/12] mm/Kconfig: changes for migrate on fault for device pages
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
@ 2026-10-21 6:04 ` mpenttil
2026-10-21 6:04 ` [PATCH v16 02/12] mm: add helper to convert HMM pfn to migrate pfn mpenttil
` (15 subsequent siblings)
16 siblings, 0 replies; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:04 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
HMM depends on MMU notifiers. With the unified HMM/migrate_device
page table walk migrate_device needs HMM enabled.
Enable them explicitly to avoid breaking random configs.
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
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>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: Balbir Singh <balbirs@nvidia.com>
---
mm/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/mm/Kconfig b/mm/Kconfig
index 604c58199acb..b7a485beb9a7 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -687,6 +687,7 @@ config MIGRATION
config DEVICE_MIGRATION
def_bool MIGRATION && ZONE_DEVICE
+ select HMM_MIRROR
config ARCH_ENABLE_HUGEPAGE_MIGRATION
bool
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* [PATCH v16 02/12] mm: add helper to convert HMM pfn to migrate pfn
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
2026-10-21 6:04 ` [PATCH v16 01/12] mm/Kconfig: changes for " mpenttil
@ 2026-10-21 6:04 ` mpenttil
2026-10-21 6:04 ` [PATCH v16 03/12] mm/hmm: preparations for HMM to participate in migration mpenttil
` (14 subsequent siblings)
16 siblings, 0 replies; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:04 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
The unified HMM/migrate_device pagewalk does the "collecting"
on the HMM side, so we need a helper to transfer pfns to the
migrate_vma world.
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Suggested-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
include/linux/hmm.h | 29 +++++++++++++++++-----
include/linux/migrate.h | 3 ++-
mm/migrate_device.c | 55 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 80 insertions(+), 7 deletions(-)
diff --git a/include/linux/hmm.h b/include/linux/hmm.h
index 6f04e3932f5b..4f56f3419cb4 100644
--- a/include/linux/hmm.h
+++ b/include/linux/hmm.h
@@ -13,6 +13,8 @@
struct mmu_interval_notifier;
+struct migrate_vma;
+
/*
* On output:
* 0 - The page is faultable and a future call with
@@ -27,13 +29,22 @@ struct mmu_interval_notifier;
* HMM_PFN_P2PDMA_BUS - Bus mapped P2P transfer
* HMM_PFN_DMA_MAPPED - Flag preserved on input-to-output transformation
* to mark that page is already DMA mapped
+ * HMM_PFN_MIGRATE - The entry is to be migrated. Note, HMM_PFN_MIGRATE
+ * alone without HMM_PFN_VALID denotes the
+ * empty page.
+ * This flag optionally together with HMM_PFN_COMPOUND
+ * are indicators for migrate_hmm_range_setup() to
+ * setup the migrate pfns.
+ * HMM_PFN_COMPOUND - The entry represents a > 0 order page
*
* On input:
- * 0 - Return the current state of the page, do not fault it.
- * HMM_PFN_REQ_FAULT - The output must have HMM_PFN_VALID or hmm_range_fault()
- * will fail
- * HMM_PFN_REQ_WRITE - The output must have HMM_PFN_WRITE or hmm_range_fault()
- * will fail. Must be combined with HMM_PFN_REQ_FAULT.
+ * 0 - Return the current state of the page, do not fault it.
+ * HMM_PFN_REQ_FAULT - The output must have HMM_PFN_VALID or hmm_range_fault()
+ * will fail
+ * HMM_PFN_REQ_WRITE - The output must have HMM_PFN_WRITE or hmm_range_fault()
+ * will fail. Must be combined with HMM_PFN_REQ_FAULT.
+ * HMM_PFN_REQ_MIGRATE - For default_flags only, request to migrate the range,
+ * according to hmm_range.migrate.flags
*/
enum hmm_pfn_flags {
/* Output fields and flags */
@@ -48,11 +59,15 @@ enum hmm_pfn_flags {
HMM_PFN_P2PDMA = 1UL << (BITS_PER_LONG - 5),
HMM_PFN_P2PDMA_BUS = 1UL << (BITS_PER_LONG - 6),
- HMM_PFN_ORDER_SHIFT = (BITS_PER_LONG - 11),
+ /* Migrate request */
+ HMM_PFN_MIGRATE = 1UL << (BITS_PER_LONG - 7),
+ HMM_PFN_COMPOUND = 1UL << (BITS_PER_LONG - 8),
+ HMM_PFN_ORDER_SHIFT = (BITS_PER_LONG - 13),
/* Input flags */
HMM_PFN_REQ_FAULT = HMM_PFN_VALID,
HMM_PFN_REQ_WRITE = HMM_PFN_WRITE,
+ HMM_PFN_REQ_MIGRATE = HMM_PFN_MIGRATE,
HMM_PFN_FLAGS = ~((1UL << HMM_PFN_ORDER_SHIFT) - 1),
};
@@ -107,6 +122,7 @@ static inline unsigned int hmm_pfn_to_map_order(unsigned long hmm_pfn)
* @default_flags: default flags for the range (write, read, ... see hmm doc)
* @pfn_flags_mask: allows to mask pfn flags so that only default_flags matter
* @dev_private_owner: owner of device private pages
+ * @migrate: structure for migrating a range of a VMA
*/
struct hmm_range {
struct mmu_interval_notifier *notifier;
@@ -117,6 +133,7 @@ struct hmm_range {
unsigned long default_flags;
unsigned long pfn_flags_mask;
void *dev_private_owner;
+ struct migrate_vma *migrate;
};
/*
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 78424b3824c2..280ec9a866c7 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -3,6 +3,7 @@
#define _LINUX_MIGRATE_H
#include <linux/mm.h>
+#include <linux/hmm.h>
#include <linux/mempolicy.h>
#include <linux/migrate_mode.h>
#include <linux/hugetlb.h>
@@ -202,7 +203,7 @@ void migrate_device_pages(unsigned long *src_pfns, unsigned long *dst_pfns,
unsigned long npages);
void migrate_device_finalize(unsigned long *src_pfns,
unsigned long *dst_pfns, unsigned long npages);
-
+void migrate_hmm_range_setup(struct hmm_range *range);
#endif /* CONFIG_MIGRATION */
#endif /* _LINUX_MIGRATE_H */
diff --git a/mm/migrate_device.c b/mm/migrate_device.c
index 009bfa8b212d..43e571e82cca 100644
--- a/mm/migrate_device.c
+++ b/mm/migrate_device.c
@@ -1528,3 +1528,58 @@ int migrate_device_coherent_folio(struct folio *folio)
return 0;
return -EBUSY;
}
+
+/**
+ * migrate_hmm_range_setup() - prepare to migrate a range of memory
+ * @range: contains pointer to struct migrate_vma to be set up.
+ *
+ * When collecting has been done with hmm_range_fault(), this
+ * should be called next, and completes range->migrate by
+ * populating migrate->src[] and migrate->dst[]
+ * using range->hmm_pfns[].
+ * Also, migrate->cpages and migrate->npages get initialized.
+ * After migrate_hmm_range_setup(), range->migrate is good
+ * for the rest of the migrate_vma_* flow.
+ */
+void migrate_hmm_range_setup(struct hmm_range *range)
+{
+ struct migrate_vma *migrate = range->migrate;
+
+ if (!migrate)
+ return;
+
+ migrate->npages = (migrate->end - migrate->start) >> PAGE_SHIFT;
+ migrate->cpages = 0;
+
+ for (unsigned long i = 0; i < migrate->npages; i++) {
+ unsigned long pfn = range->hmm_pfns[i];
+
+ /*
+ * We are only interested in entries to be
+ * migrated.
+ */
+ if (!(pfn & HMM_PFN_MIGRATE)) {
+ migrate->src[i] = 0;
+ migrate->dst[i] = 0;
+ continue;
+ }
+
+ migrate->cpages++;
+
+ /* HMM_PFN_MIGRATE without HMM_PFN_VALID denotes the special zero page */
+ if (pfn & HMM_PFN_VALID)
+ migrate->src[i] = migrate_pfn(page_to_pfn(hmm_pfn_to_page(pfn)));
+ else
+ migrate->src[i] = 0;
+
+ migrate->src[i] |= MIGRATE_PFN_MIGRATE;
+ migrate->src[i] |= (pfn & HMM_PFN_WRITE) ? MIGRATE_PFN_WRITE : 0;
+ migrate->src[i] |= (pfn & HMM_PFN_COMPOUND) ? MIGRATE_PFN_COMPOUND : 0;
+ migrate->dst[i] = 0;
+ }
+
+ if (migrate->cpages)
+ migrate_vma_unmap(migrate);
+
+}
+EXPORT_SYMBOL(migrate_hmm_range_setup);
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* [PATCH v16 03/12] mm/hmm: preparations for HMM to participate in migration
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
2026-10-21 6:04 ` [PATCH v16 01/12] mm/Kconfig: changes for " mpenttil
2026-10-21 6:04 ` [PATCH v16 02/12] mm: add helper to convert HMM pfn to migrate pfn mpenttil
@ 2026-10-21 6:04 ` mpenttil
2026-10-21 7:17 ` Balbir Singh
2026-10-22 6:06 ` sashiko-bot
2026-10-21 6:04 ` [PATCH v16 04/12] mm/hmm: do the plumbing " mpenttil
` (13 subsequent siblings)
16 siblings, 2 replies; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:04 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
For migration to happen after hmm_range_fault(), the vma has to
retrieved. Luckily, pagewalk already resolves that for us, so
just have to save it for further use. For migration, mmap_lock
has to be hold for the whole operation, so vma stays stable.
In case lock-drop behavior is requested, return an error while
migrating. Also, rename some struct hmm_vma_walk fields to solve
namespace collisions, and we are later introducing more
xxlocked fields so be unambiguous.
Take care also of firing the mmu_notifier when migrating.
Also, prepare for differencies of how mm_struct * is retrieved
in fault and migrate_vma paths.
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Suggested-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
include/linux/migrate.h | 50 +++++++++++++++++-
lib/test_hmm.c | 2 +-
mm/hmm.c | 110 ++++++++++++++++++++++++++++++++++------
3 files changed, 145 insertions(+), 17 deletions(-)
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 280ec9a866c7..dd7dd7ec6995 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -5,6 +5,7 @@
#include <linux/mm.h>
#include <linux/hmm.h>
#include <linux/mempolicy.h>
+#include <linux/mmu_notifier.h>
#include <linux/migrate_mode.h>
#include <linux/hugetlb.h>
@@ -108,6 +109,29 @@ static inline void softleaf_entry_wait_on_locked(softleaf_t entry, spinlock_t *p
spin_unlock(ptl);
}
+enum migrate_vma_info {
+ MIGRATE_VMA_SELECT_NONE = 0,
+ MIGRATE_VMA_SELECT_COMPOUND = MIGRATE_VMA_SELECT_NONE,
+};
+
+static inline enum migrate_vma_info hmm_select_migrate(struct hmm_range *range)
+{
+ return MIGRATE_VMA_SELECT_NONE;
+}
+
+static inline void hmm_fill_migrate_vma(struct hmm_range *range,
+ struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end)
+{
+}
+
+#ifdef CONFIG_MMU_NOTIFIER
+static inline struct mm_struct *hmm_range_fault_mm(struct hmm_range *range)
+{
+ return range->notifier->mm;
+}
+#endif
#endif /* CONFIG_MIGRATION */
#ifdef CONFIG_NUMA_BALANCING
@@ -151,7 +175,8 @@ static inline unsigned long migrate_pfn(unsigned long pfn)
return (pfn << MIGRATE_PFN_SHIFT) | MIGRATE_PFN_VALID;
}
-enum migrate_vma_direction {
+enum migrate_vma_info {
+ MIGRATE_VMA_SELECT_NONE = 0,
MIGRATE_VMA_SELECT_SYSTEM = 1 << 0,
MIGRATE_VMA_SELECT_DEVICE_PRIVATE = 1 << 1,
MIGRATE_VMA_SELECT_DEVICE_COHERENT = 1 << 2,
@@ -193,6 +218,29 @@ struct migrate_vma {
struct page *fault_page;
};
+// TODO: enable migration
+static inline enum migrate_vma_info hmm_select_migrate(struct hmm_range *range)
+{
+ return 0;
+}
+
+#ifdef CONFIG_MMU_NOTIFIER
+static inline struct mm_struct *hmm_range_fault_mm(struct hmm_range *range)
+{
+ return range->notifier ? range->notifier->mm : range->migrate->vma->vm_mm;
+}
+#endif
+
+static inline void hmm_fill_migrate_vma(struct hmm_range *range,
+ struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end)
+{
+ range->migrate->vma = vma;
+ range->migrate->start = start;
+ range->migrate->end = end;
+}
+
int migrate_vma_setup(struct migrate_vma *args);
void migrate_vma_pages(struct migrate_vma *migrate);
void migrate_vma_finalize(struct migrate_vma *migrate);
diff --git a/lib/test_hmm.c b/lib/test_hmm.c
index 6911daa9f854..cd88e8177d0a 100644
--- a/lib/test_hmm.c
+++ b/lib/test_hmm.c
@@ -145,7 +145,7 @@ static bool dmirror_is_private_zone(struct dmirror_device *mdevice)
HMM_DMIRROR_MEMORY_DEVICE_PRIVATE);
}
-static enum migrate_vma_direction
+static enum migrate_vma_info
dmirror_select_device(struct dmirror *dmirror)
{
return (dmirror->mdevice->zone_device_type ==
diff --git a/mm/hmm.c b/mm/hmm.c
index 2f1e98c6b644..4e9542aedc25 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -21,6 +21,7 @@
#include <linux/pagemap.h>
#include <linux/leafops.h>
#include <linux/hugetlb.h>
+#include <linux/migrate.h>
#include <linux/memremap.h>
#include <linux/sched/mm.h>
#include <linux/jump_label.h>
@@ -28,15 +29,23 @@
#include <linux/pci-p2pdma.h>
#include <linux/mmu_notifier.h>
#include <linux/memory_hotplug.h>
+#include <asm/tlbflush.h>
#include "internal.h"
struct hmm_vma_walk {
- struct hmm_range *range;
- bool *locked;
- unsigned long last;
- unsigned long end;
- unsigned int required_fault;
+ struct mmu_notifier_range mmu_range;
+ /* Set once mmu_range is armed with mmu_notifier_invalidate_range_start() */
+ bool mmu_armed;
+ struct vm_area_struct *vma;
+ struct hmm_range *range;
+ unsigned long start;
+ unsigned long end;
+ unsigned long last;
+ /* fault and lock drop related fields */
+ bool *mmlocked;
+ unsigned long fault_end;
+ unsigned int required_fault;
};
/*
@@ -95,7 +104,7 @@ static int hmm_record_fault(unsigned long addr, unsigned long end,
WARN_ON_ONCE(!required_fault);
hmm_vma_walk->last = addr;
- hmm_vma_walk->end = end;
+ hmm_vma_walk->fault_end = end;
hmm_vma_walk->required_fault = required_fault;
return HMM_FAULT_PENDING;
}
@@ -400,6 +409,58 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
}
#endif /* CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
+static int hmm_vma_capture_migrate_range(unsigned long start,
+ unsigned long end,
+ struct mm_walk *walk)
+{
+ struct hmm_vma_walk *hmm_vma_walk = walk->private;
+ struct hmm_range *range = hmm_vma_walk->range;
+
+ if (!hmm_select_migrate(range))
+ return 0;
+
+ if (hmm_vma_walk->vma && (hmm_vma_walk->vma != walk->vma))
+ return -ERANGE;
+
+ hmm_vma_walk->vma = walk->vma;
+
+ if (end - start > range->end - range->start)
+ return -ERANGE;
+
+ if (!hmm_vma_walk->mmu_armed) {
+ hmm_vma_walk->start = start;
+ hmm_vma_walk->end = end;
+ mmu_notifier_range_init_owner(&hmm_vma_walk->mmu_range, MMU_NOTIFY_MIGRATE, 0,
+ walk->vma->vm_mm, start, end,
+ range->dev_private_owner);
+ mmu_notifier_invalidate_range_start(&hmm_vma_walk->mmu_range);
+ hmm_vma_walk->mmu_armed = true;
+ }
+
+ return 0;
+}
+
+static void hmm_vma_post_range_fault(struct hmm_vma_walk *hmm_vma_walk)
+{
+
+ struct hmm_range *range = hmm_vma_walk->range;
+
+ if (hmm_select_migrate(range) &&
+ hmm_vma_walk->mmu_armed) {
+ /*
+ * The migrate_vma path has the following initialized,
+ * so take care of fault path below.
+ */
+ if (range->notifier) {
+ hmm_fill_migrate_vma(range,
+ hmm_vma_walk->vma,
+ hmm_vma_walk->start,
+ hmm_vma_walk->end);
+ }
+ mmu_notifier_invalidate_range_end(&hmm_vma_walk->mmu_range);
+ }
+}
+
static int hmm_vma_walk_pmd(pmd_t *pmdp,
unsigned long start,
unsigned long end,
@@ -594,6 +655,11 @@ static int hmm_vma_walk_test(unsigned long start, unsigned long end,
struct hmm_vma_walk *hmm_vma_walk = walk->private;
struct hmm_range *range = hmm_vma_walk->range;
struct vm_area_struct *vma = walk->vma;
+ int r;
+
+ r = hmm_vma_capture_migrate_range(start, end, walk);
+ if (r)
+ return r;
if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)) &&
vma->vm_flags & VM_READ)
@@ -646,12 +712,12 @@ static int hmm_do_fault(struct mm_struct *mm,
struct hmm_vma_walk *hmm_vma_walk)
{
unsigned long addr = hmm_vma_walk->last;
- unsigned long end = hmm_vma_walk->end;
+ unsigned long end = hmm_vma_walk->fault_end;
unsigned int required_fault = hmm_vma_walk->required_fault;
unsigned int fault_flags = FAULT_FLAG_REMOTE;
struct vm_area_struct *vma;
- if (hmm_vma_walk->locked)
+ if (hmm_vma_walk->mmlocked)
fault_flags |= FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
vma = vma_lookup(mm, addr);
@@ -670,8 +736,8 @@ static int hmm_do_fault(struct mm_struct *mm,
ret = handle_mm_fault(vma, addr, fault_flags, NULL);
if (ret & (VM_FAULT_COMPLETED | VM_FAULT_RETRY)) {
- if (hmm_vma_walk->locked) /* needed by sparse */
- *hmm_vma_walk->locked = false;
+ if (hmm_vma_walk->mmlocked) /* needed by sparse */
+ *hmm_vma_walk->mmlocked = false;
else
WARN_ON_ONCE(1); /* broken fault handler */
return HMM_FAULT_UNLOCKED;
@@ -694,19 +760,31 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
{
struct hmm_vma_walk hmm_vma_walk = {
.range = range,
- .locked = locked,
+ .mmlocked = locked,
.last = range->start,
};
- struct mm_struct *mm = range->notifier->mm;
+ /*
+ * Could be serving a device fault or come from migrate
+ * entry point. For the former we have not resolved the vma
+ * yet, and the latter we don't have a notifier (but have a vma).
+ *
+ */
+ struct mm_struct *mm = hmm_range_fault_mm(range);
int ret;
+ /* Migration is incompatible with mmap lock drop */
+ if (locked && hmm_select_migrate(range))
+ return -EINVAL;
+
mmap_assert_locked(mm);
do {
/* If range is no longer valid force retry. */
- if (mmu_interval_check_retry(range->notifier,
- range->notifier_seq))
- return -EBUSY;
+ if (range->notifier && mmu_interval_check_retry(range->notifier,
+ range->notifier_seq)) {
+ ret = -EBUSY;
+ break;
+ }
ret = walk_page_range(mm, hmm_vma_walk.last, range->end,
&hmm_walk_ops, &hmm_vma_walk);
/*
@@ -732,6 +810,8 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
* output, and all >= are still at their input values.
*/
} while (ret == -EBUSY);
+
+ hmm_vma_post_range_fault(&hmm_vma_walk);
return ret;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v16 03/12] mm/hmm: preparations for HMM to participate in migration
2026-10-21 6:04 ` [PATCH v16 03/12] mm/hmm: preparations for HMM to participate in migration mpenttil
@ 2026-10-21 7:17 ` Balbir Singh
2026-10-21 8:11 ` Mika Penttilä
2026-10-22 6:06 ` sashiko-bot
1 sibling, 1 reply; 33+ messages in thread
From: Balbir Singh @ 2026-10-21 7:17 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, linux-kernel, David Hildenbrand,
Jason Gunthorpe, Leon Romanovsky, Alistair Popple, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
On 10/21/26 5:04 PM, mpenttil@redhat.com wrote:
> From: Mika Penttilä <mpenttil@redhat.com>
>
> For migration to happen after hmm_range_fault(), the vma has to
> retrieved. Luckily, pagewalk already resolves that for us, so
> just have to save it for further use. For migration, mmap_lock
> has to be hold for the whole operation, so vma stays stable.
> In case lock-drop behavior is requested, return an error while
> migrating. Also, rename some struct hmm_vma_walk fields to solve
> namespace collisions, and we are later introducing more
> xxlocked fields so be unambiguous.
>
> Take care also of firing the mmu_notifier when migrating.
>
> Also, prepare for differencies of how mm_struct * is retrieved
> in fault and migrate_vma paths.
>
> Cc: David Hildenbrand <david@kernel.org>
> Cc: Jason Gunthorpe <jgg@nvidia.com>
> Cc: Leon Romanovsky <leonro@nvidia.com>
> Cc: Alistair Popple <apopple@nvidia.com>
> Cc: Balbir Singh <balbirs@nvidia.com>
> Cc: Zi Yan <ziy@nvidia.com>
> Cc: Matthew Brost <matthew.brost@intel.com>
> Suggested-by: Alistair Popple <apopple@nvidia.com>
> Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
> ---
> include/linux/migrate.h | 50 +++++++++++++++++-
> lib/test_hmm.c | 2 +-
> mm/hmm.c | 110 ++++++++++++++++++++++++++++++++++------
> 3 files changed, 145 insertions(+), 17 deletions(-)
>
> diff --git a/include/linux/migrate.h b/include/linux/migrate.h
> index 280ec9a866c7..dd7dd7ec6995 100644
> --- a/include/linux/migrate.h
> +++ b/include/linux/migrate.h
> @@ -5,6 +5,7 @@
> #include <linux/mm.h>
> #include <linux/hmm.h>
> #include <linux/mempolicy.h>
> +#include <linux/mmu_notifier.h>
> #include <linux/migrate_mode.h>
> #include <linux/hugetlb.h>
>
> @@ -108,6 +109,29 @@ static inline void softleaf_entry_wait_on_locked(softleaf_t entry, spinlock_t *p
> spin_unlock(ptl);
> }
>
> +enum migrate_vma_info {
> + MIGRATE_VMA_SELECT_NONE = 0,
> + MIGRATE_VMA_SELECT_COMPOUND = MIGRATE_VMA_SELECT_NONE,
> +};
> +
> +static inline enum migrate_vma_info hmm_select_migrate(struct hmm_range *range)
> +{
> + return MIGRATE_VMA_SELECT_NONE;
> +}
> +
> +static inline void hmm_fill_migrate_vma(struct hmm_range *range,
> + struct vm_area_struct *vma,
> + unsigned long start,
> + unsigned long end)
> +{
> +}
> +
> +#ifdef CONFIG_MMU_NOTIFIER
> +static inline struct mm_struct *hmm_range_fault_mm(struct hmm_range *range)
> +{
> + return range->notifier->mm;
> +}
> +#endif
> #endif /* CONFIG_MIGRATION */
>
> #ifdef CONFIG_NUMA_BALANCING
> @@ -151,7 +175,8 @@ static inline unsigned long migrate_pfn(unsigned long pfn)
> return (pfn << MIGRATE_PFN_SHIFT) | MIGRATE_PFN_VALID;
> }
>
> -enum migrate_vma_direction {
> +enum migrate_vma_info {
> + MIGRATE_VMA_SELECT_NONE = 0,
> MIGRATE_VMA_SELECT_SYSTEM = 1 << 0,
> MIGRATE_VMA_SELECT_DEVICE_PRIVATE = 1 << 1,
> MIGRATE_VMA_SELECT_DEVICE_COHERENT = 1 << 2,
> @@ -193,6 +218,29 @@ struct migrate_vma {
> struct page *fault_page;
> };
>
> +// TODO: enable migration
> +static inline enum migrate_vma_info hmm_select_migrate(struct hmm_range *range)
> +{
> + return 0;
> +}
> +
> +#ifdef CONFIG_MMU_NOTIFIER
> +static inline struct mm_struct *hmm_range_fault_mm(struct hmm_range *range)
> +{
> + return range->notifier ? range->notifier->mm : range->migrate->vma->vm_mm;
> +}
> +#endif
> +
> +static inline void hmm_fill_migrate_vma(struct hmm_range *range,
> + struct vm_area_struct *vma,
> + unsigned long start,
> + unsigned long end)
> +{
> + range->migrate->vma = vma;
> + range->migrate->start = start;
> + range->migrate->end = end;
> +}
> +
> int migrate_vma_setup(struct migrate_vma *args);
> void migrate_vma_pages(struct migrate_vma *migrate);
> void migrate_vma_finalize(struct migrate_vma *migrate);
> diff --git a/lib/test_hmm.c b/lib/test_hmm.c
> index 6911daa9f854..cd88e8177d0a 100644
> --- a/lib/test_hmm.c
> +++ b/lib/test_hmm.c
> @@ -145,7 +145,7 @@ static bool dmirror_is_private_zone(struct dmirror_device *mdevice)
> HMM_DMIRROR_MEMORY_DEVICE_PRIVATE);
> }
>
> -static enum migrate_vma_direction
> +static enum migrate_vma_info
> dmirror_select_device(struct dmirror *dmirror)
> {
> return (dmirror->mdevice->zone_device_type ==
> diff --git a/mm/hmm.c b/mm/hmm.c
> index 2f1e98c6b644..4e9542aedc25 100644
> --- a/mm/hmm.c
> +++ b/mm/hmm.c
> @@ -21,6 +21,7 @@
> #include <linux/pagemap.h>
> #include <linux/leafops.h>
> #include <linux/hugetlb.h>
> +#include <linux/migrate.h>
> #include <linux/memremap.h>
> #include <linux/sched/mm.h>
> #include <linux/jump_label.h>
> @@ -28,15 +29,23 @@
> #include <linux/pci-p2pdma.h>
> #include <linux/mmu_notifier.h>
> #include <linux/memory_hotplug.h>
> +#include <asm/tlbflush.h>
>
> #include "internal.h"
>
> struct hmm_vma_walk {
> - struct hmm_range *range;
> - bool *locked;
> - unsigned long last;
> - unsigned long end;
> - unsigned int required_fault;
> + struct mmu_notifier_range mmu_range;
> + /* Set once mmu_range is armed with mmu_notifier_invalidate_range_start() */
> + bool mmu_armed;
> + struct vm_area_struct *vma;
> + struct hmm_range *range;
> + unsigned long start;
> + unsigned long end;
> + unsigned long last;
> + /* fault and lock drop related fields */
> + bool *mmlocked;
> + unsigned long fault_end;
> + unsigned int required_fault;
> };
>
> /*
> @@ -95,7 +104,7 @@ static int hmm_record_fault(unsigned long addr, unsigned long end,
>
> WARN_ON_ONCE(!required_fault);
> hmm_vma_walk->last = addr;
> - hmm_vma_walk->end = end;
> + hmm_vma_walk->fault_end = end;
> hmm_vma_walk->required_fault = required_fault;
> return HMM_FAULT_PENDING;
> }
> @@ -400,6 +409,58 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
> }
> #endif /* CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
>
> +static int hmm_vma_capture_migrate_range(unsigned long start,
> + unsigned long end,
> + struct mm_walk *walk)
> +{
> + struct hmm_vma_walk *hmm_vma_walk = walk->private;
> + struct hmm_range *range = hmm_vma_walk->range;
> +
> + if (!hmm_select_migrate(range))
> + return 0;
> +
> + if (hmm_vma_walk->vma && (hmm_vma_walk->vma != walk->vma))
> + return -ERANGE;
> +
> + hmm_vma_walk->vma = walk->vma;
I don't quite follow the check for -ERANGE, it checks for hmm_vma_walk->vma !=
walk->vma, but then set's it later to be the same?
> +
> + if (end - start > range->end - range->start)
> + return -ERANGE;
> +
Have we established that end > start and same for range->end > range->start?
> + if (!hmm_vma_walk->mmu_armed) {
> + hmm_vma_walk->start = start;
> + hmm_vma_walk->end = end;
Does the walk range matter here?
> + mmu_notifier_range_init_owner(&hmm_vma_walk->mmu_range, MMU_NOTIFY_MIGRATE, 0,
> + walk->vma->vm_mm, start, end,
> + range->dev_private_owner);
> + mmu_notifier_invalidate_range_start(&hmm_vma_walk->mmu_range);
> + hmm_vma_walk->mmu_armed = true;
> + }
> +
> + return 0;
> +}
> +
> +static void hmm_vma_post_range_fault(struct hmm_vma_walk *hmm_vma_walk)
> +{
> +
> + struct hmm_range *range = hmm_vma_walk->range;
> +
> + if (hmm_select_migrate(range) &&
> + hmm_vma_walk->mmu_armed) {
> + /*
> + * The migrate_vma path has the following initialized,
> + * so take care of fault path below.
> + */
> + if (range->notifier) {
> + hmm_fill_migrate_vma(range,
> + hmm_vma_walk->vma,
> + hmm_vma_walk->start,
> + hmm_vma_walk->end);
> + }
> + mmu_notifier_invalidate_range_end(&hmm_vma_walk->mmu_range);
> + }
> +}
> +
> static int hmm_vma_walk_pmd(pmd_t *pmdp,
> unsigned long start,
> unsigned long end,
> @@ -594,6 +655,11 @@ static int hmm_vma_walk_test(unsigned long start, unsigned long end,
> struct hmm_vma_walk *hmm_vma_walk = walk->private;
> struct hmm_range *range = hmm_vma_walk->range;
> struct vm_area_struct *vma = walk->vma;
> + int r;
> +
> + r = hmm_vma_capture_migrate_range(start, end, walk);
> + if (r)
> + return r;
>
> if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)) &&
> vma->vm_flags & VM_READ)
> @@ -646,12 +712,12 @@ static int hmm_do_fault(struct mm_struct *mm,
> struct hmm_vma_walk *hmm_vma_walk)
> {
> unsigned long addr = hmm_vma_walk->last;
> - unsigned long end = hmm_vma_walk->end;
> + unsigned long end = hmm_vma_walk->fault_end;
> unsigned int required_fault = hmm_vma_walk->required_fault;
> unsigned int fault_flags = FAULT_FLAG_REMOTE;
> struct vm_area_struct *vma;
>
> - if (hmm_vma_walk->locked)
> + if (hmm_vma_walk->mmlocked)
> fault_flags |= FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
>
> vma = vma_lookup(mm, addr);
> @@ -670,8 +736,8 @@ static int hmm_do_fault(struct mm_struct *mm,
> ret = handle_mm_fault(vma, addr, fault_flags, NULL);
>
> if (ret & (VM_FAULT_COMPLETED | VM_FAULT_RETRY)) {
> - if (hmm_vma_walk->locked) /* needed by sparse */
> - *hmm_vma_walk->locked = false;
> + if (hmm_vma_walk->mmlocked) /* needed by sparse */
> + *hmm_vma_walk->mmlocked = false;
> else
> WARN_ON_ONCE(1); /* broken fault handler */
> return HMM_FAULT_UNLOCKED;
> @@ -694,19 +760,31 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
> {
> struct hmm_vma_walk hmm_vma_walk = {
> .range = range,
> - .locked = locked,
> + .mmlocked = locked,
> .last = range->start,
> };
> - struct mm_struct *mm = range->notifier->mm;
> + /*
> + * Could be serving a device fault or come from migrate
> + * entry point. For the former we have not resolved the vma
> + * yet, and the latter we don't have a notifier (but have a vma).
> + *
> + */
> + struct mm_struct *mm = hmm_range_fault_mm(range);
> int ret;
>
> + /* Migration is incompatible with mmap lock drop */
> + if (locked && hmm_select_migrate(range))
> + return -EINVAL;
> +
> mmap_assert_locked(mm);
>
> do {
> /* If range is no longer valid force retry. */
> - if (mmu_interval_check_retry(range->notifier,
> - range->notifier_seq))
> - return -EBUSY;
> + if (range->notifier && mmu_interval_check_retry(range->notifier,
> + range->notifier_seq)) {
> + ret = -EBUSY;
> + break;
> + }
> ret = walk_page_range(mm, hmm_vma_walk.last, range->end,
> &hmm_walk_ops, &hmm_vma_walk);
> /*
> @@ -732,6 +810,8 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
> * output, and all >= are still at their input values.
> */
> } while (ret == -EBUSY);
> +
> + hmm_vma_post_range_fault(&hmm_vma_walk);
Have you checked to see if we could end up with notifier start/end inbalance?
For example if hmm_select_migrate returns false?
> return ret;
> }
>
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v16 03/12] mm/hmm: preparations for HMM to participate in migration
2026-10-21 7:17 ` Balbir Singh
@ 2026-10-21 8:11 ` Mika Penttilä
0 siblings, 0 replies; 33+ messages in thread
From: Mika Penttilä @ 2026-10-21 8:11 UTC (permalink / raw)
To: Balbir Singh, linux-mm
Cc: dri-devel, intel-xe, linux-kernel, David Hildenbrand,
Jason Gunthorpe, Leon Romanovsky, Alistair Popple, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
On 10/21/26 10:17, Balbir Singh wrote:
> On 10/21/26 5:04 PM, mpenttil@redhat.com wrote:
>> From: Mika Penttilä <mpenttil@redhat.com>
>>
>> For migration to happen after hmm_range_fault(), the vma has to
>> retrieved. Luckily, pagewalk already resolves that for us, so
>> just have to save it for further use. For migration, mmap_lock
>> has to be hold for the whole operation, so vma stays stable.
>> In case lock-drop behavior is requested, return an error while
>> migrating. Also, rename some struct hmm_vma_walk fields to solve
>> namespace collisions, and we are later introducing more
>> xxlocked fields so be unambiguous.
>>
>> Take care also of firing the mmu_notifier when migrating.
>>
>> Also, prepare for differencies of how mm_struct * is retrieved
>> in fault and migrate_vma paths.
>>
>> Cc: David Hildenbrand <david@kernel.org>
>> Cc: Jason Gunthorpe <jgg@nvidia.com>
>> Cc: Leon Romanovsky <leonro@nvidia.com>
>> Cc: Alistair Popple <apopple@nvidia.com>
>> Cc: Balbir Singh <balbirs@nvidia.com>
>> Cc: Zi Yan <ziy@nvidia.com>
>> Cc: Matthew Brost <matthew.brost@intel.com>
>> Suggested-by: Alistair Popple <apopple@nvidia.com>
>> Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
>> ---
>> include/linux/migrate.h | 50 +++++++++++++++++-
>> lib/test_hmm.c | 2 +-
>> mm/hmm.c | 110 ++++++++++++++++++++++++++++++++++------
>> 3 files changed, 145 insertions(+), 17 deletions(-)
>>
>> diff --git a/include/linux/migrate.h b/include/linux/migrate.h
>> index 280ec9a866c7..dd7dd7ec6995 100644
>> --- a/include/linux/migrate.h
>> +++ b/include/linux/migrate.h
>> @@ -5,6 +5,7 @@
>> #include <linux/mm.h>
>> #include <linux/hmm.h>
>> #include <linux/mempolicy.h>
>> +#include <linux/mmu_notifier.h>
>> #include <linux/migrate_mode.h>
>> #include <linux/hugetlb.h>
>>
>> @@ -108,6 +109,29 @@ static inline void softleaf_entry_wait_on_locked(softleaf_t entry, spinlock_t *p
>> spin_unlock(ptl);
>> }
>>
>> +enum migrate_vma_info {
>> + MIGRATE_VMA_SELECT_NONE = 0,
>> + MIGRATE_VMA_SELECT_COMPOUND = MIGRATE_VMA_SELECT_NONE,
>> +};
>> +
>> +static inline enum migrate_vma_info hmm_select_migrate(struct hmm_range *range)
>> +{
>> + return MIGRATE_VMA_SELECT_NONE;
>> +}
>> +
>> +static inline void hmm_fill_migrate_vma(struct hmm_range *range,
>> + struct vm_area_struct *vma,
>> + unsigned long start,
>> + unsigned long end)
>> +{
>> +}
>> +
>> +#ifdef CONFIG_MMU_NOTIFIER
>> +static inline struct mm_struct *hmm_range_fault_mm(struct hmm_range *range)
>> +{
>> + return range->notifier->mm;
>> +}
>> +#endif
>> #endif /* CONFIG_MIGRATION */
>>
>> #ifdef CONFIG_NUMA_BALANCING
>> @@ -151,7 +175,8 @@ static inline unsigned long migrate_pfn(unsigned long pfn)
>> return (pfn << MIGRATE_PFN_SHIFT) | MIGRATE_PFN_VALID;
>> }
>>
>> -enum migrate_vma_direction {
>> +enum migrate_vma_info {
>> + MIGRATE_VMA_SELECT_NONE = 0,
>> MIGRATE_VMA_SELECT_SYSTEM = 1 << 0,
>> MIGRATE_VMA_SELECT_DEVICE_PRIVATE = 1 << 1,
>> MIGRATE_VMA_SELECT_DEVICE_COHERENT = 1 << 2,
>> @@ -193,6 +218,29 @@ struct migrate_vma {
>> struct page *fault_page;
>> };
>>
>> +// TODO: enable migration
>> +static inline enum migrate_vma_info hmm_select_migrate(struct hmm_range *range)
>> +{
>> + return 0;
>> +}
>> +
>> +#ifdef CONFIG_MMU_NOTIFIER
>> +static inline struct mm_struct *hmm_range_fault_mm(struct hmm_range *range)
>> +{
>> + return range->notifier ? range->notifier->mm : range->migrate->vma->vm_mm;
>> +}
>> +#endif
>> +
>> +static inline void hmm_fill_migrate_vma(struct hmm_range *range,
>> + struct vm_area_struct *vma,
>> + unsigned long start,
>> + unsigned long end)
>> +{
>> + range->migrate->vma = vma;
>> + range->migrate->start = start;
>> + range->migrate->end = end;
>> +}
>> +
>> int migrate_vma_setup(struct migrate_vma *args);
>> void migrate_vma_pages(struct migrate_vma *migrate);
>> void migrate_vma_finalize(struct migrate_vma *migrate);
>> diff --git a/lib/test_hmm.c b/lib/test_hmm.c
>> index 6911daa9f854..cd88e8177d0a 100644
>> --- a/lib/test_hmm.c
>> +++ b/lib/test_hmm.c
>> @@ -145,7 +145,7 @@ static bool dmirror_is_private_zone(struct dmirror_device *mdevice)
>> HMM_DMIRROR_MEMORY_DEVICE_PRIVATE);
>> }
>>
>> -static enum migrate_vma_direction
>> +static enum migrate_vma_info
>> dmirror_select_device(struct dmirror *dmirror)
>> {
>> return (dmirror->mdevice->zone_device_type ==
>> diff --git a/mm/hmm.c b/mm/hmm.c
>> index 2f1e98c6b644..4e9542aedc25 100644
>> --- a/mm/hmm.c
>> +++ b/mm/hmm.c
>> @@ -21,6 +21,7 @@
>> #include <linux/pagemap.h>
>> #include <linux/leafops.h>
>> #include <linux/hugetlb.h>
>> +#include <linux/migrate.h>
>> #include <linux/memremap.h>
>> #include <linux/sched/mm.h>
>> #include <linux/jump_label.h>
>> @@ -28,15 +29,23 @@
>> #include <linux/pci-p2pdma.h>
>> #include <linux/mmu_notifier.h>
>> #include <linux/memory_hotplug.h>
>> +#include <asm/tlbflush.h>
>>
>> #include "internal.h"
>>
>> struct hmm_vma_walk {
>> - struct hmm_range *range;
>> - bool *locked;
>> - unsigned long last;
>> - unsigned long end;
>> - unsigned int required_fault;
>> + struct mmu_notifier_range mmu_range;
>> + /* Set once mmu_range is armed with mmu_notifier_invalidate_range_start() */
>> + bool mmu_armed;
>> + struct vm_area_struct *vma;
>> + struct hmm_range *range;
>> + unsigned long start;
>> + unsigned long end;
>> + unsigned long last;
>> + /* fault and lock drop related fields */
>> + bool *mmlocked;
>> + unsigned long fault_end;
>> + unsigned int required_fault;
>> };
>>
>> /*
>> @@ -95,7 +104,7 @@ static int hmm_record_fault(unsigned long addr, unsigned long end,
>>
>> WARN_ON_ONCE(!required_fault);
>> hmm_vma_walk->last = addr;
>> - hmm_vma_walk->end = end;
>> + hmm_vma_walk->fault_end = end;
>> hmm_vma_walk->required_fault = required_fault;
>> return HMM_FAULT_PENDING;
>> }
>> @@ -400,6 +409,58 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
>> }
>> #endif /* CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
>>
>> +static int hmm_vma_capture_migrate_range(unsigned long start,
>> + unsigned long end,
>> + struct mm_walk *walk)
>> +{
>> + struct hmm_vma_walk *hmm_vma_walk = walk->private;
>> + struct hmm_range *range = hmm_vma_walk->range;
>> +
>> + if (!hmm_select_migrate(range))
>> + return 0;
>> +
>> + if (hmm_vma_walk->vma && (hmm_vma_walk->vma != walk->vma))
>> + return -ERANGE;
>> +
>> + hmm_vma_walk->vma = walk->vma;
> I don't quite follow the check for -ERANGE, it checks for hmm_vma_walk->vma !=
> walk->vma, but then set's it later to be the same?
The intention is to catch a range that crosses a vma boundary. hmm_vma_walk lives across the restart loop in hmm_range_fault_locked(),
so test_walk can run again for the same vma after an -EBUSY re-walk. The first call records the vma, a re-walk of the same vma passes,
and a different vma means the range spans more than one vma, which migration doesn't support, so -ERANGE.
The assignment only takes effect on the first call. I'll restructure it as "record if unset, else -ERANGE if different" and add a comment.
>
>> +
>> + if (end - start > range->end - range->start)
>> + return -ERANGE;
>> +
> Have we established that end > start and same for range->end > range->start?
Yes. walk_page_range() rejects start >= end before calling any callback, and hmm_range_fault_locked() walks from hmm_vma_walk.last
(initially range->start) to range->end, so range->start < range->end holds whenever test_walk runs.
The test_walk start/end are a sub-range of that walk clamped to the vma, so start < end too.
That also means end - start can never exceed range->end - range->start, so the check is redundant. I'll drop it in v17.
>
>> + if (!hmm_vma_walk->mmu_armed) {
>> + hmm_vma_walk->start = start;
>> + hmm_vma_walk->end = end;
> Does the walk range matter here?
The walk range is the caller's range clamped to the vma: with the caller's range inside a single vma the two are the same,
and the clamp keeps the walk range's end within the vma (migrate_vma needs that) if the caller's range extends past
the vma into a hole. The walk range is used as both the MMU_NOTIFY_MIGRATE invalidation range and the migrate_vma start/end,
and is set once on the first test_walk call. I'll also add a check that the walk range starts at range->start,
since migrate_vma indexes src[] from there.
>> + mmu_notifier_range_init_owner(&hmm_vma_walk->mmu_range, MMU_NOTIFY_MIGRATE, 0,
>> + walk->vma->vm_mm, start, end,
>> + range->dev_private_owner);
>> + mmu_notifier_invalidate_range_start(&hmm_vma_walk->mmu_range);
>> + hmm_vma_walk->mmu_armed = true;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void hmm_vma_post_range_fault(struct hmm_vma_walk *hmm_vma_walk)
>> +{
>> +
>> + struct hmm_range *range = hmm_vma_walk->range;
>> +
>> + if (hmm_select_migrate(range) &&
>> + hmm_vma_walk->mmu_armed) {
>> + /*
>> + * The migrate_vma path has the following initialized,
>> + * so take care of fault path below.
>> + */
>> + if (range->notifier) {
>> + hmm_fill_migrate_vma(range,
>> + hmm_vma_walk->vma,
>> + hmm_vma_walk->start,
>> + hmm_vma_walk->end);
>> + }
>> + mmu_notifier_invalidate_range_end(&hmm_vma_walk->mmu_range);
>> + }
>> +}
>> +
>> static int hmm_vma_walk_pmd(pmd_t *pmdp,
>> unsigned long start,
>> unsigned long end,
>> @@ -594,6 +655,11 @@ static int hmm_vma_walk_test(unsigned long start, unsigned long end,
>> struct hmm_vma_walk *hmm_vma_walk = walk->private;
>> struct hmm_range *range = hmm_vma_walk->range;
>> struct vm_area_struct *vma = walk->vma;
>> + int r;
>> +
>> + r = hmm_vma_capture_migrate_range(start, end, walk);
>> + if (r)
>> + return r;
>>
>> if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)) &&
>> vma->vm_flags & VM_READ)
>> @@ -646,12 +712,12 @@ static int hmm_do_fault(struct mm_struct *mm,
>> struct hmm_vma_walk *hmm_vma_walk)
>> {
>> unsigned long addr = hmm_vma_walk->last;
>> - unsigned long end = hmm_vma_walk->end;
>> + unsigned long end = hmm_vma_walk->fault_end;
>> unsigned int required_fault = hmm_vma_walk->required_fault;
>> unsigned int fault_flags = FAULT_FLAG_REMOTE;
>> struct vm_area_struct *vma;
>>
>> - if (hmm_vma_walk->locked)
>> + if (hmm_vma_walk->mmlocked)
>> fault_flags |= FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
>>
>> vma = vma_lookup(mm, addr);
>> @@ -670,8 +736,8 @@ static int hmm_do_fault(struct mm_struct *mm,
>> ret = handle_mm_fault(vma, addr, fault_flags, NULL);
>>
>> if (ret & (VM_FAULT_COMPLETED | VM_FAULT_RETRY)) {
>> - if (hmm_vma_walk->locked) /* needed by sparse */
>> - *hmm_vma_walk->locked = false;
>> + if (hmm_vma_walk->mmlocked) /* needed by sparse */
>> + *hmm_vma_walk->mmlocked = false;
>> else
>> WARN_ON_ONCE(1); /* broken fault handler */
>> return HMM_FAULT_UNLOCKED;
>> @@ -694,19 +760,31 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
>> {
>> struct hmm_vma_walk hmm_vma_walk = {
>> .range = range,
>> - .locked = locked,
>> + .mmlocked = locked,
>> .last = range->start,
>> };
>> - struct mm_struct *mm = range->notifier->mm;
>> + /*
>> + * Could be serving a device fault or come from migrate
>> + * entry point. For the former we have not resolved the vma
>> + * yet, and the latter we don't have a notifier (but have a vma).
>> + *
>> + */
>> + struct mm_struct *mm = hmm_range_fault_mm(range);
>> int ret;
>>
>> + /* Migration is incompatible with mmap lock drop */
>> + if (locked && hmm_select_migrate(range))
>> + return -EINVAL;
>> +
>> mmap_assert_locked(mm);
>>
>> do {
>> /* If range is no longer valid force retry. */
>> - if (mmu_interval_check_retry(range->notifier,
>> - range->notifier_seq))
>> - return -EBUSY;
>> + if (range->notifier && mmu_interval_check_retry(range->notifier,
>> + range->notifier_seq)) {
>> + ret = -EBUSY;
>> + break;
>> + }
>> ret = walk_page_range(mm, hmm_vma_walk.last, range->end,
>> &hmm_walk_ops, &hmm_vma_walk);
>> /*
>> @@ -732,6 +810,8 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
>> * output, and all >= are still at their input values.
>> */
>> } while (ret == -EBUSY);
>> +
>> + hmm_vma_post_range_fault(&hmm_vma_walk);
> Have you checked to see if we could end up with notifier start/end inbalance?
> For example if hmm_select_migrate returns false?
Yes. invalidate_range_start() is only called from hmm_vma_capture_migrate_range(), after the hmm_select_migrate()
check and only once (mmu_armed). invalidate_range_end() is only called from hmm_vma_post_range_fault() when mmu_armed
is set. hmm_select_migrate() doesn't change during the call, so if it returns false neither is called.
Every exit from the loop goes through hmm_vma_post_range_fault(); except after test for lock drop which happens before walks.
>
>> return ret;
>> }
>>
Thanks,
--Mika
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v16 03/12] mm/hmm: preparations for HMM to participate in migration
2026-10-21 6:04 ` [PATCH v16 03/12] mm/hmm: preparations for HMM to participate in migration mpenttil
2026-10-21 7:17 ` Balbir Singh
@ 2026-10-22 6:06 ` sashiko-bot
1 sibling, 0 replies; 33+ messages in thread
From: sashiko-bot @ 2026-10-22 6:06 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, David Hildenbrand, Jason Gunthorpe,
Leon Romanovsky, Alistair Popple, Balbir Singh, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] mm/hmm: dead range check in hmm_vma_capture_migrate_range() allows partial VMA
- [High] mm/hmm: mmu_notifier_invalidate_range_start() held across hmm_do_fault()
- [Medium] mm/hmm: hmm_vma_walk_test() captures VMA for migration before checking vm_flags
--
commit ca535286660d47fc1830230d8f80c9d3e5f37db0
Author: Mika Penttilä <mpenttil@redhat.com>
mm/hmm: preparations for HMM to participate in migration
This commit prepares hmm_range_fault() to support page migration by saving
the resolved VMA and range during the page walk, rejecting lock-drop mode
when migrating, and invoking MMU notifier invalidations around the walk.
> diff --git a/mm/hmm.c b/mm/hmm.c
> index 2f1e98c6b6440..4e9542aedc253 100644
> --- a/mm/hmm.c
> +++ b/mm/hmm.c
[ ... ]
> @@ -400,6 +409,58 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
> }
> #endif /* CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
>
> +static int hmm_vma_capture_migrate_range(unsigned long start,
> + unsigned long end,
> + struct mm_walk *walk)
> +{
> + struct hmm_vma_walk *hmm_vma_walk = walk->private;
> + struct hmm_range *range = hmm_vma_walk->range;
> +
> + if (!hmm_select_migrate(range))
> + return 0;
> +
> + if (hmm_vma_walk->vma && (hmm_vma_walk->vma != walk->vma))
> + return -ERANGE;
> +
> + hmm_vma_walk->vma = walk->vma;
> +
> + if (end - start > range->end - range->start)
> + return -ERANGE;
[Severity: High]
Can this condition in mm/hmm.c:hmm_vma_capture_migrate_range() ever be true?
In hmm_range_fault_locked() -> walk_page_range() ->
walk_page_range_mm_unsafe() -> walk_page_test() -> hmm_vma_walk_test(), the
walker clamps the VMA subrange to the requested walk bounds:
start >= hmm_vma_walk.last >= range->start
end = min(range->end, vma->vm_end) <= range->end
Because end - start is always less than or equal to range->end - range->start,
this check never triggers.
If [range->start, range->end) starts with an unmapped hole (without
HMM_PFN_REQ_FAULT set on the hole entries), walk_page_range_mm_unsafe() calls
hmm_vma_walk_hole() for [range->start, vma->vm_start) and then invokes
hmm_vma_walk_test() with start == vma->vm_start > range->start.
hmm_vma_capture_migrate_range() accepts this partial VMA and records
hmm_vma_walk->start = vma->vm_start, which hmm_vma_post_range_fault() writes
to range->migrate->start via hmm_fill_migrate_vma(). However, the page walk
callbacks index range->hmm_pfns[] relative to range->start:
&range->hmm_pfns[(start - range->start) >> PAGE_SHIFT]
When migrate_hmm_range_setup() later reads range->hmm_pfns[0] for
migrate->start, the PFN array is misaligned with the virtual address range.
Additionally, if the entire [range->start, range->end) falls in an unmapped
hole without fault requests, hmm_vma_walk_test() is never called and
range->migrate->vma remains uninitialized.
Should this check instead verify that the single VMA covers the entire
requested range (for example, vma->vm_start > range->start ||
vma->vm_end < range->end), and should hmm_vma_walk_hole() reject holes when
hmm_select_migrate(range) is enabled?
> +
> + if (!hmm_vma_walk->mmu_armed) {
> + hmm_vma_walk->start = start;
> + hmm_vma_walk->end = end;
> + mmu_notifier_range_init_owner(&hmm_vma_walk->mmu_range, MMU_NOTIFY_MIGRATE, 0,
> + walk->vma->vm_mm, start, end,
> + range->dev_private_owner);
> + mmu_notifier_invalidate_range_start(&hmm_vma_walk->mmu_range);
> + hmm_vma_walk->mmu_armed = true;
> + }
> +
> + return 0;
> +}
> +
> +static void hmm_vma_post_range_fault(struct hmm_vma_walk *hmm_vma_walk)
> +{
> +
> + struct hmm_range *range = hmm_vma_walk->range;
> +
> + if (hmm_select_migrate(range) &&
> + hmm_vma_walk->mmu_armed) {
> + /*
> + * The migrate_vma path has the following initialized,
> + * so take care of fault path below.
> + */
> + if (range->notifier) {
> + hmm_fill_migrate_vma(range,
> + hmm_vma_walk->vma,
> + hmm_vma_walk->start,
> + hmm_vma_walk->end);
> + }
> + mmu_notifier_invalidate_range_end(&hmm_vma_walk->mmu_range);
> + }
> +}
> +
> static int hmm_vma_walk_pmd(pmd_t *pmdp,
> unsigned long start,
> unsigned long end,
> @@ -594,6 +655,11 @@ static int hmm_vma_walk_test(unsigned long start, unsigned long end,
> struct hmm_vma_walk *hmm_vma_walk = walk->private;
> struct hmm_range *range = hmm_vma_walk->range;
> struct vm_area_struct *vma = walk->vma;
> + int r;
> +
> + r = hmm_vma_capture_migrate_range(start, end, walk);
> + if (r)
> + return r;
>
> if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)) &&
> vma->vm_flags & VM_READ)
[Severity: Medium]
In mm/hmm.c:hmm_vma_walk_test(), is it intentional that
hmm_vma_capture_migrate_range() runs before validating vma->vm_flags?
When walk->vma has VM_IO or VM_PFNMAP set, or lacks VM_READ, calling
hmm_vma_capture_migrate_range() first records hmm_vma_walk->vma = walk->vma
and invokes mmu_notifier_invalidate_range_start() on the unsupported VMA. If
hmm_range_need_fault() then returns 0, hmm_vma_walk_test() fills
range->hmm_pfns with HMM_PFN_ERROR and returns 1 (skipping the VMA), after
which hmm_vma_post_range_fault() populates range->migrate->vma with the
unsupported VMA.
Also, in the fault migration path where range->notifier is set and
migrate_vma_setup() is not used, nothing in hmm_vma_walk_test() or
hmm_vma_capture_migrate_range() rejects is_vm_hugetlb_page(vma),
(vma->vm_flags & VM_SPECIAL), or vma_is_dax(vma), which migrate_vma_setup()
rejects with -EINVAL. Should VMA eligibility for both HMM and migration be
verified before capturing the VMA and arming the MMU notifier?
[ ... ]
> @@ -694,19 +760,31 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
> {
> struct hmm_vma_walk hmm_vma_walk = {
> .range = range,
> - .locked = locked,
> + .mmlocked = locked,
> .last = range->start,
> };
> - struct mm_struct *mm = range->notifier->mm;
> + /*
> + * Could be serving a device fault or come from migrate
> + * entry point. For the former we have not resolved the vma
> + * yet, and the latter we don't have a notifier (but have a vma).
> + *
> + */
> + struct mm_struct *mm = hmm_range_fault_mm(range);
> int ret;
>
> + /* Migration is incompatible with mmap lock drop */
> + if (locked && hmm_select_migrate(range))
> + return -EINVAL;
> +
> mmap_assert_locked(mm);
>
> do {
> /* If range is no longer valid force retry. */
> - if (mmu_interval_check_retry(range->notifier,
> - range->notifier_seq))
> - return -EBUSY;
> + if (range->notifier && mmu_interval_check_retry(range->notifier,
> + range->notifier_seq)) {
> + ret = -EBUSY;
> + break;
> + }
> ret = walk_page_range(mm, hmm_vma_walk.last, range->end,
> &hmm_walk_ops, &hmm_vma_walk);
> /*
> @@ -732,6 +810,8 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
> * output, and all >= are still at their input values.
> */
> } while (ret == -EBUSY);
> +
> + hmm_vma_post_range_fault(&hmm_vma_walk);
> return ret;
> }
[Severity: High]
What happens in mm/hmm.c:hmm_range_fault_locked() when migration is enabled
(as activated in the subsequent commit "mm: enable device page migration from
HMM pagewalk") and a page in the range needs to be faulted in via
hmm_do_fault()?
On the first iteration of walk_page_range(), hmm_vma_walk_test() ->
hmm_vma_capture_migrate_range() calls mmu_notifier_invalidate_range_start()
and sets hmm_vma_walk->mmu_armed = true before any PTEs are inspected, while
mmu_notifier_invalidate_range_end() is deferred until
hmm_vma_post_range_fault() after the entire do { ... } while (ret == -EBUSY)
loop completes.
When walk_page_range() returns HMM_FAULT_PENDING, hmm_do_fault() ->
handle_mm_fault() runs inside the active mmu_notifier_invalidate_range_start()
and mmu_notifier_invalidate_range_end() section:
1. Across sleeping page faults (such as swap/file I/O, reclaim, userfaultfd,
or migrate_to_ram()), mm->notifier_subscriptions->active_invalidate_ranges
remains elevated and invalidate_seq remains odd, preventing
mn_itree_inv_end() from completing nested invalidations and blocking
concurrent mmu_interval_read_begin() and mmu_interval_notifier_remove()
callers on subscriptions->wq.
2. When range->notifier is non-NULL, any nested invalidation inside
handle_mm_fault() (for example, wp_page_copy() on a write fault or
remove_device_exclusive_entry()) or any notifier not filtered by
range->dev_private_owner updates range->notifier->invalidate_seq via
mmu_interval_set_seq(). When hmm_do_fault() returns -EBUSY to re-walk the
newly faulted page, the next iteration of the loop hits
mmu_interval_check_retry(range->notifier, range->notifier_seq) and aborts
with -EBUSY.
3. Because mmu_notifier_invalidate_range_start() is only called once before
faulting when !hmm_vma_walk->mmu_armed, any PTE faulted into a previously
empty entry by hmm_do_fault() is subsequently unmapped and replaced with a
migration entry on the retry walk without a post-fault
mmu_notifier_invalidate_range_start() notification.
Should the mmu_notifier_invalidate_range_start() and
mmu_notifier_invalidate_range_end() pair be scoped around the migration
unmapping step rather than held across the hmm_do_fault() loop?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021060506.2377545-1-mpenttil@redhat.com?part=3
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v16 04/12] mm/hmm: do the plumbing for HMM to participate in migration
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (2 preceding siblings ...)
2026-10-21 6:04 ` [PATCH v16 03/12] mm/hmm: preparations for HMM to participate in migration mpenttil
@ 2026-10-21 6:04 ` mpenttil
2026-10-22 6:06 ` sashiko-bot
2026-10-21 6:04 ` [PATCH v16 05/12] mm/hmm: migrate collection in HMM pagewalk - pte level mpenttil
` (12 subsequent siblings)
16 siblings, 1 reply; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:04 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
Do the preparations in hmm_range_fault() and pagewalk callbacks to
do the "collecting" part of migration, needed for migration.
These steps include locking for pmd/pte if migrating, and calling the
still dummy hmm_vma_handle_migrate_prepare_pmd() and
hmm_vma_handle_migrate_prepare() functions in the pagewalk.
When doing migration, have to have pmd/pte table locked for the
duration of both hmm_vma_handle*() and hmm_vma_handle_migrate_prepare*()
walks, and unlock when handling the faults.
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Suggested-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
mm/hmm.c | 343 ++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 289 insertions(+), 54 deletions(-)
diff --git a/mm/hmm.c b/mm/hmm.c
index 4e9542aedc25..119e70dbca56 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -42,6 +42,16 @@ struct hmm_vma_walk {
unsigned long start;
unsigned long end;
unsigned long last;
+ /*
+ * For migration we need pte/pmd locked for the handle_* and
+ * prepare_* regions. While faulting we have to drop the locks
+ * and start again. ptelocked and pmdlocked hold the state
+ * and tell if need to drop locks before faulting.
+ * ptl is the lock held for pte or pmd.
+ */
+ bool ptelocked;
+ bool pmdlocked;
+ spinlock_t *ptl;
/* fault and lock drop related fields */
bool *mmlocked;
unsigned long fault_end;
@@ -63,6 +73,16 @@ struct hmm_vma_walk {
*/
#define HMM_FAULT_UNLOCKED -ENOLCK
+#define HMM_ASSERT_PTE_LOCKED(hmm_vma_walk, locked) \
+ WARN_ON_ONCE((hmm_vma_walk)->ptelocked != locked)
+
+#define HMM_ASSERT_PMD_LOCKED(hmm_vma_walk, locked) \
+ WARN_ON_ONCE((hmm_vma_walk)->pmdlocked != locked)
+
+#define HMM_ASSERT_UNLOCKED(hmm_vma_walk) \
+ WARN_ON_ONCE((hmm_vma_walk)->ptelocked || \
+ (hmm_vma_walk)->pmdlocked)
+
enum {
HMM_NEED_FAULT = 1 << 0,
HMM_NEED_WRITE_FAULT = 1 << 1,
@@ -76,14 +96,38 @@ enum {
};
static int hmm_pfns_fill(unsigned long addr, unsigned long end,
- struct hmm_range *range, unsigned long cpu_flags)
+ struct hmm_vma_walk *hmm_vma_walk, unsigned long cpu_flags)
{
+ struct hmm_range *range = hmm_vma_walk->range;
unsigned long i = (addr - range->start) >> PAGE_SHIFT;
+ enum migrate_vma_info minfo;
+ bool migrate = false;
+
+ minfo = hmm_select_migrate(range);
+ if (cpu_flags != HMM_PFN_ERROR) {
+ if (minfo && (vma_is_anonymous(hmm_vma_walk->vma))) {
+ cpu_flags |= HMM_PFN_MIGRATE;
+ migrate = true;
+ }
+ }
+
+ if (migrate && thp_migration_supported() &&
+ (minfo & MIGRATE_VMA_SELECT_COMPOUND) &&
+ IS_ALIGNED(addr, HPAGE_PMD_SIZE) &&
+ IS_ALIGNED(end, HPAGE_PMD_SIZE) &&
+ end-addr == HPAGE_PMD_SIZE) {
+ range->hmm_pfns[i] &= HMM_PFN_INOUT_FLAGS;
+ range->hmm_pfns[i] |= cpu_flags | HMM_PFN_COMPOUND;
+ addr += PAGE_SIZE;
+ i++;
+ cpu_flags = 0;
+ }
for (; addr < end; addr += PAGE_SIZE, i++) {
range->hmm_pfns[i] &= HMM_PFN_INOUT_FLAGS;
range->hmm_pfns[i] |= cpu_flags;
}
+
return 0;
}
@@ -103,6 +147,7 @@ static int hmm_record_fault(unsigned long addr, unsigned long end,
struct hmm_vma_walk *hmm_vma_walk = walk->private;
WARN_ON_ONCE(!required_fault);
+ HMM_ASSERT_UNLOCKED(hmm_vma_walk);
hmm_vma_walk->last = addr;
hmm_vma_walk->fault_end = end;
hmm_vma_walk->required_fault = required_fault;
@@ -187,11 +232,16 @@ static int hmm_vma_walk_hole(unsigned long addr, unsigned long end,
if (!walk->vma) {
if (required_fault)
return -EFAULT;
- return hmm_pfns_fill(addr, end, range, HMM_PFN_ERROR);
+ return hmm_pfns_fill(addr, end, hmm_vma_walk, HMM_PFN_ERROR);
}
- if (required_fault)
+ if (required_fault) {
+ if (hmm_vma_walk->pmdlocked) {
+ spin_unlock(hmm_vma_walk->ptl);
+ hmm_vma_walk->pmdlocked = false;
+ }
return hmm_record_fault(addr, end, required_fault, walk);
- return hmm_pfns_fill(addr, end, range, 0);
+ }
+ return hmm_pfns_fill(addr, end, hmm_vma_walk, 0);
}
static inline unsigned long hmm_pfn_flags_order(unsigned long order)
@@ -224,8 +274,13 @@ static int hmm_vma_handle_pmd(struct mm_walk *walk, unsigned long addr,
cpu_flags = pmd_to_hmm_pfn_flags(range, pmd);
required_fault =
hmm_range_need_fault(hmm_vma_walk, hmm_pfns, npages, cpu_flags);
- if (required_fault)
+ if (required_fault) {
+ if (hmm_vma_walk->pmdlocked) {
+ spin_unlock(hmm_vma_walk->ptl);
+ hmm_vma_walk->pmdlocked = false;
+ }
return hmm_record_fault(addr, end, required_fault, walk);
+ }
pfn = pmd_pfn(pmd) + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
for (i = 0; addr < end; addr += PAGE_SIZE, i++, pfn++) {
@@ -305,14 +360,25 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
goto fault;
if (softleaf_is_migration(entry)) {
- pte_unmap(ptep);
- hmm_vma_walk->last = addr;
- migration_entry_wait(walk->mm, pmdp, addr);
- return -EBUSY;
+ if (!hmm_select_migrate(range)) {
+ HMM_ASSERT_UNLOCKED(hmm_vma_walk);
+ pte_unmap(ptep);
+ hmm_vma_walk->last = addr;
+ migration_entry_wait(walk->mm, pmdp, addr);
+ return -EBUSY;
+ }
+ return 0;
}
/* Report error for everything else */
- pte_unmap(ptep);
+
+ if (hmm_vma_walk->ptelocked) {
+ pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
+ hmm_vma_walk->ptelocked = false;
+ } else {
+ pte_unmap(ptep);
+ }
+
return -EFAULT;
}
@@ -329,7 +395,13 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
if (!vm_normal_page(walk->vma, addr, pte) &&
!is_zero_pfn(pte_pfn(pte))) {
if (hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0)) {
- pte_unmap(ptep);
+ if (hmm_vma_walk->ptelocked) {
+ pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
+ hmm_vma_walk->ptelocked = false;
+ } else {
+ pte_unmap(ptep);
+ }
+
return -EFAULT;
}
new_pfn_flags = HMM_PFN_ERROR;
@@ -342,7 +414,12 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
return 0;
fault:
- pte_unmap(ptep);
+ if (hmm_vma_walk->ptelocked) {
+ pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
+ hmm_vma_walk->ptelocked = false;
+ } else {
+ pte_unmap(ptep);
+ }
/* Fault any virtual address we were asked to fault */
return hmm_record_fault(addr, end, required_fault, walk);
}
@@ -386,13 +463,18 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
required_fault = hmm_range_need_fault(hmm_vma_walk, hmm_pfns,
npages, 0);
if (required_fault) {
- if (softleaf_is_device_private(entry))
+ if (softleaf_is_device_private(entry)) {
+ if (hmm_vma_walk->pmdlocked) {
+ spin_unlock(hmm_vma_walk->ptl);
+ hmm_vma_walk->pmdlocked = false;
+ }
return hmm_record_fault(addr, end, required_fault, walk);
+ }
else
return -EFAULT;
}
- return hmm_pfns_fill(start, end, range, HMM_PFN_ERROR);
+ return hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
}
#else
static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
@@ -400,15 +482,58 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
pmd_t pmd)
{
struct hmm_vma_walk *hmm_vma_walk = walk->private;
- struct hmm_range *range = hmm_vma_walk->range;
unsigned long npages = (end - start) >> PAGE_SHIFT;
if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns, npages, 0))
return -EFAULT;
- return hmm_pfns_fill(start, end, range, HMM_PFN_ERROR);
+ return hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
}
#endif /* CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
+#ifdef CONFIG_DEVICE_MIGRATION
+static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
+ pmd_t *pmdp,
+ unsigned long start,
+ unsigned long end,
+ unsigned long *hmm_pfn)
+{
+ // TODO: implement migration entry insertion
+ return 0;
+}
+
+static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
+ pmd_t *pmdp,
+ pte_t *ptep,
+ unsigned long addr,
+ unsigned long *hmm_pfn,
+ bool *unmapped)
+{
+ // TODO: implement migration entry insertion
+ return 0;
+}
+
+#else
+static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
+ pmd_t *pmdp,
+ unsigned long start,
+ unsigned long end,
+ unsigned long *hmm_pfn)
+{
+ return 0;
+}
+
+static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
+ pmd_t *pmdp,
+ pte_t *ptep,
+ unsigned long addr,
+ unsigned long *hmm_pfn,
+ bool *unmapped)
+{
+ return 0;
+}
+
+#endif
+
static int hmm_vma_capture_migrate_range(unsigned long start,
unsigned long end,
struct mm_walk *walk)
@@ -468,46 +593,116 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
{
struct hmm_vma_walk *hmm_vma_walk = walk->private;
struct hmm_range *range = hmm_vma_walk->range;
- unsigned long *hmm_pfns =
- &range->hmm_pfns[(start - range->start) >> PAGE_SHIFT];
unsigned long npages = (end - start) >> PAGE_SHIFT;
+ struct mm_struct *mm = walk->vma->vm_mm;
+ unsigned long *hmm_pfns, *hmm_pfns_start;
+ enum migrate_vma_info minfo;
unsigned long addr = start;
+ bool unmapped = false;
+ unsigned long i;
pte_t *ptep;
pmd_t pmd;
+ int r = 0;
+ minfo = hmm_select_migrate(range);
+ hmm_pfns_start = &range->hmm_pfns[(start - range->start) >> PAGE_SHIFT];
again:
- pmd = pmdp_get_lockless(pmdp);
- if (pmd_none(pmd))
- return hmm_vma_walk_hole(start, end, -1, walk);
+ hmm_pfns = &range->hmm_pfns[(addr - range->start) >> PAGE_SHIFT];
+ hmm_vma_walk->ptelocked = false;
+ hmm_vma_walk->pmdlocked = false;
+
+ if (minfo) {
+ hmm_vma_walk->ptl = pmd_lock(mm, pmdp);
+ hmm_vma_walk->pmdlocked = true;
+ pmd = pmdp_get(pmdp);
+ } else
+ pmd = pmdp_get_lockless(pmdp);
+
+ if (pmd_none(pmd)) {
+ r = hmm_vma_walk_hole(start, end, -1, walk);
+
+ if (hmm_vma_walk->pmdlocked) {
+ spin_unlock(hmm_vma_walk->ptl);
+ hmm_vma_walk->pmdlocked = false;
+ }
+ return r;
+ }
if (thp_migration_supported() && pmd_is_migration_entry(pmd)) {
- if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns, npages, 0)) {
- hmm_vma_walk->last = addr;
- pmd_migration_entry_wait(walk->mm, pmdp);
- return -EBUSY;
+ if (!minfo) {
+ if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns_start, npages, 0)) {
+ hmm_vma_walk->last = addr;
+ pmd_migration_entry_wait(walk->mm, pmdp);
+ return -EBUSY;
+ }
+ for (i = 0; start < end; start += PAGE_SIZE, i++)
+ hmm_pfns_start[i] &= HMM_PFN_INOUT_FLAGS;
+ }
+
+ if (hmm_vma_walk->pmdlocked) {
+ spin_unlock(hmm_vma_walk->ptl);
+ hmm_vma_walk->pmdlocked = false;
}
- return hmm_pfns_fill(start, end, range, 0);
+
+ return 0;
}
- if (!pmd_present(pmd))
- return hmm_vma_handle_absent_pmd(walk, start, end, hmm_pfns,
- pmd);
+ if (pmd_trans_huge(pmd) || !pmd_present(pmd)) {
+ if (!pmd_present(pmd)) {
+ r = hmm_vma_handle_absent_pmd(walk, start, end, hmm_pfns_start,
+ pmd);
+ // If not migrating we are done
+ if (r || !minfo) {
+ if (hmm_vma_walk->pmdlocked) {
+ spin_unlock(hmm_vma_walk->ptl);
+ hmm_vma_walk->pmdlocked = false;
+ }
+ return r;
+ }
+ }
- if (pmd_trans_huge(pmd)) {
- /*
- * No need to take pmd_lock here, even if some other thread
- * is splitting the huge pmd we will get that event through
- * mmu_notifier callback.
- *
- * So just read pmd value and check again it's a transparent
- * huge or device mapping one and compute corresponding pfn
- * values.
- */
- pmd = pmdp_get_lockless(pmdp);
- if (!pmd_trans_huge(pmd))
- goto again;
+ if (pmd_trans_huge(pmd)) {
+ /*
+ * No need to take pmd_lock here if not migrating,
+ * even if some other thread is splitting the huge
+ * pmd we will get that event through mmu_notifier callback.
+ *
+ * So just read pmd value and check again it's a transparent
+ * huge or device mapping one and compute corresponding pfn
+ * values.
+ */
+
+ if (!minfo) {
+ pmd = pmdp_get_lockless(pmdp);
+ if (!pmd_trans_huge(pmd))
+ goto again;
+ }
- return hmm_vma_handle_pmd(walk, addr, end, hmm_pfns, pmd);
+ r = hmm_vma_handle_pmd(walk, start, end, hmm_pfns_start, pmd);
+
+ // If not migrating we are done
+ if (r || !minfo) {
+ if (hmm_vma_walk->pmdlocked) {
+ spin_unlock(hmm_vma_walk->ptl);
+ hmm_vma_walk->pmdlocked = false;
+ }
+ return r;
+ }
+ }
+
+ r = hmm_vma_handle_migrate_prepare_pmd(walk, pmdp, start, end, hmm_pfns_start);
+
+ if (hmm_vma_walk->pmdlocked) {
+ spin_unlock(hmm_vma_walk->ptl);
+ hmm_vma_walk->pmdlocked = false;
+ }
+
+ return r;
+ }
+
+ if (hmm_vma_walk->pmdlocked) {
+ spin_unlock(hmm_vma_walk->ptl);
+ hmm_vma_walk->pmdlocked = false;
}
/*
@@ -517,24 +712,64 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
* recover.
*/
if (pmd_bad(pmd)) {
- if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns, npages, 0))
+ if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns_start, npages, 0))
return -EFAULT;
- return hmm_pfns_fill(start, end, range, HMM_PFN_ERROR);
+ return hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
}
- ptep = pte_offset_map(pmdp, addr);
- if (!ptep)
+ if (minfo) {
+ ptep = pte_offset_map_lock(mm, pmdp, addr, &hmm_vma_walk->ptl);
+ if (ptep)
+ hmm_vma_walk->ptelocked = true;
+ } else {
+ ptep = pte_offset_map(pmdp, addr);
+ }
+ if (!ptep) {
+ addr = start;
goto again;
+ }
+
for (; addr < end; addr += PAGE_SIZE, ptep++, hmm_pfns++) {
- int r;
r = hmm_vma_handle_pte(walk, addr, end, pmdp, ptep, hmm_pfns);
if (r) {
- /* hmm_vma_handle_pte() did pte_unmap() */
+ /* hmm_vma_handle_pte() did pte_unmap() / pte_unmap_unlock */
+ if (unmapped)
+ flush_tlb_range(walk->vma, start, addr);
return r;
}
+
+ r = hmm_vma_handle_migrate_prepare(walk, pmdp, ptep, addr, hmm_pfns, &unmapped);
+ if (r == -EAGAIN) {
+ HMM_ASSERT_UNLOCKED(hmm_vma_walk);
+ if (unmapped) {
+ flush_tlb_range(walk->vma, start, addr);
+ unmapped = false;
+ }
+ goto again;
+ }
+ if (r) {
+ /* A non -EAGAIN error here means migrate_vma_split_folio()
+ * already dropped the PTE lock and cleared ptelocked.
+ */
+ HMM_ASSERT_UNLOCKED(hmm_vma_walk);
+ if (unmapped)
+ flush_tlb_range(walk->vma, start, addr);
+ hmm_pfns_fill(addr, end, hmm_vma_walk, HMM_PFN_ERROR);
+ return 0;
+ }
}
- pte_unmap(ptep - 1);
+
+ if (unmapped)
+ flush_tlb_range(walk->vma, start, addr);
+
+ if (hmm_vma_walk->ptelocked) {
+ pte_unmap_unlock(ptep - 1, hmm_vma_walk->ptl);
+ hmm_vma_walk->ptelocked = false;
+ } else {
+ pte_unmap(ptep - 1);
+ }
+
return 0;
}
@@ -682,7 +917,7 @@ static int hmm_vma_walk_test(unsigned long start, unsigned long end,
(end - start) >> PAGE_SHIFT, 0))
return -EFAULT;
- hmm_pfns_fill(start, end, range, HMM_PFN_ERROR);
+ hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
/* Skip this vma and continue processing the next vma. */
return 1;
@@ -798,9 +1033,9 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
if (ret == HMM_FAULT_PENDING) {
ret = hmm_do_fault(mm, &hmm_vma_walk);
if (ret == HMM_FAULT_UNLOCKED) {
- if (fatal_signal_pending(current))
- return -EINTR;
- return -EBUSY;
+ ret = fatal_signal_pending(current) ? -EINTR :
+ -EBUSY;
+ break;
}
}
/*
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v16 04/12] mm/hmm: do the plumbing for HMM to participate in migration
2026-10-21 6:04 ` [PATCH v16 04/12] mm/hmm: do the plumbing " mpenttil
@ 2026-10-22 6:06 ` sashiko-bot
0 siblings, 0 replies; 33+ messages in thread
From: sashiko-bot @ 2026-10-22 6:06 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, David Hildenbrand, Jason Gunthorpe,
Leon Romanovsky, Alistair Popple, Balbir Singh, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] mm/hmm: broken migration entries in hmm_vma_handle_pte() and hmm_vma_walk_pmd()
- [High] mm/hmm: broken state and rollback in hmm_vma_walk_pmd() on retry after -EAGAIN
- [Medium] mm/hmm: hmm_vma_walk_pmd() aborts PMD walk and clobbers PFNs on split failure
--
commit 25901a209351c6985ba22f8dfc40a2db03ec4bdf
Author: Mika Penttilä <mpenttil@redhat.com>
mm/hmm: do the plumbing for HMM to participate in migration
This commit adds page table locking state and migration preparation plumbing
to hmm_range_fault() and its pagewalk callbacks in mm/hmm.c so that PTE and
PMD locks are held across entry handling and migration collection and dropped
before faulting.
> diff --git a/mm/hmm.c b/mm/hmm.c
> index 4e9542aedc253..119e70dbca56f 100644
> --- a/mm/hmm.c
> +++ b/mm/hmm.c
[ ... ]
> @@ -305,14 +360,25 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
> goto fault;
>
> if (softleaf_is_migration(entry)) {
> - pte_unmap(ptep);
> - hmm_vma_walk->last = addr;
> - migration_entry_wait(walk->mm, pmdp, addr);
> - return -EBUSY;
> + if (!hmm_select_migrate(range)) {
> + HMM_ASSERT_UNLOCKED(hmm_vma_walk);
> + pte_unmap(ptep);
> + hmm_vma_walk->last = addr;
> + migration_entry_wait(walk->mm, pmdp, addr);
> + return -EBUSY;
> + }
> + return 0;
> }
[Severity: High]
In include/linux/hmm.h, the input request flags share the same bit positions
as the output flags (HMM_PFN_REQ_FAULT == HMM_PFN_VALID,
HMM_PFN_REQ_WRITE == HMM_PFN_WRITE, HMM_PFN_REQ_MIGRATE == HMM_PFN_MIGRATE),
and callers using range->default_flags with range->pfn_flags_mask == 0 are
not required to initialize range->hmm_pfns[] on input.
In hmm_vma_handle_pte(), the !pte_present(pte) path evaluates
required_fault = hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0) first:
required_fault =
hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0);
if (!required_fault)
goto out;
Because of that check, if (softleaf_is_migration(entry)) is only reached when
required_fault != 0 (HMM_PFN_REQ_FAULT was requested). When
hmm_select_migrate(range) is non-zero, returning 0 directly here skips both
migration_entry_wait() (which would require unlocking hmm_vma_walk->ptl first)
and the out: label that masks *hmm_pfn to HMM_PFN_INOUT_FLAGS:
out:
*hmm_pfn = (*hmm_pfn & HMM_PFN_INOUT_FLAGS) | new_pfn_flags;
return 0;
Won't returning 0 directly on a concurrent migration entry leave stale input
flags or uninitialized bits (such as HMM_PFN_REQ_FAULT / HMM_PFN_VALID and
HMM_PFN_REQ_MIGRATE / HMM_PFN_MIGRATE) in *hmm_pfn, pass a migration PTE into
hmm_vma_handle_migrate_prepare(), and allow hmm_range_fault() to succeed
without waiting for the migration entry to resolve despite HMM_PFN_REQ_FAULT?
Conversely, when HMM_PFN_REQ_FAULT is not set (such as the default in
migrate_vma_setup()), if (!required_fault) goto out runs before checking
softleaf_is_migration(entry). If a retry re-walks a migration PTE that was
already installed by this walk, won't jumping to out: clear *hmm_pfn (and
trigger rollback in the later patch "mm/hmm: implement rollback for device
page migration in HMM pagewalk") while leaving the migration PTE in the page
table?
[ ... ]
> @@ -468,46 +593,116 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
> {
> struct hmm_vma_walk *hmm_vma_walk = walk->private;
> struct hmm_range *range = hmm_vma_walk->range;
> - unsigned long *hmm_pfns =
> - &range->hmm_pfns[(start - range->start) >> PAGE_SHIFT];
> unsigned long npages = (end - start) >> PAGE_SHIFT;
> + struct mm_struct *mm = walk->vma->vm_mm;
> + unsigned long *hmm_pfns, *hmm_pfns_start;
> + enum migrate_vma_info minfo;
> unsigned long addr = start;
> + bool unmapped = false;
> + unsigned long i;
> pte_t *ptep;
> pmd_t pmd;
> + int r = 0;
>
> + minfo = hmm_select_migrate(range);
> + hmm_pfns_start = &range->hmm_pfns[(start - range->start) >> PAGE_SHIFT];
> again:
> - pmd = pmdp_get_lockless(pmdp);
> - if (pmd_none(pmd))
> - return hmm_vma_walk_hole(start, end, -1, walk);
> + hmm_pfns = &range->hmm_pfns[(addr - range->start) >> PAGE_SHIFT];
> + hmm_vma_walk->ptelocked = false;
> + hmm_vma_walk->pmdlocked = false;
> +
> + if (minfo) {
> + hmm_vma_walk->ptl = pmd_lock(mm, pmdp);
> + hmm_vma_walk->pmdlocked = true;
> + pmd = pmdp_get(pmdp);
> + } else
> + pmd = pmdp_get_lockless(pmdp);
> +
> + if (pmd_none(pmd)) {
> + r = hmm_vma_walk_hole(start, end, -1, walk);
> +
> + if (hmm_vma_walk->pmdlocked) {
> + spin_unlock(hmm_vma_walk->ptl);
> + hmm_vma_walk->pmdlocked = false;
> + }
> + return r;
> + }
>
> if (thp_migration_supported() && pmd_is_migration_entry(pmd)) {
> - if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns, npages, 0)) {
> - hmm_vma_walk->last = addr;
> - pmd_migration_entry_wait(walk->mm, pmdp);
> - return -EBUSY;
> + if (!minfo) {
> + if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns_start, npages, 0)) {
> + hmm_vma_walk->last = addr;
> + pmd_migration_entry_wait(walk->mm, pmdp);
> + return -EBUSY;
> + }
> + for (i = 0; start < end; start += PAGE_SIZE, i++)
> + hmm_pfns_start[i] &= HMM_PFN_INOUT_FLAGS;
> + }
> +
> + if (hmm_vma_walk->pmdlocked) {
> + spin_unlock(hmm_vma_walk->ptl);
> + hmm_vma_walk->pmdlocked = false;
> }
> - return hmm_pfns_fill(start, end, range, 0);
> +
> + return 0;
> }
[Severity: High]
Similarly, in hmm_vma_walk_pmd(), when thp_migration_supported() &&
pmd_is_migration_entry(pmd) is true and minfo != 0, both the
hmm_range_need_fault() check and the loop masking hmm_pfns_start[] to
HMM_PFN_INOUT_FLAGS are skipped by if (!minfo).
When a concurrent PMD migration entry is encountered during a migration walk,
doesn't skipping that block leave hmm_pfns_start[0..npages - 1] unmasked and
uninitialized, and also fail to unlock hmm_vma_walk->ptl and wait in
pmd_migration_entry_wait() when a fault was requested? Neither this path nor
the PTE migration entry path in hmm_vma_handle_pte() appears to be updated in
the subsequent patches in the series.
> - if (!pmd_present(pmd))
> - return hmm_vma_handle_absent_pmd(walk, start, end, hmm_pfns,
> - pmd);
> + if (pmd_trans_huge(pmd) || !pmd_present(pmd)) {
> + if (!pmd_present(pmd)) {
> + r = hmm_vma_handle_absent_pmd(walk, start, end, hmm_pfns_start,
> + pmd);
> + // If not migrating we are done
> + if (r || !minfo) {
> + if (hmm_vma_walk->pmdlocked) {
> + spin_unlock(hmm_vma_walk->ptl);
> + hmm_vma_walk->pmdlocked = false;
> + }
> + return r;
> + }
> + }
>
> - if (pmd_trans_huge(pmd)) {
> - /*
> - * No need to take pmd_lock here, even if some other thread
> - * is splitting the huge pmd we will get that event through
> - * mmu_notifier callback.
> - *
> - * So just read pmd value and check again it's a transparent
> - * huge or device mapping one and compute corresponding pfn
> - * values.
> - */
> - pmd = pmdp_get_lockless(pmdp);
> - if (!pmd_trans_huge(pmd))
> - goto again;
> + if (pmd_trans_huge(pmd)) {
> + /*
> + * No need to take pmd_lock here if not migrating,
> + * even if some other thread is splitting the huge
> + * pmd we will get that event through mmu_notifier callback.
> + *
> + * So just read pmd value and check again it's a transparent
> + * huge or device mapping one and compute corresponding pfn
> + * values.
> + */
> +
> + if (!minfo) {
> + pmd = pmdp_get_lockless(pmdp);
> + if (!pmd_trans_huge(pmd))
> + goto again;
> + }
>
> - return hmm_vma_handle_pmd(walk, addr, end, hmm_pfns, pmd);
> + r = hmm_vma_handle_pmd(walk, start, end, hmm_pfns_start, pmd);
> +
> + // If not migrating we are done
> + if (r || !minfo) {
> + if (hmm_vma_walk->pmdlocked) {
> + spin_unlock(hmm_vma_walk->ptl);
> + hmm_vma_walk->pmdlocked = false;
> + }
> + return r;
> + }
> + }
> +
> + r = hmm_vma_handle_migrate_prepare_pmd(walk, pmdp, start, end, hmm_pfns_start);
> +
> + if (hmm_vma_walk->pmdlocked) {
> + spin_unlock(hmm_vma_walk->ptl);
> + hmm_vma_walk->pmdlocked = false;
> + }
> +
> + return r;
> + }
> +
> + if (hmm_vma_walk->pmdlocked) {
> + spin_unlock(hmm_vma_walk->ptl);
> + hmm_vma_walk->pmdlocked = false;
> }
>
> /*
> @@ -517,24 +712,64 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
> * recover.
> */
> if (pmd_bad(pmd)) {
> - if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns, npages, 0))
> + if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns_start, npages, 0))
> return -EFAULT;
> - return hmm_pfns_fill(start, end, range, HMM_PFN_ERROR);
> + return hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
> }
>
> - ptep = pte_offset_map(pmdp, addr);
> - if (!ptep)
> + if (minfo) {
> + ptep = pte_offset_map_lock(mm, pmdp, addr, &hmm_vma_walk->ptl);
> + if (ptep)
> + hmm_vma_walk->ptelocked = true;
> + } else {
> + ptep = pte_offset_map(pmdp, addr);
> + }
> + if (!ptep) {
> + addr = start;
> goto again;
> + }
> +
> for (; addr < end; addr += PAGE_SIZE, ptep++, hmm_pfns++) {
> - int r;
>
> r = hmm_vma_handle_pte(walk, addr, end, pmdp, ptep, hmm_pfns);
> if (r) {
> - /* hmm_vma_handle_pte() did pte_unmap() */
> + /* hmm_vma_handle_pte() did pte_unmap() / pte_unmap_unlock */
> + if (unmapped)
> + flush_tlb_range(walk->vma, start, addr);
> return r;
> }
> +
> + r = hmm_vma_handle_migrate_prepare(walk, pmdp, ptep, addr, hmm_pfns, &unmapped);
> + if (r == -EAGAIN) {
> + HMM_ASSERT_UNLOCKED(hmm_vma_walk);
> + if (unmapped) {
> + flush_tlb_range(walk->vma, start, addr);
> + unmapped = false;
> + }
> + goto again;
> + }
[Severity: High]
When hmm_vma_handle_migrate_prepare() (populated in the later patch "mm/hmm:
migrate collection in HMM pagewalk - pte level") encounters a PTE-mapped large
folio at addr > start after order-0 pages in [start, addr) have already been
collected, migrate_vma_split_folio() drops the PTE lock and returns -EAGAIN,
jumping to again: with addr > start.
Even with the later patch "mm/hmm: implement rollback for device page
migration in HMM pagewalk", can jumping back to again: with addr > start leave
stale collected state in [start, addr) or leak folio locks and references?
1. If pte_offset_map_lock() returns null (!ptep) at addr > start because the
PTE table disappeared while the PTE lock was dropped, the rollback patch
calls hmm_vma_handle_migrate_prepare_rollback(walk->private, addr, end,
hmm_pfns) on the unwalked tail [addr, end) instead of rolling back the
already-collected prefix [start, addr) at hmm_pfns_start before resetting
addr = start.
2. If the PTE page table was removed or replaced while the PTE lock was
dropped in migrate_vma_split_folio() (or after !ptep jumps to again:), the
PMD-level paths at again: do not roll back [start, addr) when
pmd_is_migration_entry(pmd) is true (which returns 0 with [start, addr)
still marked HMM_PFN_VALID | HMM_PFN_MIGRATE and addr still marked
HMM_PFN_VALID from hmm_vma_handle_pte()), or when hmm_vma_walk_hole(),
hmm_vma_handle_absent_pmd(), hmm_vma_handle_pmd(), or pmd_bad() returns
HMM_FAULT_PENDING or -EFAULT. Likewise, if the PTE table was replaced by a
new PTE table while the lock was dropped, again: resumes at addr > start
without rolling back or re-walking [start, addr).
> + if (r) {
> + /* A non -EAGAIN error here means migrate_vma_split_folio()
> + * already dropped the PTE lock and cleared ptelocked.
> + */
> + HMM_ASSERT_UNLOCKED(hmm_vma_walk);
> + if (unmapped)
> + flush_tlb_range(walk->vma, start, addr);
> + hmm_pfns_fill(addr, end, hmm_vma_walk, HMM_PFN_ERROR);
> + return 0;
> + }
[Severity: Medium]
When hmm_vma_handle_migrate_prepare() returns a non-EAGAIN error in the later
patch "mm/hmm: migrate collection in HMM pagewalk - pte level" because
migrate_vma_split_folio() failed to split a PTE-mapped large folio, why does
hmm_vma_walk_pmd() fill [addr, end) with HMM_PFN_ERROR and return 0?
First, hmm_vma_handle_pte() has already recorded the valid PFN and
HMM_PFN_VALID in *hmm_pfns for addr. Overwriting addr with HMM_PFN_ERROR means
callers such as nouveau_dmem_migrate_fault() (in "drm/nouveau/svm: add support
for migrate on fault") that fall back to mapping present CPU pages in place
when migration does not happen cannot use the PFN, unlike folio_trylock() or
folio_try_share_anon_rmap_pte() failures which preserve the valid PFN without
HMM_PFN_MIGRATE.
Second, returning 0 immediately aborts the loop for the rest of the PMD range
[addr + PAGE_SIZE, end), skipping both faulting (hmm_vma_handle_pte()) and
migration collection (hmm_vma_handle_migrate_prepare()) for all remaining PTEs
in that PMD and returning 0 from hmm_range_fault() with HMM_PFN_ERROR entries
even when HMM_PFN_REQ_FAULT was requested.
> }
> - pte_unmap(ptep - 1);
> +
> + if (unmapped)
> + flush_tlb_range(walk->vma, start, addr);
> +
> + if (hmm_vma_walk->ptelocked) {
> + pte_unmap_unlock(ptep - 1, hmm_vma_walk->ptl);
> + hmm_vma_walk->ptelocked = false;
> + } else {
> + pte_unmap(ptep - 1);
> + }
> +
> return 0;
> }
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021060506.2377545-1-mpenttil@redhat.com?part=4
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v16 05/12] mm/hmm: migrate collection in HMM pagewalk - pte level
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (3 preceding siblings ...)
2026-10-21 6:04 ` [PATCH v16 04/12] mm/hmm: do the plumbing " mpenttil
@ 2026-10-21 6:04 ` mpenttil
2026-10-21 6:56 ` Balbir Singh
2026-10-22 6:06 ` sashiko-bot
2026-10-21 6:05 ` [PATCH v16 06/12] mm/hmm: migrate collection in HMM pagewalk - pmd level mpenttil
` (11 subsequent siblings)
16 siblings, 2 replies; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:04 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
Implement the needed hmm_vma_handle_migrate_prepare() function
which is mostly carried over from migrate_device.c's
migrate_vma_collect_pmd() function.
Also implement the migrate_vma_split_folio(), for splitting
pte mapped large folios. It is also mostly from migrate_device.c,
with care taken to reference folio before relasing page table
lock.
With HMM pagewalk based migration, the idea is that
hmm_vma_handle_*() are responsible for faulting,
and the pfn collecting part. hmm_vma_handle_migrate_prepare*()
do the migration decisions (with HMM_PFN_MIGRATE), possibly split
folios, and insert migration ptes/pmds.
HMM pagewalk based migration is enabled in later commit, for now
now hmm_select_migrate() returns 0.
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Suggested-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
mm/hmm.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 262 insertions(+), 1 deletion(-)
diff --git a/mm/hmm.c b/mm/hmm.c
index 119e70dbca56..0ce947d0e572 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -491,6 +491,63 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
#endif /* CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
#ifdef CONFIG_DEVICE_MIGRATION
+/**
+ * migrate_vma_split_folio() - Helper function to split a THP folio
+ * @folio: the folio to split
+ * @fault_page: struct page associated with the fault if any
+ * @hmm_vma_walk: walk in progress
+ * @ptep: pte_t * for unmap and unlock ptl
+ *
+ * Returns 0 on success
+ */
+static int migrate_vma_split_folio(struct folio *folio,
+ struct page *fault_page,
+ struct hmm_vma_walk *hmm_vma_walk,
+ pte_t *ptep)
+{
+ int ret;
+ struct folio *fault_folio = fault_page ? page_folio(fault_page) : NULL;
+ struct folio *new_fault_folio = NULL;
+
+ if (folio != fault_folio)
+ folio_get(folio);
+
+ pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
+ hmm_vma_walk->ptelocked = false;
+
+ if (folio != fault_folio)
+ folio_lock(folio);
+
+ ret = split_folio(folio);
+ if (ret) {
+ if (folio != fault_folio) {
+ folio_unlock(folio);
+ folio_put(folio);
+ }
+ return ret;
+ }
+
+ new_fault_folio = fault_page ? page_folio(fault_page) : NULL;
+
+ /*
+ * Ensure the lock is held on the correct
+ * folio after the split
+ */
+ if (!new_fault_folio) {
+ folio_unlock(folio);
+ folio_put(folio);
+ } else if (folio != new_fault_folio) {
+ if (new_fault_folio != fault_folio) {
+ folio_get(new_fault_folio);
+ folio_lock(new_fault_folio);
+ }
+ folio_unlock(folio);
+ folio_put(folio);
+ }
+
+ return 0;
+}
+
static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
pmd_t *pmdp,
unsigned long start,
@@ -501,6 +558,11 @@ static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
return 0;
}
+/*
+ * Install migration entries if migration requested, either from fault
+ * or migrate paths.
+ *
+ */
static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
pmd_t *pmdp,
pte_t *ptep,
@@ -508,8 +570,207 @@ static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
unsigned long *hmm_pfn,
bool *unmapped)
{
- // TODO: implement migration entry insertion
+ struct hmm_vma_walk *hmm_vma_walk = walk->private;
+ struct hmm_range *range = hmm_vma_walk->range;
+ struct migrate_vma *migrate = range->migrate;
+ struct mm_struct *mm = walk->vma->vm_mm;
+ struct folio *fault_folio = NULL;
+ enum migrate_vma_info minfo;
+ struct dev_pagemap *pgmap;
+ bool anon_exclusive;
+ struct folio *folio;
+ unsigned long pfn;
+ struct page *page;
+ softleaf_t entry;
+ pte_t pte, swp_pte;
+ bool writable = false;
+
+ // Do we want to migrate at all?
+ minfo = hmm_select_migrate(range);
+ if (!minfo)
+ return 0;
+
+ WARN_ON_ONCE(!migrate);
+ HMM_ASSERT_PTE_LOCKED(hmm_vma_walk, true);
+
+ fault_folio = migrate->fault_page ?
+ page_folio(migrate->fault_page) : NULL;
+
+ pte = ptep_get(ptep);
+
+ if (pte_none(pte)) {
+ if (vma_is_anonymous(walk->vma)) {
+ *hmm_pfn &= HMM_PFN_INOUT_FLAGS;
+ *hmm_pfn |= HMM_PFN_MIGRATE;
+ goto out;
+ }
+ }
+
+ if (!(hmm_pfn[0] & HMM_PFN_VALID))
+ goto out;
+
+ if (!pte_present(pte)) {
+ /*
+ * Only care about unaddressable device page special
+ * page table entry. Other special swap entries are not
+ * migratable, and we ignore regular swapped page.
+ */
+ entry = softleaf_from_pte(pte);
+ if (!softleaf_is_device_private(entry))
+ goto out;
+
+ if (!(minfo & MIGRATE_VMA_SELECT_DEVICE_PRIVATE))
+ goto out;
+
+ page = softleaf_to_page(entry);
+ folio = page_folio(page);
+ if (folio->pgmap->owner != migrate->pgmap_owner)
+ goto out;
+
+ if (folio_test_large(folio)) {
+ int ret;
+
+ ret = migrate_vma_split_folio(folio,
+ migrate->fault_page,
+ hmm_vma_walk,
+ ptep);
+ if (ret)
+ goto out_error;
+ return -EAGAIN;
+ }
+
+ pfn = page_to_pfn(page);
+ if (softleaf_is_device_private_write(entry))
+ writable = true;
+ } else {
+ pfn = pte_pfn(pte);
+ if (is_zero_pfn(pfn) &&
+ (minfo & MIGRATE_VMA_SELECT_SYSTEM)) {
+ *hmm_pfn = HMM_PFN_MIGRATE;
+ goto out;
+ }
+ page = vm_normal_page(walk->vma, addr, pte);
+ if (page && !is_zone_device_page(page) &&
+ !(minfo & MIGRATE_VMA_SELECT_SYSTEM)) {
+ goto out;
+ } else if (page && is_device_coherent_page(page)) {
+ pgmap = page_pgmap(page);
+
+ if (!(minfo &
+ MIGRATE_VMA_SELECT_DEVICE_COHERENT) ||
+ pgmap->owner != migrate->pgmap_owner)
+ goto out;
+ }
+
+ folio = page ? page_folio(page) : NULL;
+ if (folio && folio_test_large(folio)) {
+ int ret;
+
+ ret = migrate_vma_split_folio(folio,
+ migrate->fault_page,
+ hmm_vma_walk,
+ ptep);
+ if (ret)
+ goto out_error;
+ return -EAGAIN;
+ }
+
+ writable = pte_write(pte);
+ }
+
+ if (!page || !page->mapping)
+ goto out;
+
+ /*
+ * By getting a reference on the folio we pin it and that blocks
+ * any kind of migration. Side effect is that it "freezes" the
+ * pte.
+ *
+ * We drop this reference after isolating the folio from the lru
+ * for non device folio (device folio are not on the lru and thus
+ * can't be dropped from it).
+ */
+ folio = page_folio(page);
+ folio_get(folio);
+
+ /*
+ * We rely on folio_trylock() to avoid deadlock between
+ * concurrent migrations where each is waiting on the others
+ * folio lock. If we can't immediately lock the folio we fail this
+ * migration as it is only best effort anyway.
+ *
+ * If we can lock the folio it's safe to set up a migration entry
+ * now. In the common case where the folio is mapped once in a
+ * single process setting up the migration entry now is an
+ * optimisation to avoid walking the rmap later with
+ * try_to_migrate().
+ */
+
+ if (fault_folio == folio || folio_trylock(folio)) {
+ anon_exclusive = folio_test_anon(folio) &&
+ PageAnonExclusive(page);
+
+ if (pte_present(pte))
+ flush_cache_page(walk->vma, addr, pfn);
+
+ if (anon_exclusive) {
+ pte = ptep_clear_flush(walk->vma, addr, ptep);
+
+ if (folio_try_share_anon_rmap_pte(folio, page)) {
+ set_pte_at(mm, addr, ptep, pte);
+ if (fault_folio != folio)
+ folio_unlock(folio);
+ folio_put(folio);
+ goto out;
+ }
+ } else {
+ pte = ptep_get_and_clear(mm, addr, ptep);
+ }
+
+ if (pte_present(pte) && pte_dirty(pte))
+ folio_mark_dirty(folio);
+
+ /* Setup special migration page table entry */
+ if (writable)
+ entry = make_writable_migration_entry(pfn);
+ else if (anon_exclusive)
+ entry = make_readable_exclusive_migration_entry(pfn);
+ else
+ entry = make_readable_migration_entry(pfn);
+
+ if (pte_present(pte)) {
+ if (pte_young(pte))
+ entry = make_migration_entry_young(entry);
+ if (pte_dirty(pte))
+ entry = make_migration_entry_dirty(entry);
+ }
+
+ swp_pte = swp_entry_to_pte(entry);
+ if (pte_present(pte)) {
+ if (pte_soft_dirty(pte))
+ swp_pte = pte_swp_mksoft_dirty(swp_pte);
+ if (pte_uffd(pte))
+ swp_pte = pte_swp_mkuffd(swp_pte);
+ } else {
+ if (pte_swp_soft_dirty(pte))
+ swp_pte = pte_swp_mksoft_dirty(swp_pte);
+ if (pte_swp_uffd(pte))
+ swp_pte = pte_swp_mkuffd(swp_pte);
+ }
+
+ set_pte_at(mm, addr, ptep, swp_pte);
+ folio_remove_rmap_pte(folio, page, walk->vma);
+ folio_put(folio);
+ *hmm_pfn |= HMM_PFN_MIGRATE;
+ if (pte_present(pte))
+ *unmapped = true;
+ } else {
+ folio_put(folio);
+ }
+out:
return 0;
+out_error:
+ return -EFAULT;
}
#else
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v16 05/12] mm/hmm: migrate collection in HMM pagewalk - pte level
2026-10-21 6:04 ` [PATCH v16 05/12] mm/hmm: migrate collection in HMM pagewalk - pte level mpenttil
@ 2026-10-21 6:56 ` Balbir Singh
2026-10-21 7:09 ` Mika Penttilä
2026-10-22 6:06 ` sashiko-bot
1 sibling, 1 reply; 33+ messages in thread
From: Balbir Singh @ 2026-10-21 6:56 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, linux-kernel, David Hildenbrand,
Jason Gunthorpe, Leon Romanovsky, Alistair Popple, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
On 10/21/26 5:04 PM, mpenttil@redhat.com wrote:
> From: Mika Penttilä <mpenttil@redhat.com>
>
> Implement the needed hmm_vma_handle_migrate_prepare() function
> which is mostly carried over from migrate_device.c's
> migrate_vma_collect_pmd() function.
>
> Also implement the migrate_vma_split_folio(), for splitting
> pte mapped large folios. It is also mostly from migrate_device.c,
> with care taken to reference folio before relasing page table
> lock.
Typo - releasing
>
> With HMM pagewalk based migration, the idea is that
> hmm_vma_handle_*() are responsible for faulting,
> and the pfn collecting part. hmm_vma_handle_migrate_prepare*()
> do the migration decisions (with HMM_PFN_MIGRATE), possibly split
> folios, and insert migration ptes/pmds.
>
> HMM pagewalk based migration is enabled in later commit, for now
> now hmm_select_migrate() returns 0.
>
now now -> now
> Cc: David Hildenbrand <david@kernel.org>
> Cc: Jason Gunthorpe <jgg@nvidia.com>
> Cc: Leon Romanovsky <leonro@nvidia.com>
> Cc: Alistair Popple <apopple@nvidia.com>
> Cc: Balbir Singh <balbirs@nvidia.com>
> Cc: Zi Yan <ziy@nvidia.com>
> Cc: Matthew Brost <matthew.brost@intel.com>
> Suggested-by: Alistair Popple <apopple@nvidia.com>
> Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
> ---
> mm/hmm.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 262 insertions(+), 1 deletion(-)
>
> diff --git a/mm/hmm.c b/mm/hmm.c
> index 119e70dbca56..0ce947d0e572 100644
> --- a/mm/hmm.c
> +++ b/mm/hmm.c
> @@ -491,6 +491,63 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
> #endif /* CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
>
> #ifdef CONFIG_DEVICE_MIGRATION
> +/**
> + * migrate_vma_split_folio() - Helper function to split a THP folio
> + * @folio: the folio to split
> + * @fault_page: struct page associated with the fault if any
> + * @hmm_vma_walk: walk in progress
> + * @ptep: pte_t * for unmap and unlock ptl
> + *
> + * Returns 0 on success
and drops the pte_lock associated with the pte
> + */
> +static int migrate_vma_split_folio(struct folio *folio,
> + struct page *fault_page,
> + struct hmm_vma_walk *hmm_vma_walk,
> + pte_t *ptep)
> +{
> + int ret;
> + struct folio *fault_folio = fault_page ? page_folio(fault_page) : NULL;
> + struct folio *new_fault_folio = NULL;
> +
> + if (folio != fault_folio)
> + folio_get(folio);
> +
> + pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
> + hmm_vma_walk->ptelocked = false;
> +
> + if (folio != fault_folio)
> + folio_lock(folio);
> +
Could you add a comment on why the get and lock is split into separate steps
with the pte lock dropped in between
> + ret = split_folio(folio);
> + if (ret) {
> + if (folio != fault_folio) {
> + folio_unlock(folio);
> + folio_put(folio);
> + }
> + return ret;
> + }
> +
> + new_fault_folio = fault_page ? page_folio(fault_page) : NULL;
> +
> + /*
> + * Ensure the lock is held on the correct
> + * folio after the split
> + */
> + if (!new_fault_folio) {
> + folio_unlock(folio);
> + folio_put(folio);
> + } else if (folio != new_fault_folio) {
> + if (new_fault_folio != fault_folio) {
> + folio_get(new_fault_folio);
> + folio_lock(new_fault_folio);
> + }
> + folio_unlock(folio);
> + folio_put(folio);
> + }
> +
> + return 0;
> +}
> +
> static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
> pmd_t *pmdp,
> unsigned long start,
> @@ -501,6 +558,11 @@ static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
> return 0;
> }
>
> +/*
> + * Install migration entries if migration requested, either from fault
> + * or migrate paths.
> + *
> + */
> static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
> pmd_t *pmdp,
> pte_t *ptep,
> @@ -508,8 +570,207 @@ static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
> unsigned long *hmm_pfn,
> bool *unmapped)
> {
> - // TODO: implement migration entry insertion
> + struct hmm_vma_walk *hmm_vma_walk = walk->private;
> + struct hmm_range *range = hmm_vma_walk->range;
> + struct migrate_vma *migrate = range->migrate;
> + struct mm_struct *mm = walk->vma->vm_mm;
> + struct folio *fault_folio = NULL;
> + enum migrate_vma_info minfo;
> + struct dev_pagemap *pgmap;
> + bool anon_exclusive;
> + struct folio *folio;
> + unsigned long pfn;
> + struct page *page;
> + softleaf_t entry;
> + pte_t pte, swp_pte;
> + bool writable = false;
> +
> + // Do we want to migrate at all?
> + minfo = hmm_select_migrate(range);
> + if (!minfo)
> + return 0;
> +
> + WARN_ON_ONCE(!migrate);
> + HMM_ASSERT_PTE_LOCKED(hmm_vma_walk, true);
> +
> + fault_folio = migrate->fault_page ?
> + page_folio(migrate->fault_page) : NULL;
> +
> + pte = ptep_get(ptep);
> +
> + if (pte_none(pte)) {
> + if (vma_is_anonymous(walk->vma)) {
> + *hmm_pfn &= HMM_PFN_INOUT_FLAGS;
> + *hmm_pfn |= HMM_PFN_MIGRATE;
> + goto out;
> + }
> + }
> +
> + if (!(hmm_pfn[0] & HMM_PFN_VALID))
> + goto out;
> +
We use *hmm_pfn and then hmm_pfn[0], could we be consistent. Based on this I
assuming that there is just one entry in hmm_pfn?
> + if (!pte_present(pte)) {
> + /*
> + * Only care about unaddressable device page special
> + * page table entry. Other special swap entries are not
> + * migratable, and we ignore regular swapped page.
> + */
> + entry = softleaf_from_pte(pte);
> + if (!softleaf_is_device_private(entry))
> + goto out;
> +
> + if (!(minfo & MIGRATE_VMA_SELECT_DEVICE_PRIVATE))
> + goto out;
> +
> + page = softleaf_to_page(entry);
> + folio = page_folio(page);
> + if (folio->pgmap->owner != migrate->pgmap_owner)
> + goto out;
> +
> + if (folio_test_large(folio)) {
> + int ret;
> +
> + ret = migrate_vma_split_folio(folio,
> + migrate->fault_page,
> + hmm_vma_walk,
> + ptep);
> + if (ret)
> + goto out_error;
> + return -EAGAIN;
> + }
> +
> + pfn = page_to_pfn(page);
> + if (softleaf_is_device_private_write(entry))
> + writable = true;
> + } else {
> + pfn = pte_pfn(pte);
> + if (is_zero_pfn(pfn) &&
> + (minfo & MIGRATE_VMA_SELECT_SYSTEM)) {
> + *hmm_pfn = HMM_PFN_MIGRATE;
> + goto out;
> + }
> + page = vm_normal_page(walk->vma, addr, pte);
> + if (page && !is_zone_device_page(page) &&
> + !(minfo & MIGRATE_VMA_SELECT_SYSTEM)) {
> + goto out;
> + } else if (page && is_device_coherent_page(page)) {
> + pgmap = page_pgmap(page);
> +
> + if (!(minfo &
> + MIGRATE_VMA_SELECT_DEVICE_COHERENT) ||
> + pgmap->owner != migrate->pgmap_owner)
> + goto out;
> + }
> +
> + folio = page ? page_folio(page) : NULL;
> + if (folio && folio_test_large(folio)) {
> + int ret;
> +
> + ret = migrate_vma_split_folio(folio,
> + migrate->fault_page,
> + hmm_vma_walk,
> + ptep);
> + if (ret)
> + goto out_error;
> + return -EAGAIN;
> + }
> +
> + writable = pte_write(pte);
> + }
> +
> + if (!page || !page->mapping)
> + goto out;
> +
> + /*
> + * By getting a reference on the folio we pin it and that blocks
> + * any kind of migration. Side effect is that it "freezes" the
> + * pte.
> + *
> + * We drop this reference after isolating the folio from the lru
> + * for non device folio (device folio are not on the lru and thus
> + * can't be dropped from it).
> + */
> + folio = page_folio(page);
> + folio_get(folio);
> +
> + /*
> + * We rely on folio_trylock() to avoid deadlock between
> + * concurrent migrations where each is waiting on the others
> + * folio lock. If we can't immediately lock the folio we fail this
> + * migration as it is only best effort anyway.
> + *
> + * If we can lock the folio it's safe to set up a migration entry
> + * now. In the common case where the folio is mapped once in a
> + * single process setting up the migration entry now is an
> + * optimisation to avoid walking the rmap later with
> + * try_to_migrate().
> + */
> +
> + if (fault_folio == folio || folio_trylock(folio)) {
> + anon_exclusive = folio_test_anon(folio) &&
> + PageAnonExclusive(page);
> +
> + if (pte_present(pte))
> + flush_cache_page(walk->vma, addr, pfn);
> +
> + if (anon_exclusive) {
> + pte = ptep_clear_flush(walk->vma, addr, ptep);
> +
> + if (folio_try_share_anon_rmap_pte(folio, page)) {
> + set_pte_at(mm, addr, ptep, pte);
> + if (fault_folio != folio)
> + folio_unlock(folio);
> + folio_put(folio);
> + goto out;
> + }
> + } else {
> + pte = ptep_get_and_clear(mm, addr, ptep);
> + }
> +
> + if (pte_present(pte) && pte_dirty(pte))
> + folio_mark_dirty(folio);
> +
> + /* Setup special migration page table entry */
> + if (writable)
> + entry = make_writable_migration_entry(pfn);
> + else if (anon_exclusive)
> + entry = make_readable_exclusive_migration_entry(pfn);
> + else
> + entry = make_readable_migration_entry(pfn);
> +
> + if (pte_present(pte)) {
> + if (pte_young(pte))
> + entry = make_migration_entry_young(entry);
> + if (pte_dirty(pte))
> + entry = make_migration_entry_dirty(entry);
> + }
> +
> + swp_pte = swp_entry_to_pte(entry);
> + if (pte_present(pte)) {
> + if (pte_soft_dirty(pte))
> + swp_pte = pte_swp_mksoft_dirty(swp_pte);
> + if (pte_uffd(pte))
> + swp_pte = pte_swp_mkuffd(swp_pte);
> + } else {
> + if (pte_swp_soft_dirty(pte))
> + swp_pte = pte_swp_mksoft_dirty(swp_pte);
> + if (pte_swp_uffd(pte))
> + swp_pte = pte_swp_mkuffd(swp_pte);
> + }
> +
> + set_pte_at(mm, addr, ptep, swp_pte);
> + folio_remove_rmap_pte(folio, page, walk->vma);
> + folio_put(folio);
> + *hmm_pfn |= HMM_PFN_MIGRATE;
> + if (pte_present(pte))
> + *unmapped = true;
> + } else {
> + folio_put(folio);
> + }
> +out:
> return 0;
> +out_error:
> + return -EFAULT;
> }
>
> #else
Thanks,
Balbir
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v16 05/12] mm/hmm: migrate collection in HMM pagewalk - pte level
2026-10-21 6:56 ` Balbir Singh
@ 2026-10-21 7:09 ` Mika Penttilä
0 siblings, 0 replies; 33+ messages in thread
From: Mika Penttilä @ 2026-10-21 7:09 UTC (permalink / raw)
To: Balbir Singh, linux-mm
Cc: dri-devel, intel-xe, linux-kernel, David Hildenbrand,
Jason Gunthorpe, Leon Romanovsky, Alistair Popple, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
On 10/21/26 09:56, Balbir Singh wrote:
> On 10/21/26 5:04 PM, mpenttil@redhat.com wrote:
>> From: Mika Penttilä <mpenttil@redhat.com>
>>
>> Implement the needed hmm_vma_handle_migrate_prepare() function
>> which is mostly carried over from migrate_device.c's
>> migrate_vma_collect_pmd() function.
>>
>> Also implement the migrate_vma_split_folio(), for splitting
>> pte mapped large folios. It is also mostly from migrate_device.c,
>> with care taken to reference folio before relasing page table
>> lock.
> Typo - releasing
ack
>
>> With HMM pagewalk based migration, the idea is that
>> hmm_vma_handle_*() are responsible for faulting,
>> and the pfn collecting part. hmm_vma_handle_migrate_prepare*()
>> do the migration decisions (with HMM_PFN_MIGRATE), possibly split
>> folios, and insert migration ptes/pmds.
>>
>> HMM pagewalk based migration is enabled in later commit, for now
>> now hmm_select_migrate() returns 0.
>>
> now now -> now
thanks
>
>> Cc: David Hildenbrand <david@kernel.org>
>> Cc: Jason Gunthorpe <jgg@nvidia.com>
>> Cc: Leon Romanovsky <leonro@nvidia.com>
>> Cc: Alistair Popple <apopple@nvidia.com>
>> Cc: Balbir Singh <balbirs@nvidia.com>
>> Cc: Zi Yan <ziy@nvidia.com>
>> Cc: Matthew Brost <matthew.brost@intel.com>
>> Suggested-by: Alistair Popple <apopple@nvidia.com>
>> Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
>> ---
>> mm/hmm.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 262 insertions(+), 1 deletion(-)
>>
>> diff --git a/mm/hmm.c b/mm/hmm.c
>> index 119e70dbca56..0ce947d0e572 100644
>> --- a/mm/hmm.c
>> +++ b/mm/hmm.c
>> @@ -491,6 +491,63 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
>> #endif /* CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
>>
>> #ifdef CONFIG_DEVICE_MIGRATION
>> +/**
>> + * migrate_vma_split_folio() - Helper function to split a THP folio
>> + * @folio: the folio to split
>> + * @fault_page: struct page associated with the fault if any
>> + * @hmm_vma_walk: walk in progress
>> + * @ptep: pte_t * for unmap and unlock ptl
>> + *
>> + * Returns 0 on success
> and drops the pte_lock associated with the pte
agreed
>
>> + */
>> +static int migrate_vma_split_folio(struct folio *folio,
>> + struct page *fault_page,
>> + struct hmm_vma_walk *hmm_vma_walk,
>> + pte_t *ptep)
>> +{
>> + int ret;
>> + struct folio *fault_folio = fault_page ? page_folio(fault_page) : NULL;
>> + struct folio *new_fault_folio = NULL;
>> +
>> + if (folio != fault_folio)
>> + folio_get(folio);
>> +
>> + pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
>> + hmm_vma_walk->ptelocked = false;
>> +
>> + if (folio != fault_folio)
>> + folio_lock(folio);
>> +
> Could you add a comment on why the get and lock is split into separate steps
> with the pte lock dropped in between
yes will add
>> + ret = split_folio(folio);
>> + if (ret) {
>> + if (folio != fault_folio) {
>> + folio_unlock(folio);
>> + folio_put(folio);
>> + }
>> + return ret;
>> + }
>> +
>> + new_fault_folio = fault_page ? page_folio(fault_page) : NULL;
>> +
>> + /*
>> + * Ensure the lock is held on the correct
>> + * folio after the split
>> + */
>> + if (!new_fault_folio) {
>> + folio_unlock(folio);
>> + folio_put(folio);
>> + } else if (folio != new_fault_folio) {
>> + if (new_fault_folio != fault_folio) {
>> + folio_get(new_fault_folio);
>> + folio_lock(new_fault_folio);
>> + }
>> + folio_unlock(folio);
>> + folio_put(folio);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
>> pmd_t *pmdp,
>> unsigned long start,
>> @@ -501,6 +558,11 @@ static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
>> return 0;
>> }
>>
>> +/*
>> + * Install migration entries if migration requested, either from fault
>> + * or migrate paths.
>> + *
>> + */
>> static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
>> pmd_t *pmdp,
>> pte_t *ptep,
>> @@ -508,8 +570,207 @@ static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
>> unsigned long *hmm_pfn,
>> bool *unmapped)
>> {
>> - // TODO: implement migration entry insertion
>> + struct hmm_vma_walk *hmm_vma_walk = walk->private;
>> + struct hmm_range *range = hmm_vma_walk->range;
>> + struct migrate_vma *migrate = range->migrate;
>> + struct mm_struct *mm = walk->vma->vm_mm;
>> + struct folio *fault_folio = NULL;
>> + enum migrate_vma_info minfo;
>> + struct dev_pagemap *pgmap;
>> + bool anon_exclusive;
>> + struct folio *folio;
>> + unsigned long pfn;
>> + struct page *page;
>> + softleaf_t entry;
>> + pte_t pte, swp_pte;
>> + bool writable = false;
>> +
>> + // Do we want to migrate at all?
>> + minfo = hmm_select_migrate(range);
>> + if (!minfo)
>> + return 0;
>> +
>> + WARN_ON_ONCE(!migrate);
>> + HMM_ASSERT_PTE_LOCKED(hmm_vma_walk, true);
>> +
>> + fault_folio = migrate->fault_page ?
>> + page_folio(migrate->fault_page) : NULL;
>> +
>> + pte = ptep_get(ptep);
>> +
>> + if (pte_none(pte)) {
>> + if (vma_is_anonymous(walk->vma)) {
>> + *hmm_pfn &= HMM_PFN_INOUT_FLAGS;
>> + *hmm_pfn |= HMM_PFN_MIGRATE;
>> + goto out;
>> + }
>> + }
>> +
>> + if (!(hmm_pfn[0] & HMM_PFN_VALID))
>> + goto out;
>> +
> We use *hmm_pfn and then hmm_pfn[0], could we be consistent. Based on this I
> assuming that there is just one entry in hmm_pfn?
yes
>
>> + if (!pte_present(pte)) {
>> + /*
>> + * Only care about unaddressable device page special
>> + * page table entry. Other special swap entries are not
>> + * migratable, and we ignore regular swapped page.
>> + */
>> + entry = softleaf_from_pte(pte);
>> + if (!softleaf_is_device_private(entry))
>> + goto out;
>> +
>> + if (!(minfo & MIGRATE_VMA_SELECT_DEVICE_PRIVATE))
>> + goto out;
>> +
>> + page = softleaf_to_page(entry);
>> + folio = page_folio(page);
>> + if (folio->pgmap->owner != migrate->pgmap_owner)
>> + goto out;
>> +
>> + if (folio_test_large(folio)) {
>> + int ret;
>> +
>> + ret = migrate_vma_split_folio(folio,
>> + migrate->fault_page,
>> + hmm_vma_walk,
>> + ptep);
>> + if (ret)
>> + goto out_error;
>> + return -EAGAIN;
>> + }
>> +
>> + pfn = page_to_pfn(page);
>> + if (softleaf_is_device_private_write(entry))
>> + writable = true;
>> + } else {
>> + pfn = pte_pfn(pte);
>> + if (is_zero_pfn(pfn) &&
>> + (minfo & MIGRATE_VMA_SELECT_SYSTEM)) {
>> + *hmm_pfn = HMM_PFN_MIGRATE;
>> + goto out;
>> + }
>> + page = vm_normal_page(walk->vma, addr, pte);
>> + if (page && !is_zone_device_page(page) &&
>> + !(minfo & MIGRATE_VMA_SELECT_SYSTEM)) {
>> + goto out;
>> + } else if (page && is_device_coherent_page(page)) {
>> + pgmap = page_pgmap(page);
>> +
>> + if (!(minfo &
>> + MIGRATE_VMA_SELECT_DEVICE_COHERENT) ||
>> + pgmap->owner != migrate->pgmap_owner)
>> + goto out;
>> + }
>> +
>> + folio = page ? page_folio(page) : NULL;
>> + if (folio && folio_test_large(folio)) {
>> + int ret;
>> +
>> + ret = migrate_vma_split_folio(folio,
>> + migrate->fault_page,
>> + hmm_vma_walk,
>> + ptep);
>> + if (ret)
>> + goto out_error;
>> + return -EAGAIN;
>> + }
>> +
>> + writable = pte_write(pte);
>> + }
>> +
>> + if (!page || !page->mapping)
>> + goto out;
>> +
>> + /*
>> + * By getting a reference on the folio we pin it and that blocks
>> + * any kind of migration. Side effect is that it "freezes" the
>> + * pte.
>> + *
>> + * We drop this reference after isolating the folio from the lru
>> + * for non device folio (device folio are not on the lru and thus
>> + * can't be dropped from it).
>> + */
>> + folio = page_folio(page);
>> + folio_get(folio);
>> +
>> + /*
>> + * We rely on folio_trylock() to avoid deadlock between
>> + * concurrent migrations where each is waiting on the others
>> + * folio lock. If we can't immediately lock the folio we fail this
>> + * migration as it is only best effort anyway.
>> + *
>> + * If we can lock the folio it's safe to set up a migration entry
>> + * now. In the common case where the folio is mapped once in a
>> + * single process setting up the migration entry now is an
>> + * optimisation to avoid walking the rmap later with
>> + * try_to_migrate().
>> + */
>> +
>> + if (fault_folio == folio || folio_trylock(folio)) {
>> + anon_exclusive = folio_test_anon(folio) &&
>> + PageAnonExclusive(page);
>> +
>> + if (pte_present(pte))
>> + flush_cache_page(walk->vma, addr, pfn);
>> +
>> + if (anon_exclusive) {
>> + pte = ptep_clear_flush(walk->vma, addr, ptep);
>> +
>> + if (folio_try_share_anon_rmap_pte(folio, page)) {
>> + set_pte_at(mm, addr, ptep, pte);
>> + if (fault_folio != folio)
>> + folio_unlock(folio);
>> + folio_put(folio);
>> + goto out;
>> + }
>> + } else {
>> + pte = ptep_get_and_clear(mm, addr, ptep);
>> + }
>> +
>> + if (pte_present(pte) && pte_dirty(pte))
>> + folio_mark_dirty(folio);
>> +
>> + /* Setup special migration page table entry */
>> + if (writable)
>> + entry = make_writable_migration_entry(pfn);
>> + else if (anon_exclusive)
>> + entry = make_readable_exclusive_migration_entry(pfn);
>> + else
>> + entry = make_readable_migration_entry(pfn);
>> +
>> + if (pte_present(pte)) {
>> + if (pte_young(pte))
>> + entry = make_migration_entry_young(entry);
>> + if (pte_dirty(pte))
>> + entry = make_migration_entry_dirty(entry);
>> + }
>> +
>> + swp_pte = swp_entry_to_pte(entry);
>> + if (pte_present(pte)) {
>> + if (pte_soft_dirty(pte))
>> + swp_pte = pte_swp_mksoft_dirty(swp_pte);
>> + if (pte_uffd(pte))
>> + swp_pte = pte_swp_mkuffd(swp_pte);
>> + } else {
>> + if (pte_swp_soft_dirty(pte))
>> + swp_pte = pte_swp_mksoft_dirty(swp_pte);
>> + if (pte_swp_uffd(pte))
>> + swp_pte = pte_swp_mkuffd(swp_pte);
>> + }
>> +
>> + set_pte_at(mm, addr, ptep, swp_pte);
>> + folio_remove_rmap_pte(folio, page, walk->vma);
>> + folio_put(folio);
>> + *hmm_pfn |= HMM_PFN_MIGRATE;
>> + if (pte_present(pte))
>> + *unmapped = true;
>> + } else {
>> + folio_put(folio);
>> + }
>> +out:
>> return 0;
>> +out_error:
>> + return -EFAULT;
>> }
>>
>> #else
> Thanks,
> Balbir
Thanks Balbir!
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v16 05/12] mm/hmm: migrate collection in HMM pagewalk - pte level
2026-10-21 6:04 ` [PATCH v16 05/12] mm/hmm: migrate collection in HMM pagewalk - pte level mpenttil
2026-10-21 6:56 ` Balbir Singh
@ 2026-10-22 6:06 ` sashiko-bot
1 sibling, 0 replies; 33+ messages in thread
From: sashiko-bot @ 2026-10-22 6:06 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, David Hildenbrand, Jason Gunthorpe,
Leon Romanovsky, Alistair Popple, Balbir Singh, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [Critical] mm/hmm: folio locks held across handle_mm_fault() and broken migration PTE rollback
- [High] mm/hmm: folio split failure in hmm_vma_handle_migrate_prepare() aborts PMD walk
- [High] mm/hmm: hmm_vma_handle_migrate_prepare() skips pte_protnone() and unowned PTEs
- [High] mm/hmm: blocking folio_lock() after folio_get() in migrate_vma_split_folio()
- [High] mm/hmm: UAF and lock drop on tail fault_page in migrate_vma_split_folio()
- [Medium] mm/hmm: fix zero pfn handling in hmm_vma_handle_migrate_prepare()
--
commit 16c2ec58848b6b4b76d718d33377a04eaa06ff45
Author: Mika Penttilä <mpenttil@redhat.com>
mm/hmm: migrate collection in HMM pagewalk - pte level
This commit implements migrate_vma_split_folio() and
hmm_vma_handle_migrate_prepare() in mm/hmm.c to split large folios and
install migration page table entries during pagewalk-based device
migration.
> diff --git a/mm/hmm.c b/mm/hmm.c
> index 119e70dbca56f..0ce947d0e5727 100644
> --- a/mm/hmm.c
> +++ b/mm/hmm.c
> @@ -491,6 +491,63 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
> #endif /* CONFIG_ARCH_HAS_PMD_SOFTLEAVES */
>
> #ifdef CONFIG_DEVICE_MIGRATION
> +/**
> + * migrate_vma_split_folio() - Helper function to split a THP folio
> + * @folio: the folio to split
> + * @fault_page: struct page associated with the fault if any
> + * @hmm_vma_walk: walk in progress
> + * @ptep: pte_t * for unmap and unlock ptl
> + *
> + * Returns 0 on success
> + */
> +static int migrate_vma_split_folio(struct folio *folio,
> + struct page *fault_page,
> + struct hmm_vma_walk *hmm_vma_walk,
> + pte_t *ptep)
> +{
> + int ret;
> + struct folio *fault_folio = fault_page ? page_folio(fault_page) : NULL;
> + struct folio *new_fault_folio = NULL;
> +
> + if (folio != fault_folio)
> + folio_get(folio);
> +
> + pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
> + hmm_vma_walk->ptelocked = false;
> +
> + if (folio != fault_folio)
> + folio_lock(folio);
> +
> + ret = split_folio(folio);
[Severity: High]
When hmm_range_fault() -> hmm_vma_walk_pmd() ->
hmm_vma_handle_migrate_prepare() calls migrate_vma_split_folio() on a large
system or device-private folio with folio != fault_folio,
migrate_vma_split_folio() takes a reference via folio_get(folio), drops the
page table lock with pte_unmap_unlock(ptep, hmm_vma_walk->ptl), and then
blocks on folio_lock(folio) before calling split_folio(folio).
Does this sequence introduce three regressions?
First, when concurrent tasks attempt to split or migrate the same large
folio, any task blocked in folio_lock(folio) holds an extra reference on
folio, causing the lock holder's split_folio() -> __folio_split() reference
count freeze check to fail with -EAGAIN (which
hmm_vma_handle_migrate_prepare() converts into -EFAULT).
Second, because the page table lock is dropped before folio_lock(folio) is
acquired, another thread can finish splitting folio and release the folio
lock before folio_lock(folio) returns. Calling split_folio(folio) without
re-checking folio_test_large(folio) under the folio lock will trigger
VM_WARN_ON_ONCE_FOLIO(!folio_test_large(folio), folio) in __folio_split()
and fail with -EINVAL.
Third, earlier iterations of the page table walk in hmm_vma_walk_pmd() lock
collected folios via folio_trylock() and replace their page table entries
with migration entries (and fault_folio is also held locked when
migrate->fault_page is set). Blocking unconditionally on folio_lock(folio)
while holding locks and active migration entries on previously collected
folios violates the trylock-only requirement documented in
hmm_vma_handle_migrate_prepare() and can deadlock against concurrent
migrations or tasks waiting in migration_entry_wait().
> + if (ret) {
> + if (folio != fault_folio) {
> + folio_unlock(folio);
> + folio_put(folio);
> + }
> + return ret;
> + }
> +
> + new_fault_folio = fault_page ? page_folio(fault_page) : NULL;
> +
> + /*
> + * Ensure the lock is held on the correct
> + * folio after the split
> + */
> + if (!new_fault_folio) {
> + folio_unlock(folio);
> + folio_put(folio);
> + } else if (folio != new_fault_folio) {
> + if (new_fault_folio != fault_folio) {
> + folio_get(new_fault_folio);
> + folio_lock(new_fault_folio);
> + }
> + folio_unlock(folio);
> + folio_put(folio);
> + }
[Severity: High]
Can this trigger a use-after-free when fault_page is a tail subpage of a
large device-private folio?
In mm/memory.c:do_swap_page(), when a page fault hits a device-private
entry mapping a tail subpage (vmf->page), do_swap_page() locks and takes a
single reference on folio = page_folio(vmf->page), drops vmf->ptl, and
calls pgmap->ops->migrate_to_ram(vmf) with migrate->fault_page = vmf->page:
mm/memory.c:do_swap_page() {
...
folio = page_folio(vmf->page);
if (folio_trylock(folio)) {
struct dev_pagemap *pgmap;
folio_get(folio);
pte_unmap_unlock(vmf->pte, vmf->ptl);
pgmap = page_pgmap(vmf->page);
ret = pgmap->ops->migrate_to_ram(vmf);
/* migrate_to_ram() might have split the folio. */
folio = page_folio(vmf->page);
folio_unlock(folio);
folio_put(folio);
...
}
In migrate_vma_split_folio(), fault_folio = page_folio(fault_page) equals
folio on entry. Calling split_folio(folio) passes lock_at = &folio->page
instead of fault_page (unlike split_huge_page(fault_page)) to
mm/huge_memory.c:__folio_split():
mm/huge_memory.c:__folio_split() {
...
for (new_folio = folio; new_folio != end_folio; new_folio = next) {
next = folio_next(new_folio);
if (new_folio == page_folio(lock_at))
continue;
...
if (is_swapcache && !folio_mapped(new_folio))
folio_free_swap(new_folio);
folio_unlock(new_folio);
folio_put(new_folio);
}
}
Because lock_at is &folio->page (subpage 0), __folio_split() unlocks and
calls folio_put() on every other subfolio resulting from the split,
including new_fault_folio = page_folio(fault_page). If fault_page's page
table entry was concurrently zapped (for instance via MADV_DONTNEED after
do_swap_page() dropped vmf->ptl or right after __folio_split() unlocked
new_fault_folio), new_fault_folio has no remaining references and is freed
before split_folio(folio) returns.
Won't migrate_vma_split_folio() then call folio_get(new_fault_folio) and
folio_lock(new_fault_folio) on the unpinned and freed new_fault_folio
(hitting VM_BUG_ON_FOLIO(folio_ref_zero_or_close_to_overflow(folio), folio)
or a use-after-free) while also holding two order-0 folio locks at once?
> +
> + return 0;
> +}
> +
> static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
> pmd_t *pmdp,
> unsigned long start,
> @@ -501,6 +558,11 @@ static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
> return 0;
> }
>
> +/*
> + * Install migration entries if migration requested, either from fault
> + * or migrate paths.
> + *
> + */
> static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
> pmd_t *pmdp,
> pte_t *ptep,
> @@ -508,8 +570,207 @@ static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
> unsigned long *hmm_pfn,
> bool *unmapped)
> {
> - // TODO: implement migration entry insertion
> + struct hmm_vma_walk *hmm_vma_walk = walk->private;
> + struct hmm_range *range = hmm_vma_walk->range;
> + struct migrate_vma *migrate = range->migrate;
> + struct mm_struct *mm = walk->vma->vm_mm;
> + struct folio *fault_folio = NULL;
> + enum migrate_vma_info minfo;
> + struct dev_pagemap *pgmap;
> + bool anon_exclusive;
> + struct folio *folio;
> + unsigned long pfn;
> + struct page *page;
> + softleaf_t entry;
> + pte_t pte, swp_pte;
> + bool writable = false;
> +
> + // Do we want to migrate at all?
> + minfo = hmm_select_migrate(range);
> + if (!minfo)
> + return 0;
> +
> + WARN_ON_ONCE(!migrate);
> + HMM_ASSERT_PTE_LOCKED(hmm_vma_walk, true);
> +
> + fault_folio = migrate->fault_page ?
> + page_folio(migrate->fault_page) : NULL;
> +
> + pte = ptep_get(ptep);
> +
> + if (pte_none(pte)) {
> + if (vma_is_anonymous(walk->vma)) {
> + *hmm_pfn &= HMM_PFN_INOUT_FLAGS;
> + *hmm_pfn |= HMM_PFN_MIGRATE;
> + goto out;
> + }
> + }
> +
> + if (!(hmm_pfn[0] & HMM_PFN_VALID))
> + goto out;
> +
> + if (!pte_present(pte)) {
> + /*
> + * Only care about unaddressable device page special
> + * page table entry. Other special swap entries are not
> + * migratable, and we ignore regular swapped page.
> + */
> + entry = softleaf_from_pte(pte);
> + if (!softleaf_is_device_private(entry))
> + goto out;
> +
> + if (!(minfo & MIGRATE_VMA_SELECT_DEVICE_PRIVATE))
> + goto out;
> +
> + page = softleaf_to_page(entry);
> + folio = page_folio(page);
> + if (folio->pgmap->owner != migrate->pgmap_owner)
> + goto out;
[Severity: High]
Does gating hmm_vma_handle_migrate_prepare() on HMM_PFN_VALID cause
hmm_range_fault() to skip pte_protnone() pages and unowned device-private
entries?
When migrate_vma_setup() is switched to hmm_range_fault() in the later
commit "mm: enable device page migration from HMM pagewalk", existing
callers (drm_pagemap_migrate_to_devmem(), svm_migrate_ram_to_vram(),
nouveau_dmem_migrate_vma(), and dmirror_migrate_to_device()) do not set
MIGRATE_VMA_FAULT, so range.default_flags is HMM_PFN_REQ_MIGRATE without
HMM_PFN_REQ_FAULT.
In hmm_vma_walk_pmd() -> hmm_vma_handle_pte(), when a present entry has
pte_protnone(pte) set (for example by task_numa_work() ->
change_prot_numa() or userfaultfd), pte_to_hmm_pfn_flags() returns 0:
mm/hmm.c:pte_to_hmm_pfn_flags() {
if (pte_none(pte) || !pte_present(pte) || pte_protnone(pte))
return 0;
return pte_write(pte) ? (HMM_PFN_VALID | HMM_PFN_WRITE) : HMM_PFN_VALID;
}
Because hmm_pte_need_fault() also returns 0 when HMM_PFN_REQ_FAULT is not
set, hmm_vma_handle_pte() writes pte_pfn(pte) without HMM_PFN_VALID into
*hmm_pfn. Then hmm_vma_handle_migrate_prepare() checks
!(hmm_pfn[0] & HMM_PFN_VALID) and skips the page, whereas
migrate_vma_collect_pmd() previously collected all present normal pages
regardless of pte_protnone(pte) (and migrate_hmm_range_setup() and
hmm_pfn_collected() also require HMM_PFN_VALID to distinguish a collected
page from a zero page). This causes full-range migrations such as
drm_pagemap_migrate_to_devmem() to fail with -EBUSY and partial migrations
in amdkfd and nouveau to leave pages behind in system memory.
Similarly, for non-present device-private entries, hmm_vma_handle_pte()
only sets HMM_PFN_VALID when page_pgmap(softleaf_to_page(entry))->owner
matches range->dev_private_owner (and faults a read-only device-private
entry to system memory if HMM_PFN_REQ_FAULT | HMM_PFN_REQ_WRITE is set):
mm/hmm.c:hmm_vma_handle_pte() {
...
if (softleaf_is_device_private(entry) &&
page_pgmap(softleaf_to_page(entry))->owner ==
range->dev_private_owner) {
cpu_flags = HMM_PFN_VALID;
if (softleaf_is_device_private_write(entry))
cpu_flags |= HMM_PFN_WRITE;
new_pfn_flags = softleaf_to_pfn(entry) | cpu_flags;
goto out;
}
}
Doesn't that make the !pte_present(pte) device-private migration path here
unreachable unless range->dev_private_owner is also set to
migrate->pgmap_owner?
> +
> + if (folio_test_large(folio)) {
> + int ret;
> +
> + ret = migrate_vma_split_folio(folio,
> + migrate->fault_page,
> + hmm_vma_walk,
> + ptep);
> + if (ret)
> + goto out_error;
> + return -EAGAIN;
> + }
> +
> + pfn = page_to_pfn(page);
> + if (softleaf_is_device_private_write(entry))
> + writable = true;
> + } else {
> + pfn = pte_pfn(pte);
> + if (is_zero_pfn(pfn) &&
> + (minfo & MIGRATE_VMA_SELECT_SYSTEM)) {
> + *hmm_pfn = HMM_PFN_MIGRATE;
> + goto out;
> + }
[Severity: Medium]
When is_zero_pfn(pfn) && (minfo & MIGRATE_VMA_SELECT_SYSTEM) is true,
hmm_vma_handle_pte() has already set:
*hmm_pfn = (*hmm_pfn & HMM_PFN_INOUT_FLAGS) | pte_pfn(pte) | HMM_PFN_VALID;
Unlike the pte_none(pte) branch above (which preserves HMM_PFN_INOUT_FLAGS
and checks vma_is_anonymous(walk->vma)) and hmm_pfns_fill() (used for
pmd_none and is_huge_zero_folio() in the later commit "mm/hmm: migrate
collection in HMM pagewalk - pmd level"), assigning *hmm_pfn =
HMM_PFN_MIGRATE directly wipes out sticky HMM_PFN_INOUT_FLAGS
(HMM_PFN_DMA_MAPPED | HMM_PFN_P2PDMA | HMM_PFN_P2PDMA_BUS).
It also omits the vma_is_anonymous(walk->vma) check, even though
mm/migrate_device.c:migrate_vma_insert_page() refuses to populate
non-anonymous mappings:
mm/migrate_device.c:migrate_vma_insert_page() {
/* Only allow populating anonymous memory */
if (!vma_is_anonymous(vma))
goto abort;
}
If a non-anonymous mapping maps a zero page (for example via ksm zero-page
merging in a private file mapping or dax_load_hole()), won't setting
*hmm_pfn = HMM_PFN_MIGRATE cause migrate_hmm_range_setup() to set
migrate->src[i] = MIGRATE_PFN_MIGRATE and increment migrate->cpages for a
page that migrate_vma_insert_page() will reject, while also losing the
valid zero-page pfn and HMM_PFN_VALID in range->hmm_pfns for callers like
nouveau_dmem_migrate_fault() that fall back to mapping in place?
> + page = vm_normal_page(walk->vma, addr, pte);
> + if (page && !is_zone_device_page(page) &&
> + !(minfo & MIGRATE_VMA_SELECT_SYSTEM)) {
> + goto out;
> + } else if (page && is_device_coherent_page(page)) {
> + pgmap = page_pgmap(page);
> +
> + if (!(minfo &
> + MIGRATE_VMA_SELECT_DEVICE_COHERENT) ||
> + pgmap->owner != migrate->pgmap_owner)
> + goto out;
> + }
> +
> + folio = page ? page_folio(page) : NULL;
> + if (folio && folio_test_large(folio)) {
> + int ret;
> +
> + ret = migrate_vma_split_folio(folio,
> + migrate->fault_page,
> + hmm_vma_walk,
> + ptep);
> + if (ret)
> + goto out_error;
> + return -EAGAIN;
> + }
[Severity: High]
When migrate_vma_split_folio() fails (both here and in the !pte_present(pte)
branch above), hmm_vma_handle_migrate_prepare() jumps to out_error and
returns -EFAULT.
In hmm_vma_walk_pmd(), any non-zero, non--EAGAIN return from
hmm_vma_handle_migrate_prepare() fills [addr, end) with HMM_PFN_ERROR and
aborts the loop while returning 0:
mm/hmm.c:hmm_vma_walk_pmd() {
...
r = hmm_vma_handle_migrate_prepare(walk, pmdp, ptep, addr, hmm_pfns, &unmapped);
...
if (r) {
/* A non -EAGAIN error here means migrate_vma_split_folio()
* already dropped the PTE lock and cleared ptelocked.
*/
HMM_ASSERT_UNLOCKED(hmm_vma_walk);
if (unmapped)
flush_tlb_range(walk->vma, start, addr);
hmm_pfns_fill(addr, end, hmm_vma_walk, HMM_PFN_ERROR);
return 0;
}
}
split_folio() can routinely fail with -EBUSY or -EAGAIN when a folio has
extra references (such as gup pins or per-cpu lru caches) or -EINVAL when a
mapping has min_order > 0. When that happens during a call to
hmm_range_fault() with HMM_PFN_REQ_MIGRATE (such as migrate_vma_setup() in
"mm: enable device page migration from HMM pagewalk",
do_fault_and_migrate() in "lib/test_hmm: add a new testcase for the migrate
on fault", or nouveau_dmem_migrate_fault() in "drm/nouveau/svm: add support
for migrate on fault"), doesn't returning -EFAULT cause two regressions?
First, at addr, hmm_vma_handle_pte() already populated *hmm_pfns with the
valid pfn and HMM_PFN_VALID, which hmm_pfns_fill() overwrites with
HMM_PFN_ERROR. For callers like nouveau_dmem_migrate_fault() that fall back
to mapping range.hmm_pfns[0] in place via nouveau_dmem_hmm_pfn_to_map()
when a page is not migrated, losing HMM_PFN_VALID causes the in-place
mapping to fail.
Second, for the remaining entries in [addr + PAGE_SIZE, end) of the pmd,
hmm_vma_walk_pmd() never runs hmm_vma_handle_pte() or
hmm_vma_handle_migrate_prepare(), so unmapped or non-present pages in
[addr + PAGE_SIZE, end) are never faulted in when HMM_PFN_REQ_FAULT (or
MIGRATE_VMA_FAULT / MIGRATE_VMA_WRITE) is set, and valid order-0 pages in
[addr + PAGE_SIZE, end) are never collected for migration, yet
hmm_range_fault() returns 0 with HMM_PFN_ERROR in range->hmm_pfns.
> +
> + writable = pte_write(pte);
> + }
> +
> + if (!page || !page->mapping)
> + goto out;
> +
> + /*
> + * By getting a reference on the folio we pin it and that blocks
> + * any kind of migration. Side effect is that it "freezes" the
> + * pte.
> + *
> + * We drop this reference after isolating the folio from the lru
> + * for non device folio (device folio are not on the lru and thus
> + * can't be dropped from it).
> + */
> + folio = page_folio(page);
> + folio_get(folio);
> +
> + /*
> + * We rely on folio_trylock() to avoid deadlock between
> + * concurrent migrations where each is waiting on the others
> + * folio lock. If we can't immediately lock the folio we fail this
> + * migration as it is only best effort anyway.
> + *
> + * If we can lock the folio it's safe to set up a migration entry
> + * now. In the common case where the folio is mapped once in a
> + * single process setting up the migration entry now is an
> + * optimisation to avoid walking the rmap later with
> + * try_to_migrate().
> + */
> +
> + if (fault_folio == folio || folio_trylock(folio)) {
> + anon_exclusive = folio_test_anon(folio) &&
> + PageAnonExclusive(page);
> +
> + if (pte_present(pte))
> + flush_cache_page(walk->vma, addr, pfn);
> +
> + if (anon_exclusive) {
> + pte = ptep_clear_flush(walk->vma, addr, ptep);
> +
> + if (folio_try_share_anon_rmap_pte(folio, page)) {
> + set_pte_at(mm, addr, ptep, pte);
> + if (fault_folio != folio)
> + folio_unlock(folio);
> + folio_put(folio);
> + goto out;
> + }
> + } else {
> + pte = ptep_get_and_clear(mm, addr, ptep);
> + }
> +
> + if (pte_present(pte) && pte_dirty(pte))
> + folio_mark_dirty(folio);
> +
> + /* Setup special migration page table entry */
> + if (writable)
> + entry = make_writable_migration_entry(pfn);
> + else if (anon_exclusive)
> + entry = make_readable_exclusive_migration_entry(pfn);
> + else
> + entry = make_readable_migration_entry(pfn);
> +
> + if (pte_present(pte)) {
> + if (pte_young(pte))
> + entry = make_migration_entry_young(entry);
> + if (pte_dirty(pte))
> + entry = make_migration_entry_dirty(entry);
> + }
> +
> + swp_pte = swp_entry_to_pte(entry);
> + if (pte_present(pte)) {
> + if (pte_soft_dirty(pte))
> + swp_pte = pte_swp_mksoft_dirty(swp_pte);
> + if (pte_uffd(pte))
> + swp_pte = pte_swp_mkuffd(swp_pte);
> + } else {
> + if (pte_swp_soft_dirty(pte))
> + swp_pte = pte_swp_mksoft_dirty(swp_pte);
> + if (pte_swp_uffd(pte))
> + swp_pte = pte_swp_mkuffd(swp_pte);
> + }
> +
> + set_pte_at(mm, addr, ptep, swp_pte);
> + folio_remove_rmap_pte(folio, page, walk->vma);
> + folio_put(folio);
> + *hmm_pfn |= HMM_PFN_MIGRATE;
> + if (pte_present(pte))
> + *unmapped = true;
[Severity: Critical]
While the later commit "mm/hmm: implement rollback for device page
migration in HMM pagewalk" adds hmm_vma_handle_migrate_prepare_rollback()
and "mm: enable device page migration from HMM pagewalk" documents
caller-side abort via migrate_hmm_range_setup(), does locking folios and
installing migration entries per-entry during the walk still leave three
regressions across the series when a range contains a mix of present
entries, entries requiring faults, or large folios?
1. Holding folio_lock across handle_mm_fault():
In hmm_vma_walk_pmd(), hmm_vma_handle_migrate_prepare() locks each
collected folio with folio_trylock(), pins it with folio_get(), and
installs a migration entry immediately. When a subsequent entry or hole in
the walk requires a page fault, hmm_vma_handle_pte() or hmm_vma_walk_hole()
returns HMM_FAULT_PENDING and hmm_range_fault_locked() calls hmm_do_fault()
-> handle_mm_fault() while the task still holds folio_lock on all folios
collected earlier in the range:
mm/hmm.c:hmm_range_fault_locked() {
...
ret = walk_page_range(mm, hmm_vma_walk.last, range->end,
&hmm_walk_ops, &hmm_vma_walk);
if (ret == HMM_FAULT_PENDING) {
ret = hmm_do_fault(mm, &hmm_vma_walk);
if (ret == HMM_FAULT_UNLOCKED) {
ret = fatal_signal_pending(current) ? -EINTR :
-EBUSY;
break;
}
}
}
Holding folio_lock across handle_mm_fault() violates lock ordering
(folio_lock held before handle_mm_fault(), mapping->invalidate_lock, and
other folio locks) and deadlocks if handle_mm_fault() touches a locked
folio, or if hmm_do_fault() (which loops for addr < fault_end calling
handle_mm_fault() on every page up to the end of the pmd) encounters a
migration entry installed in an earlier pass/retry and blocks forever in
do_swap_page() -> migration_entry_wait() on a folio locked by current.
2. Orphaned migration entries when required_fault == 0:
In hmm_vma_handle_pte(), the check for !required_fault precedes the check
for softleaf_is_migration(entry):
mm/hmm.c:hmm_vma_handle_pte() {
...
required_fault =
hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0);
if (!required_fault)
goto out;
...
if (softleaf_is_migration(entry)) {
if (!hmm_select_migrate(range)) {
...
}
return 0;
}
}
When required_fault == 0 (the default for migrate_vma_setup() without
MIGRATE_VMA_FAULT) and a walk re-visits an already-installed migration
entry (for example when !ptep resets addr = start and jumps to again:, or
when hmm_pfns_fill(addr, end, ..., HMM_PFN_ERROR) runs on a split failure
after a retry), hmm_vma_handle_pte() jumps to out:, which calls
hmm_vma_handle_migrate_prepare_rollback() (unlocking the folio and dropping
its migration reference) and overwrites *hmm_pfn with 0 while leaving the
migration entry installed in the page table.
3. Wrong rollback range on !ptep and missing rollback before fault:
In hmm_vma_walk_pmd(), if migrate_vma_split_folio() at addr > start drops
the page table lock and returns -EAGAIN, and pte_offset_map_lock()
subsequently sees the page table gone (!ptep), the rollback patch calls
hmm_vma_handle_migrate_prepare_rollback(walk->private, addr, end, hmm_pfns)
on [addr, end) instead of [start, addr) where the entries from the vanished
page table were actually collected:
mm/hmm.c:hmm_vma_walk_pmd() {
again:
ptep = pte_offset_map_lock(walk->mm, pmdp, addr, &hmm_vma_walk->ptl);
if (!ptep) {
addr = start;
goto again;
}
for (; addr < end; addr += PAGE_SIZE, ptep++, hmm_pfns++) {
r = hmm_vma_handle_pte(walk, addr, end, pmdp, ptep, hmm_pfns);
...
r = hmm_vma_handle_migrate_prepare(walk, pmdp, ptep, addr, hmm_pfns, &unmapped);
}
Furthermore, when a vanished page table becomes pmd_none (or an entry
requires a fault on retry) with required_fault != 0, hmm_vma_walk_hole()
and the fault: path in hmm_vma_handle_pte() return HMM_FAULT_PENDING
without rolling back previously collected entries in the range before
hmm_do_fault() runs.
> + } else {
> + folio_put(folio);
> + }
> +out:
> return 0;
> +out_error:
> + return -EFAULT;
> }
>
> #else
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021060506.2377545-1-mpenttil@redhat.com?part=5
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v16 06/12] mm/hmm: migrate collection in HMM pagewalk - pmd level
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (4 preceding siblings ...)
2026-10-21 6:04 ` [PATCH v16 05/12] mm/hmm: migrate collection in HMM pagewalk - pte level mpenttil
@ 2026-10-21 6:05 ` mpenttil
2026-10-22 6:06 ` sashiko-bot
2026-10-21 6:05 ` [PATCH v16 07/12] mm/hmm: add lazy MMU mode support for migration in HMM pagewalk mpenttil
` (10 subsequent siblings)
16 siblings, 1 reply; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:05 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
Implement the needed hmm_vma_handle_migrate_prepare_pmd() function
which is mostly carried over from migrate_device.c's
migrate_vma_collect_huge_pmd() function.
With HMM pagewalk based migration, the idea is that
hmm_vma_handle_*() are responsible for faulting, and the pfn
collecting part. hmm_vma_handle_migrate_prepare*() do the
migration decisions (with HMM_PFN_MIGRATE), possibly split
folios, and insert migration ptes/pmds.
HMM pagewalk based migration is enabled in later commit, for now
now hmm_select_migrate() returns 0.
Also avoid the problems present in the migrate_vma_collect_huge_pmd()
split fallback path this HMM path supersedes:
- extra refcount for fault_folio makes split_folio() fail
- wrong folio unlocked after split_folio()
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Suggested-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
mm/hmm.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 151 insertions(+), 21 deletions(-)
diff --git a/mm/hmm.c b/mm/hmm.c
index 0ce947d0e572..5891efee3e18 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -492,31 +492,19 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
#ifdef CONFIG_DEVICE_MIGRATION
/**
- * migrate_vma_split_folio() - Helper function to split a THP folio
+ * __migrate_vma_split_folio() - split a folio and move the lock/ref to the
+ * order-0 folio backing @fault_page after the split
* @folio: the folio to split
- * @fault_page: struct page associated with the fault if any
- * @hmm_vma_walk: walk in progress
- * @ptep: pte_t * for unmap and unlock ptl
+ * @fault_page: fault page if any
*
- * Returns 0 on success
+ * Returns 0 on success.
*/
-static int migrate_vma_split_folio(struct folio *folio,
- struct page *fault_page,
- struct hmm_vma_walk *hmm_vma_walk,
- pte_t *ptep)
+static int __migrate_vma_split_folio(struct folio *folio,
+ struct page *fault_page)
{
- int ret;
struct folio *fault_folio = fault_page ? page_folio(fault_page) : NULL;
struct folio *new_fault_folio = NULL;
-
- if (folio != fault_folio)
- folio_get(folio);
-
- pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
- hmm_vma_walk->ptelocked = false;
-
- if (folio != fault_folio)
- folio_lock(folio);
+ int ret;
ret = split_folio(folio);
if (ret) {
@@ -548,14 +536,145 @@ static int migrate_vma_split_folio(struct folio *folio,
return 0;
}
+/**
+ * migrate_vma_split_folio() - drop the pte lock and split a THP folio
+ * @folio: the folio to split
+ * @fault_page: struct page associated with the fault if any
+ * @hmm_vma_walk: walk in progress
+ * @ptep: pte_t * for unmap and unlock ptl
+ *
+ * Returns 0 on success
+ */
+static int migrate_vma_split_folio(struct folio *folio,
+ struct page *fault_page,
+ struct hmm_vma_walk *hmm_vma_walk,
+ pte_t *ptep)
+{
+ struct folio *fault_folio = fault_page ? page_folio(fault_page) : NULL;
+
+ if (folio != fault_folio)
+ folio_get(folio);
+
+ pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
+ hmm_vma_walk->ptelocked = false;
+
+ if (folio != fault_folio)
+ folio_lock(folio);
+
+ return __migrate_vma_split_folio(folio, fault_page);
+}
+
static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
pmd_t *pmdp,
unsigned long start,
unsigned long end,
unsigned long *hmm_pfn)
{
- // TODO: implement migration entry insertion
- return 0;
+ struct hmm_vma_walk *hmm_vma_walk = walk->private;
+ struct hmm_range *range = hmm_vma_walk->range;
+ struct migrate_vma *migrate = range->migrate;
+ struct folio *fault_folio = NULL;
+ enum migrate_vma_info minfo;
+ struct folio *folio;
+ unsigned long i;
+ int r = 0;
+
+ // Do we want to migrate at all?
+ minfo = hmm_select_migrate(range);
+ if (!minfo)
+ return r;
+
+ WARN_ON_ONCE(!migrate);
+ HMM_ASSERT_PMD_LOCKED(hmm_vma_walk, true);
+
+ fault_folio = migrate->fault_page ?
+ page_folio(migrate->fault_page) : NULL;
+
+ if (pmd_none(*pmdp))
+ return hmm_pfns_fill(start, end, hmm_vma_walk, 0);
+
+ if (!(hmm_pfn[0] & HMM_PFN_VALID))
+ goto out;
+
+ if (pmd_trans_huge(*pmdp)) {
+ if (!(minfo & MIGRATE_VMA_SELECT_SYSTEM))
+ goto out;
+
+ folio = pmd_folio(*pmdp);
+ if (is_huge_zero_folio(folio))
+ return hmm_pfns_fill(start, end, hmm_vma_walk, 0);
+
+ } else if (!pmd_present(*pmdp)) {
+ const softleaf_t entry = softleaf_from_pmd(*pmdp);
+
+ if (!softleaf_is_device_private(entry))
+ goto out;
+
+ if (!(minfo & MIGRATE_VMA_SELECT_DEVICE_PRIVATE))
+ goto out;
+
+ folio = softleaf_to_folio(entry);
+ if (folio->pgmap->owner != migrate->pgmap_owner)
+ goto out;
+ } else {
+ hmm_vma_walk->last = start;
+ return -EBUSY;
+ }
+
+ folio_get(folio);
+
+ if (folio != fault_folio && unlikely(!folio_trylock(folio))) {
+ folio_put(folio);
+ hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
+ return 0;
+ }
+
+ if (thp_migration_supported() &&
+ (migrate->flags & MIGRATE_VMA_SELECT_COMPOUND) &&
+ (IS_ALIGNED(start, HPAGE_PMD_SIZE) &&
+ IS_ALIGNED(end, HPAGE_PMD_SIZE))) {
+ struct page_vma_mapped_walk pvmw = {
+ .ptl = hmm_vma_walk->ptl,
+ .address = start,
+ .pmd = pmdp,
+ .vma = walk->vma,
+ };
+
+ hmm_pfn[0] |= HMM_PFN_MIGRATE | HMM_PFN_COMPOUND;
+
+ r = set_pmd_migration_entry(&pvmw, folio_page(folio, 0));
+ if (r) {
+ hmm_pfn[0] &= ~(HMM_PFN_MIGRATE | HMM_PFN_COMPOUND);
+ goto split; /* fall back to splitting the pmd */
+ }
+ for (i = 1, start += PAGE_SIZE; start < end; start += PAGE_SIZE, i++)
+ hmm_pfn[i] &= HMM_PFN_INOUT_FLAGS;
+
+ } else {
+ goto split; /* fall back to splitting the pmd */
+ }
+
+out:
+ return r;
+
+split:
+ spin_unlock(hmm_vma_walk->ptl);
+ hmm_vma_walk->pmdlocked = false;
+
+ /*
+ * folio_get() above took an extra reference. For the fault folio the
+ * caller still holds a reference and the lock, which is the
+ * precondition of __migrate_vma_split_folio(), so drop the extra one.
+ */
+ if (folio == fault_folio)
+ folio_put(folio);
+
+ r = __migrate_vma_split_folio(folio, migrate->fault_page);
+ if (r)
+ return -EFAULT;
+
+ hmm_vma_walk->last = start;
+ return -EBUSY;
}
/*
@@ -958,6 +1077,17 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
hmm_vma_walk->pmdlocked = false;
}
+ /*
+ * hmm_vma_handle_migrate_prepare_pmd() splits the huge pmd in
+ * place when needed and returns -EBUSY to re-walk the range as
+ * PTEs; any other error means the split failed.
+ */
+ if (r == -EBUSY)
+ return -EBUSY;
+ if (r) {
+ /* Split not successful, skip */
+ return hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
+ }
return r;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v16 06/12] mm/hmm: migrate collection in HMM pagewalk - pmd level
2026-10-21 6:05 ` [PATCH v16 06/12] mm/hmm: migrate collection in HMM pagewalk - pmd level mpenttil
@ 2026-10-22 6:06 ` sashiko-bot
0 siblings, 0 replies; 33+ messages in thread
From: sashiko-bot @ 2026-10-22 6:06 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, David Hildenbrand, Jason Gunthorpe,
Leon Romanovsky, Alistair Popple, Balbir Singh, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] mm/hmm: stale hmm_pfns left across PMD split re-walk in hmm_vma_walk_pmd()
- [Medium] mm/hmm: hmm_vma_handle_migrate_prepare_pmd() clobbers valid PFNs on skip
--
commit 19d71de5ba9a8df49f896d9047f6e5016503f7dc
Author: Mika Penttilä <mpenttil@redhat.com>
mm/hmm: migrate collection in HMM pagewalk - pmd level
This commit implements hmm_vma_handle_migrate_prepare_pmd() and integrates it
into hmm_vma_walk_pmd() to prepare PMD-level THP and device-private entries
for migration or split them for PTE re-walking.
> diff --git a/mm/hmm.c b/mm/hmm.c
> index 0ce947d0e5727..5891efee3e182 100644
> --- a/mm/hmm.c
> +++ b/mm/hmm.c
[ ... ]
> @@ -548,14 +536,145 @@ static int migrate_vma_split_folio(struct folio *folio,
> return 0;
> }
>
> +/**
> + * migrate_vma_split_folio() - drop the pte lock and split a THP folio
> + * @folio: the folio to split
> + * @fault_page: struct page associated with the fault if any
> + * @hmm_vma_walk: walk in progress
> + * @ptep: pte_t * for unmap and unlock ptl
> + *
> + * Returns 0 on success
> + */
> +static int migrate_vma_split_folio(struct folio *folio,
> + struct page *fault_page,
> + struct hmm_vma_walk *hmm_vma_walk,
> + pte_t *ptep)
> +{
> + struct folio *fault_folio = fault_page ? page_folio(fault_page) : NULL;
> +
> + if (folio != fault_folio)
> + folio_get(folio);
> +
> + pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
> + hmm_vma_walk->ptelocked = false;
> +
> + if (folio != fault_folio)
> + folio_lock(folio);
> +
> + return __migrate_vma_split_folio(folio, fault_page);
> +}
> +
> static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
> pmd_t *pmdp,
> unsigned long start,
> unsigned long end,
> unsigned long *hmm_pfn)
> {
[ ... ]
> + folio_get(folio);
> +
> + if (folio != fault_folio && unlikely(!folio_trylock(folio))) {
> + folio_put(folio);
> + hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
> + return 0;
> + }
> +
> + if (thp_migration_supported() &&
> + (migrate->flags & MIGRATE_VMA_SELECT_COMPOUND) &&
> + (IS_ALIGNED(start, HPAGE_PMD_SIZE) &&
> + IS_ALIGNED(end, HPAGE_PMD_SIZE))) {
> + struct page_vma_mapped_walk pvmw = {
> + .ptl = hmm_vma_walk->ptl,
> + .address = start,
> + .pmd = pmdp,
> + .vma = walk->vma,
> + };
> +
> + hmm_pfn[0] |= HMM_PFN_MIGRATE | HMM_PFN_COMPOUND;
> +
> + r = set_pmd_migration_entry(&pvmw, folio_page(folio, 0));
> + if (r) {
> + hmm_pfn[0] &= ~(HMM_PFN_MIGRATE | HMM_PFN_COMPOUND);
> + goto split; /* fall back to splitting the pmd */
> + }
> + for (i = 1, start += PAGE_SIZE; start < end; start += PAGE_SIZE, i++)
> + hmm_pfn[i] &= HMM_PFN_INOUT_FLAGS;
> +
> + } else {
> + goto split; /* fall back to splitting the pmd */
> + }
> +
> +out:
> + return r;
> +
> +split:
> + spin_unlock(hmm_vma_walk->ptl);
> + hmm_vma_walk->pmdlocked = false;
> +
> + /*
> + * folio_get() above took an extra reference. For the fault folio the
> + * caller still holds a reference and the lock, which is the
> + * precondition of __migrate_vma_split_folio(), so drop the extra one.
> + */
> + if (folio == fault_folio)
> + folio_put(folio);
> +
> + r = __migrate_vma_split_folio(folio, migrate->fault_page);
> + if (r)
> + return -EFAULT;
> +
> + hmm_vma_walk->last = start;
> + return -EBUSY;
> }
[Severity: High]
Can returning -EBUSY from the split path in
hmm_vma_handle_migrate_prepare_pmd() leave stale pre-split PMD entries in
range->hmm_pfns[] across the re-walk?
When migration is enabled (in the later commit "mm: enable device page
migration from HMM pagewalk"), hmm_vma_walk_pmd() first calls
hmm_vma_handle_pmd() or hmm_vma_handle_absent_pmd() before calling
hmm_vma_handle_migrate_prepare_pmd():
mm/hmm.c:hmm_vma_walk_pmd()
hmm_vma_handle_pmd() / hmm_vma_handle_absent_pmd()
for (i = 0; addr < end; addr += PAGE_SIZE, i++, pfn++) {
hmm_pfns[i] &= HMM_PFN_INOUT_FLAGS;
hmm_pfns[i] |= pfn | cpu_flags;
}
hmm_vma_handle_migrate_prepare_pmd()
This populates hmm_pfns_start[0..npages-1] with the pre-split PMD PFNs,
HMM_PFN_VALID, HMM_PFN_WRITE, and hmm_pfn_flags_order(PMD_SHIFT - PAGE_SHIFT).
When hmm_vma_handle_migrate_prepare_pmd() then takes the split path (for
example, when MIGRATE_VMA_SELECT_COMPOUND is not set, [start, end) is smaller
than HPAGE_PMD_SIZE, or set_pmd_migration_entry() fails), it drops
hmm_vma_walk->ptl, splits the folio via __migrate_vma_split_folio() (which
also unlocks the folio when folio != fault_folio), sets
hmm_vma_walk->last = start, and returns -EBUSY without clearing
hmm_pfns_start[0..npages-1].
This breaks the hmm_range_fault_locked() expectation that range->hmm_pfns[]
entries at or after hmm_vma_walk.last have not been overwritten with output
flags when -EBUSY is returned.
On the subsequent PTE re-walk of [start, end), if any split page is
concurrently turned into a migration entry while the page table and folio
locks were dropped (with HMM_PFN_REQ_FAULT set), hmm_vma_handle_pte() returns
0 without updating *hmm_pfn:
mm/hmm.c:hmm_vma_handle_pte()
if (softleaf_is_migration(entry)) {
if (!hmm_select_migrate(range)) {
...
return -EBUSY;
}
return 0;
}
and hmm_vma_handle_migrate_prepare() sees !pte_present(pte) and
!softleaf_is_device_private(entry) and also returns 0 without updating
*hmm_pfn (similarly, if the PMD became a PMD migration entry,
hmm_vma_walk_pmd() returns 0 without clearing hmm_pfns_start). The later
commit "mm/hmm: implement rollback for device page migration in HMM pagewalk"
only rolls back entries that have both HMM_PFN_VALID and HMM_PFN_MIGRATE set,
so these pre-split entries (which lack HMM_PFN_MIGRATE) remain in
range->hmm_pfns[], allowing callers that map non-migrated HMM PFNs in place
(such as nouveau_dmem_migrate_fault()) to map a stale 2MB host range into the
device MMU.
Furthermore, if a caller sets range->pfn_flags_mask, overwriting
hmm_pfns_start[0..npages-1] with HMM_PFN_VALID (which shares its bit position
with HMM_PFN_REQ_FAULT) and HMM_PFN_WRITE (which shares its bit position with
HMM_PFN_REQ_WRITE) before the split clobbers the per-page request flags for
the PTE re-walk.
> @@ -958,6 +1077,17 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
> hmm_vma_walk->pmdlocked = false;
> }
>
> + /*
> + * hmm_vma_handle_migrate_prepare_pmd() splits the huge pmd in
> + * place when needed and returns -EBUSY to re-walk the range as
> + * PTEs; any other error means the split failed.
> + */
> + if (r == -EBUSY)
> + return -EBUSY;
> + if (r) {
> + /* Split not successful, skip */
> + return hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
> + }
> return r;
> }
[Severity: Medium]
Should the folio_trylock() failure path in
hmm_vma_handle_migrate_prepare_pmd() and the split failure path here in
hmm_vma_walk_pmd() preserve the valid PFNs in range->hmm_pfns[] instead of
overwriting them with HMM_PFN_ERROR?
Before hmm_vma_handle_migrate_prepare_pmd() is called, hmm_vma_handle_pmd()
(or hmm_vma_handle_absent_pmd()) has already populated
hmm_pfns_start[0..npages-1] with the valid PFNs (HMM_PFN_VALID without
HMM_PFN_MIGRATE).
However, in two best-effort migration skip cases, those valid PFNs are
clobbered with HMM_PFN_ERROR:
1. In hmm_vma_handle_migrate_prepare_pmd(), when folio_trylock(folio) fails
while holding hmm_vma_walk->ptl, it calls
hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR) even though the PMD
lock was never dropped and the mapping is still valid.
2. When compound migration is not selected or [start, end) is smaller than
HPAGE_PMD_SIZE (such as single-page faults in nouveau_dmem_migrate_fault()
in the later commit "drm/nouveau/svm: add support for migrate on fault"),
hmm_vma_handle_migrate_prepare_pmd() jumps to split and calls
__migrate_vma_split_folio(). If split_folio() fails (for example, when the
THP is pinned or has extra references), it returns -EFAULT and
hmm_vma_walk_pmd() overwrites the range with HMM_PFN_ERROR.
By contrast, the other non-migrating exits in
hmm_vma_handle_migrate_prepare_pmd() (goto out) and folio_trylock() failure
at the PTE level in hmm_vma_handle_migrate_prepare():
mm/hmm.c:hmm_vma_handle_migrate_prepare()
if (fault_folio == folio || folio_trylock(folio)) {
...
} else {
folio_put(folio);
}
out:
return 0;
leave range->hmm_pfns[] with the valid PFNs and without HMM_PFN_MIGRATE.
Because migrate_hmm_range_setup() only collects entries with HMM_PFN_MIGRATE
set, leaving the valid PFNs intact still skips migration while allowing
callers such as nouveau_dmem_migrate_fault() to map the present THP in place
instead of treating it as an error and falling back to a redundant page table
walk and GPU PFNMAP ioctl.
Could both skip paths return 0 without calling hmm_pfns_fill(...,
HMM_PFN_ERROR)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021060506.2377545-1-mpenttil@redhat.com?part=6
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v16 07/12] mm/hmm: add lazy MMU mode support for migration in HMM pagewalk
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (5 preceding siblings ...)
2026-10-21 6:05 ` [PATCH v16 06/12] mm/hmm: migrate collection in HMM pagewalk - pmd level mpenttil
@ 2026-10-21 6:05 ` mpenttil
2026-10-21 6:05 ` [PATCH v16 08/12] mm/hmm: implement rollback for device page " mpenttil
` (9 subsequent siblings)
16 siblings, 0 replies; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:05 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
Add calls to lazy_mmu_mode_enable() and lazy_mmu_mode_disable()
while doing migration.
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Suggested-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
mm/hmm.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/mm/hmm.c b/mm/hmm.c
index 5891efee3e18..36a4edde9823 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -373,6 +373,7 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
/* Report error for everything else */
if (hmm_vma_walk->ptelocked) {
+ lazy_mmu_mode_disable();
pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
hmm_vma_walk->ptelocked = false;
} else {
@@ -396,6 +397,7 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
!is_zero_pfn(pte_pfn(pte))) {
if (hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0)) {
if (hmm_vma_walk->ptelocked) {
+ lazy_mmu_mode_disable();
pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
hmm_vma_walk->ptelocked = false;
} else {
@@ -415,6 +417,7 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
fault:
if (hmm_vma_walk->ptelocked) {
+ lazy_mmu_mode_disable();
pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
hmm_vma_walk->ptelocked = false;
} else {
@@ -555,6 +558,7 @@ static int migrate_vma_split_folio(struct folio *folio,
if (folio != fault_folio)
folio_get(folio);
+ lazy_mmu_mode_disable();
pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
hmm_vma_walk->ptelocked = false;
@@ -1110,8 +1114,10 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
if (minfo) {
ptep = pte_offset_map_lock(mm, pmdp, addr, &hmm_vma_walk->ptl);
- if (ptep)
+ if (ptep) {
+ lazy_mmu_mode_enable();
hmm_vma_walk->ptelocked = true;
+ }
} else {
ptep = pte_offset_map(pmdp, addr);
}
@@ -1155,6 +1161,7 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
flush_tlb_range(walk->vma, start, addr);
if (hmm_vma_walk->ptelocked) {
+ lazy_mmu_mode_disable();
pte_unmap_unlock(ptep - 1, hmm_vma_walk->ptl);
hmm_vma_walk->ptelocked = false;
} else {
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* [PATCH v16 08/12] mm/hmm: implement rollback for device page migration in HMM pagewalk
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (6 preceding siblings ...)
2026-10-21 6:05 ` [PATCH v16 07/12] mm/hmm: add lazy MMU mode support for migration in HMM pagewalk mpenttil
@ 2026-10-21 6:05 ` mpenttil
2026-10-22 6:06 ` sashiko-bot
2026-10-21 6:05 ` [PATCH v16 09/12] mm: enable device page migration from " mpenttil
` (8 subsequent siblings)
16 siblings, 1 reply; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:05 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
During the migration pagewalk, the PTE table could be cleared and/or
changed into PMD leaf or even another PTE table while dropped locks.
In these cases the possibly inserted migration ptes are gone. We have
to however undo the collecting done so far, so unlock the folios and
drop reference taken.
During the pagewalk we notice such scenarios if going to recollect a pfn
but have already committed to migrate the entry with HMM_PFN_MIGRATE, in
which case do rollback. Rollback clears (HMM_PFN_VALID | HMM_PFN_MIGRATE)
which is safe, as migration is entirely driven by default_flags.
If we encounter migration ptes they are just skipped to allow for restart
own walks.
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Suggested-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
include/linux/hmm.h | 22 +++++++++++++
mm/hmm.c | 79 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 101 insertions(+)
diff --git a/include/linux/hmm.h b/include/linux/hmm.h
index 4f56f3419cb4..b08ebc1343dd 100644
--- a/include/linux/hmm.h
+++ b/include/linux/hmm.h
@@ -111,6 +111,28 @@ static inline unsigned int hmm_pfn_to_map_order(unsigned long hmm_pfn)
return (hmm_pfn >> HMM_PFN_ORDER_SHIFT) & 0x1F;
}
+/*
+ * hmm_pfn_collected() - is this pfn entry prepared for migration ?
+ * If collected the folio's refcount is increased and the folio
+ * is locked.
+ */
+static inline bool hmm_pfn_collected(unsigned long hmm_pfn)
+{
+ return (hmm_pfn & (HMM_PFN_VALID | HMM_PFN_MIGRATE)) ==
+ (HMM_PFN_VALID | HMM_PFN_MIGRATE);
+}
+
+/*
+ * hmm_pfn_rollback_collected() - undoes the collection of hmm_pfn
+ *
+ * Note for total rollback the folio's refcount has to be put
+ * and folio has to be unlocked.
+ */
+static inline unsigned long hmm_pfn_rollback_collected(unsigned long hmm_pfn)
+{
+ return hmm_pfn & ~(HMM_PFN_VALID | HMM_PFN_MIGRATE | HMM_PFN_COMPOUND);
+}
+
/*
* struct hmm_range - track invalidation lock on virtual address range
*
diff --git a/mm/hmm.c b/mm/hmm.c
index 36a4edde9823..5a1471fd5d28 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -95,6 +95,11 @@ enum {
HMM_PFN_P2PDMA_BUS,
};
+static void hmm_vma_handle_migrate_prepare_rollback(const struct hmm_vma_walk *hmm_vma_walk,
+ unsigned long start,
+ unsigned long end,
+ unsigned long *hmm_pfn);
+
static int hmm_pfns_fill(unsigned long addr, unsigned long end,
struct hmm_vma_walk *hmm_vma_walk, unsigned long cpu_flags)
{
@@ -111,6 +116,8 @@ static int hmm_pfns_fill(unsigned long addr, unsigned long end,
}
}
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk, addr, end, &range->hmm_pfns[i]);
+
if (migrate && thp_migration_supported() &&
(minfo & MIGRATE_VMA_SELECT_COMPOUND) &&
IS_ALIGNED(addr, HPAGE_PMD_SIZE) &&
@@ -282,6 +289,8 @@ static int hmm_vma_handle_pmd(struct mm_walk *walk, unsigned long addr,
return hmm_record_fault(addr, end, required_fault, walk);
}
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk, addr,
+ end, hmm_pfns);
pfn = pmd_pfn(pmd) + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
for (i = 0; addr < end; addr += PAGE_SIZE, i++, pfn++) {
hmm_pfns[i] &= HMM_PFN_INOUT_FLAGS;
@@ -412,6 +421,9 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
new_pfn_flags = pte_pfn(pte) | cpu_flags;
out:
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk, addr,
+ addr + PAGE_SIZE,
+ hmm_pfn);
*hmm_pfn = (*hmm_pfn & HMM_PFN_INOUT_FLAGS) | new_pfn_flags;
return 0;
@@ -450,6 +462,9 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
if (softleaf_is_device_private_write(entry))
cpu_flags |= HMM_PFN_WRITE;
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk,
+ start, end,
+ hmm_pfns);
/*
* Fully populate the PFN list though subsequent PFNs could be
* inferred, because drivers which are not yet aware of large
@@ -568,6 +583,51 @@ static int migrate_vma_split_folio(struct folio *folio,
return __migrate_vma_split_folio(folio, fault_page);
}
+/*
+ * Due to dropping ptl locks for splitting for instance, would we
+ * overwrite already collected pfns? This could happen when pmd
+ * pointing to a page table has vanished and been replaced with
+ * a leaf pmd, or another page table. In that case unref and unlock
+ * the folios, the pfns of which were collected from the disappeared
+ * page tables.
+ *
+ * Migrate mode drives fault/migration requests only via range->default_flags.
+ * (HMM_PFN_VALID | HMM_PFN_MIGRATE) denotes a collected entry and can safely
+ * be cleared from hmm_pfn[].
+ */
+static void hmm_vma_handle_migrate_prepare_rollback(const struct hmm_vma_walk *hmm_vma_walk,
+ unsigned long start,
+ unsigned long end,
+ unsigned long *hmm_pfn)
+{
+ struct hmm_range *range = hmm_vma_walk->range;
+ struct migrate_vma *migrate = range->migrate;
+ struct folio *fault_folio = NULL;
+ enum migrate_vma_info minfo;
+ struct folio *folio;
+ unsigned long i;
+
+ minfo = hmm_select_migrate(range);
+ if (!minfo)
+ return;
+
+ WARN_ON_ONCE(!migrate);
+
+ fault_folio = migrate->fault_page ?
+ page_folio(migrate->fault_page) : NULL;
+
+ for (i = 0; start < end; start += PAGE_SIZE, i++) {
+ if (hmm_pfn_collected(hmm_pfn[i])) {
+ folio = page_folio(hmm_pfn_to_page(hmm_pfn[i]));
+ if (folio != fault_folio)
+ folio_unlock(folio);
+ folio_put(folio);
+ hmm_pfn[i] = hmm_pfn_rollback_collected(hmm_pfn[i]);
+
+ }
+ }
+}
+
static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
pmd_t *pmdp,
unsigned long start,
@@ -722,6 +782,11 @@ static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
pte = ptep_get(ptep);
if (pte_none(pte)) {
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk,
+ addr,
+ addr + PAGE_SIZE,
+ hmm_pfn);
+
if (vma_is_anonymous(walk->vma)) {
*hmm_pfn &= HMM_PFN_INOUT_FLAGS;
*hmm_pfn |= HMM_PFN_MIGRATE;
@@ -769,6 +834,10 @@ static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
pfn = pte_pfn(pte);
if (is_zero_pfn(pfn) &&
(minfo & MIGRATE_VMA_SELECT_SYSTEM)) {
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk,
+ addr,
+ addr + PAGE_SIZE,
+ hmm_pfn);
*hmm_pfn = HMM_PFN_MIGRATE;
goto out;
}
@@ -897,6 +966,13 @@ static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
}
#else
+static void hmm_vma_handle_migrate_prepare_rollback(const struct hmm_vma_walk *hmm_vma_walk,
+ unsigned long start,
+ unsigned long end,
+ unsigned long *hmm_pfn)
+{
+}
+
static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
pmd_t *pmdp,
unsigned long start,
@@ -1117,6 +1193,9 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
if (ptep) {
lazy_mmu_mode_enable();
hmm_vma_walk->ptelocked = true;
+ } else {
+ /* The pte table is gone */
+ hmm_vma_handle_migrate_prepare_rollback(walk->private, addr, end, hmm_pfns);
}
} else {
ptep = pte_offset_map(pmdp, addr);
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v16 08/12] mm/hmm: implement rollback for device page migration in HMM pagewalk
2026-10-21 6:05 ` [PATCH v16 08/12] mm/hmm: implement rollback for device page " mpenttil
@ 2026-10-22 6:06 ` sashiko-bot
0 siblings, 0 replies; 33+ messages in thread
From: sashiko-bot @ 2026-10-22 6:06 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, David Hildenbrand, Jason Gunthorpe,
Leon Romanovsky, Alistair Popple, Balbir Singh, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] mm/hmm: premature rollback of migration PTEs in hmm_vma_handle_pte()
- [High] mm/hmm: incomplete rollback on mid-PMD lock drop in hmm_vma_walk_pmd()
- [High] mm/hmm: missing rollback on fault and PMD migration in hmm_vma_walk_pmd()
--
commit 5c75620371e34a43110051163d33f29ab4f700b4
Author: Mika Penttilä <mpenttil@redhat.com>
mm/hmm: implement rollback for device page migration in HMM pagewalk
This commit adds rollback handling during HMM migration page walks to unlock
and drop references on previously collected folios if page tables change while
locks are dropped.
> diff --git a/mm/hmm.c b/mm/hmm.c
> index 36a4edde9823c..5a1471fd5d288 100644
> --- a/mm/hmm.c
> +++ b/mm/hmm.c
[ ... ]
> @@ -282,6 +289,8 @@ static int hmm_vma_handle_pmd(struct mm_walk *walk, unsigned long addr,
> return hmm_record_fault(addr, end, required_fault, walk);
> }
>
> + hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk, addr,
> + end, hmm_pfns);
> pfn = pmd_pfn(pmd) + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
> for (i = 0; addr < end; addr += PAGE_SIZE, i++, pfn++) {
> hmm_pfns[i] &= HMM_PFN_INOUT_FLAGS;
[Severity: High]
What happens if entries in hmm_pfns were previously collected, locks were
dropped, and on re-walk the page table entry now requires a fault, fails with
-EFAULT, or is a PMD migration entry?
In hmm_vma_handle_pmd(), if required_fault is non-zero, it returns
hmm_record_fault() before calling hmm_vma_handle_migrate_prepare_rollback().
Several other paths similarly return before rolling back previously collected
entries in range->hmm_pfns:
- hmm_vma_walk_hole() returns -EFAULT (when !walk->vma) or
hmm_record_fault() when required_fault is non-zero before reaching
hmm_pfns_fill().
- hmm_vma_handle_absent_pmd() returns hmm_record_fault() or -EFAULT when
required_fault is non-zero without calling
hmm_vma_handle_migrate_prepare_rollback().
- hmm_vma_handle_pte() jumps to the fault: label or returns -EFAULT without
rolling back *hmm_pfn.
- hmm_vma_walk_pmd() returns -EFAULT on pmd_bad(pmd) when
hmm_range_need_fault() is non-zero, and returns 0 when
thp_migration_supported() && pmd_is_migration_entry(pmd) is true with
minfo non-zero, without rolling back collected PTE entries in
hmm_pfns_start.
If hmm_record_fault() returns HMM_FAULT_PENDING while the current task still
holds folio_lock() on previously collected folios in that range, can
hmm_do_fault() -> handle_mm_fault() deadlock trying to lock the same folio, or
can the early returns leave stale collected folios locked and referenced in
range->hmm_pfns?
> @@ -412,6 +421,9 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
>
> new_pfn_flags = pte_pfn(pte) | cpu_flags;
> out:
> + hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk, addr,
> + addr + PAGE_SIZE,
> + hmm_pfn);
> *hmm_pfn = (*hmm_pfn & HMM_PFN_INOUT_FLAGS) | new_pfn_flags;
> return 0;
>
[Severity: Critical]
Could reaching the out: label in hmm_vma_handle_pte() prematurely roll back a
migration PTE that this walk already installed?
In hmm_vma_handle_pte(), when !pte_present(pte) is true, the required_fault
check runs before softleaf_is_migration(entry):
if (!pte_present(pte)) {
...
required_fault =
hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0);
if (!required_fault)
goto out;
...
if (softleaf_is_migration(entry)) {
if (!hmm_select_migrate(range)) {
...
return -EBUSY;
}
return 0;
}
During a migration walk without HMM_PFN_REQ_FAULT (such as migrate_vma_setup()
where range.default_flags is HMM_PFN_REQ_MIGRATE),
hmm_vma_handle_migrate_prepare() locks the folio, takes a reference, installs
a migration PTE, and marks *hmm_pfn with HMM_PFN_VALID | HMM_PFN_MIGRATE.
If the walk restarts over that range (for example, after dropping locks in
migrate_vma_split_folio() or on an -EBUSY retry), hmm_vma_handle_pte() sees
!pte_present(pte) for its own migration PTE. Because HMM_PFN_REQ_FAULT is not
set, hmm_pte_need_fault() returns 0 and jumps to out: with new_pfn_flags = 0.
At out:, hmm_vma_handle_migrate_prepare_rollback() unlocks the folio, calls
folio_put(), and clears HMM_PFN_VALID | HMM_PFN_MIGRATE from *hmm_pfn while
the migration PTE remains installed in the page table, so
remove_migration_ptes() will never be called for it.
Conversely, when HMM_PFN_REQ_FAULT is set (required_fault != 0), the
softleaf_is_migration(entry) branch returns 0 whenever
hmm_select_migrate(range) is non-zero without checking that
hmm_pfn_collected(*hmm_pfn) is true and that softleaf_to_pfn(entry) matches
the PFN in *hmm_pfn. If the migration PTE belongs to a concurrent migration
(at an uncollected slot or in a replacement PTE table), shouldn't
hmm_vma_handle_pte() roll back any mismatched *hmm_pfn and wait via
migration_entry_wait()?
[ ... ]
> @@ -1117,6 +1193,9 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
> if (ptep) {
> lazy_mmu_mode_enable();
> hmm_vma_walk->ptelocked = true;
> + } else {
> + /* The pte table is gone */
> + hmm_vma_handle_migrate_prepare_rollback(walk->private, addr, end, hmm_pfns);
> }
> } else {
> ptep = pte_offset_map(pmdp, addr);
[Severity: High]
Does this rollback miss entries collected in [start, addr) when the PTE lock
is dropped partway through a PMD?
In hmm_vma_walk_pmd(), the PTE loop advances addr and hmm_pfns from start
toward end while collecting folios into hmm_pfns_start. If
hmm_vma_handle_migrate_prepare() hits a large folio at addr > start,
migrate_vma_split_folio() drops the PTE lock and returns -EAGAIN, and
hmm_vma_walk_pmd() jumps to again: without resetting addr = start:
again:
hmm_pfns = &range->hmm_pfns[(addr - range->start) >> PAGE_SHIFT];
...
if (minfo) {
ptep = pte_offset_map_lock(mm, pmdp, addr, &hmm_vma_walk->ptl);
if (ptep) {
lazy_mmu_mode_enable();
hmm_vma_walk->ptelocked = true;
} else {
/* The pte table is gone */
hmm_vma_handle_migrate_prepare_rollback(walk->private, addr, end, hmm_pfns);
}
}
if (!ptep) {
addr = start;
goto again;
}
When ptep is NULL at addr > start, hmm_vma_handle_migrate_prepare_rollback()
is called with addr and hmm_pfns before addr is reset to start, so it only
scans the uncollected tail [addr, end) and leaves folios collected in
[start, addr) (at hmm_pfns_start) locked and referenced.
In addition, if the PTE table was cleared and replaced by another PTE table
while the lock was dropped in migrate_vma_split_folio() (or during a mid-PMD
fault where hmm_record_fault() sets hmm_vma_walk->last = addr),
pte_offset_map_lock() succeeds at addr > start on the new PTE table and resumes
from addr without re-walking or rolling back [start, addr). Should mid-PMD lock
drops restart from start (with hmm_pfns_start) so that [start, addr) is
re-validated?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021060506.2377545-1-mpenttil@redhat.com?part=8
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v16 09/12] mm: enable device page migration from HMM pagewalk
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (7 preceding siblings ...)
2026-10-21 6:05 ` [PATCH v16 08/12] mm/hmm: implement rollback for device page " mpenttil
@ 2026-10-21 6:05 ` mpenttil
2026-10-21 6:19 ` Balbir Singh
2026-10-22 6:06 ` sashiko-bot
2026-10-21 6:05 ` [PATCH v16 10/12] lib/test_hmm: add a new testcase for the migrate on fault mpenttil
` (7 subsequent siblings)
16 siblings, 2 replies; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:05 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
HMM pagewalk has now the machinery to do the first phase of
device page migration, collecting the pfns and installing
migration ptes.
Enable migration in hmm_range_fault(), and change migrate_vma_setup()
to use HMM pagewalk path. Two new flags, MIGRATE_VMA_FAULT and
MIGRATE_VMA_WRITE are introduced for migrate_vma_setup(),
to request for faulting missing pages, and requesting write
access.
Also, the migrate_vma_collect*() based paths are now unused,
so delete them.
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Suggested-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
include/linux/migrate.h | 10 +-
mm/hmm.c | 33 ++-
mm/migrate_device.c | 562 ++++------------------------------------
3 files changed, 83 insertions(+), 522 deletions(-)
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index dd7dd7ec6995..3780c4c116b8 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -181,6 +181,8 @@ enum migrate_vma_info {
MIGRATE_VMA_SELECT_DEVICE_PRIVATE = 1 << 1,
MIGRATE_VMA_SELECT_DEVICE_COHERENT = 1 << 2,
MIGRATE_VMA_SELECT_COMPOUND = 1 << 3,
+ MIGRATE_VMA_FAULT = 1 << 4,
+ MIGRATE_VMA_WRITE = 1 << 5,
};
struct migrate_vma {
@@ -218,10 +220,14 @@ struct migrate_vma {
struct page *fault_page;
};
-// TODO: enable migration
static inline enum migrate_vma_info hmm_select_migrate(struct hmm_range *range)
{
- return 0;
+ enum migrate_vma_info minfo;
+
+ minfo = (range->default_flags & HMM_PFN_REQ_MIGRATE) ?
+ range->migrate->flags : 0;
+
+ return minfo;
}
#ifdef CONFIG_MMU_NOTIFIER
diff --git a/mm/hmm.c b/mm/hmm.c
index 5a1471fd5d28..4d853ee8e8b8 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -1542,14 +1542,43 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
* the invalidation to finish.
* -EFAULT: A page was requested to be valid and could not be made valid
* ie it has no backing VMA or it is illegal to access
+ * -ERANGE: The range crosses multiple VMAs, or space for hmm_pfns array
+ * is too low.
*
* This is similar to get_user_pages(), except that it can read the page tables
* without mutating them (ie causing faults).
*
* The mmap lock must be held by the caller and will remain held on return.
* New users should prefer hmm_range_fault_unlocked_timeout() unless they
- * specifically need to keep the mmap lock held across the call. This helper
- * cannot support VMAs whose fault handlers need to drop the mmap lock.
+ * specifically need to keep the mmap lock held across the call like while
+ * migrating. This helper cannot support VMAs whose fault handlers need to
+ * drop the mmap lock.
+ *
+ * If want to do migration after faulting, call hmm_range_fault() with
+ * range.default_flags of HMM_PFN_REQ_MIGRATE, and optionally
+ * HMM_PFN_REQ_FAULT|HMM_PFN_REQ_WRITE, and initialize range->migrate field.
+ * range->migrate->vma will be populated during the call,
+ * and must be stable across the whole migrate process, which is
+ * why mmap_lock must be held around this call.
+ *
+ * When HMM_PFN_REQ_MIGRATE is set, migration collection may be partial on
+ * return and the caller takes responsibility for completing or aborting it.
+ *
+ * On success, the caller must call migrate_hmm_range_setup() and may then
+ * proceed with the normal migrate_vma sequence: prepare destination pages,
+ * call migrate_vma_pages(), update device mappings as needed, and finally
+ * call migrate_vma_finalize().
+ *
+ * On -EBUSY, the caller may retry hmm_range_fault() using the same range and
+ * PFN array without undoing entries collected by the previous attempt. If
+ * the caller stops retrying, it must abort the partial migration.
+ *
+ * On any other error, or when abandoning a retry, the caller must call
+ * migrate_hmm_range_setup(), migrate_vma_pages() with no valid destination
+ * entries, and migrate_vma_finalize() to abort the partial migration.
+ *
+ * The mmap read lock must remain held until the migration has either been
+ * completed or aborted.
*/
int hmm_range_fault(struct hmm_range *range)
{
diff --git a/mm/migrate_device.c b/mm/migrate_device.c
index 43e571e82cca..1e1a592e1267 100644
--- a/mm/migrate_device.c
+++ b/mm/migrate_device.c
@@ -18,519 +18,6 @@
#include <asm/tlbflush.h>
#include "internal.h"
-static int migrate_vma_collect_skip(unsigned long start,
- unsigned long end,
- struct mm_walk *walk)
-{
- struct migrate_vma *migrate = walk->private;
- unsigned long addr;
-
- for (addr = start; addr < end; addr += PAGE_SIZE) {
- migrate->dst[migrate->npages] = 0;
- migrate->src[migrate->npages++] = 0;
- }
-
- return 0;
-}
-
-static int migrate_vma_collect_hole(unsigned long start,
- unsigned long end,
- __always_unused int depth,
- struct mm_walk *walk)
-{
- struct migrate_vma *migrate = walk->private;
- unsigned long addr;
-
- /* Only allow populating anonymous memory. */
- if (!vma_is_anonymous(walk->vma))
- return migrate_vma_collect_skip(start, end, walk);
-
- if (thp_migration_supported() &&
- (migrate->flags & MIGRATE_VMA_SELECT_COMPOUND) &&
- (IS_ALIGNED(start, HPAGE_PMD_SIZE) &&
- IS_ALIGNED(end, HPAGE_PMD_SIZE))) {
- migrate->src[migrate->npages] = MIGRATE_PFN_MIGRATE |
- MIGRATE_PFN_COMPOUND;
- migrate->dst[migrate->npages] = 0;
- migrate->npages++;
- migrate->cpages++;
-
- /*
- * Collect the remaining entries as holes, in case we
- * need to split later
- */
- return migrate_vma_collect_skip(start + PAGE_SIZE, end, walk);
- }
-
- for (addr = start; addr < end; addr += PAGE_SIZE) {
- migrate->src[migrate->npages] = MIGRATE_PFN_MIGRATE;
- migrate->dst[migrate->npages] = 0;
- migrate->npages++;
- migrate->cpages++;
- }
-
- return 0;
-}
-
-/**
- * migrate_vma_split_folio() - Helper function to split a THP folio
- * @folio: the folio to split
- * @fault_page: struct page associated with the fault if any
- *
- * If @folio is not the folio containing @fault_page, the caller must hold a
- * reference on @folio. The helper consumes that reference.
- *
- * Returns 0 on success
- */
-static int migrate_vma_split_folio(struct folio *folio,
- struct page *fault_page)
-{
- int ret;
- struct folio *fault_folio = fault_page ? page_folio(fault_page) : NULL;
- struct folio *new_fault_folio = NULL;
-
- if (folio != fault_folio)
- folio_lock(folio);
-
- ret = split_folio(folio);
- if (ret) {
- if (folio != fault_folio) {
- folio_unlock(folio);
- folio_put(folio);
- }
- return ret;
- }
-
- new_fault_folio = fault_page ? page_folio(fault_page) : NULL;
-
- /*
- * Ensure the lock is held on the correct
- * folio after the split
- */
- if (!new_fault_folio) {
- folio_unlock(folio);
- folio_put(folio);
- } else if (folio != new_fault_folio) {
- if (new_fault_folio != fault_folio) {
- folio_get(new_fault_folio);
- folio_lock(new_fault_folio);
- }
- folio_unlock(folio);
- folio_put(folio);
- }
-
- return 0;
-}
-
-/** migrate_vma_collect_huge_pmd - collect THP pages without splitting the
- * folio for device private pages.
- * @pmdp: pointer to pmd entry
- * @start: start address of the range for migration
- * @end: end address of the range for migration
- * @walk: mm_walk callback structure
- * @fault_folio: folio associated with the fault if any
- *
- * Collect the huge pmd entry at @pmdp for migration and set the
- * MIGRATE_PFN_COMPOUND flag in the migrate src entry to indicate that
- * migration will occur at HPAGE_PMD granularity
- */
-static int migrate_vma_collect_huge_pmd(pmd_t *pmdp, unsigned long start,
- unsigned long end, struct mm_walk *walk,
- struct folio *fault_folio)
-{
- struct mm_struct *mm = walk->mm;
- struct folio *folio;
- struct migrate_vma *migrate = walk->private;
- spinlock_t *ptl;
- int ret;
- unsigned long write = 0;
-
- ptl = pmd_lock(mm, pmdp);
- if (pmd_none(*pmdp)) {
- spin_unlock(ptl);
- return migrate_vma_collect_hole(start, end, -1, walk);
- }
-
- if (pmd_trans_huge(*pmdp)) {
- if (!(migrate->flags & MIGRATE_VMA_SELECT_SYSTEM)) {
- spin_unlock(ptl);
- return migrate_vma_collect_skip(start, end, walk);
- }
-
- folio = pmd_folio(*pmdp);
- if (is_huge_zero_folio(folio)) {
- spin_unlock(ptl);
- return migrate_vma_collect_hole(start, end, -1, walk);
- }
- if (pmd_write(*pmdp))
- write = MIGRATE_PFN_WRITE;
- } else if (!pmd_present(*pmdp)) {
- const softleaf_t entry = softleaf_from_pmd(*pmdp);
-
- if (!softleaf_is_device_private(entry) ||
- !(migrate->flags & MIGRATE_VMA_SELECT_DEVICE_PRIVATE)) {
- spin_unlock(ptl);
- return migrate_vma_collect_skip(start, end, walk);
- }
-
- folio = softleaf_to_folio(entry);
- if (folio->pgmap->owner != migrate->pgmap_owner) {
- spin_unlock(ptl);
- return migrate_vma_collect_skip(start, end, walk);
- }
-
- if (softleaf_is_device_private_write(entry))
- write = MIGRATE_PFN_WRITE;
- } else {
- spin_unlock(ptl);
- return -EAGAIN;
- }
-
- folio_get(folio);
- if (folio != fault_folio && unlikely(!folio_trylock(folio))) {
- spin_unlock(ptl);
- folio_put(folio);
- return migrate_vma_collect_skip(start, end, walk);
- }
-
- if (thp_migration_supported() &&
- (migrate->flags & MIGRATE_VMA_SELECT_COMPOUND) &&
- (IS_ALIGNED(start, HPAGE_PMD_SIZE) &&
- IS_ALIGNED(end, HPAGE_PMD_SIZE))) {
-
- struct page_vma_mapped_walk pvmw = {
- .ptl = ptl,
- .address = start,
- .pmd = pmdp,
- .vma = walk->vma,
- };
-
- unsigned long pfn = page_to_pfn(folio_page(folio, 0));
-
- migrate->src[migrate->npages] = migrate_pfn(pfn) | write
- | MIGRATE_PFN_MIGRATE
- | MIGRATE_PFN_COMPOUND;
- migrate->dst[migrate->npages++] = 0;
- migrate->cpages++;
- ret = set_pmd_migration_entry(&pvmw, folio_page(folio, 0));
- if (ret) {
- migrate->npages--;
- migrate->cpages--;
- migrate->src[migrate->npages] = 0;
- migrate->dst[migrate->npages] = 0;
- goto fallback;
- }
- migrate_vma_collect_skip(start + PAGE_SIZE, end, walk);
- spin_unlock(ptl);
- return 0;
- }
-
-fallback:
- spin_unlock(ptl);
- if (!folio_test_large(folio))
- goto done;
- ret = split_folio(folio);
- if (fault_folio != folio)
- folio_unlock(folio);
- folio_put(folio);
- if (ret)
- return migrate_vma_collect_skip(start, end, walk);
- if (pmd_none(pmdp_get_lockless(pmdp)))
- return migrate_vma_collect_hole(start, end, -1, walk);
-
-done:
- return -ENOENT;
-}
-
-static int migrate_vma_collect_pmd(pmd_t *pmdp,
- unsigned long start,
- unsigned long end,
- struct mm_walk *walk)
-{
- struct migrate_vma *migrate = walk->private;
- struct vm_area_struct *vma = walk->vma;
- struct mm_struct *mm = vma->vm_mm;
- unsigned long addr = start, unmapped = 0;
- spinlock_t *ptl;
- struct folio *fault_folio = migrate->fault_page ?
- page_folio(migrate->fault_page) : NULL;
- pte_t *ptep;
-
-again:
- if (pmd_trans_huge(*pmdp) || !pmd_present(*pmdp)) {
- int ret = migrate_vma_collect_huge_pmd(pmdp, start, end, walk, fault_folio);
-
- if (ret == -EAGAIN)
- goto again;
- if (ret == 0)
- return 0;
- }
-
- ptep = pte_offset_map_lock(mm, pmdp, start, &ptl);
- if (!ptep)
- goto again;
- lazy_mmu_mode_enable();
- ptep += (addr - start) / PAGE_SIZE;
-
- for (; addr < end; addr += PAGE_SIZE, ptep++) {
- struct dev_pagemap *pgmap;
- unsigned long mpfn = 0, pfn;
- struct folio *folio;
- struct page *page;
- softleaf_t entry;
- pte_t pte;
-
- pte = ptep_get(ptep);
-
- if (pte_none(pte)) {
- if (vma_is_anonymous(vma)) {
- mpfn = MIGRATE_PFN_MIGRATE;
- migrate->cpages++;
- }
- goto next;
- }
-
- if (!pte_present(pte)) {
- /*
- * Only care about unaddressable device page special
- * page table entry. Other special swap entries are not
- * migratable, and we ignore regular swapped page.
- */
- entry = softleaf_from_pte(pte);
- if (!softleaf_is_device_private(entry))
- goto next;
-
- page = softleaf_to_page(entry);
- pgmap = page_pgmap(page);
- if (!(migrate->flags &
- MIGRATE_VMA_SELECT_DEVICE_PRIVATE) ||
- pgmap->owner != migrate->pgmap_owner)
- goto next;
-
- folio = page_folio(page);
- if (folio_test_large(folio)) {
- int ret;
-
- /* migrate_vma_split_folio() consumes this reference */
- if (folio != fault_folio)
- folio_get(folio);
- lazy_mmu_mode_disable();
- pte_unmap_unlock(ptep, ptl);
- ret = migrate_vma_split_folio(folio,
- migrate->fault_page);
-
- if (ret) {
- if (unmapped)
- flush_tlb_range(walk->vma, start, end);
-
- return migrate_vma_collect_skip(addr, end, walk);
- }
-
- goto again;
- }
-
- mpfn = migrate_pfn(page_to_pfn(page)) |
- MIGRATE_PFN_MIGRATE;
- if (softleaf_is_device_private_write(entry))
- mpfn |= MIGRATE_PFN_WRITE;
- } else {
- pfn = pte_pfn(pte);
- if (is_zero_pfn(pfn) &&
- (migrate->flags & MIGRATE_VMA_SELECT_SYSTEM)) {
- mpfn = MIGRATE_PFN_MIGRATE;
- migrate->cpages++;
- goto next;
- }
- page = vm_normal_page(migrate->vma, addr, pte);
- if (page && !is_zone_device_page(page) &&
- !(migrate->flags & MIGRATE_VMA_SELECT_SYSTEM)) {
- goto next;
- } else if (page && is_device_coherent_page(page)) {
- pgmap = page_pgmap(page);
-
- if (!(migrate->flags &
- MIGRATE_VMA_SELECT_DEVICE_COHERENT) ||
- pgmap->owner != migrate->pgmap_owner)
- goto next;
- }
- folio = page ? page_folio(page) : NULL;
- if (folio && folio_test_large(folio)) {
- int ret;
-
- /* migrate_vma_split_folio() consumes this reference */
- if (folio != fault_folio)
- folio_get(folio);
- lazy_mmu_mode_disable();
- pte_unmap_unlock(ptep, ptl);
- ret = migrate_vma_split_folio(folio,
- migrate->fault_page);
-
- if (ret) {
- if (unmapped)
- flush_tlb_range(walk->vma, start, end);
-
- return migrate_vma_collect_skip(addr, end, walk);
- }
-
- goto again;
- }
- mpfn = migrate_pfn(pfn) | MIGRATE_PFN_MIGRATE;
- mpfn |= pte_write(pte) ? MIGRATE_PFN_WRITE : 0;
- }
-
- if (!page || !page->mapping) {
- mpfn = 0;
- goto next;
- }
-
- /*
- * By getting a reference on the folio we pin it and that blocks
- * any kind of migration. Side effect is that it "freezes" the
- * pte.
- *
- * We drop this reference after isolating the folio from the lru
- * for non device folio (device folio are not on the lru and thus
- * can't be dropped from it).
- */
- folio = page_folio(page);
- folio_get(folio);
-
- /*
- * We rely on folio_trylock() to avoid deadlock between
- * concurrent migrations where each is waiting on the others
- * folio lock. If we can't immediately lock the folio we fail this
- * migration as it is only best effort anyway.
- *
- * If we can lock the folio it's safe to set up a migration entry
- * now. In the common case where the folio is mapped once in a
- * single process setting up the migration entry now is an
- * optimisation to avoid walking the rmap later with
- * try_to_migrate().
- */
- if (fault_folio == folio || folio_trylock(folio)) {
- bool anon_exclusive;
- pte_t swp_pte;
-
- if (pte_present(pte))
- flush_cache_page(vma, addr, pte_pfn(pte));
- anon_exclusive = folio_test_anon(folio) &&
- PageAnonExclusive(page);
- if (anon_exclusive) {
- pte = ptep_clear_flush(vma, addr, ptep);
-
- if (folio_try_share_anon_rmap_pte(folio, page)) {
- set_pte_at(mm, addr, ptep, pte);
- if (fault_folio != folio)
- folio_unlock(folio);
- folio_put(folio);
- mpfn = 0;
- goto next;
- }
- } else {
- pte = ptep_get_and_clear(mm, addr, ptep);
- }
-
- migrate->cpages++;
-
- /* Set the dirty flag on the folio now the pte is gone. */
- if (pte_present(pte) && pte_dirty(pte))
- folio_mark_dirty(folio);
-
- /* Setup special migration page table entry */
- if (mpfn & MIGRATE_PFN_WRITE)
- entry = make_writable_migration_entry(
- page_to_pfn(page));
- else if (anon_exclusive)
- entry = make_readable_exclusive_migration_entry(
- page_to_pfn(page));
- else
- entry = make_readable_migration_entry(
- page_to_pfn(page));
- if (pte_present(pte)) {
- if (pte_young(pte))
- entry = make_migration_entry_young(entry);
- if (pte_dirty(pte))
- entry = make_migration_entry_dirty(entry);
- }
- swp_pte = swp_entry_to_pte(entry);
- if (pte_present(pte)) {
- if (pte_soft_dirty(pte))
- swp_pte = pte_swp_mksoft_dirty(swp_pte);
- if (pte_uffd(pte))
- swp_pte = pte_swp_mkuffd(swp_pte);
- } else {
- if (pte_swp_soft_dirty(pte))
- swp_pte = pte_swp_mksoft_dirty(swp_pte);
- if (pte_swp_uffd(pte))
- swp_pte = pte_swp_mkuffd(swp_pte);
- }
- set_pte_at(mm, addr, ptep, swp_pte);
-
- /*
- * This is like regular unmap: we remove the rmap and
- * drop the folio refcount. The folio won't be freed, as
- * we took a reference just above.
- */
- folio_remove_rmap_pte(folio, page, vma);
- folio_put(folio);
-
- if (pte_present(pte))
- unmapped++;
- } else {
- folio_put(folio);
- mpfn = 0;
- }
-
-next:
- migrate->dst[migrate->npages] = 0;
- migrate->src[migrate->npages++] = mpfn;
- }
-
- /* Only flush the TLB if we actually modified any entries */
- if (unmapped)
- flush_tlb_range(walk->vma, start, end);
-
- lazy_mmu_mode_disable();
- pte_unmap_unlock(ptep - 1, ptl);
-
- return 0;
-}
-
-static const struct mm_walk_ops migrate_vma_walk_ops = {
- .pmd_entry = migrate_vma_collect_pmd,
- .pte_hole = migrate_vma_collect_hole,
- .walk_lock = PGWALK_RDLOCK,
-};
-
-/*
- * migrate_vma_collect() - collect pages over a range of virtual addresses
- * @migrate: migrate struct containing all migration information
- *
- * This will walk the CPU page table. For each virtual address backed by a
- * valid page, it updates the src array and takes a reference on the page, in
- * order to pin the page until we lock it and unmap it.
- */
-static void migrate_vma_collect(struct migrate_vma *migrate)
-{
- struct mmu_notifier_range range;
-
- /*
- * Note that the pgmap_owner is passed to the mmu notifier callback so
- * that the registered device driver can skip invalidating device
- * private page mappings that won't be migrated.
- */
- mmu_notifier_range_init_owner(&range, MMU_NOTIFY_MIGRATE, 0,
- migrate->vma->vm_mm, migrate->start, migrate->end,
- migrate->pgmap_owner);
- mmu_notifier_invalidate_range_start(&range);
-
- walk_page_range_vma(migrate->vma, migrate->start, migrate->end,
- &migrate_vma_walk_ops, migrate);
-
- mmu_notifier_invalidate_range_end(&range);
- migrate->end = migrate->start + (migrate->npages << PAGE_SHIFT);
-}
-
/*
* migrate_vma_check_page() - check if page is pinned or not
* @page: struct page to check
@@ -677,8 +164,9 @@ static void migrate_vma_unmap(struct migrate_vma *migrate)
* migrate_vma_setup() - prepare to migrate a range of memory
* @args: contains the vma, start, and pfns arrays for the migration
*
- * Returns: negative errno on failures, 0 when 0 or more pages were migrated
- * without an error.
+ * Returns: -EINVAL on invalid arguments, 0 otherwise. A 0 return does not
+ * imply anything was collected; on return @args->cpages holds the number of
+ * pages prepared for migration (possibly 0). See the note on faulting below.
*
* Prepare to migrate a range of memory virtual address range by collecting all
* the pages backing each virtual address in the range, saving them inside the
@@ -688,6 +176,20 @@ static void migrate_vma_unmap(struct migrate_vma *migrate)
* corresponding src array entry. Then restores any pages that are pinned, by
* remapping and unlocking those pages.
*
+ * By default migrate_vma_setup() is best-effort: virtual addresses that cannot
+ * be collected are left with an empty src[] entry and the rest of the range
+ * still proceeds.
+ *
+ * The optional flags MIGRATE_VMA_FAULT and MIGRATE_VMA_WRITE in @args->flags
+ * additionally fault in missing pages before collecting them, for read and for
+ * write respectively. Unlike the best-effort default, if such a fault cannot be
+ * satisfied the whole range is aborted: the partial collection is rolled back,
+ * @args->src is cleared, @args->cpages and @args->npages are reset to 0,
+ * and migrate_vma_setup() still returns 0. The fault error is therefore not
+ * observable through this interface. Callers that need to act on fault failures
+ * should instead drive the migration directly via hmm_range_fault() followed by
+ * migrate_hmm_range_setup(), which preserves the error code.
+ *
* The caller should then allocate destination memory and copy source memory to
* it for all those entries (ie with MIGRATE_PFN_VALID and MIGRATE_PFN_MIGRATE
* flag set). Once these are allocated and copied, the caller must update each
@@ -739,10 +241,20 @@ static void migrate_vma_unmap(struct migrate_vma *migrate)
*/
int migrate_vma_setup(struct migrate_vma *args)
{
+ int ret;
long nr_pages = (args->end - args->start) >> PAGE_SHIFT;
+ struct hmm_range range = {
+ .notifier = NULL,
+ .hmm_pfns = args->src,
+ .dev_private_owner = args->pgmap_owner,
+ .migrate = args,
+ .default_flags = HMM_PFN_REQ_MIGRATE
+ };
args->start &= PAGE_MASK;
args->end &= PAGE_MASK;
+ range.start = args->start;
+ range.end = args->end;
if (!args->vma || is_vm_hugetlb_page(args->vma) ||
(args->vma->vm_flags & VM_SPECIAL) || vma_is_dax(args->vma))
return -EINVAL;
@@ -764,10 +276,24 @@ int migrate_vma_setup(struct migrate_vma *args)
args->cpages = 0;
args->npages = 0;
- migrate_vma_collect(args);
+ if (args->flags & MIGRATE_VMA_FAULT)
+ range.default_flags |= HMM_PFN_REQ_FAULT;
- if (args->cpages)
- migrate_vma_unmap(args);
+ if (args->flags & MIGRATE_VMA_WRITE)
+ range.default_flags |= HMM_PFN_REQ_FAULT | HMM_PFN_REQ_WRITE;
+
+ ret = hmm_range_fault(&range);
+
+ migrate_hmm_range_setup(&range);
+
+ /* Remove migration PTEs */
+ if (ret) {
+ migrate_vma_pages(args);
+ migrate_vma_finalize(args);
+ memset(args->src, 0, sizeof(*args->src) * nr_pages);
+ args->cpages = 0;
+ args->npages = 0;
+ }
/*
* At this point pages are locked and unmapped, and thus they have
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v16 09/12] mm: enable device page migration from HMM pagewalk
2026-10-21 6:05 ` [PATCH v16 09/12] mm: enable device page migration from " mpenttil
@ 2026-10-21 6:19 ` Balbir Singh
2026-10-21 6:30 ` Mika Penttilä
2026-10-22 6:06 ` sashiko-bot
1 sibling, 1 reply; 33+ messages in thread
From: Balbir Singh @ 2026-10-21 6:19 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, linux-kernel, David Hildenbrand,
Jason Gunthorpe, Leon Romanovsky, Alistair Popple, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
On 10/21/26 5:05 PM, mpenttil@redhat.com wrote:
> From: Mika Penttilä <mpenttil@redhat.com>
>
> HMM pagewalk has now the machinery to do the first phase of
> device page migration, collecting the pfns and installing
> migration ptes.
>
> Enable migration in hmm_range_fault(), and change migrate_vma_setup()
> to use HMM pagewalk path. Two new flags, MIGRATE_VMA_FAULT and
> MIGRATE_VMA_WRITE are introduced for migrate_vma_setup(),
> to request for faulting missing pages, and requesting write
> access.
>
> Also, the migrate_vma_collect*() based paths are now unused,
> so delete them.
>
> Cc: David Hildenbrand <david@kernel.org>
> Cc: Jason Gunthorpe <jgg@nvidia.com>
> Cc: Leon Romanovsky <leonro@nvidia.com>
> Cc: Alistair Popple <apopple@nvidia.com>
> Cc: Balbir Singh <balbirs@nvidia.com>
> Cc: Zi Yan <ziy@nvidia.com>
> Cc: Matthew Brost <matthew.brost@intel.com>
> Suggested-by: Alistair Popple <apopple@nvidia.com>
> Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
> ---
> include/linux/migrate.h | 10 +-
> mm/hmm.c | 33 ++-
> mm/migrate_device.c | 562 ++++------------------------------------
> 3 files changed, 83 insertions(+), 522 deletions(-)
>
I got a conflict applying this patch on the latest mm-everything with
mm: avoid use of VMA_SPECIAL_FLAGS in migrate_vma_setup(), quite a simple fixup
Balbir
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v16 09/12] mm: enable device page migration from HMM pagewalk
2026-10-21 6:19 ` Balbir Singh
@ 2026-10-21 6:30 ` Mika Penttilä
0 siblings, 0 replies; 33+ messages in thread
From: Mika Penttilä @ 2026-10-21 6:30 UTC (permalink / raw)
To: Balbir Singh, linux-mm
Cc: dri-devel, intel-xe, linux-kernel, David Hildenbrand,
Jason Gunthorpe, Leon Romanovsky, Alistair Popple, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
On 10/21/26 09:19, Balbir Singh wrote:
> On 10/21/26 5:05 PM, mpenttil@redhat.com wrote:
>> From: Mika Penttilä <mpenttil@redhat.com>
>>
>> HMM pagewalk has now the machinery to do the first phase of
>> device page migration, collecting the pfns and installing
>> migration ptes.
>>
>> Enable migration in hmm_range_fault(), and change migrate_vma_setup()
>> to use HMM pagewalk path. Two new flags, MIGRATE_VMA_FAULT and
>> MIGRATE_VMA_WRITE are introduced for migrate_vma_setup(),
>> to request for faulting missing pages, and requesting write
>> access.
>>
>> Also, the migrate_vma_collect*() based paths are now unused,
>> so delete them.
>>
>> Cc: David Hildenbrand <david@kernel.org>
>> Cc: Jason Gunthorpe <jgg@nvidia.com>
>> Cc: Leon Romanovsky <leonro@nvidia.com>
>> Cc: Alistair Popple <apopple@nvidia.com>
>> Cc: Balbir Singh <balbirs@nvidia.com>
>> Cc: Zi Yan <ziy@nvidia.com>
>> Cc: Matthew Brost <matthew.brost@intel.com>
>> Suggested-by: Alistair Popple <apopple@nvidia.com>
>> Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
>> ---
>> include/linux/migrate.h | 10 +-
>> mm/hmm.c | 33 ++-
>> mm/migrate_device.c | 562 ++++------------------------------------
>> 3 files changed, 83 insertions(+), 522 deletions(-)
>>
> I got a conflict applying this patch on the latest mm-everything with
> mm: avoid use of VMA_SPECIAL_FLAGS in migrate_vma_setup(), quite a simple fixup
>
> Balbir
Ah okay - yes this is on drm-tip
--Mika
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v16 09/12] mm: enable device page migration from HMM pagewalk
2026-10-21 6:05 ` [PATCH v16 09/12] mm: enable device page migration from " mpenttil
2026-10-21 6:19 ` Balbir Singh
@ 2026-10-22 6:06 ` sashiko-bot
1 sibling, 0 replies; 33+ messages in thread
From: sashiko-bot @ 2026-10-22 6:06 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, David Hildenbrand, Jason Gunthorpe,
Leon Romanovsky, Alistair Popple, Balbir Singh, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [Critical] mm: hmm_vma_handle_pte() corrupts migration PTE state during migration
- [High] mm: migrate_vma_setup() skips non-VM_READ VMAs via hmm_vma_walk_test()
- [High] mm: hmm_vma_handle_pte() faults entire PMD range [addr, end) on fault
- [High] mm: hmm_range_fault_locked() calls handle_mm_fault() under folio_lock()
- [High] mm: hmm_vma_walk_pmd() fails to roll back collected entries on retry
- [High] mm: uninitialized migrate bounds and pfn offset in hmm_range_fault()
- [High] mm: self-invalidation of range->notifier during hmm_range_fault()
- [High] mm/hmm: refcount-before-lock and blocking folio_lock() in migrate_vma_split_folio()
- [Medium] mm: migrate_vma_setup() skips protnone pages when fault flag is unset
--
commit 6029fe80390f5816cec1bea4014e1df1b5d1785d
Author: Mika Penttilä <mpenttil@redhat.com>
mm: enable device page migration from HMM pagewalk
This commit enables device page migration through the HMM page table walk in
hmm_range_fault(), switches migrate_vma_setup() to use hmm_range_fault() and
migrate_hmm_range_setup(), and removes the legacy migrate_vma_collect() walk.
> diff --git a/include/linux/migrate.h b/include/linux/migrate.h
> index dd7dd7ec6995e..3780c4c116b8a 100644
> --- a/include/linux/migrate.h
> +++ b/include/linux/migrate.h
> @@ -181,6 +181,8 @@ enum migrate_vma_info {
> MIGRATE_VMA_SELECT_DEVICE_PRIVATE = 1 << 1,
> MIGRATE_VMA_SELECT_DEVICE_COHERENT = 1 << 2,
> MIGRATE_VMA_SELECT_COMPOUND = 1 << 3,
> + MIGRATE_VMA_FAULT = 1 << 4,
> + MIGRATE_VMA_WRITE = 1 << 5,
> };
>
> struct migrate_vma {
> @@ -218,10 +220,14 @@ struct migrate_vma {
> struct page *fault_page;
> };
>
> -// TODO: enable migration
> static inline enum migrate_vma_info hmm_select_migrate(struct hmm_range *range)
> {
> - return 0;
> + enum migrate_vma_info minfo;
> +
> + minfo = (range->default_flags & HMM_PFN_REQ_MIGRATE) ?
> + range->migrate->flags : 0;
> +
> + return minfo;
> }
[Severity: Critical]
When hmm_select_migrate() is enabled, can hmm_vma_handle_pte() in mm/hmm.c
roll back an already-installed migration PTE without restoring the page table
entry, and also skip waiting on foreign migration entries?
In mm/hmm.c:hmm_vma_handle_pte():
if (!pte_present(pte)) {
const softleaf_t entry = softleaf_from_pte(pte);
...
required_fault =
hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0);
if (!required_fault)
goto out;
...
if (softleaf_is_migration(entry)) {
if (!hmm_select_migrate(range)) {
HMM_ASSERT_UNLOCKED(hmm_vma_walk);
pte_unmap(ptep);
hmm_vma_walk->last = addr;
migration_entry_wait(walk->mm, pmdp, addr);
return -EBUSY;
}
return 0;
}
...
out:
hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk, addr,
addr + PAGE_SIZE,
hmm_pfn);
*hmm_pfn = (*hmm_pfn & HMM_PFN_INOUT_FLAGS) | new_pfn_flags;
return 0;
First, when HMM_PFN_REQ_FAULT is not set (the default in migrate_vma_setup()),
required_fault is 0. If hmm_vma_handle_migrate_prepare() collects a page at
addr (locking the folio, taking a reference, installing a migration PTE, and
setting HMM_PFN_VALID | HMM_PFN_MIGRATE in *hmm_pfn) and that PTE is visited
again (for example when hmm_vma_walk_pmd() restarts from start after !ptep,
when hmm_range_fault_locked() loops on -EBUSY after a THP split, or when a
caller retries hmm_range_fault() on -EBUSY), hmm_vma_handle_pte() sees
!pte_present(pte) and jumps to out: before checking softleaf_is_migration().
At out:, hmm_vma_handle_migrate_prepare_rollback() unlocks the folio, drops
its reference, and clears *hmm_pfn to 0, leaving the migration PTE dangling
in the page table. A similar issue happens if migrate_vma_split_folio() fails
in hmm_vma_walk_pmd() and calls hmm_pfns_fill(addr, end, hmm_vma_walk,
HMM_PFN_ERROR) over entries that were already collected in a prior pass.
Second, when HMM_PFN_REQ_FAULT is set and hmm_vma_handle_pte() or
hmm_vma_walk_pmd() encounters a migration PTE or PMD installed by another
thread (!hmm_pfn_collected(*hmm_pfn)), checking if (!hmm_select_migrate(range))
or if (!minfo) causes the walk to return 0 without waiting via
migration_entry_wait() / pmd_migration_entry_wait() and without populating
*hmm_pfn.
Should hmm_vma_handle_pte() check softleaf_is_migration(entry) before the
!required_fault branch and distinguish entries already collected by this walk
(hmm_pfn_collected(*hmm_pfn)) from foreign migration entries?
[Severity: High]
Also in mm/hmm.c:hmm_vma_walk_pmd(), when minfo is non-zero and the PTE lock
is dropped mid-PMD (such as in migrate_vma_split_folio() returning -EAGAIN at
addr > start), could already-collected entries in [start, addr) fail to be
rolled back if the PTE page table disappears or is replaced?
In mm/hmm.c:hmm_vma_walk_pmd():
if (minfo) {
ptep = pte_offset_map_lock(mm, pmdp, addr, &hmm_vma_walk->ptl);
if (ptep) {
lazy_mmu_mode_enable();
hmm_vma_walk->ptelocked = true;
} else {
/* The pte table is gone */
hmm_vma_handle_migrate_prepare_rollback(walk->private, addr, end, hmm_pfns);
}
} else {
ptep = pte_offset_map(pmdp, addr);
}
if (!ptep) {
addr = start;
goto again;
}
When addr > start, the entries collected earlier in the same PMD are in
[start, addr) starting at hmm_pfns_start, whereas [addr, end) starting at
hmm_pfns is the unwalked remainder of the PMD. Passing addr, end, hmm_pfns to
hmm_vma_handle_migrate_prepare_rollback() leaves [start, addr) locked and
referenced with HMM_PFN_VALID | HMM_PFN_MIGRATE set.
Moreover, if addr is reset to start and goto again finds that *pmdp is now a
PMD migration entry (pmd_is_migration_entry(pmd)), or if hmm_vma_walk_hole(),
hmm_vma_handle_pmd(), or hmm_vma_handle_absent_pmd() returns HMM_FAULT_PENDING
or -EFAULT before reaching their rollback calls, the previously collected
folios in hmm_pfns_start are never rolled back either.
Should the rollback when !ptep (and before early returns after goto again)
cover start to end using hmm_pfns_start?
[Severity: High]
Enabling hmm_select_migrate() also activates migrate_vma_split_folio() in
mm/hmm.c when hmm_vma_handle_migrate_prepare() encounters a PTE-mapped large
folio:
static int migrate_vma_split_folio(struct folio *folio,
struct page *fault_page,
struct hmm_vma_walk *hmm_vma_walk,
pte_t *ptep)
{
struct folio *fault_folio = fault_page ? page_folio(fault_page) : NULL;
if (folio != fault_folio)
folio_get(folio);
lazy_mmu_mode_disable();
pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
hmm_vma_walk->ptelocked = false;
if (folio != fault_folio)
folio_lock(folio);
return __migrate_vma_split_folio(folio, fault_page);
}
Unlike hmm_vma_handle_migrate_prepare_pmd() and the order-0 path in
hmm_vma_handle_migrate_prepare(), which use folio_trylock() because current
may already hold folio_lock on fault_folio and on folios collected at earlier
addresses in the walk, migrate_vma_split_folio() calls blocking folio_lock().
Can this deadlock if two concurrent migrations lock folios in opposite order,
or if another task holds folio_lock(folio) while waiting on a migration entry
installed earlier in this walk?
In addition, calling folio_get(folio) before blocking on folio_lock(folio)
means that if two tasks concurrently enter migrate_vma_split_folio() on the
same large folio, the waiting task's extra reference will cause the lock
holder's split_folio() call to fail with -EAGAIN. Would it be safer to use
folio_trylock() here as well?
> diff --git a/mm/hmm.c b/mm/hmm.c
> index 5a1471fd5d288..4d853ee8e8b8c 100644
> --- a/mm/hmm.c
> +++ b/mm/hmm.c
> @@ -1542,14 +1542,43 @@ static int hmm_range_fault_locked(struct hmm_range *range, bool *locked)
> * the invalidation to finish.
> * -EFAULT: A page was requested to be valid and could not be made valid
> * ie it has no backing VMA or it is illegal to access
> + * -ERANGE: The range crosses multiple VMAs, or space for hmm_pfns array
> + * is too low.
> *
> * This is similar to get_user_pages(), except that it can read the page tables
> * without mutating them (ie causing faults).
> *
> * The mmap lock must be held by the caller and will remain held on return.
> * New users should prefer hmm_range_fault_unlocked_timeout() unless they
> - * specifically need to keep the mmap lock held across the call. This helper
> - * cannot support VMAs whose fault handlers need to drop the mmap lock.
> + * specifically need to keep the mmap lock held across the call like while
> + * migrating. This helper cannot support VMAs whose fault handlers need to
> + * drop the mmap lock.
> + *
> + * If want to do migration after faulting, call hmm_range_fault() with
> + * range.default_flags of HMM_PFN_REQ_MIGRATE, and optionally
> + * HMM_PFN_REQ_FAULT|HMM_PFN_REQ_WRITE, and initialize range->migrate field.
> + * range->migrate->vma will be populated during the call,
> + * and must be stable across the whole migrate process, which is
> + * why mmap_lock must be held around this call.
> + *
> + * When HMM_PFN_REQ_MIGRATE is set, migration collection may be partial on
> + * return and the caller takes responsibility for completing or aborting it.
> + *
> + * On success, the caller must call migrate_hmm_range_setup() and may then
> + * proceed with the normal migrate_vma sequence: prepare destination pages,
> + * call migrate_vma_pages(), update device mappings as needed, and finally
> + * call migrate_vma_finalize().
> + *
> + * On -EBUSY, the caller may retry hmm_range_fault() using the same range and
> + * PFN array without undoing entries collected by the previous attempt. If
> + * the caller stops retrying, it must abort the partial migration.
> + *
> + * On any other error, or when abandoning a retry, the caller must call
> + * migrate_hmm_range_setup(), migrate_vma_pages() with no valid destination
> + * entries, and migrate_vma_finalize() to abort the partial migration.
[Severity: High]
What happens in migrate_hmm_range_setup() if hmm_range_fault() fails before
hmm_vma_capture_migrate_range() arms hmm_vma_walk->mmu_armed, or if
range->start begins in an unmapped hole before walk->vma->vm_start?
In mm/hmm.c:hmm_vma_post_range_fault():
if (hmm_select_migrate(range) &&
hmm_vma_walk->mmu_armed) {
if (range->notifier) {
hmm_fill_migrate_vma(range,
hmm_vma_walk->vma,
hmm_vma_walk->start,
hmm_vma_walk->end);
}
mmu_notifier_invalidate_range_end(&hmm_vma_walk->mmu_range);
}
When a caller drives migration directly through hmm_range_fault() with
range->notifier set, range->migrate->vma, range->migrate->start, and
range->migrate->end are only populated if hmm_vma_walk->mmu_armed is true. If
hmm_range_fault_locked() fails before mmu_armed is set (for instance, if
mmu_interval_check_retry() returns -EBUSY on entry, hmm_vma_walk_hole()
returns -EFAULT when !walk->vma, or hmm_vma_capture_migrate_range() returns
-ERANGE), calling migrate_hmm_range_setup() as documented above will compute
migrate->npages = (migrate->end - migrate->start) >> PAGE_SHIFT from
uninitialized or stale fields in range->migrate.
Additionally, in hmm_vma_capture_migrate_range():
if (end - start > range->end - range->start)
return -ERANGE;
if (!hmm_vma_walk->mmu_armed) {
hmm_vma_walk->start = start;
hmm_vma_walk->end = end;
Because walk_page_range() clamps start and end to the VMA boundaries within
[range->start, range->end), end - start is never greater than
range->end - range->start. And if range->start < vma->vm_start (with
HMM_PFN_REQ_FAULT unset across the hole), hmm_vma_walk->start is set to
vma->vm_start while hmm_vma_walk_pmd() indexes range->hmm_pfns by
(addr - range->start) >> PAGE_SHIFT. When migrate_hmm_range_setup() then
reads range->hmm_pfns[0 .. migrate->npages - 1], won't it read from the
beginning of range->hmm_pfns instead of the VMA offset, misaligning
migrate->src[] and leaking any collected folios and migration PTEs at the end
of the range?
[Severity: High]
When hmm_range_fault() is called with both range->notifier and
HMM_PFN_REQ_MIGRATE set, won't internal MMU notifier invalidations during the
walk trip mmu_interval_check_retry() and cause premature termination of the
internal -EBUSY loop?
In mm/hmm.c:hmm_range_fault_locked():
do {
/* If range is no longer valid force retry. */
if (range->notifier && mmu_interval_check_retry(range->notifier,
range->notifier_seq)) {
ret = -EBUSY;
break;
}
ret = walk_page_range(mm, hmm_vma_walk.last, range->end,
&hmm_walk_ops, &hmm_vma_walk);
if (ret == HMM_FAULT_PENDING) {
ret = hmm_do_fault(mm, &hmm_vma_walk);
...
}
} while (ret == -EBUSY);
hmm_vma_post_range_fault(&hmm_vma_walk);
return ret;
During the walk, hmm_vma_capture_migrate_range() calls
mmu_notifier_invalidate_range_start() with MMU_NOTIFY_MIGRATE, and any page
fault in hmm_do_fault() (such as a CoW or swap fault) or THP split in
hmm_vma_handle_migrate_prepare_pmd() triggers an MMU notifier invalidation
with owner = NULL. If range->notifier covers the migrated range, those
invalidations increment range->notifier's sequence count. When hmm_do_fault()
or hmm_vma_handle_migrate_prepare_pmd() returns -EBUSY to re-walk the faulted
or split pages, mmu_interval_check_retry() will immediately break out of the
loop with -EBUSY, and hmm_vma_post_range_fault() will call
mmu_notifier_invalidate_range_end() while partial migration PTEs from earlier
addresses are still installed.
> + *
> + * The mmap read lock must remain held until the migration has either been
> + * completed or aborted.
> */
> int hmm_range_fault(struct hmm_range *range)
> {
> diff --git a/mm/migrate_device.c b/mm/migrate_device.c
> index 3bcb398c4e02c..c61a9e54e06bb 100644
> --- a/mm/migrate_device.c
> +++ b/mm/migrate_device.c
[ ... ]
> @@ -764,10 +276,24 @@ int migrate_vma_setup(struct migrate_vma *args)
> args->cpages = 0;
> args->npages = 0;
>
> - migrate_vma_collect(args);
> + if (args->flags & MIGRATE_VMA_FAULT)
> + range.default_flags |= HMM_PFN_REQ_FAULT;
>
> - if (args->cpages)
> - migrate_vma_unmap(args);
> + if (args->flags & MIGRATE_VMA_WRITE)
> + range.default_flags |= HMM_PFN_REQ_FAULT | HMM_PFN_REQ_WRITE;
[Severity: High]
When MIGRATE_VMA_FAULT or MIGRATE_VMA_WRITE is used (or HMM_PFN_REQ_MIGRATE
is combined with HMM_PFN_REQ_FAULT), can a fault on one PTE cause
hmm_do_fault() to fault across the rest of the PMD range, deadlocking on
already-locked folios or faulting caller-owned device-private pages back to
RAM?
In mm/hmm.c:hmm_vma_handle_pte():
fault:
if (hmm_vma_walk->ptelocked) {
lazy_mmu_mode_disable();
pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
hmm_vma_walk->ptelocked = false;
} else {
pte_unmap(ptep);
}
/* Fault any virtual address we were asked to fault */
return hmm_record_fault(addr, end, required_fault, walk);
Here end is the end of the PMD walk range passed from hmm_vma_walk_pmd(), and
hmm_do_fault() loops from addr to end calling handle_mm_fault() on every page
in [addr, end):
for (; addr < end; addr += PAGE_SIZE) {
vm_fault_t ret;
ret = handle_mm_fault(vma, addr, fault_flags, NULL);
If a subsequent PTE in [addr + PAGE_SIZE, end) is a device-private entry
owned by args->pgmap_owner, handle_mm_fault() will invoke do_swap_page() ->
pgmap->ops->migrate_to_ram() even though hmm_vma_handle_pte() normally avoids
faulting caller-owned device-private pages (and if that entry is
args->fault_page, which is already locked, do_swap_page() will wait forever
in softleaf_entry_wait_on_locked()). Similarly, if a subsequent PTE in
[addr + PAGE_SIZE, end) already has a migration entry installed by the
current thread during an earlier pass, handle_mm_fault() will call
migration_entry_wait() and deadlock on the folio lock held by current.
Should hmm_vma_handle_pte() pass addr + PAGE_SIZE instead of end to
hmm_record_fault()?
[Severity: High]
Relatedly, when hmm_range_fault_locked() calls hmm_do_fault() ->
handle_mm_fault() after a walk callback returns HMM_FAULT_PENDING, current
still holds folio_lock on all folios collected at earlier addresses in the
walk (via hmm_vma_handle_migrate_prepare() or
hmm_vma_handle_migrate_prepare_pmd()).
Does calling handle_mm_fault() while holding folio_lock on previously
collected folios violate mm lock ordering (where mapping->invalidate_lock in
filemap_fault() is acquired outside folio_lock) and risk a self-deadlock if
the faulted address resolves to the same folio that was already locked at an
earlier address in the range (such as a shared, KSM, or swap-cached folio
mapped at two addresses)?
> +
> + ret = hmm_range_fault(&range);
> +
> + migrate_hmm_range_setup(&range);
[Severity: High]
By switching migrate_vma_setup() from migrate_vma_collect() to
hmm_range_fault(), the walk now runs hmm_vma_walk_test() in mm/hmm.c:
if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)) &&
vma->vm_flags & VM_READ)
return 0;
...
hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
/* Skip this vma and continue processing the next vma. */
return 1;
Previously, migrate_vma_collect() did not have a .test_walk callback requiring
VM_READ. With this change, if a VMA containing device-private or
device-coherent pages does not have VM_READ set (for example, an execute-only
VMA that faults on instruction fetch, or a VMA changed to PROT_NONE via
mprotect() before driver eviction or a FOLL_FORCE access), hmm_vma_walk_test()
skips the VMA, migrate_hmm_range_setup() sets args->cpages = 0, and
migrate_vma_setup() returns 0.
In pgmap->ops->migrate_to_ram() handlers (such as nouveau_dmem_migrate_to_ram(),
__drm_pagemap_migrate_to_ram(), svm_migrate_to_ram(), and
dmirror_devmem_fault()), a 0 return from migrate_vma_setup() with cpages == 0
is treated as a race where another thread already migrated the page, so the
handler returns 0 without resolving the device-private swap PTE and the CPU
page fault retries indefinitely. Driver eviction paths also fail to migrate
device pages back to RAM when VM_READ is clear.
Should hmm_vma_walk_test() allow non-VM_READ VMAs when migrating (or when
faulting is not requested during migration)?
[Severity: Medium]
Does switching migrate_vma_setup() to hmm_range_fault() also cause present
pte_protnone() and pmd_protnone() pages (such as pages marked for NUMA
hinting faults by automatic NUMA balancing) to be skipped when
MIGRATE_VMA_FAULT is not set?
In mm/hmm.c, pte_to_hmm_pfn_flags() and pmd_to_hmm_pfn_flags() return 0
(without HMM_PFN_VALID) when pte_protnone(pte) or pmd_protnone(pmd) is true:
static inline unsigned long pte_to_hmm_pfn_flags(struct hmm_range *range,
pte_t pte)
{
if (pte_none(pte) || !pte_present(pte) || pte_protnone(pte))
return 0;
return pte_write(pte) ? (HMM_PFN_VALID | HMM_PFN_WRITE) : HMM_PFN_VALID;
}
When callers invoke migrate_vma_setup() without MIGRATE_VMA_FAULT, no fault is
triggered for protnone entries, and both hmm_vma_handle_migrate_prepare() and
hmm_vma_handle_migrate_prepare_pmd() bail out at:
if (!(hmm_pfn[0] & HMM_PFN_VALID))
goto out;
Previously, migrate_vma_collect_pmd() and migrate_vma_collect_huge_pmd()
collected and migrated present protnone PTEs and THP PMDs without requiring a
fault.
[ ... ]
>
> /*
> * At this point pages are locked and unmapped, and thus they have
титься
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021060506.2377545-1-mpenttil@redhat.com?part=9
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v16 10/12] lib/test_hmm: add a new testcase for the migrate on fault
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (8 preceding siblings ...)
2026-10-21 6:05 ` [PATCH v16 09/12] mm: enable device page migration from " mpenttil
@ 2026-10-21 6:05 ` mpenttil
2026-10-22 6:06 ` sashiko-bot
2026-10-21 6:05 ` [PATCH v16 11/12] Documentation/mm/hmm: document migration through hmm_range_fault() mpenttil
` (6 subsequent siblings)
16 siblings, 1 reply; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:05 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich, Marco Pagani
From: Mika Penttilä <mpenttil@redhat.com>
Enhance the hmm test driver (lib/test_hmm) with migrate on fault case.
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Marco Pagani <marpagan@redhat.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
lib/test_hmm.c | 172 +++++++++++++++++++++++--
lib/test_hmm_uapi.h | 21 +--
tools/testing/selftests/mm/hmm-tests.c | 54 ++++++++
3 files changed, 224 insertions(+), 23 deletions(-)
diff --git a/lib/test_hmm.c b/lib/test_hmm.c
index cd88e8177d0a..31608b6998bb 100644
--- a/lib/test_hmm.c
+++ b/lib/test_hmm.c
@@ -36,6 +36,7 @@
#define DMIRROR_RANGE_FAULT_TIMEOUT 1000
#define DEVMEM_CHUNK_SIZE (256 * 1024 * 1024U)
#define DEVMEM_CHUNKS_RESERVE 16
+#define PFNS_ARRAY_SIZE 64
/*
* For device_private pages, dpage is just a dummy struct page
@@ -355,6 +356,7 @@ static int dmirror_range_fault(struct dmirror *dmirror,
struct mm_struct *mm = dmirror->notifier.mm;
unsigned long timeout =
jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
+ bool migrate = range->default_flags & HMM_PFN_REQ_MIGRATE;
int ret;
while (true) {
@@ -364,9 +366,15 @@ static int dmirror_range_fault(struct dmirror *dmirror,
}
range->notifier_seq = mmu_interval_read_begin(range->notifier);
- mmap_read_lock(mm);
- ret = hmm_range_fault(range);
- mmap_read_unlock(mm);
+
+ /* mmap lock held for whole migrate on fault operation */
+ if (!migrate) {
+ mmap_read_lock(mm);
+ ret = hmm_range_fault(range);
+ mmap_read_unlock(mm);
+ } else {
+ ret = hmm_range_fault(range);
+ }
if (ret) {
if (ret == -EBUSY)
continue;
@@ -382,7 +390,9 @@ static int dmirror_range_fault(struct dmirror *dmirror,
break;
}
- ret = dmirror_do_fault(dmirror, range);
+ /* update device page table after migration */
+ if (!migrate)
+ ret = dmirror_do_fault(dmirror, range);
mutex_unlock(&dmirror->mutex);
out:
@@ -994,8 +1004,12 @@ static int dmirror_atomic_map(unsigned long addr, struct page *page,
return 0;
}
-static int dmirror_migrate_finalize_and_map(struct migrate_vma *args,
- struct dmirror *dmirror)
+/*
+ * Map the migrated pages into the device's page table. Caller must hold
+ * dmirror->mutex.
+ */
+static int __dmirror_migrate_map_locked(struct migrate_vma *args,
+ struct dmirror *dmirror)
{
unsigned long start = args->start;
unsigned long end = args->end;
@@ -1005,9 +1019,6 @@ static int dmirror_migrate_finalize_and_map(struct migrate_vma *args,
const unsigned long start_pfn = start >> PAGE_SHIFT;
const unsigned long end_pfn = end >> PAGE_SHIFT;
- /* Map the migrated pages into the device's page tables. */
- mutex_lock(&dmirror->mutex);
-
for (pfn = start_pfn; pfn < end_pfn; pfn++, src++, dst++) {
struct page *dpage;
void *entry;
@@ -1036,17 +1047,27 @@ static int dmirror_migrate_finalize_and_map(struct migrate_vma *args,
if (*dst & MIGRATE_PFN_WRITE)
entry = xa_tag_pointer(entry, DPT_XA_TAG_WRITE);
entry = xa_store(&dmirror->pt, pfn + i, entry, GFP_ATOMIC);
- if (xa_is_err(entry)) {
- mutex_unlock(&dmirror->mutex);
+ if (xa_is_err(entry))
return xa_err(entry);
- }
}
}
- mutex_unlock(&dmirror->mutex);
return 0;
}
+static int dmirror_migrate_finalize_and_map(struct migrate_vma *args,
+ struct dmirror *dmirror)
+{
+ int ret;
+
+ /* Map the migrated pages into the device's page tables. */
+ mutex_lock(&dmirror->mutex);
+ ret = __dmirror_migrate_map_locked(args, dmirror);
+ mutex_unlock(&dmirror->mutex);
+
+ return ret;
+}
+
static int dmirror_exclusive(struct dmirror *dmirror,
struct hmm_dmirror_cmd *cmd)
{
@@ -1377,6 +1398,127 @@ static int dmirror_migrate_to_device(struct dmirror *dmirror,
return ret;
}
+static int do_fault_and_migrate(struct dmirror *dmirror, struct hmm_range *range)
+{
+ struct migrate_vma *migrate = range->migrate;
+ unsigned long timeout =
+ jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
+ int ret;
+
+ do {
+ mmap_read_lock(dmirror->notifier.mm);
+
+ /* Fault-in pages for migration */
+ ret = dmirror_range_fault(dmirror, range);
+ /*
+ * Set this up even on error: hmm_range_fault() may have collected
+ * part of the range before failing.
+ */
+ migrate_hmm_range_setup(range);
+ if (ret) {
+ /*
+ * dst[] entries are empty, so this marks every collected
+ * migration as failed. finalize then restores the source
+ * mappings and drops the associated locks/references.
+ */
+ migrate_vma_pages(migrate);
+ migrate_vma_finalize(migrate);
+ goto unlock;
+ }
+
+ pr_debug("Migrating from sys mem to device mem\n");
+
+ dmirror_migrate_alloc_and_copy(migrate, dmirror);
+ migrate_vma_pages(migrate);
+
+ mutex_lock(&dmirror->mutex);
+ if (mmu_interval_read_retry(&dmirror->notifier,
+ range->notifier_seq))
+ ret = -EBUSY;
+ else
+ ret = __dmirror_migrate_map_locked(migrate, dmirror);
+ mutex_unlock(&dmirror->mutex);
+
+ migrate_vma_finalize(migrate);
+unlock:
+ mmap_read_unlock(dmirror->notifier.mm);
+ } while (ret == -EBUSY && !time_after(jiffies, timeout));
+
+ return ret;
+}
+
+static int dmirror_fault_and_migrate_to_device(struct dmirror *dmirror,
+ struct hmm_dmirror_cmd *cmd)
+{
+ unsigned long start, size, end, next;
+ unsigned long src_pfns[PFNS_ARRAY_SIZE] = { 0 };
+ unsigned long dst_pfns[PFNS_ARRAY_SIZE] = { 0 };
+ struct migrate_vma migrate = { 0 };
+ struct hmm_range range = { 0 };
+ struct dmirror_bounce bounce;
+ int ret = 0;
+
+ /* Whole range */
+ start = cmd->addr;
+ size = cmd->npages << PAGE_SHIFT;
+ end = start + size;
+
+ if (!mmget_not_zero(dmirror->notifier.mm)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ migrate.pgmap_owner = dmirror->mdevice;
+ migrate.src = src_pfns;
+ migrate.dst = dst_pfns;
+ migrate.flags = MIGRATE_VMA_SELECT_SYSTEM;
+
+ range.migrate = &migrate;
+ range.hmm_pfns = src_pfns;
+ range.pfn_flags_mask = 0;
+ range.default_flags = HMM_PFN_REQ_FAULT | HMM_PFN_REQ_MIGRATE;
+ range.dev_private_owner = dmirror->mdevice;
+ range.notifier = &dmirror->notifier;
+
+ for (next = start; next < end; next = range.end) {
+ range.start = next;
+ range.end = min(end, next + (PFNS_ARRAY_SIZE << PAGE_SHIFT));
+
+ pr_debug("Fault and migrate range start:%#lx end:%#lx\n",
+ range.start, range.end);
+
+ ret = do_fault_and_migrate(dmirror, &range);
+ if (ret)
+ goto out_mmput;
+ }
+
+ /*
+ * Return the migrated data for verification.
+ * Only for pages in device zone
+ */
+ ret = dmirror_bounce_init(&bounce, start, size);
+ if (ret)
+ goto out_mmput;
+
+ mutex_lock(&dmirror->mutex);
+ ret = dmirror_do_read(dmirror, start, end, &bounce);
+ mutex_unlock(&dmirror->mutex);
+ if (ret == 0) {
+ ret = copy_to_user(u64_to_user_ptr(cmd->ptr), bounce.ptr, bounce.size);
+ if (ret)
+ ret = -EFAULT;
+ }
+
+ cmd->cpages = bounce.cpages;
+ dmirror_bounce_fini(&bounce);
+
+
+out_mmput:
+ mmput(dmirror->notifier.mm);
+out:
+ return ret;
+}
+
static void dmirror_mkentry(struct dmirror *dmirror, struct hmm_range *range,
unsigned char *perm, unsigned long entry)
{
@@ -1643,6 +1785,10 @@ static long dmirror_fops_unlocked_ioctl(struct file *filp,
ret = dmirror_migrate_to_device(dmirror, &cmd);
break;
+ case HMM_DMIRROR_MIGRATE_ON_FAULT_TO_DEV:
+ ret = dmirror_fault_and_migrate_to_device(dmirror, &cmd);
+ break;
+
case HMM_DMIRROR_MIGRATE_TO_SYS:
ret = dmirror_migrate_to_system(dmirror, &cmd);
break;
diff --git a/lib/test_hmm_uapi.h b/lib/test_hmm_uapi.h
index ea9b0ec404fb..67d267a3b999 100644
--- a/lib/test_hmm_uapi.h
+++ b/lib/test_hmm_uapi.h
@@ -29,16 +29,17 @@ struct hmm_dmirror_cmd {
};
/* Expose the address space of the calling process through hmm device file */
-#define HMM_DMIRROR_READ _IOWR('H', 0x00, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_WRITE _IOWR('H', 0x01, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_MIGRATE_TO_DEV _IOWR('H', 0x02, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_MIGRATE_TO_SYS _IOWR('H', 0x03, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_SNAPSHOT _IOWR('H', 0x04, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_EXCLUSIVE _IOWR('H', 0x05, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_CHECK_EXCLUSIVE _IOWR('H', 0x06, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_RELEASE _IOWR('H', 0x07, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_FLAGS _IOWR('H', 0x08, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_READ_UNLOCKED _IOWR('H', 0x09, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_READ _IOWR('H', 0x00, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_WRITE _IOWR('H', 0x01, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_MIGRATE_TO_DEV _IOWR('H', 0x02, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_MIGRATE_TO_SYS _IOWR('H', 0x03, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_SNAPSHOT _IOWR('H', 0x04, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_EXCLUSIVE _IOWR('H', 0x05, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_CHECK_EXCLUSIVE _IOWR('H', 0x06, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_RELEASE _IOWR('H', 0x07, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_FLAGS _IOWR('H', 0x08, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_READ_UNLOCKED _IOWR('H', 0x09, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_MIGRATE_ON_FAULT_TO_DEV _IOWR('H', 0x0a, struct hmm_dmirror_cmd)
#define HMM_DMIRROR_FLAG_FAIL_ALLOC (1ULL << 0)
diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c
index e2642eca0d02..a2d1b8f494b6 100644
--- a/tools/testing/selftests/mm/hmm-tests.c
+++ b/tools/testing/selftests/mm/hmm-tests.c
@@ -334,6 +334,13 @@ static int hmm_migrate_sys_to_dev(int fd,
return hmm_dmirror_cmd(fd, HMM_DMIRROR_MIGRATE_TO_DEV, buffer, npages);
}
+static int hmm_migrate_on_fault_sys_to_dev(int fd,
+ struct hmm_buffer *buffer,
+ unsigned long npages)
+{
+ return hmm_dmirror_cmd(fd, HMM_DMIRROR_MIGRATE_ON_FAULT_TO_DEV, buffer, npages);
+}
+
static int hmm_migrate_dev_to_sys(int fd,
struct hmm_buffer *buffer,
unsigned long npages)
@@ -938,6 +945,53 @@ TEST_F(hmm, migrate)
hmm_buffer_free(buffer);
}
+
+/*
+ * Fault and migrate anonymous memory to device private memory.
+ */
+TEST_F(hmm, migrate_on_fault)
+{
+ struct hmm_buffer *buffer;
+ unsigned long npages;
+ unsigned long size;
+ unsigned long i;
+ int *ptr;
+ int ret;
+
+ npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
+ ASSERT_NE(npages, 0);
+ size = npages << self->page_shift;
+
+ buffer = malloc(sizeof(*buffer));
+ ASSERT_NE(buffer, NULL);
+
+ buffer->fd = -1;
+ buffer->size = size;
+ buffer->mirror = malloc(size);
+ ASSERT_NE(buffer->mirror, NULL);
+
+ buffer->ptr = mmap(NULL, size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ buffer->fd, 0);
+ ASSERT_NE(buffer->ptr, MAP_FAILED);
+
+ /* Initialize buffer in system memory. */
+ for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
+ ptr[i] = i;
+
+ /* Fault and migrate memory to device. */
+ ret = hmm_migrate_on_fault_sys_to_dev(self->fd, buffer, npages);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(buffer->cpages, npages);
+
+ /* Check what the device read. */
+ for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
+ ASSERT_EQ(ptr[i], i);
+
+ hmm_buffer_free(buffer);
+}
+
/*
* Migrate private file memory to device private memory.
*/
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v16 10/12] lib/test_hmm: add a new testcase for the migrate on fault
2026-10-21 6:05 ` [PATCH v16 10/12] lib/test_hmm: add a new testcase for the migrate on fault mpenttil
@ 2026-10-22 6:06 ` sashiko-bot
0 siblings, 0 replies; 33+ messages in thread
From: sashiko-bot @ 2026-10-22 6:06 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, David Hildenbrand, Jason Gunthorpe,
Leon Romanovsky, Alistair Popple, Balbir Singh, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich, Marco Pagani
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] mm: test_hmm: unmapped device pages on retry in do_fault_and_migrate()
- [Medium] selftests/mm: pre-faulting buffer in migrate_on_fault skips hmm_do_fault()
--
commit 43a1dd324a1ecfe103c0cf9ba76ea8935506e50c
Author: Mika Penttilä <mpenttil@redhat.com>
lib/test_hmm: add a new testcase for the migrate on fault
This commit adds the HMM_DMIRROR_MIGRATE_ON_FAULT_TO_DEV ioctl to the
test_hmm driver to test faulting and migrating memory to device private
memory via hmm_range_fault(), along with a corresponding kselftest.
> diff --git a/lib/test_hmm.c b/lib/test_hmm.c
> index f05f801b8404b..2045896493ae3 100644
> --- a/lib/test_hmm.c
> +++ b/lib/test_hmm.c
[ ... ]
> @@ -1377,6 +1398,127 @@ static int dmirror_migrate_to_device(struct dmirror *dmirror,
> return ret;
> }
>
> +static int do_fault_and_migrate(struct dmirror *dmirror, struct hmm_range *range)
> +{
> + struct migrate_vma *migrate = range->migrate;
> + unsigned long timeout =
> + jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
> + int ret;
> +
> + do {
> + mmap_read_lock(dmirror->notifier.mm);
> +
> + /* Fault-in pages for migration */
> + ret = dmirror_range_fault(dmirror, range);
> + /*
> + * Set this up even on error: hmm_range_fault() may have collected
> + * part of the range before failing.
> + */
> + migrate_hmm_range_setup(range);
> + if (ret) {
> + /*
> + * dst[] entries are empty, so this marks every collected
> + * migration as failed. finalize then restores the source
> + * mappings and drops the associated locks/references.
> + */
> + migrate_vma_pages(migrate);
> + migrate_vma_finalize(migrate);
> + goto unlock;
> + }
> +
> + pr_debug("Migrating from sys mem to device mem\n");
> +
> + dmirror_migrate_alloc_and_copy(migrate, dmirror);
> + migrate_vma_pages(migrate);
> +
> + mutex_lock(&dmirror->mutex);
> + if (mmu_interval_read_retry(&dmirror->notifier,
> + range->notifier_seq))
> + ret = -EBUSY;
> + else
> + ret = __dmirror_migrate_map_locked(migrate, dmirror);
> + mutex_unlock(&dmirror->mutex);
> +
> + migrate_vma_finalize(migrate);
> +unlock:
> + mmap_read_unlock(dmirror->notifier.mm);
> + } while (ret == -EBUSY && !time_after(jiffies, timeout));
> +
> + return ret;
> +}
[Severity: Medium]
What happens in do_fault_and_migrate() if mmu_interval_read_retry() returns
true after migrate_vma_pages() has already migrated the folios?
When mmu_interval_read_retry() is true (for example, if an invalidation bumps
dmirror->notifier.invalidate_seq after dmirror_range_fault() drops
dmirror->mutex, such as during migrate_vma_unmap() on a shared page or
split_huge_pmd() in migrate_vma_insert_page()), __dmirror_migrate_map_locked()
is skipped and ret is set to -EBUSY, but migrate_vma_finalize() still commits
the device private entries into the CPU page tables.
On the next iteration of the retry loop, dmirror_fault_and_migrate_to_device()
has configured migrate.flags with only MIGRATE_VMA_SELECT_SYSTEM:
migrate.pgmap_owner = dmirror->mdevice;
migrate.src = src_pfns;
migrate.dst = dst_pfns;
migrate.flags = MIGRATE_VMA_SELECT_SYSTEM;
Because the pages are now in device private memory, the retry walk in
hmm_range_fault() will not set HMM_PFN_MIGRATE on them, and
dmirror_range_fault() also skips dmirror_do_fault() when HMM_PFN_REQ_MIGRATE
is set:
/* update device page table after migration */
if (!migrate)
ret = dmirror_do_fault(dmirror, range);
Won't this leave those migrated pages missing from dmirror->pt, causing the
subsequent dmirror_do_read() call in dmirror_fault_and_migrate_to_device() to
fail with -ENOENT?
[ ... ]
> diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c
> index e5f273ca84c10..897ff2eb34061 100644
> --- a/tools/testing/selftests/mm/hmm-tests.c
> +++ b/tools/testing/selftests/mm/hmm-tests.c
[ ... ]
> @@ -937,6 +944,53 @@ TEST_F(hmm, migrate)
> hmm_buffer_free(buffer);
> }
>
> +
> +/*
> + * Fault and migrate anonymous memory to device private memory.
> + */
> +TEST_F(hmm, migrate_on_fault)
> +{
> + struct hmm_buffer *buffer;
> + unsigned long npages;
> + unsigned long size;
> + unsigned long i;
> + int *ptr;
> + int ret;
> +
> + npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
> + ASSERT_NE(npages, 0);
> + size = npages << self->page_shift;
> +
> + buffer = malloc(sizeof(*buffer));
> + ASSERT_NE(buffer, NULL);
> +
> + buffer->fd = -1;
> + buffer->size = size;
> + buffer->mirror = malloc(size);
> + ASSERT_NE(buffer->mirror, NULL);
> +
> + buffer->ptr = mmap(NULL, size,
> + PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS,
> + buffer->fd, 0);
> + ASSERT_NE(buffer->ptr, MAP_FAILED);
> +
> + /* Initialize buffer in system memory. */
> + for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
> + ptr[i] = i;
> +
> + /* Fault and migrate memory to device. */
> + ret = hmm_migrate_on_fault_sys_to_dev(self->fd, buffer, npages);
[Severity: Medium]
Does TEST_F(hmm, migrate_on_fault) actually trigger page faults during
hmm_range_fault()?
Writing to every element of buffer->ptr in the initialization loop populates
all PTEs in the range as present and writable before
hmm_migrate_on_fault_sys_to_dev() is called. When hmm_range_fault() then walks
the range with HMM_PFN_REQ_FAULT | HMM_PFN_REQ_MIGRATE, hmm_pte_need_fault()
in mm/hmm.c sees HMM_PFN_VALID on every PTE and returns 0:
/* If CPU page table is not valid then we need to fault */
if (!(cpu_flags & HMM_PFN_VALID))
return HMM_NEED_FAULT;
return 0;
As a result, hmm_record_fault() and hmm_do_fault() are never invoked during
the migration walk. Should part or all of the buffer be left unpopulated
before calling hmm_migrate_on_fault_sys_to_dev() (similar to TEST_F(hmm,
anon_read)), and could this also use the existing hmm_buffer_alloc() helper
instead of open-coding the buffer and mmap allocation?
> + ASSERT_EQ(ret, 0);
> + ASSERT_EQ(buffer->cpages, npages);
> +
> + /* Check what the device read. */
> + for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
> + ASSERT_EQ(ptr[i], i);
> +
> + hmm_buffer_free(buffer);
> +}
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021060506.2377545-1-mpenttil@redhat.com?part=10
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v16 11/12] Documentation/mm/hmm: document migration through hmm_range_fault()
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (9 preceding siblings ...)
2026-10-21 6:05 ` [PATCH v16 10/12] lib/test_hmm: add a new testcase for the migrate on fault mpenttil
@ 2026-10-21 6:05 ` mpenttil
2026-10-22 6:06 ` sashiko-bot
2026-10-21 6:05 ` [PATCH v16 12/12] drm/nouveau/svm: add support for migrate on fault mpenttil
` (5 subsequent siblings)
16 siblings, 1 reply; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:05 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
Describe the two new MIGRATE_VMA_FAULT / MIGRATE_VMA_WRITE flags of
migrate_vma_setup(), and add a section on driving the migration
collection phase directly from hmm_range_fault() via HMM_PFN_REQ_MIGRATE
and migrate_hmm_range_setup().
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
Documentation/mm/hmm.rst | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/Documentation/mm/hmm.rst b/Documentation/mm/hmm.rst
index fc1b8dc19825..58424e5f5873 100644
--- a/Documentation/mm/hmm.rst
+++ b/Documentation/mm/hmm.rst
@@ -348,6 +348,13 @@ between device driver specific code and shared common code:
Currently only anonymous private VMA ranges can be migrated to or from
system memory and device private memory.
+ By default only pages already present are collected. Two additional flags
+ ask migrate_vma_setup() to fault in missing pages first:
+
+ * ``MIGRATE_VMA_FAULT`` faults in missing pages with read access.
+ * ``MIGRATE_VMA_WRITE`` faults in missing pages with write access
+ (implies faulting).
+
One of the first steps migrate_vma_setup() does is to invalidate other
device's MMUs with the ``mmu_notifier_invalidate_range_start()`` and
``mmu_notifier_invalidate_range_end()`` calls around the page table
@@ -427,6 +434,38 @@ between device driver specific code and shared common code:
The lock can now be released.
+Migration collection through hmm_range_fault()
+==============================================
+
+The collection phase of migration (steps 1 and 2 above) can also be driven by
+hmm_range_fault() directly, sharing its page table walk. This lets a driver
+fault in and collect a range for migration in one walk, which is useful for
+migrate on fault.
+
+To do so, the driver sets ``HMM_PFN_REQ_MIGRATE`` in ``range->default_flags``
+and points ``range->migrate`` at a ``struct migrate_vma`` it has filled in
+(``flags``, ``src``, ``dst``, ``pgmap_owner``). Usually ``HMM_PFN_REQ_FAULT``
+(and ``HMM_PFN_REQ_WRITE``) is set as well, so missing pages are faulted in
+before being collected. The mmap_read_lock() has to be held for the whole
+migration, since the vma must stay stable.
+
+hmm_range_fault() collects the entries the same way migrate_vma_setup() does,
+taking a folio reference, locking it and installing a migration PTE. Collected
+entries are marked with ``HMM_PFN_VALID | HMM_PFN_MIGRATE`` in
+``range->hmm_pfns``. If the page tables change while locks are dropped the
+partially collected entries are rolled back automatically.
+
+After hmm_range_fault() returns, the driver calls::
+
+ void migrate_hmm_range_setup(struct hmm_range *range);
+
+to translate ``range->hmm_pfns`` into ``migrate->src[]`` (``migrate->dst[]`` is
+zeroed) and initialize ``migrate->cpages`` and ``migrate->npages``. From here on
+the ``range->migrate`` struct is ready for the rest of the flow (steps 3
+onwards), i.e. migrate_vma_pages() and migrate_vma_finalize(). This should be
+called even on error, since hmm_range_fault() may have collected part of the
+range before failing.
+
Exclusive access memory
=======================
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v16 11/12] Documentation/mm/hmm: document migration through hmm_range_fault()
2026-10-21 6:05 ` [PATCH v16 11/12] Documentation/mm/hmm: document migration through hmm_range_fault() mpenttil
@ 2026-10-22 6:06 ` sashiko-bot
0 siblings, 0 replies; 33+ messages in thread
From: sashiko-bot @ 2026-10-22 6:06 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, David Hildenbrand, Jason Gunthorpe,
Leon Romanovsky, Alistair Popple, Balbir Singh, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Critical] mm/hmm: dangling migration PTE and UAF on migration collection rollback
- [High] mm/hmm: incomplete rollback of collected folios in hmm_vma_walk_pmd()
- [High] mm/hmm: uninitialized bounds and pfn state bugs in migrate_hmm_range_setup()
- [Medium] mm/hmm: test_hmm: unmapped device pages on retry in do_fault_and_migrate()
--
commit d7bcd4b72dc6ea1ed912615ed1934d28e4808508
Author: Mika Penttilä <mpenttil@redhat.com>
Documentation/mm/hmm: document migration through hmm_range_fault()
This patch series enables driving device page migration collection through
hmm_range_fault() and migrate_hmm_range_setup(), updates migrate_vma_setup()
to use the HMM pagewalk path, and adds a migrate-on-fault selftest and
documentation.
> diff --git a/Documentation/mm/hmm.rst b/Documentation/mm/hmm.rst
> index fc1b8dc198250..58424e5f5873c 100644
> --- a/Documentation/mm/hmm.rst
> +++ b/Documentation/mm/hmm.rst
> @@ -427,6 +434,38 @@ between device driver specific code and shared common code:
>
> The lock can now be released.
>
> +Migration collection through hmm_range_fault()
> +==============================================
> +
> +The collection phase of migration (steps 1 and 2 above) can also be driven by
> +hmm_range_fault() directly, sharing its page table walk. This lets a driver
> +fault in and collect a range for migration in one walk, which is useful for
> +migrate on fault.
> +
> +To do so, the driver sets ``HMM_PFN_REQ_MIGRATE`` in ``range->default_flags``
> +and points ``range->migrate`` at a ``struct migrate_vma`` it has filled in
> +(``flags``, ``src``, ``dst``, ``pgmap_owner``). Usually ``HMM_PFN_REQ_FAULT``
> +(and ``HMM_PFN_REQ_WRITE``) is set as well, so missing pages are faulted in
> +before being collected. The mmap_read_lock() has to be held for the whole
> +migration, since the vma must stay stable.
> +
> +hmm_range_fault() collects the entries the same way migrate_vma_setup() does,
> +taking a folio reference, locking it and installing a migration PTE. Collected
> +entries are marked with ``HMM_PFN_VALID | HMM_PFN_MIGRATE`` in
> +``range->hmm_pfns``. If the page tables change while locks are dropped the
> +partially collected entries are rolled back automatically.
> +
> +After hmm_range_fault() returns, the driver calls::
> +
> + void migrate_hmm_range_setup(struct hmm_range *range);
> +
> +to translate ``range->hmm_pfns`` into ``migrate->src[]`` (``migrate->dst[]`` is
> +zeroed) and initialize ``migrate->cpages`` and ``migrate->npages``. From here on
> +the ``range->migrate`` struct is ready for the rest of the flow (steps 3
> +onwards), i.e. migrate_vma_pages() and migrate_vma_finalize(). This should be
> +called even on error, since hmm_range_fault() may have collected part of the
> +range before failing.
> +
> Exclusive access memory
> =======================
>
> diff --git a/lib/test_hmm.c b/lib/test_hmm.c
> index b409c42bfe6fc..2045896493ae3 100644
> --- a/lib/test_hmm.c
> +++ b/lib/test_hmm.c
[ ... ]
> @@ -1377,6 +1398,127 @@ static int dmirror_migrate_to_device(struct dmirror *dmirror,
> return ret;
> }
>
> +static int do_fault_and_migrate(struct dmirror *dmirror, struct hmm_range *range)
> +{
> + struct migrate_vma *migrate = range->migrate;
> + unsigned long timeout =
> + jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
> + int ret;
> +
> + do {
> + mmap_read_lock(dmirror->notifier.mm);
> +
> + /* Fault-in pages for migration */
> + ret = dmirror_range_fault(dmirror, range);
> + /*
> + * Set this up even on error: hmm_range_fault() may have collected
> + * part of the range before failing.
> + */
> + migrate_hmm_range_setup(range);
> + if (ret) {
> + /*
> + * dst[] entries are empty, so this marks every collected
> + * migration as failed. finalize then restores the source
> + * mappings and drops the associated locks/references.
> + */
> + migrate_vma_pages(migrate);
> + migrate_vma_finalize(migrate);
> + goto unlock;
> + }
> +
> + pr_debug("Migrating from sys mem to device mem\n");
> +
> + dmirror_migrate_alloc_and_copy(migrate, dmirror);
> + migrate_vma_pages(migrate);
> +
> + mutex_lock(&dmirror->mutex);
> + if (mmu_interval_read_retry(&dmirror->notifier,
> + range->notifier_seq))
> + ret = -EBUSY;
> + else
> + ret = __dmirror_migrate_map_locked(migrate, dmirror);
> + mutex_unlock(&dmirror->mutex);
> +
> + migrate_vma_finalize(migrate);
> +unlock:
> + mmap_read_unlock(dmirror->notifier.mm);
> + } while (ret == -EBUSY && !time_after(jiffies, timeout));
> +
> + return ret;
> +}
> +
> +static int dmirror_fault_and_migrate_to_device(struct dmirror *dmirror,
> + struct hmm_dmirror_cmd *cmd)
> +{
> + unsigned long start, size, end, next;
> + unsigned long src_pfns[PFNS_ARRAY_SIZE] = { 0 };
> + unsigned long dst_pfns[PFNS_ARRAY_SIZE] = { 0 };
> + struct migrate_vma migrate = { 0 };
> + struct hmm_range range = { 0 };
> + struct dmirror_bounce bounce;
> + int ret = 0;
> +
> + /* Whole range */
> + start = cmd->addr;
> + size = cmd->npages << PAGE_SHIFT;
> + end = start + size;
> +
> + if (!mmget_not_zero(dmirror->notifier.mm)) {
> + ret = -EFAULT;
> + goto out;
> + }
> +
> + migrate.pgmap_owner = dmirror->mdevice;
> + migrate.src = src_pfns;
> + migrate.dst = dst_pfns;
> + migrate.flags = MIGRATE_VMA_SELECT_SYSTEM;
[Severity: Medium]
In do_fault_and_migrate() in lib/test_hmm.c, dmirror_range_fault() runs
hmm_range_fault() with HMM_PFN_REQ_FAULT | HMM_PFN_REQ_MIGRATE and unlocks
dmirror->mutex, after which migrate_hmm_range_setup(),
dmirror_migrate_alloc_and_copy(), and migrate_vma_pages() commit the folio
migration from system memory to device-private pages.
If a concurrent invalidation in the process address space updates
dmirror->notifier before mutex_lock(&dmirror->mutex) is acquired in
do_fault_and_migrate(), mmu_interval_read_retry() returns true, setting
ret = -EBUSY and skipping __dmirror_migrate_map_locked(), while
migrate_vma_finalize() still installs device-private swap ptes into the cpu
page table and frees the source system pages.
On the next iteration of the retry loop, the pages in the cpu page table are
already device-private pages owned by dmirror->mdevice, while
dmirror_fault_and_migrate_to_device() only sets migrate.flags to
MIGRATE_VMA_SELECT_SYSTEM. Because hmm_vma_handle_migrate_prepare() does not
set HMM_PFN_MIGRATE on those entries and migrate_hmm_range_setup() zeroes
migrate->src[], __dmirror_migrate_map_locked() skips them.
Won't this leave the migrated device pages absent from dmirror->pt on retry
and cause dmirror_do_read() to fail with -ENOENT when invoked via
HMM_DMIRROR_MIGRATE_ON_FAULT_TO_DEV?
[ ... ]
> diff --git a/mm/hmm.c b/mm/hmm.c
> index 2f1e98c6b6440..4d853ee8e8b8c 100644
> --- a/mm/hmm.c
> +++ b/mm/hmm.c
[ ... ]
> @@ -296,14 +369,26 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
> goto fault;
>
> if (softleaf_is_migration(entry)) {
> - pte_unmap(ptep);
> - hmm_vma_walk->last = addr;
> - migration_entry_wait(walk->mm, pmdp, addr);
> - return -EBUSY;
> + if (!hmm_select_migrate(range)) {
> + HMM_ASSERT_UNLOCKED(hmm_vma_walk);
> + pte_unmap(ptep);
> + hmm_vma_walk->last = addr;
> + migration_entry_wait(walk->mm, pmdp, addr);
> + return -EBUSY;
> + }
> + return 0;
> }
>
> /* Report error for everything else */
> - pte_unmap(ptep);
> +
> + if (hmm_vma_walk->ptelocked) {
> + lazy_mmu_mode_disable();
> + pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
> + hmm_vma_walk->ptelocked = false;
> + } else {
> + pte_unmap(ptep);
> + }
> +
> return -EFAULT;
> }
>
> @@ -320,7 +405,14 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
> if (!vm_normal_page(walk->vma, addr, pte) &&
> !is_zero_pfn(pte_pfn(pte))) {
> if (hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0)) {
> - pte_unmap(ptep);
> + if (hmm_vma_walk->ptelocked) {
> + lazy_mmu_mode_disable();
> + pte_unmap_unlock(ptep, hmm_vma_walk->ptl);
> + hmm_vma_walk->ptelocked = false;
> + } else {
> + pte_unmap(ptep);
> + }
> +
> return -EFAULT;
> }
> new_pfn_flags = HMM_PFN_ERROR;
> @@ -329,11 +421,20 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
>
> new_pfn_flags = pte_pfn(pte) | cpu_flags;
> out:
> + hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk, addr,
> + addr + PAGE_SIZE,
> + hmm_pfn);
> *hmm_pfn = (*hmm_pfn & HMM_PFN_INOUT_FLAGS) | new_pfn_flags;
> return 0;
[Severity: Critical]
When hmm_vma_handle_migrate_prepare() in mm/hmm.c collects a present page, it
takes a folio reference with folio_get(), locks the folio with
folio_trylock(), installs a migration pte via set_pte_at(), removes the rmap
with folio_remove_rmap_pte(), drops the pte reference with folio_put(), and
marks *hmm_pfn with HMM_PFN_VALID | HMM_PFN_MIGRATE.
In hmm_vma_handle_pte(), when !pte_present(pte) is true, the check:
required_fault =
hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0);
if (!required_fault)
goto out;
is evaluated before softleaf_is_migration(entry). When HMM_PFN_REQ_FAULT is
not set for an entry (for example when hmm_range_fault() is called with
HMM_PFN_REQ_MIGRATE only, or with per-pfn fault flags) and the walk restarts
or retries over a migration pte that was already installed by this walk,
hmm_vma_handle_pte() jumps to out: and calls
hmm_vma_handle_migrate_prepare_rollback().
That rollback unlocks the folio, drops the collection reference via
folio_put(folio), and clears HMM_PFN_VALID | HMM_PFN_MIGRATE without calling
remove_migration_ptes(). Because HMM_PFN_MIGRATE is cleared,
migrate_hmm_range_setup() and migrate_vma_finalize() never restore the pte.
Similarly, in hmm_vma_walk_pmd(), if hmm_vma_handle_migrate_prepare() fails
with a non--EAGAIN error at addr (when migrate_vma_split_folio() fails), it
calls hmm_pfns_fill(addr, end, hmm_vma_walk, HMM_PFN_ERROR), which runs
hmm_vma_handle_migrate_prepare_rollback() across [addr, end) without removing
any migration ptes that may already be installed in (addr, end) from an
earlier pass. Doesn't this leave dangling migration ptes in the process page
tables pointing to unlocked and potentially freed folios?
Conversely, when HMM_PFN_REQ_FAULT and HMM_PFN_REQ_MIGRATE are both set,
softleaf_is_migration(entry) in hmm_vma_handle_pte() and
pmd_is_migration_entry(pmd) in hmm_vma_walk_pmd():
if (thp_migration_supported() && pmd_is_migration_entry(pmd)) {
if (!minfo) {
if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns_start, npages, 0)) {
hmm_vma_walk->last = addr;
pmd_migration_entry_wait(walk->mm, pmdp);
return -EBUSY;
}
for (i = 0; start < end; start += PAGE_SIZE, i++)
hmm_pfns_start[i] &= HMM_PFN_INOUT_FLAGS;
}
...
return 0;
}
return 0 whenever migration is enabled without checking
hmm_pfn_collected(*hmm_pfn). If a migration pte or pmd was installed by
another concurrent thread (such as compaction, reclaim, or another migration)
rather than the current walk, won't hmm_range_fault() skip
migration_entry_wait() and pmd_migration_entry_wait() and return 0 with
unpopulated hmm_pfns entries?
[ ... ]
> @@ -456,24 +1183,70 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
> * recover.
> */
> if (pmd_bad(pmd)) {
> - if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns, npages, 0))
> + if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns_start, npages, 0))
> return -EFAULT;
> - return hmm_pfns_fill(start, end, range, HMM_PFN_ERROR);
> + return hmm_pfns_fill(start, end, hmm_vma_walk, HMM_PFN_ERROR);
> }
>
> - ptep = pte_offset_map(pmdp, addr);
> - if (!ptep)
> + if (minfo) {
> + ptep = pte_offset_map_lock(mm, pmdp, addr, &hmm_vma_walk->ptl);
> + if (ptep) {
> + lazy_mmu_mode_enable();
> + hmm_vma_walk->ptelocked = true;
> + } else {
> + /* The pte table is gone */
> + hmm_vma_handle_migrate_prepare_rollback(walk->private, addr, end, hmm_pfns);
> + }
> + } else {
> + ptep = pte_offset_map(pmdp, addr);
> + }
> + if (!ptep) {
> + addr = start;
> goto again;
> + }
> +
> for (; addr < end; addr += PAGE_SIZE, ptep++, hmm_pfns++) {
> - int r;
>
> r = hmm_vma_handle_pte(walk, addr, end, pmdp, ptep, hmm_pfns);
> if (r) {
> - /* hmm_vma_handle_pte() did pte_unmap() */
> + /* hmm_vma_handle_pte() did pte_unmap() / pte_unmap_unlock */
> + if (unmapped)
> + flush_tlb_range(walk->vma, start, addr);
> return r;
> }
> +
> + r = hmm_vma_handle_migrate_prepare(walk, pmdp, ptep, addr, hmm_pfns, &unmapped);
> + if (r == -EAGAIN) {
> + HMM_ASSERT_UNLOCKED(hmm_vma_walk);
> + if (unmapped) {
> + flush_tlb_range(walk->vma, start, addr);
> + unmapped = false;
> + }
> + goto again;
> + }
> + if (r) {
> + /* A non -EAGAIN error here means migrate_vma_split_folio()
> + * already dropped the PTE lock and cleared ptelocked.
> + */
> + HMM_ASSERT_UNLOCKED(hmm_vma_walk);
> + if (unmapped)
> + flush_tlb_range(walk->vma, start, addr);
> + hmm_pfns_fill(addr, end, hmm_vma_walk, HMM_PFN_ERROR);
> + return 0;
> + }
> }
[Severity: High]
In hmm_vma_walk_pmd() in mm/hmm.c, after entries in [start, addr) have been
collected into hmm_pfns_start with HMM_PFN_VALID | HMM_PFN_MIGRATE,
hmm_vma_handle_migrate_prepare() may encounter a pte-mapped large folio at
addr > start and call migrate_vma_split_folio(), which drops
hmm_vma_walk->ptl, splits the folio, and returns -EAGAIN.
hmm_vma_walk_pmd() then jumps to again: without resetting addr = start:
1. At again:, hmm_pfns points to addr rather than start. If
pte_offset_map_lock() returns NULL because the pte table disappeared while
the lock was dropped, hmm_vma_handle_migrate_prepare_rollback(walk->private,
addr, end, hmm_pfns) runs before addr = start, rolling back the unvisited
tail [addr, end) instead of [start, addr) (hmm_pfns_start).
2. If while the pte lock was dropped a concurrent MADV_DONTNEED zapped the
migration ptes in [start, addr) (or the pte table was freed and replaced
by a new pte table) and pte_offset_map_lock() succeeds at addr > start,
the loop resumes from addr without re-walking or rolling back
[start, addr). hmm_range_fault() then returns 0 with
HMM_PFN_VALID | HMM_PFN_MIGRATE still set for folios whose migration ptes
were already cleared, so remove_migration_ptes() installs no ptes for the
destination device folio and migrate_vma_finalize() frees the destination
folio while it is mapped by the device.
3. If the pte table was replaced by a pmd migration entry while the lock was
dropped, the pmd_is_migration_entry(pmd) check in hmm_vma_walk_pmd() sees
minfo != 0 and returns 0 without rolling back hmm_pfns_start.
4. When re-walking a range that already has collected entries in hmm_pfns,
the fault and -EFAULT paths in hmm_vma_handle_pte(), hmm_vma_walk_hole(),
hmm_vma_handle_pmd(), and hmm_vma_handle_absent_pmd() return
HMM_FAULT_PENDING or -EFAULT without calling
hmm_vma_handle_migrate_prepare_rollback(), leaving the previously
collected folio locked while hmm_do_fault() runs or when
hmm_range_fault_locked() aborts on mmu_interval_check_retry().
Can these paths leak folio locks and references or self-deadlock on
folio_lock() during fault handling?
[ ... ]
> diff --git a/mm/migrate_device.c b/mm/migrate_device.c
> index 0c437004329d9..c61a9e54e06bb 100644
> --- a/mm/migrate_device.c
> +++ b/mm/migrate_device.c
[ ... ]
> @@ -1528,3 +1054,58 @@ int migrate_device_coherent_folio(struct folio *folio)
> return 0;
> return -EBUSY;
> }
> +
> +/**
> + * migrate_hmm_range_setup() - prepare to migrate a range of memory
> + * @range: contains pointer to struct migrate_vma to be set up.
> + *
> + * When collecting has been done with hmm_range_fault(), this
> + * should be called next, and completes range->migrate by
> + * populating migrate->src[] and migrate->dst[]
> + * using range->hmm_pfns[].
> + * Also, migrate->cpages and migrate->npages get initialized.
> + * After migrate_hmm_range_setup(), range->migrate is good
> + * for the rest of the migrate_vma_* flow.
> + */
> +void migrate_hmm_range_setup(struct hmm_range *range)
> +{
> + struct migrate_vma *migrate = range->migrate;
> +
> + if (!migrate)
> + return;
> +
> + migrate->npages = (migrate->end - migrate->start) >> PAGE_SHIFT;
> + migrate->cpages = 0;
> +
> + for (unsigned long i = 0; i < migrate->npages; i++) {
> + unsigned long pfn = range->hmm_pfns[i];
> +
> + /*
> + * We are only interested in entries to be
> + * migrated.
> + */
> + if (!(pfn & HMM_PFN_MIGRATE)) {
> + migrate->src[i] = 0;
> + migrate->dst[i] = 0;
> + continue;
> + }
> +
> + migrate->cpages++;
> +
> + /* HMM_PFN_MIGRATE without HMM_PFN_VALID denotes the special zero page */
> + if (pfn & HMM_PFN_VALID)
> + migrate->src[i] = migrate_pfn(page_to_pfn(hmm_pfn_to_page(pfn)));
> + else
> + migrate->src[i] = 0;
> +
> + migrate->src[i] |= MIGRATE_PFN_MIGRATE;
> + migrate->src[i] |= (pfn & HMM_PFN_WRITE) ? MIGRATE_PFN_WRITE : 0;
> + migrate->src[i] |= (pfn & HMM_PFN_COMPOUND) ? MIGRATE_PFN_COMPOUND : 0;
> + migrate->dst[i] = 0;
> + }
> +
> + if (migrate->cpages)
> + migrate_vma_unmap(migrate);
> +
> +}
> +EXPORT_SYMBOL(migrate_hmm_range_setup);
[Severity: High]
There appear to be three issues with how migrate_hmm_range_setup() in
mm/migrate_device.c and hmm_vma_post_range_fault() in mm/hmm.c handle range
bounds and range->hmm_pfns state:
1. Documentation/mm/hmm.rst states that drivers initialize flags, src, dst,
and pgmap_owner in range->migrate and call migrate_hmm_range_setup(range)
even on error. However, hmm_vma_post_range_fault() in mm/hmm.c only calls
hmm_fill_migrate_vma() to set migrate->vma, migrate->start, and
migrate->end when hmm_vma_walk->mmu_armed is true:
if (hmm_select_migrate(range) &&
hmm_vma_walk->mmu_armed) {
if (range->notifier) {
hmm_fill_migrate_vma(range,
hmm_vma_walk->vma,
hmm_vma_walk->start,
hmm_vma_walk->end);
}
mmu_notifier_invalidate_range_end(&hmm_vma_walk->mmu_range);
}
If hmm_range_fault() fails before hmm_vma_capture_migrate_range() sets
mmu_armed = true (for example when mmu_interval_check_retry() fails at the
start of hmm_range_fault_locked(), or when range->start falls in an
unmapped hole so hmm_vma_walk_hole() returns -EFAULT before test_walk
runs), migrate->start and migrate->end are never updated. Doesn't
migrate_hmm_range_setup() then compute migrate->npages from uninitialized
memory or stale bounds from a previous loop iteration (such as the chunk
loop in dmirror_fault_and_migrate_to_device())?
2. Pagewalk callbacks in mm/hmm.c index range->hmm_pfns using
(addr - range->start) >> PAGE_SHIFT. If [range->start, range->end) starts
in a vma hole (range->start < vma->vm_start) and HMM_PFN_REQ_FAULT is not
set for the hole, hmm_vma_walk_hole() fills the leading hole entries with
HMM_PFN_ERROR and the walk continues into the vma, where
hmm_vma_capture_migrate_range() sets hmm_vma_walk->start = vma->vm_start
and hmm_fill_migrate_vma() sets migrate->start = vma->vm_start. Because
migrate_hmm_range_setup() indexes range->hmm_pfns from 0 rather than
(migrate->start - range->start) >> PAGE_SHIFT, won't it read the leading
HMM_PFN_ERROR entries and ignore the trailing collected entries in
range->hmm_pfns, leaking their folio locks, folio references, and
installed migration ptes?
3. Documentation/mm/hmm.rst states that migrate_hmm_range_setup() translates
range->hmm_pfns into migrate->src[], without requiring range->hmm_pfns to
alias migrate->src or be zero-initialized, and migrate_hmm_range_setup()
does not clear HMM_PFN_VALID | HMM_PFN_MIGRATE in range->hmm_pfns[i]. When
range->hmm_pfns and migrate->src are separate arrays and range->hmm_pfns is
reused across -EBUSY retries or multi-chunk walks (or contains
uninitialized data), won't hmm_vma_handle_migrate_prepare_rollback() see
hmm_pfn_collected(range->hmm_pfns[i]) as true and call folio_unlock() and
folio_put() on already-finalized or bogus pfns?
([
{
"id": "PVF1",
"Patch": "mm/hmm: implement rollback for device page migration in HMM pagewalk",
"Commit": "5c75620371e34a43110051163d33f29ab4f700b4"
},
{
"id": "PVF2",
"Patch": "mm/hmm: implement rollback for device page migration in HMM pagewalk",
"Commit": "5c75620371e34a43110051163d33f29ab4f700b4"
},
{
"id": "PVF3",
"Patch": "mm: add helper to convert HMM pfn to migrate pfn",
"Commit": "9636fd16690a9c1da892fd55feb0d227311adfe2"
},
{
"id": "PVF4",
"Patch": "lib/test_hmm: add a new testcase for the migrate on fault",
"Commit": "43a1dd324a1ecfe103c0cf9ba76ea8935506e50c"
}
])
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021060506.2377545-1-mpenttil@redhat.com?part=11
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v16 12/12] drm/nouveau/svm: add support for migrate on fault
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (10 preceding siblings ...)
2026-10-21 6:05 ` [PATCH v16 11/12] Documentation/mm/hmm: document migration through hmm_range_fault() mpenttil
@ 2026-10-21 6:05 ` mpenttil
2026-10-22 6:06 ` sashiko-bot
2026-10-21 6:50 ` ✗ CI.checkpatch: warning for Migrate on fault for device pages (rev8) Patchwork
` (4 subsequent siblings)
16 siblings, 1 reply; 33+ messages in thread
From: mpenttil @ 2026-10-21 6:05 UTC (permalink / raw)
To: linux-mm
Cc: dri-devel, intel-xe, linux-kernel, Mika Penttilä,
David Hildenbrand, Jason Gunthorpe, Leon Romanovsky,
Alistair Popple, Balbir Singh, Zi Yan, Matthew Brost,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Lyude Paul,
Danilo Krummrich
From: Mika Penttilä <mpenttil@redhat.com>
Add a direct user for the new HMM_PFN_REQ_MIGRATE flag and
implement migrate on fault for nouveau driver. It is gated
by the svm_migrate_on_fault module parameter, default off.
Added nouveau_dmem_migrate_fault() that faults a range in and
does migrate collecting in a single hmm_range_fault() walk.
As an optimization, a migration policy - deciding which faulting
ranges are worth migrating to VRAM and which are better left
mirrored in system memory - would be useful. This patch
establishes the migrate-on-fault mechanism as a basis for later
refinement.
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
drivers/gpu/drm/nouveau/nouveau_dmem.c | 281 ++++++++++++++++++++++++-
drivers/gpu/drm/nouveau/nouveau_dmem.h | 12 ++
drivers/gpu/drm/nouveau/nouveau_svm.c | 141 +++++++++----
drivers/gpu/drm/nouveau/nouveau_svm.h | 5 +
4 files changed, 384 insertions(+), 55 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c
index e74d7bb975a8..998c63e2ae78 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dmem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c
@@ -40,6 +40,9 @@
#include <linux/hmm.h>
#include <linux/memremap.h>
#include <linux/migrate.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/mmu_notifier.h>
/*
* FIXME: this is ugly right now we are using TTM to allocate vram and we pin
@@ -139,10 +142,12 @@ static void nouveau_dmem_folio_free(struct folio *folio)
spin_unlock(&dmem->lock);
}
-static void nouveau_dmem_fence_done(struct nouveau_fence **fence)
+static int nouveau_dmem_fence_done(struct nouveau_fence **fence)
{
+ int ret = 0;
+
if (fence) {
- nouveau_fence_wait(*fence, true, false);
+ ret = nouveau_fence_wait(*fence, true, false);
nouveau_fence_unref(fence);
} else {
/*
@@ -150,6 +155,32 @@ static void nouveau_dmem_fence_done(struct nouveau_fence **fence)
* the hmem object.
*/
}
+
+ /* 0 on completion, -EBUSY on timeout, or other errno; propagated. */
+ return ret;
+}
+
+/*
+ * Poll the copy fence instead of the lazy (interrupt-driven) wait since
+ * completion IRQ is randomly missed, hitting the timeout.
+ *
+ * Returns 0 on completion, -EBUSY on timeout. Consumes the fence reference.
+ */
+static int nouveau_dmem_fence_poll(struct nouveau_fence **fence)
+{
+ unsigned long deadline = jiffies + 30 * HZ;
+ int ret = 0;
+
+ while (!nouveau_fence_done(*fence)) {
+ if (time_after(jiffies, deadline)) {
+ ret = -EBUSY;
+ break;
+ }
+ schedule_timeout_uninterruptible(msecs_to_jiffies(1));
+ }
+ nouveau_fence_unref(fence);
+
+ return ret;
}
static int nouveau_dmem_copy_folio(struct nouveau_drm *drm,
@@ -188,7 +219,7 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf)
struct nouveau_svmm *svmm;
struct page *dpage;
vm_fault_t ret = 0;
- int err;
+ int err, fret = 0;
struct migrate_vma args = {
.vma = vmf->vma,
.pgmap_owner = drm->dev,
@@ -233,10 +264,12 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf)
* than just one page on CPU fault. When such fault happens it is very
* likely that more surrounding page will CPU fault too.
*/
- if (migrate_vma_setup(&args) < 0)
- return VM_FAULT_SIGBUS;
+ if (migrate_vma_setup(&args) < 0) {
+ ret = VM_FAULT_SIGBUS;
+ goto err;
+ }
if (!args.cpages)
- return 0;
+ goto done;
if (order)
dpage = folio_page(vma_alloc_folio(GFP_HIGHUSER | __GFP_ZERO,
@@ -266,9 +299,12 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf)
nouveau_fence_new(&fence, dmem->migrate.chan);
migrate_vma_pages(&args);
- nouveau_dmem_fence_done(&fence);
+ fret = nouveau_dmem_fence_poll(&fence);
dma_unmap_page(drm->dev->dev, dma_info.dma_addr, dma_info.size,
DMA_BIDIRECTIONAL);
+ if (fret)
+ /* Copy failed; the pte now points at possibly stale sysram data. */
+ ret = VM_FAULT_SIGBUS;
done:
migrate_vma_finalize(&args);
err:
@@ -794,11 +830,12 @@ static unsigned long nouveau_dmem_migrate_copy_one(struct nouveau_drm *drm,
return 0;
}
-static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
+static unsigned long
+nouveau_dmem_migrate_alloc_and_copy(struct nouveau_drm *drm,
struct nouveau_svmm *svmm, struct migrate_vma *args,
- struct nouveau_dmem_dma_info *dma_info, u64 *pfns)
+ struct nouveau_dmem_dma_info *dma_info, u64 *pfns,
+ unsigned long *nr_dma_out, unsigned long *order_out)
{
- struct nouveau_fence *fence;
unsigned long addr = args->start, nr_dma = 0, i;
unsigned long order = 0;
@@ -820,6 +857,21 @@ static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
addr += (1 << order) * PAGE_SIZE;
}
+ *nr_dma_out = nr_dma;
+ *order_out = order;
+ return i;
+}
+
+static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
+ struct nouveau_svmm *svmm, struct migrate_vma *args,
+ struct nouveau_dmem_dma_info *dma_info, u64 *pfns)
+{
+ struct nouveau_fence *fence;
+ unsigned long nr_dma, order, i;
+
+ i = nouveau_dmem_migrate_alloc_and_copy(drm, svmm, args, dma_info, pfns,
+ &nr_dma, &order);
+
nouveau_fence_new(&fence, drm->dmem->migrate.chan);
migrate_vma_pages(args);
nouveau_dmem_fence_done(&fence);
@@ -832,6 +884,215 @@ static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
migrate_vma_finalize(args);
}
+/*
+ * Encode an hmm_range_fault() pfn for @start into the nouveau PFNMAP format,
+ * shared by nouveau_hmm_convert_pfn() and the in-place map in
+ * nouveau_dmem_migrate_fault().
+ */
+u64 nouveau_dmem_hmm_pfn_to_map(unsigned long hmm_pfn, unsigned long start,
+ unsigned long *map_addr, unsigned int *page_shift)
+{
+ unsigned long order;
+ struct page *page;
+ u64 pfn;
+
+ *map_addr = start;
+ *page_shift = PAGE_SHIFT;
+
+ if (!(hmm_pfn & HMM_PFN_VALID))
+ return NVIF_VMM_PFNMAP_V0_NONE;
+
+ page = hmm_pfn_to_page(hmm_pfn);
+
+ order = hmm_pfn_to_map_order(hmm_pfn);
+ if (order) {
+ *page_shift = order + PAGE_SHIFT;
+ *map_addr = start & ~((1UL << *page_shift) - 1);
+ page -= (start - *map_addr) >> PAGE_SHIFT;
+ }
+
+ if (is_device_private_page(page))
+ pfn = nouveau_dmem_page_addr(page) |
+ NVIF_VMM_PFNMAP_V0_V | NVIF_VMM_PFNMAP_V0_VRAM;
+ else
+ pfn = page_to_phys(page) |
+ NVIF_VMM_PFNMAP_V0_V | NVIF_VMM_PFNMAP_V0_HOST;
+ if (hmm_pfn & HMM_PFN_WRITE)
+ pfn |= NVIF_VMM_PFNMAP_V0_W;
+
+ return pfn;
+}
+
+/*
+ * Fault a range in and migrate it to VRAM.
+ * Returns 0 on success, or an error (so the caller
+ * falls back to nouveau_range_fault()) if nothing could be mapped.
+ */
+int
+nouveau_dmem_migrate_fault(struct nouveau_drm *drm, struct nouveau_svmm *svmm,
+ struct mmu_interval_notifier *notifier,
+ unsigned long start, unsigned long end,
+ unsigned long hmm_flags,
+ u64 *out_pfn0, unsigned long *out_addr,
+ unsigned int *out_shift)
+{
+ unsigned long timeout =
+ jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
+ unsigned long npages = (end - start) >> PAGE_SHIFT;
+ struct mm_struct *mm = notifier->mm;
+ struct nouveau_dmem_dma_info *dma_info;
+ struct nouveau_fence *fence = NULL;
+ struct migrate_vma migrate = {
+ .start = start,
+ .end = end,
+ .pgmap_owner = drm->dev,
+ .flags = MIGRATE_VMA_SELECT_SYSTEM,
+ };
+ struct hmm_range range = {
+ .notifier = notifier,
+ .start = start,
+ .end = end,
+ .dev_private_owner = drm->dev,
+ .migrate = &migrate,
+ .default_flags = hmm_flags | HMM_PFN_REQ_MIGRATE,
+ };
+ unsigned long nr_dma, order, n, i;
+ unsigned long hmm_pfn0 = 0;
+ bool migrated;
+ u64 *pfns;
+ int ret, fret = 0;
+
+ if (!drm->dmem)
+ return -ENODEV;
+
+ migrate.src = kcalloc(npages, sizeof(*migrate.src), GFP_KERNEL);
+ if (!migrate.src)
+ return -ENOMEM;
+ migrate.dst = kcalloc(npages, sizeof(*migrate.dst), GFP_KERNEL);
+ if (!migrate.dst) {
+ ret = -ENOMEM;
+ goto out_free_src;
+ }
+ dma_info = kmalloc_objs(*dma_info, npages);
+ if (!dma_info) {
+ ret = -ENOMEM;
+ goto out_free_dst;
+ }
+ pfns = nouveau_pfns_alloc(npages);
+ if (!pfns) {
+ ret = -ENOMEM;
+ goto out_free_dma;
+ }
+
+ /* hmm_range_fault() shares the source pfn array with migrate_vma. */
+ range.hmm_pfns = migrate.src;
+
+ do {
+ mmap_read_lock(mm);
+ range.notifier_seq = mmu_interval_read_begin(notifier);
+
+ ret = hmm_range_fault(&range);
+ /*
+ * Snapshot the pfn before migrate_hmm_range_setup() overwrites the
+ * shared array; used to map in place if nothing migrates.
+ */
+ if (!ret)
+ hmm_pfn0 = range.hmm_pfns[0];
+ migrate_hmm_range_setup(&range);
+ if (ret) {
+ migrate_vma_pages(&migrate);
+ migrate_vma_finalize(&migrate);
+ goto unlock;
+ }
+
+ n = nouveau_dmem_migrate_alloc_and_copy(drm, svmm, &migrate,
+ dma_info, pfns,
+ &nr_dma, &order);
+
+ /* Only a migrated page has an in-flight CE copy to unblock below. */
+ for (i = 0, migrated = false; i < npages; i++) {
+ if (migrate.dst[i]) {
+ migrated = true;
+ break;
+ }
+ }
+
+ /*
+ * Track a copy fence only when a copy was enqueued; waiting on an
+ * empty fence would block until the fault's CTXSW_TIMEOUT.
+ */
+ if (migrated)
+ nouveau_fence_new(&fence, drm->dmem->migrate.chan);
+ migrate_vma_pages(&migrate);
+
+ /*
+ * The fault-in path must replay the faulting channel before waiting on
+ * the copy fence: with the fault still unreplayed the copy does not
+ * make progress. GPU has no mapping so it might refault, until it
+ * gets the migrated or mirrored mapping.
+ */
+ if (drm->svm && migrated)
+ nouveau_svm_fault_replay(drm->svm);
+
+ if (migrated)
+ fret = nouveau_dmem_fence_poll(&fence);
+
+ mutex_lock(&svmm->mutex);
+ if (fret) {
+ /* Copy did not complete; don't map a half-copied page. */
+ ret = -EIO;
+ } else if (mmu_interval_read_retry(notifier, range.notifier_seq)) {
+ ret = -EBUSY;
+ } else {
+ unsigned long map_addr = migrate.start;
+ unsigned int page_shift = PAGE_SHIFT + order;
+
+ /*
+ * If nothing migrated might still be able to mirror.
+ * In that case use the snapshot hmm_pfn.
+ * npages == 1 always today.
+ */
+ if (npages == 1 && !(pfns[0] & NVIF_VMM_PFNMAP_V0_V))
+ pfns[0] = nouveau_dmem_hmm_pfn_to_map(hmm_pfn0,
+ start, &map_addr, &page_shift);
+
+ __nouveau_pfns_map_locked(svmm, map_addr, pfns, n,
+ page_shift);
+
+ *out_pfn0 = pfns[0];
+ *out_addr = map_addr;
+ *out_shift = page_shift;
+ }
+ mutex_unlock(&svmm->mutex);
+
+ if (fret)
+ NV_ERROR(drm,
+ "svm: migrate copy did not complete (%d) for %lx-%lx\n",
+ fret, start, end);
+
+ while (nr_dma--) {
+ dma_unmap_page(drm->dev->dev, dma_info[nr_dma].dma_addr,
+ dma_info[nr_dma].size, DMA_BIDIRECTIONAL);
+ }
+ migrate_vma_finalize(&migrate);
+unlock:
+ mmap_read_unlock(mm);
+ } while (ret == -EBUSY && !time_after(jiffies, timeout));
+
+ /* Nothing migrated or mappable in place, fallback to nouveau_range_fault(). */
+ if (!ret && !(pfns[0] & NVIF_VMM_PFNMAP_V0_V))
+ ret = -ENOENT;
+
+ nouveau_pfns_free(pfns);
+out_free_dma:
+ kfree(dma_info);
+out_free_dst:
+ kfree(migrate.dst);
+out_free_src:
+ kfree(migrate.src);
+ return ret;
+}
+
int
nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
struct nouveau_svmm *svmm,
diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.h b/drivers/gpu/drm/nouveau/nouveau_dmem.h
index 64da5d3635c8..91e8910cadbf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dmem.h
+++ b/drivers/gpu/drm/nouveau/nouveau_dmem.h
@@ -27,6 +27,7 @@ struct drm_file;
struct nouveau_drm;
struct nouveau_svmm;
struct hmm_range;
+struct mmu_interval_notifier;
#if IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM)
void nouveau_dmem_init(struct nouveau_drm *);
@@ -39,7 +40,18 @@ int nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
struct vm_area_struct *vma,
unsigned long start,
unsigned long end);
+int nouveau_dmem_migrate_fault(struct nouveau_drm *drm,
+ struct nouveau_svmm *svmm,
+ struct mmu_interval_notifier *notifier,
+ unsigned long start,
+ unsigned long end,
+ unsigned long hmm_flags,
+ u64 *out_pfn0,
+ unsigned long *out_addr,
+ unsigned int *out_shift);
unsigned long nouveau_dmem_page_addr(struct page *page);
+u64 nouveau_dmem_hmm_pfn_to_map(unsigned long hmm_pfn, unsigned long start,
+ unsigned long *map_addr, unsigned int *page_shift);
#else /* IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM) */
static inline void nouveau_dmem_init(struct nouveau_drm *drm) {}
diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c
index c519c28164fa..960cbf8af974 100644
--- a/drivers/gpu/drm/nouveau/nouveau_svm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_svm.c
@@ -37,6 +37,7 @@
#include <linux/hmm.h>
#include <linux/memremap.h>
#include <linux/rmap.h>
+#include <linux/moduleparam.h>
struct nouveau_svm {
struct nouveau_drm *drm;
@@ -78,6 +79,13 @@ struct nouveau_svm {
#define SVM_DBG(s,f,a...) NV_DEBUG((s)->drm, "svm: "f"\n", ##a)
#define SVM_ERR(s,f,a...) NV_WARN((s)->drm, "svm: "f"\n", ##a)
+/* When set, migrate the faulting range to VRAM on GPU fault (default off). */
+static bool nouveau_svm_migrate_on_fault;
+module_param_named(svm_migrate_on_fault, nouveau_svm_migrate_on_fault, bool,
+ 0644);
+MODULE_PARM_DESC(svm_migrate_on_fault,
+ "migrate system memory to VRAM on GPU fault (default off)");
+
struct nouveau_pfnmap_args {
struct nvif_ioctl_v0_hdr i;
struct nvif_ioctl_mthd_v0_hdr m;
@@ -182,9 +190,10 @@ nouveau_svmm_bind(struct drm_device *dev, void *data,
addr = max(addr, vma->vm_start);
next = min(vma->vm_end, end);
- /* This is a best effort so we ignore errors */
- nouveau_dmem_migrate_vma(cli->drm, cli->svm.svmm, vma, addr,
- next);
+ /* Best effort; skipped when migrate-on-fault does the migration. */
+ if (!nouveau_svm_migrate_on_fault)
+ nouveau_dmem_migrate_vma(cli->drm, cli->svm.svmm, vma,
+ addr, next);
addr = next;
}
@@ -390,7 +399,7 @@ nouveau_svmm_init(struct drm_device *dev, void *data,
}
/* Issue fault replay for GPU to retry accesses that faulted previously. */
-static void
+void
nouveau_svm_fault_replay(struct nouveau_svm *svm)
{
SVM_DBG(svm, "replay");
@@ -527,6 +536,14 @@ static bool nouveau_svm_range_invalidate(struct mmu_interval_notifier *mni,
range->owner == sn->svmm->vmm->cli->drm->dev)
return true;
+ /*
+ * Ignore our own migrate-on-fault invalidation; otherwise its
+ * MMU_NOTIFY_MIGRATE bumps the seq and read_retry() spins to timeout.
+ */
+ if (range->event == MMU_NOTIFY_MIGRATE &&
+ range->owner == sn->svmm->vmm->cli->drm->dev)
+ return true;
+
/*
* serializes the update to mni->invalidate_seq done by caller and
* prevents invalidation of the PTE from progressing while HW is being
@@ -551,48 +568,25 @@ static void nouveau_hmm_convert_pfn(struct nouveau_drm *drm,
struct hmm_range *range,
struct nouveau_pfnmap_args *args)
{
- struct page *page;
+ unsigned long map_addr;
+ unsigned int page_shift;
/*
* The address prepared here is passed through nvif_object_ioctl()
* to an eventual DMA map in something like gp100_vmm_pgt_pfn()
*
* This is all just encoding the internal hmm representation into a
- * different nouveau internal representation.
+ * different nouveau internal representation; see the shared encoder
+ * nouveau_dmem_hmm_pfn_to_map() (also widens to the CPU folio order).
*/
- if (!(range->hmm_pfns[0] & HMM_PFN_VALID)) {
- args->p.phys[0] = 0;
- return;
+ args->p.phys[0] = nouveau_dmem_hmm_pfn_to_map(range->hmm_pfns[0],
+ args->p.addr, &map_addr,
+ &page_shift);
+ if (page_shift != PAGE_SHIFT) {
+ args->p.addr = map_addr;
+ args->p.page = page_shift;
+ args->p.size = 1UL << page_shift;
}
-
- page = hmm_pfn_to_page(range->hmm_pfns[0]);
- /*
- * Only map compound pages to the GPU if the CPU is also mapping the
- * page as a compound page. Otherwise, the PTE protections might not be
- * consistent (e.g., CPU only maps part of a compound page).
- * Note that the underlying page might still be larger than the
- * CPU mapping (e.g., a PUD sized compound page partially mapped with
- * a PMD sized page table entry).
- */
- if (hmm_pfn_to_map_order(range->hmm_pfns[0])) {
- unsigned long addr = args->p.addr;
-
- args->p.page = hmm_pfn_to_map_order(range->hmm_pfns[0]) +
- PAGE_SHIFT;
- args->p.size = 1UL << args->p.page;
- args->p.addr &= ~(args->p.size - 1);
- page -= (addr - args->p.addr) >> PAGE_SHIFT;
- }
- if (is_device_private_page(page))
- args->p.phys[0] = nouveau_dmem_page_addr(page) |
- NVIF_VMM_PFNMAP_V0_V |
- NVIF_VMM_PFNMAP_V0_VRAM;
- else
- args->p.phys[0] = page_to_phys(page) |
- NVIF_VMM_PFNMAP_V0_V |
- NVIF_VMM_PFNMAP_V0_HOST;
- if (range->hmm_pfns[0] & HMM_PFN_WRITE)
- args->p.phys[0] |= NVIF_VMM_PFNMAP_V0_W;
}
static int nouveau_atomic_range_fault(struct nouveau_svmm *svmm,
@@ -728,6 +722,44 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm,
return ret;
}
+static int nouveau_range_fault_and_migrate(struct nouveau_svmm *svmm,
+ struct nouveau_drm *drm,
+ struct nouveau_pfnmap_args *args,
+ unsigned long hmm_flags,
+ struct svm_notifier *notifier)
+{
+ struct mm_struct *mm = svmm->notifier.mm;
+ unsigned long start = args->p.addr;
+ unsigned long end = start + args->p.size;
+ unsigned long map_addr;
+ unsigned int page_shift;
+ u64 pfn0;
+ int ret;
+
+ ret = mmu_interval_notifier_insert(¬ifier->notifier, mm,
+ start, args->p.size,
+ &nouveau_svm_mni_ops);
+ if (ret)
+ return ret;
+
+ ret = nouveau_dmem_migrate_fault(drm, svmm, ¬ifier->notifier,
+ start, end, hmm_flags,
+ &pfn0, &map_addr, &page_shift);
+
+ if (!ret) {
+ args->p.phys[0] = pfn0;
+ if (page_shift != PAGE_SHIFT) {
+ args->p.addr = map_addr;
+ args->p.page = page_shift;
+ args->p.size = 1UL << page_shift;
+ }
+ }
+
+ mmu_interval_notifier_remove(¬ifier->notifier);
+
+ return ret;
+}
+
static void
nouveau_svm_fault(struct work_struct *work)
{
@@ -843,14 +875,25 @@ nouveau_svm_fault(struct work_struct *work)
}
notifier.svmm = svmm;
- if (atomic)
+ if (atomic) {
ret = nouveau_atomic_range_fault(svmm, svm->drm, args,
__struct_size(args),
¬ifier);
- else
+ } else if (nouveau_svm_migrate_on_fault &&
+ buffer->fault[fi]->access != FAULT_ACCESS_PREFETCH) {
+ /* Fault+migrate in one walk; fall back if nothing migrated. */
+ ret = nouveau_range_fault_and_migrate(svmm, svm->drm,
+ args, hmm_flags,
+ ¬ifier);
+ if (ret)
+ ret = nouveau_range_fault(svmm, svm->drm, args,
+ __struct_size(args),
+ hmm_flags, ¬ifier);
+ } else {
ret = nouveau_range_fault(svmm, svm->drm, args,
__struct_size(args),
hmm_flags, ¬ifier);
+ }
mmput(mm);
limit = args->p.addr + args->p.size;
@@ -935,21 +978,29 @@ nouveau_pfns_free(u64 *pfns)
}
void
-nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm,
- unsigned long addr, u64 *pfns, unsigned long npages,
- unsigned int page_shift)
+__nouveau_pfns_map_locked(struct nouveau_svmm *svmm, unsigned long addr,
+ u64 *pfns, unsigned long npages,
+ unsigned int page_shift)
{
struct nouveau_pfnmap_args *args = nouveau_pfns_to_args(pfns);
+ lockdep_assert_held(&svmm->mutex);
+
args->p.addr = addr;
args->p.size = npages << page_shift;
args->p.page = page_shift;
- mutex_lock(&svmm->mutex);
-
nvif_object_ioctl(&svmm->vmm->vmm.object, args,
struct_size(args, p.phys, npages), NULL);
+}
+void
+nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm,
+ unsigned long addr, u64 *pfns, unsigned long npages,
+ unsigned int page_shift)
+{
+ mutex_lock(&svmm->mutex);
+ __nouveau_pfns_map_locked(svmm, addr, pfns, npages, page_shift);
mutex_unlock(&svmm->mutex);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.h b/drivers/gpu/drm/nouveau/nouveau_svm.h
index 3fd78662f17e..0e7ff03f80ea 100644
--- a/drivers/gpu/drm/nouveau/nouveau_svm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_svm.h
@@ -5,6 +5,7 @@
struct drm_device;
struct drm_file;
struct nouveau_drm;
+struct nouveau_svm;
struct nouveau_svmm {
struct mmu_notifier notifier;
@@ -35,6 +36,10 @@ void nouveau_pfns_free(u64 *pfns);
void nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm,
unsigned long addr, u64 *pfns, unsigned long npages,
unsigned int page_shift);
+void __nouveau_pfns_map_locked(struct nouveau_svmm *svmm, unsigned long addr,
+ u64 *pfns, unsigned long npages,
+ unsigned int page_shift);
+void nouveau_svm_fault_replay(struct nouveau_svm *svm);
#else /* IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM) */
static inline void nouveau_svm_init(struct nouveau_drm *drm) {}
static inline void nouveau_svm_fini(struct nouveau_drm *drm) {}
--
2.55.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v16 12/12] drm/nouveau/svm: add support for migrate on fault
2026-10-21 6:05 ` [PATCH v16 12/12] drm/nouveau/svm: add support for migrate on fault mpenttil
@ 2026-10-22 6:06 ` sashiko-bot
0 siblings, 0 replies; 33+ messages in thread
From: sashiko-bot @ 2026-10-22 6:06 UTC (permalink / raw)
To: mpenttil, linux-mm
Cc: dri-devel, intel-xe, David Hildenbrand, Jason Gunthorpe,
Leon Romanovsky, Alistair Popple, Balbir Singh, Zi Yan,
Matthew Brost, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Lyude Paul, Danilo Krummrich
Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [Critical] drm/nouveau/dmem: freed VRAM page mapped on migrate_vma_pages() abort
- [Critical] drm/nouveau/dmem: copy timeout in nouveau_dmem_migrate_fault() maps uncopied page
- [Critical] drm/nouveau/svm: nouveau_svm_range_invalidate() ignores all driver migrations
- [High] drm/nouveau/dmem: unchecked nouveau_fence_new() in nouveau_dmem_fence_poll() callers
- [High] drm/nouveau/svm: unguarded __nouveau_pfns_map_locked() on empty pfn in nouveau_dmem_migrate_fault()
- [High] drm/nouveau/dmem: unsynchronized access to migrate.chan in nouveau_dmem_migrate_fault()
- [Medium] drm/nouveau: unguarded pfn map and retry state in nouveau_dmem_migrate_fault()
- [Medium] drm/nouveau/svm: __nouveau_pfns_map_locked() drops nvif_object_ioctl() error
- [Low] drm/nouveau/svm: missing kernel-parameters.txt entry for svm_migrate_on_fault
--
commit 44e0adde7e1aeb837684fa123e764779afbd3db4
Author: Mika Penttilä <mpenttil@redhat.com>
drm/nouveau/svm: add support for migrate on fault
This commit adds migrate-on-fault support for Nouveau SVM using
HMM_PFN_REQ_MIGRATE and migrate_hmm_range_setup(), gated by a new
svm_migrate_on_fault module parameter. It introduces
nouveau_dmem_migrate_fault() to fault and collect migratable pages in a
single hmm_range_fault() walk, and polls migration fences via
nouveau_dmem_fence_poll().
> diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c
> index e74d7bb975a86..998c63e2ae78b 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_dmem.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c
[ ... ]
> @@ -150,6 +155,32 @@ static void nouveau_dmem_fence_done(struct nouveau_fence **fence)
> * the hmem object.
> */
> }
> +
> + /* 0 on completion, -EBUSY on timeout, or other errno; propagated. */
> + return ret;
> +}
> +
> +/*
> + * Poll the copy fence instead of the lazy (interrupt-driven) wait since
> + * completion IRQ is randomly missed, hitting the timeout.
> + *
> + * Returns 0 on completion, -EBUSY on timeout. Consumes the fence reference.
> + */
> +static int nouveau_dmem_fence_poll(struct nouveau_fence **fence)
> +{
> + unsigned long deadline = jiffies + 30 * HZ;
> + int ret = 0;
> +
> + while (!nouveau_fence_done(*fence)) {
[Severity: High]
What happens in nouveau_dmem_fence_poll() in
drivers/gpu/drm/nouveau/nouveau_dmem.c when nouveau_fence_new() fails in its
callers?
In drivers/gpu/drm/nouveau/nouveau_fence.c, nouveau_fence_new() can fail in
nouveau_fence_create() (without writing *pfence) or in nouveau_fence_emit()
(which calls nouveau_fence_unref(pfence) and sets *pfence = NULL).
Both callers of nouveau_dmem_fence_poll() ignore the return value of
nouveau_fence_new():
1. In nouveau_dmem_migrate_to_ram() in
drivers/gpu/drm/nouveau/nouveau_dmem.c, fence is declared uninitialized on
the stack:
struct nouveau_fence *fence;
...
nouveau_fence_new(&fence, dmem->migrate.chan);
migrate_vma_pages(&args);
fret = nouveau_dmem_fence_poll(&fence);
2. In nouveau_dmem_migrate_fault() in
drivers/gpu/drm/nouveau/nouveau_dmem.c, fence is initialized to NULL:
if (migrated)
nouveau_fence_new(&fence, drm->dmem->migrate.chan);
...
if (migrated)
fret = nouveau_dmem_fence_poll(&fence);
Since nouveau_fence_done() in drivers/gpu/drm/nouveau/nouveau_fence.c
immediately dereferences fence via nouveau_fctx(fence) and
dma_fence_is_signaled(&fence->base), won't a failure in nouveau_fence_new()
cause an uninitialized or NULL pointer dereference in
nouveau_dmem_fence_poll()?
> + if (time_after(jiffies, deadline)) {
> + ret = -EBUSY;
> + break;
> + }
> + schedule_timeout_uninterruptible(msecs_to_jiffies(1));
> + }
> + nouveau_fence_unref(fence);
> +
> + return ret;
> }
[ ... ]
> @@ -266,9 +299,12 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf)
>
> nouveau_fence_new(&fence, dmem->migrate.chan);
> migrate_vma_pages(&args);
> - nouveau_dmem_fence_done(&fence);
> + fret = nouveau_dmem_fence_poll(&fence);
> dma_unmap_page(drm->dev->dev, dma_info.dma_addr, dma_info.size,
> DMA_BIDIRECTIONAL);
> + if (fret)
> + /* Copy failed; the pte now points at possibly stale sysram data. */
> + ret = VM_FAULT_SIGBUS;
> done:
> migrate_vma_finalize(&args);
> err:
[ ... ]
> @@ -832,6 +884,215 @@ static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
[ ... ]
> +int
> +nouveau_dmem_migrate_fault(struct nouveau_drm *drm, struct nouveau_svmm *svmm,
> + struct mmu_interval_notifier *notifier,
> + unsigned long start, unsigned long end,
> + unsigned long hmm_flags,
> + u64 *out_pfn0, unsigned long *out_addr,
> + unsigned int *out_shift)
> +{
[ ... ]
> + /* hmm_range_fault() shares the source pfn array with migrate_vma. */
> + range.hmm_pfns = migrate.src;
> +
> + do {
> + mmap_read_lock(mm);
> + range.notifier_seq = mmu_interval_read_begin(notifier);
> +
> + ret = hmm_range_fault(&range);
> + /*
> + * Snapshot the pfn before migrate_hmm_range_setup() overwrites the
> + * shared array; used to map in place if nothing migrates.
> + */
> + if (!ret)
> + hmm_pfn0 = range.hmm_pfns[0];
> + migrate_hmm_range_setup(&range);
[Severity: Medium]
When the retry loop in nouveau_dmem_migrate_fault() in
drivers/gpu/drm/nouveau/nouveau_dmem.c repeats after ret == -EBUSY (either
from hmm_range_fault() or from mmu_interval_read_retry()), does migrate.src
(aliased by range.hmm_pfns) retain stale migrate_pfn values from the previous
iteration?
migrate_hmm_range_setup() in mm/migrate_device.c overwrites range.hmm_pfns[i]
with migrate_pfn(...) flags, and neither migrate_vma_pages() nor
migrate_vma_finalize() clears migrate.src[]. Unlike migrate_vma_setup() in
mm/migrate_device.c, which zeroes args->src before calling hmm_range_fault(),
nouveau_dmem_migrate_fault() re-enters hmm_range_fault(&range) without
clearing migrate.src. If the next walk hits an early return path that does
not overwrite *hmm_pfn (for example, softleaf_is_migration() in
hmm_vma_handle_pte()), won't range.hmm_pfns still hold stale migrate_pfn data
from the prior attempt?
> + if (ret) {
> + migrate_vma_pages(&migrate);
> + migrate_vma_finalize(&migrate);
> + goto unlock;
> + }
> +
> + n = nouveau_dmem_migrate_alloc_and_copy(drm, svmm, &migrate,
> + dma_info, pfns,
> + &nr_dma, &order);
> +
> + /* Only a migrated page has an in-flight CE copy to unblock below. */
> + for (i = 0, migrated = false; i < npages; i++) {
> + if (migrate.dst[i]) {
> + migrated = true;
> + break;
> + }
> + }
> +
> + /*
> + * Track a copy fence only when a copy was enqueued; waiting on an
> + * empty fence would block until the fault's CTXSW_TIMEOUT.
> + */
> + if (migrated)
> + nouveau_fence_new(&fence, drm->dmem->migrate.chan);
[Severity: High]
How is access to drm->dmem->migrate.chan synchronized in
nouveau_dmem_migrate_fault() in drivers/gpu/drm/nouveau/nouveau_dmem.c?
Here, nouveau_dmem_migrate_alloc_and_copy() (which calls
nvc0b5_migrate_copy() and nvc0b5_migrate_clear() to push multi-word DMA
commands via PUSH_WAIT(push, ...) on drm->dmem->migrate.chan->chan.push) and
nouveau_fence_new(&fence, drm->dmem->migrate.chan) run while holding only
mmap_read_lock(mm).
Because drm->dmem->migrate.chan aliases drm->ttm.chan (set up in
nouveau_dmem_migrate_init()), can this race with concurrent CPU faults in
nouveau_dmem_migrate_to_ram() (which pushes copy commands under svmm->mutex
and calls nouveau_fence_new() outside svmm->mutex) or concurrent TTM buffer
moves in nouveau_bo_move_m2mf() in drivers/gpu/drm/nouveau/nouveau_bo.c
(which serializes using cli->mutex), corrupting the shared channel pushbuffer
or racing on ++fctx->sequence?
> + migrate_vma_pages(&migrate);
> +
> + /*
> + * The fault-in path must replay the faulting channel before waiting on
> + * the copy fence: with the fault still unreplayed the copy does not
> + * make progress. GPU has no mapping so it might refault, until it
> + * gets the migrated or mirrored mapping.
> + */
> + if (drm->svm && migrated)
> + nouveau_svm_fault_replay(drm->svm);
> +
> + if (migrated)
> + fret = nouveau_dmem_fence_poll(&fence);
> +
> + mutex_lock(&svmm->mutex);
> + if (fret) {
> + /* Copy did not complete; don't map a half-copied page. */
> + ret = -EIO;
[Severity: Critical]
If nouveau_dmem_fence_poll(&fence) times out and returns -EBUSY here in
nouveau_dmem_migrate_fault() (or above in nouveau_dmem_migrate_to_ram()) in
drivers/gpu/drm/nouveau/nouveau_dmem.c, doesn't the page migration still get
committed with uncopied data while DMA may still be active?
Because migrate_vma_pages(&migrate) was already called before
nouveau_dmem_fence_poll(&fence), the folio metadata migration has already
succeeded and MIGRATE_PFN_MIGRATE remains set in migrate.src[0]. When fret is
non-zero:
1. dma_unmap_page() is called immediately on the source page (or destination
page in nouveau_dmem_migrate_to_ram()) even though the timed-out copy engine
DMA may still be in flight.
2. migrate_vma_finalize(&migrate) sees MIGRATE_PFN_MIGRATE still set in
migrate.src[0], so it installs a device-private swap PTE for the half-copied
VRAM page into the CPU page tables and frees the valid source system RAM
folio (or in nouveau_dmem_migrate_to_ram(), installs a present CPU PTE to
the stale system RAM page and frees the source VRAM folio).
3. In the GPU fault path, nouveau_dmem_migrate_fault() returns -EIO to
nouveau_range_fault_and_migrate(), and nouveau_svm_fault() in
drivers/gpu/drm/nouveau/nouveau_svm.c then executes:
ret = nouveau_range_fault_and_migrate(svmm, svm->drm,
args, hmm_flags,
¬ifier);
if (ret)
ret = nouveau_range_fault(svmm, svm->drm, args,
__struct_size(args),
hmm_flags, ¬ifier);
Won't nouveau_range_fault() walk the CPU page table, find the device-private
swap PTE just installed by migrate_vma_finalize(), and map that half-copied
VRAM page into the GPU anyway?
> + } else if (mmu_interval_read_retry(notifier, range.notifier_seq)) {
> + ret = -EBUSY;
> + } else {
> + unsigned long map_addr = migrate.start;
> + unsigned int page_shift = PAGE_SHIFT + order;
> +
> + /*
> + * If nothing migrated might still be able to mirror.
> + * In that case use the snapshot hmm_pfn.
> + * npages == 1 always today.
> + */
> + if (npages == 1 && !(pfns[0] & NVIF_VMM_PFNMAP_V0_V))
> + pfns[0] = nouveau_dmem_hmm_pfn_to_map(hmm_pfn0,
> + start, &map_addr, &page_shift);
> +
> + __nouveau_pfns_map_locked(svmm, map_addr, pfns, n,
> + page_shift);
[Severity: Critical]
Can nouveau_dmem_migrate_fault() in drivers/gpu/drm/nouveau/nouveau_dmem.c
map a VRAM page into the GPU that migrate_vma_pages() rejected and that
migrate_vma_finalize() is about to free?
Before migrate_vma_pages(&migrate) is called,
nouveau_dmem_migrate_alloc_and_copy() -> nouveau_dmem_migrate_copy_one()
allocates a destination VRAM page dpage for any entry with
MIGRATE_PFN_MIGRATE set and populates pfns[0]:
*pfn = NVIF_VMM_PFNMAP_V0_V | NVIF_VMM_PFNMAP_V0_VRAM |
((paddr >> PAGE_SHIFT) << NVIF_VMM_PFNMAP_V0_ADDR_SHIFT);
Next, migrate_vma_pages(&migrate) calls __migrate_device_pages() in
mm/migrate_device.c. If migration of the folio is rejected or fails — which
happens for all present file-backed or shared/shmem pages (collected by
hmm_vma_handle_migrate_prepare(), then rejected by __migrate_device_pages()
at !folio_test_anon(folio)), or when folio_free_swap() or
folio_migrate_mapping() fails with -EAGAIN due to extra references —
__migrate_device_pages() aborts the migration by clearing MIGRATE_PFN_MIGRATE
in migrate.src[0].
However, pfns[0] still has NVIF_VMM_PFNMAP_V0_V set from
nouveau_dmem_migrate_copy_one(). Because nouveau_dmem_migrate_fault() checks
!(pfns[0] & NVIF_VMM_PFNMAP_V0_V) without checking whether
migrate.src[0] & MIGRATE_PFN_MIGRATE is still set after migrate_vma_pages():
1. The in-place mirror fallback is skipped.
2. __nouveau_pfns_map_locked() maps the aborted VRAM page dpage into the GPU
VMM.
3. Immediately below, migrate_vma_finalize(&migrate) sees
!(migrate.src[0] & MIGRATE_PFN_MIGRATE), restores the CPU PTE to the original
system RAM folio, and calls folio_put(dst) on dpage, freeing it back to
dmem->free_pages via nouveau_dmem_folio_free() while the GPU retains a live
mapping to it.
Should nouveau_dmem_migrate_fault() check migrate.src[i] & MIGRATE_PFN_MIGRATE
after migrate_vma_pages(&migrate) and clear pfns[i] when migration did not
succeed?
> +
> + *out_pfn0 = pfns[0];
> + *out_addr = map_addr;
> + *out_shift = page_shift;
> + }
> + mutex_unlock(&svmm->mutex);
> +
> + if (fret)
> + NV_ERROR(drm,
> + "svm: migrate copy did not complete (%d) for %lx-%lx\n",
> + fret, start, end);
> +
> + while (nr_dma--) {
> + dma_unmap_page(drm->dev->dev, dma_info[nr_dma].dma_addr,
> + dma_info[nr_dma].size, DMA_BIDIRECTIONAL);
> + }
> + migrate_vma_finalize(&migrate);
> +unlock:
> + mmap_read_unlock(mm);
> + } while (ret == -EBUSY && !time_after(jiffies, timeout));
> +
> + /* Nothing migrated or mappable in place, fallback to nouveau_range_fault(). */
> + if (!ret && !(pfns[0] & NVIF_VMM_PFNMAP_V0_V))
> + ret = -ENOENT;
[Severity: High]
Why is __nouveau_pfns_map_locked() called before checking whether
pfns[0] & NVIF_VMM_PFNMAP_V0_V is set in nouveau_dmem_migrate_fault() in
drivers/gpu/drm/nouveau/nouveau_dmem.c?
hmm_range_fault(&range) can return 0 while hmm_pfn0 does not have
HMM_PFN_VALID set — for example:
- when faulting on a PMD-mapped THP or PTE-mapped large folio where
folio_trylock() or folio splitting fails in
hmm_vma_handle_migrate_prepare_pmd() or hmm_vma_walk_pmd() in mm/hmm.c
(setting HMM_PFN_ERROR and returning 0),
- when faulting on the huge zero folio in
hmm_vma_handle_migrate_prepare_pmd(), or
- on a read fault to the shared zero page where
hmm_vma_handle_migrate_prepare() sets *hmm_pfn = HMM_PFN_MIGRATE (without
HMM_PFN_VALID) and VRAM allocation in nouveau_dmem_migrate_copy_one() fails.
In those cases, nothing is migrated (pfns[0] is NVIF_VMM_PFNMAP_V0_NONE) and
nouveau_dmem_hmm_pfn_to_map(hmm_pfn0, ...) also returns
NVIF_VMM_PFNMAP_V0_NONE with page_shift = PAGE_SHIFT. Calling
__nouveau_pfns_map_locked() with pfns[0] == NVIF_VMM_PFNMAP_V0_NONE invokes
nvkm_vmm_pfn_map() in drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c with
map == false at 4KB granularity. If the faulting address was already mapped
in the GPU VMM (for instance, mapped read-only prior to a write fault),
nvkm_vmm_pfn_map() splits the GPU VMA and unmaps the 4KB range; and if the
existing GPU VMM mapping was a 2MB page (vma->refd at shift 21 with no 4KB
page table allocated), walking down to shift 12 with ref == false in
nvkm_vmm_iter() leaves it.pt[0] == NULL and dereferences it in
nvkm_vmm_unref_ptes().
Should __nouveau_pfns_map_locked() only be called when
pfns[0] & NVIF_VMM_PFNMAP_V0_V is set?
> +
> + nouveau_pfns_free(pfns);
> +out_free_dma:
> + kfree(dma_info);
> +out_free_dst:
> + kfree(migrate.dst);
> +out_free_src:
> + kfree(migrate.src);
> + return ret;
> +}
[ ... ]
> diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c
> index 58735446d7832..83ea480abcf58 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_svm.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_svm.c
[ ... ]
> @@ -78,6 +79,13 @@ struct nouveau_svm {
> #define SVM_DBG(s,f,a...) NV_DEBUG((s)->drm, "svm: "f"\n", ##a)
> #define SVM_ERR(s,f,a...) NV_WARN((s)->drm, "svm: "f"\n", ##a)
>
> +/* When set, migrate the faulting range to VRAM on GPU fault (default off). */
> +static bool nouveau_svm_migrate_on_fault;
> +module_param_named(svm_migrate_on_fault, nouveau_svm_migrate_on_fault, bool,
> + 0644);
> +MODULE_PARM_DESC(svm_migrate_on_fault,
> + "migrate system memory to VRAM on GPU fault (default off)");
[Severity: Low]
This adds the nouveau.svm_migrate_on_fault module/boot parameter in
drivers/gpu/drm/nouveau/nouveau_svm.c. Should this parameter also be
documented in Documentation/admin-guide/kernel-parameters.txt?
[ ... ]
> @@ -514,6 +523,14 @@ static bool nouveau_svm_range_invalidate(struct mmu_interval_notifier *mni,
> range->owner == sn->svmm->vmm->cli->drm->dev)
> return true;
>
> + /*
> + * Ignore our own migrate-on-fault invalidation; otherwise its
> + * MMU_NOTIFY_MIGRATE bumps the seq and read_retry() spins to timeout.
> + */
> + if (range->event == MMU_NOTIFY_MIGRATE &&
> + range->owner == sn->svmm->vmm->cli->drm->dev)
> + return true;
[Severity: Critical]
Doesn't ignoring all MMU_NOTIFY_MIGRATE events with
range->owner == sn->svmm->vmm->cli->drm->dev in
nouveau_svm_range_invalidate() in drivers/gpu/drm/nouveau/nouveau_svm.c also
ignore concurrent migrations triggered by other paths on the same device,
allowing freed VRAM or system RAM pages to be mapped into the GPU VMM?
drm->dev is also passed as pgmap_owner in nouveau_dmem_migrate_to_ram() (on
CPU page faults migrating device-private VRAM pages back to system RAM) and
in nouveau_dmem_migrate_vma() (on nouveau_svmm_bind() migrating system RAM to
VRAM).
Consider two races:
1. A page is currently in device-private VRAM. The GPU faults on it (either
via nouveau_range_fault() when svm_migrate_on_fault is off or on
FAULT_ACCESS_PREFETCH, or via nouveau_dmem_migrate_fault() which only sets
MIGRATE_VMA_SELECT_SYSTEM so hmm_vma_handle_migrate_prepare() skips the
device-private page without locking or referencing it). HMM records the VRAM
page into range.hmm_pfns[0] / hmm_pfn0. Concurrently under shared
mmap_read_lock(mm), a CPU fault on the same address runs
nouveau_dmem_migrate_to_ram(). Its migrate_vma_setup() emits
MMU_NOTIFY_MIGRATE with owner == drm->dev, which
nouveau_svm_range_invalidate() now ignores without taking svmm->mutex or
calling mmu_interval_set_seq(). nouveau_dmem_migrate_to_ram() invalidates the
GPU VMM under svmm->mutex, copies the page to RAM, and frees the VRAM folio
in migrate_vma_finalize(). The GPU fault worker then takes svmm->mutex, sees
mmu_interval_read_retry() == false because invalidate_seq was never bumped,
and maps the freed VRAM page into the GPU VMM.
2. In nouveau_range_fault(), after hmm_range_fault_unlocked_timeout() reads a
system RAM PFN and drops mmap_read_lock(mm), a concurrent
nouveau_dmem_migrate_vma() or nouveau_dmem_migrate_fault() unmaps the
single-mapped PTE in hmm_vma_handle_migrate_prepare() while emitting only
MMU_NOTIFY_MIGRATE with owner == drm->dev, migrates the page to VRAM, and
frees the system RAM folio. Because nouveau_svm_range_invalidate() ignored
that MMU_NOTIFY_MIGRATE event, nouveau_range_fault() sees
mmu_interval_read_retry() == false and maps the freed system RAM page into
the GPU VMM.
[ ... ]
> @@ -922,21 +965,29 @@ nouveau_pfns_free(u64 *pfns)
> }
>
> void
> -nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm,
> - unsigned long addr, u64 *pfns, unsigned long npages,
> - unsigned int page_shift)
> +__nouveau_pfns_map_locked(struct nouveau_svmm *svmm, unsigned long addr,
> + u64 *pfns, unsigned long npages,
> + unsigned int page_shift)
> {
> struct nouveau_pfnmap_args *args = nouveau_pfns_to_args(pfns);
>
> + lockdep_assert_held(&svmm->mutex);
> +
> args->p.addr = addr;
> args->p.size = npages << page_shift;
> args->p.page = page_shift;
>
> - mutex_lock(&svmm->mutex);
> -
> nvif_object_ioctl(&svmm->vmm->vmm.object, args,
> struct_size(args, p.phys, npages), NULL);
> +}
[Severity: Medium]
Should __nouveau_pfns_map_locked() in drivers/gpu/drm/nouveau/nouveau_svm.c
propagate the return value of nvif_object_ioctl() to
nouveau_dmem_migrate_fault()?
In nouveau_range_fault() and nouveau_atomic_range_fault(), the return value
of nvif_object_ioctl() is returned to nouveau_svm_fault() so that failed
mappings trigger nouveau_svm_fault_cancel_fault().
In contrast, __nouveau_pfns_map_locked() discards the return value of
nvif_object_ioctl(), and nouveau_dmem_migrate_fault() only checks
!(pfns[0] & NVIF_VMM_PFNMAP_V0_V). If nvkm_vmm_pfn_map() in
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c returns early with -EINVAL (for
example, when hmm_pfn_to_map_order() returns an order such as a 1GiB PUD or
64KiB hugetlb page that the GPU VMM page table descriptor does not support)
or -ENOENT (when the address is not in a managed GPU VMA), nvkm_vmm_pfn_map()
returns before the loop that clears NVKM_VMM_PFN_V in pfns[0]. Won't
nouveau_dmem_migrate_fault() then falsely return 0, causing
nouveau_svm_fault() to replay the unhandled GPU fault in an infinite fault
loop instead of cancelling it?
>
> +void
> +nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm,
> + unsigned long addr, u64 *pfns, unsigned long npages,
> + unsigned int page_shift)
> +{
> + mutex_lock(&svmm->mutex);
> + __nouveau_pfns_map_locked(svmm, addr, pfns, npages, page_shift);
> mutex_unlock(&svmm->mutex);
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021060506.2377545-1-mpenttil@redhat.com?part=12
^ permalink raw reply [flat|nested] 33+ messages in thread
* ✗ CI.checkpatch: warning for Migrate on fault for device pages (rev8)
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (11 preceding siblings ...)
2026-10-21 6:05 ` [PATCH v16 12/12] drm/nouveau/svm: add support for migrate on fault mpenttil
@ 2026-10-21 6:50 ` Patchwork
2026-10-21 6:53 ` ✓ CI.KUnit: success " Patchwork
` (3 subsequent siblings)
16 siblings, 0 replies; 33+ messages in thread
From: Patchwork @ 2026-10-21 6:50 UTC (permalink / raw)
To: Mika Penttilä; +Cc: intel-xe
== Series Details ==
Series: Migrate on fault for device pages (rev8)
URL : https://patchwork.freedesktop.org/series/165953/
State : warning
== Summary ==
+ KERNEL=/kernel
+ git clone https://gitlab.freedesktop.org/drm/maintainer-tools mt
Cloning into 'mt'...
warning: redirecting to https://gitlab.freedesktop.org/drm/maintainer-tools.git/
+ git -C mt rev-list -n1 origin/master
6bef5ce5c74dc76b4ee69ab2832c0d1fd63c91c7
+ cd /kernel
+ git config --global --add safe.directory /kernel
+ git log -n1
commit cf6180ecc35752df281a39567fae90ba9269f3da
Author: Mika Penttilä <mpenttil@redhat.com>
Date: Wed Oct 21 09:05:06 2026 +0300
drm/nouveau/svm: add support for migrate on fault
Add a direct user for the new HMM_PFN_REQ_MIGRATE flag and
implement migrate on fault for nouveau driver. It is gated
by the svm_migrate_on_fault module parameter, default off.
Added nouveau_dmem_migrate_fault() that faults a range in and
does migrate collecting in a single hmm_range_fault() walk.
As an optimization, a migration policy - deciding which faulting
ranges are worth migrating to VRAM and which are better left
mirrored in system memory - would be useful. This patch
establishes the migrate-on-fault mechanism as a basis for later
refinement.
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
+ /mt/dim checkpatch f3bbda7128124e54c4881b56958249a18d79a110 drm-intel
f13478ecc5fc mm/Kconfig: changes for migrate on fault for device pages
15404a960e5e mm: add helper to convert HMM pfn to migrate pfn
-:179: CHECK:BRACES: Blank lines aren't necessary before a close brace '}'
#179: FILE: mm/migrate_device.c:1584:
+
+}
total: 0 errors, 0 warnings, 1 checks, 138 lines checked
c887b5b56a44 mm/hmm: preparations for HMM to participate in migration
-:192: CHECK:UNNECESSARY_PARENTHESES: Unnecessary parentheses around 'hmm_vma_walk->vma != walk->vma'
#192: FILE: mm/hmm.c:422:
+ if (hmm_vma_walk->vma && (hmm_vma_walk->vma != walk->vma))
-:215: CHECK:BRACES: Blank lines aren't necessary after an open brace '{'
#215: FILE: mm/hmm.c:445:
+{
+
total: 0 errors, 0 warnings, 2 checks, 262 lines checked
1a03bf49a90a mm/hmm: do the plumbing for HMM to participate in migration
-:47: CHECK:UNCOMMENTED_DEFINITION: spinlock_t definition without comment
#47: FILE: mm/hmm.c:54:
+ spinlock_t *ptl;
-:55: CHECK:MACRO_ARG_PRECEDENCE: Macro argument 'locked' may be better as '(locked)' to avoid precedence issues
#55: FILE: mm/hmm.c:76:
+#define HMM_ASSERT_PTE_LOCKED(hmm_vma_walk, locked) \
+ WARN_ON_ONCE((hmm_vma_walk)->ptelocked != locked)
-:58: CHECK:MACRO_ARG_PRECEDENCE: Macro argument 'locked' may be better as '(locked)' to avoid precedence issues
#58: FILE: mm/hmm.c:79:
+#define HMM_ASSERT_PMD_LOCKED(hmm_vma_walk, locked) \
+ WARN_ON_ONCE((hmm_vma_walk)->pmdlocked != locked)
-:61: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'hmm_vma_walk' - possible side-effects?
#61: FILE: mm/hmm.c:82:
+#define HMM_ASSERT_UNLOCKED(hmm_vma_walk) \
+ WARN_ON_ONCE((hmm_vma_walk)->ptelocked || \
+ (hmm_vma_walk)->pmdlocked)
-:92: CHECK:SPACING: spaces preferred around that '-' (ctx:VxV)
#92: FILE: mm/hmm.c:118:
+ end-addr == HPAGE_PMD_SIZE) {
^
-:216: CHECK:BRACES: braces {} should be used on all arms of this statement
#216: FILE: mm/hmm.c:466:
+ if (softleaf_is_device_private(entry)) {
[...]
else
[...]
-:320: CHECK:BRACES: braces {} should be used on all arms of this statement
#320: FILE: mm/hmm.c:614:
+ if (minfo) {
[...]
+ } else
[...]
-:324: CHECK:BRACES: Unbalanced braces around else statement
#324: FILE: mm/hmm.c:618:
+ } else
total: 0 errors, 0 warnings, 8 checks, 482 lines checked
62069f077190 mm/hmm: migrate collection in HMM pagewalk - pte level
8c37a25bb300 mm/hmm: migrate collection in HMM pagewalk - pmd level
448794534cf2 mm/hmm: add lazy MMU mode support for migration in HMM pagewalk
59a63360adff mm/hmm: implement rollback for device page migration in HMM pagewalk
-:167: CHECK:BRACES: Blank lines aren't necessary before a close brace '}'
#167: FILE: mm/hmm.c:627:
+
+ }
total: 0 errors, 0 warnings, 1 checks, 167 lines checked
90eee00843a8 mm: enable device page migration from HMM pagewalk
741c9c6d33d2 lib/test_hmm: add a new testcase for the migrate on fault
-:246: CHECK:LINE_SPACING: Please don't use multiple blank lines
#246: FILE: lib/test_hmm.c:1515:
+
+
-:321: CHECK:LINE_SPACING: Please don't use multiple blank lines
#321: FILE: tools/testing/selftests/mm/hmm-tests.c:948:
+
total: 0 errors, 0 warnings, 2 checks, 326 lines checked
b9fd3fbebaa1 Documentation/mm/hmm: document migration through hmm_range_fault()
cf6180ecc357 drm/nouveau/svm: add support for migrate on fault
-:132: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#132: FILE: drivers/gpu/drm/nouveau/nouveau_dmem.c:835:
+nouveau_dmem_migrate_alloc_and_copy(struct nouveau_drm *drm,
struct nouveau_svmm *svmm, struct migrate_vma *args,
-:151: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#151: FILE: drivers/gpu/drm/nouveau/nouveau_dmem.c:866:
+static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
+ struct nouveau_svmm *svmm, struct migrate_vma *args,
-:337: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#337: FILE: drivers/gpu/drm/nouveau/nouveau_dmem.c:1057:
+ pfns[0] = nouveau_dmem_hmm_pfn_to_map(hmm_pfn0,
+ start, &map_addr, &page_shift);
total: 0 errors, 0 warnings, 3 checks, 603 lines checked
^ permalink raw reply [flat|nested] 33+ messages in thread* ✓ CI.KUnit: success for Migrate on fault for device pages (rev8)
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (12 preceding siblings ...)
2026-10-21 6:50 ` ✗ CI.checkpatch: warning for Migrate on fault for device pages (rev8) Patchwork
@ 2026-10-21 6:53 ` Patchwork
2026-10-21 7:09 ` ✗ CI.checksparse: warning " Patchwork
` (2 subsequent siblings)
16 siblings, 0 replies; 33+ messages in thread
From: Patchwork @ 2026-10-21 6:53 UTC (permalink / raw)
To: Mika Penttilä; +Cc: intel-xe
== Series Details ==
Series: Migrate on fault for device pages (rev8)
URL : https://patchwork.freedesktop.org/series/165953/
State : success
== Summary ==
+ trap cleanup EXIT
+ kunitconfigs=('/kernel/drivers/gpu/tests/.kunitconfig' '/kernel/drivers/gpu/drm/xe/.kunitconfig' '/kernel/drivers/gpu/drm/tests/.kunitconfig' '/kernel/drivers/gpu/drm/ttm/tests/.kunitconfig' '/kernel/drivers/dma-buf/.kunitconfig')
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/tests/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/tests/.kunitconfig
[06:50:56] Configuring KUnit Kernel ...
Generating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[06:51:01] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[06:51:22] Starting KUnit Kernel (1/1)...
[06:51:22] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[06:51:22] ================= gpu_buddy (14 subtests) ==================
[06:51:22] [PASSED] gpu_test_buddy_alloc_limit
[06:51:22] [PASSED] gpu_test_buddy_alloc_optimistic
[06:51:22] [PASSED] gpu_test_buddy_alloc_pessimistic
[06:51:22] [PASSED] gpu_test_buddy_alloc_pathological
[06:51:22] [PASSED] gpu_test_buddy_alloc_contiguous
[06:51:22] [PASSED] gpu_test_buddy_alloc_clear
[06:51:22] [PASSED] gpu_test_buddy_alloc_range
[06:51:22] [PASSED] gpu_test_buddy_alloc_range_bias
[06:51:23] [PASSED] gpu_test_buddy_fragmentation_performance
[06:51:23] [PASSED] gpu_test_buddy_dirty_tracker_performance
[06:51:23] [PASSED] gpu_test_buddy_alloc_exceeds_max_order
[06:51:23] [PASSED] gpu_test_buddy_offset_aligned_allocation
[06:51:23] [PASSED] gpu_test_buddy_subtree_offset_alignment_stress
[06:51:23] [PASSED] gpu_test_buddy_addr_to_block
[06:51:23] ==================== [PASSED] gpu_buddy ====================
[06:51:23] ============================================================
[06:51:23] Testing complete. Ran 14 tests: passed: 14
[06:51:23] Elapsed time: 27.247s total, 4.447s configuring, 20.933s building, 1.829s running
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/drm/xe/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/xe/.kunitconfig
[06:51:24] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[06:51:25] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[06:52:05] Starting KUnit Kernel (1/1)...
[06:52:05] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[06:52:05] ================== guc_buf (11 subtests) ===================
[06:52:05] [PASSED] test_smallest
[06:52:05] [PASSED] test_largest
[06:52:05] [PASSED] test_granular
[06:52:05] [PASSED] test_unique
[06:52:05] [PASSED] test_overlap
[06:52:05] [PASSED] test_reusable
[06:52:05] [PASSED] test_too_big
[06:52:05] [PASSED] test_flush
[06:52:05] [PASSED] test_lookup
[06:52:05] [PASSED] test_data
[06:52:05] [PASSED] test_class
[06:52:05] ===================== [PASSED] guc_buf =====================
[06:52:05] =================== guc_dbm (7 subtests) ===================
[06:52:05] [PASSED] test_empty
[06:52:05] [PASSED] test_default
[06:52:05] ======================== test_size ========================
[06:52:05] [PASSED] 4
[06:52:05] [PASSED] 8
[06:52:05] [PASSED] 32
[06:52:05] [PASSED] 256
[06:52:05] ==================== [PASSED] test_size ====================
[06:52:05] ======================= test_reuse ========================
[06:52:05] [PASSED] 4
[06:52:05] [PASSED] 8
[06:52:05] [PASSED] 32
[06:52:05] [PASSED] 256
[06:52:05] =================== [PASSED] test_reuse ====================
[06:52:05] =================== test_range_overlap ====================
[06:52:05] [PASSED] 4
[06:52:05] [PASSED] 8
[06:52:05] [PASSED] 32
[06:52:05] [PASSED] 256
[06:52:05] =============== [PASSED] test_range_overlap ================
[06:52:05] =================== test_range_compact ====================
[06:52:05] [PASSED] 4
[06:52:05] [PASSED] 8
[06:52:05] [PASSED] 32
[06:52:05] [PASSED] 256
[06:52:05] =============== [PASSED] test_range_compact ================
[06:52:05] ==================== test_range_spare =====================
[06:52:05] [PASSED] 4
[06:52:05] [PASSED] 8
[06:52:05] [PASSED] 32
[06:52:05] [PASSED] 256
[06:52:05] ================ [PASSED] test_range_spare =================
[06:52:05] ===================== [PASSED] guc_dbm =====================
[06:52:05] ================== guc_idm (22 subtests) ===================
[06:52:05] [PASSED] bad_init
[06:52:05] [PASSED] no_init
[06:52:05] [PASSED] init_fini
[06:52:05] [PASSED] check_init_small
[06:52:05] [PASSED] check_init_shared
[06:52:05] [PASSED] check_used
[06:52:05] [PASSED] check_quota
[06:52:05] [PASSED] check_all
[06:52:05] [PASSED] check_limits
[06:52:05] [PASSED] check_overlap
[06:52:05] [PASSED] check_overlap_alloc
[06:52:05] [PASSED] check_overlap_release
[06:52:05] [PASSED] check_overlap_partial_init
[06:52:05] [PASSED] check_overlap_partial_shared_range_blocking
[06:52:05] [PASSED] check_used_usable
[06:52:05] [PASSED] check_used_shareable
[06:52:05] [PASSED] check_used_mixed
[06:52:05] [PASSED] check_release_usable_range
[06:52:05] [PASSED] check_release_shareable_range
[06:52:05] [PASSED] check_split_boundaries
[06:52:05] [PASSED] check_shareable_spare
[06:52:05] [PASSED] check_shareable_spare_fragmented_tail
[06:52:05] ===================== [PASSED] guc_idm =====================
[06:52:05] ============== guc_klv_helpers (13 subtests) ===============
[06:52:05] [PASSED] test_count
[06:52:05] [PASSED] test_encode_u32
[06:52:05] [PASSED] test_encode_u64
[06:52:05] [PASSED] test_encode_string
[06:52:05] [PASSED] test_encode_object_raw
[06:52:05] [PASSED] test_encode_object_klv
[06:52:05] [PASSED] test_encode_object_nested
[06:52:05] [PASSED] test_encode_object_basic
[06:52:05] ===================== test_decode_u16 =====================
[06:52:05] [PASSED] empty
[06:52:05] [PASSED] valid
[06:52:05] [PASSED] max
[06:52:05] [PASSED] big
[06:52:05] [PASSED] long
[06:52:05] ================= [PASSED] test_decode_u16 =================
[06:52:05] ===================== test_decode_u32 =====================
[06:52:05] [PASSED] empty
[06:52:05] [PASSED] valid
[06:52:05] [PASSED] max
[06:52:05] [PASSED] long
[06:52:05] ================= [PASSED] test_decode_u32 =================
[06:52:05] ===================== test_decode_u64 =====================
[06:52:05] [PASSED] empty
[06:52:05] [PASSED] short
[06:52:05] [PASSED] valid
[06:52:05] [PASSED] max
[06:52:05] [PASSED] long
[06:52:05] ================= [PASSED] test_decode_u64 =================
[06:52:05] ===================== test_decode_str =====================
[06:52:05] [PASSED] empty
[06:52:05] [PASSED] one
[06:52:05] [PASSED] one_trash
[06:52:05] [PASSED] two
[06:52:05] [PASSED] two_trash
[06:52:05] [PASSED] three
[06:52:05] [PASSED] dword
[06:52:05] [PASSED] four
[06:52:05] [PASSED] five
[06:52:05] [PASSED] six
[06:52:05] [PASSED] seven
[06:52:05] [PASSED] qword
[06:52:05] ================= [PASSED] test_decode_str =================
[06:52:05] [PASSED] test_print
[06:52:05] ================= [PASSED] guc_klv_helpers =================
[06:52:05] =================== xe_log (4 subtests) ====================
[06:52:05] [PASSED] demo_cper
[06:52:05] [PASSED] demo_dmesg
[06:52:05] ======================= test_dmesg ========================
[06:52:05] [PASSED] test_fatal
[06:52:05] [PASSED] test_fatal_tile
[06:52:05] [PASSED] test_fatal_gt
[06:52:05] [PASSED] test_fatal_comp
[06:52:05] [PASSED] test_fatal_comp_tile
[06:52:05] [PASSED] test_fatal_comp_gt
[06:52:05] [PASSED] test_fatal_all
[06:52:05] [PASSED] test_recoverable
[06:52:05] [PASSED] test_recoverable_tile
[06:52:05] [PASSED] test_recoverable_gt
[06:52:05] [PASSED] test_recoverable_comp
[06:52:05] [PASSED] test_recoverable_comp_tile
[06:52:05] [PASSED] test_recoverable_comp_gt
[06:52:05] [PASSED] test_recoverable_all
[06:52:05] [PASSED] test_info
[06:52:05] [PASSED] test_info_tile
[06:52:05] [PASSED] test_info_gt
[06:52:05] [PASSED] test_info_err
[06:52:05] [PASSED] test_info_comp
[06:52:05] [PASSED] test_info_comp_tile
[06:52:05] [PASSED] test_info_comp_gt
[06:52:05] [PASSED] test_info_all
[06:52:05] [PASSED] test_hw_fatal
[06:52:05] [PASSED] test_hw_recoverable
[06:52:05] [PASSED] test_hw_corrected
[06:52:05] [PASSED] test_hw_informational
[06:52:05] =================== [PASSED] test_dmesg ====================
[06:52:05] ====================== test_invalid =======================
[06:52:05] [SKIPPED] no-component no-location no-warn (requires CONFIG_DRM_XE_DEBUG)
[06:52:05] [SKIPPED] reserved location (requires CONFIG_DRM_XE_DEBUG)
[06:52:05] [SKIPPED] unknown location (requires CONFIG_DRM_XE_DEBUG)
[06:52:05] [SKIPPED] nonzero-device-id location (requires CONFIG_DRM_XE_DEBUG)
[06:52:05] [SKIPPED] invalid-tile-id location (requires CONFIG_DRM_XE_DEBUG)
[06:52:05] [SKIPPED] invalid-gt-id location (requires CONFIG_DRM_XE_DEBUG)
[06:52:05] [SKIPPED] unknown component class (requires CONFIG_DRM_XE_DEBUG)
[06:52:05] [SKIPPED] unknown system component (requires CONFIG_DRM_XE_DEBUG)
[06:52:05] [SKIPPED] unknown hardware component (requires CONFIG_DRM_XE_DEBUG)
[06:52:05] [SKIPPED] unknown component and location (requires CONFIG_DRM_XE_DEBUG)
[06:52:05] ================== [SKIPPED] test_invalid ==================
[06:52:05] ===================== [PASSED] xe_log ======================
[06:52:05] ================== no_relay (3 subtests) ===================
[06:52:05] [PASSED] xe_drops_guc2pf_if_not_ready
[06:52:05] [PASSED] xe_drops_guc2vf_if_not_ready
[06:52:05] [PASSED] xe_rejects_send_if_not_ready
[06:52:05] ==================== [PASSED] no_relay =====================
[06:52:05] ================== pf_relay (14 subtests) ==================
[06:52:05] [PASSED] pf_rejects_guc2pf_too_short
[06:52:05] [PASSED] pf_rejects_guc2pf_too_long
[06:52:05] [PASSED] pf_rejects_guc2pf_no_payload
[06:52:05] [PASSED] pf_fails_no_payload
[06:52:05] [PASSED] pf_fails_bad_origin
[06:52:05] [PASSED] pf_fails_bad_type
[06:52:05] [PASSED] pf_txn_reports_error
[06:52:05] [PASSED] pf_txn_sends_pf2guc
[06:52:05] [PASSED] pf_sends_pf2guc
[06:52:05] [SKIPPED] pf_loopback_nop (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[06:52:05] [SKIPPED] pf_loopback_echo (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[06:52:05] [SKIPPED] pf_loopback_fail (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[06:52:05] [SKIPPED] pf_loopback_busy (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[06:52:05] [SKIPPED] pf_loopback_retry (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[06:52:05] ==================== [PASSED] pf_relay =====================
[06:52:05] ================== vf_relay (3 subtests) ===================
[06:52:05] [PASSED] vf_rejects_guc2vf_too_short
[06:52:05] [PASSED] vf_rejects_guc2vf_too_long
[06:52:05] [PASSED] vf_rejects_guc2vf_no_payload
[06:52:05] ==================== [PASSED] vf_relay =====================
[06:52:05] ================ pf_gt_config (9 subtests) =================
[06:52:05] [PASSED] fair_contexts_1vf
[06:52:05] [PASSED] fair_doorbells_1vf
[06:52:05] [PASSED] fair_ggtt_1vf
[06:52:05] ====================== fair_vram_1vf ======================
[06:52:05] [PASSED] 3.50 GiB
[06:52:05] [PASSED] 11.5 GiB
[06:52:05] [PASSED] 15.5 GiB
[06:52:05] [PASSED] 31.5 GiB
[06:52:05] [PASSED] 63.5 GiB
[06:52:05] [PASSED] 1.91 GiB
[06:52:05] ================== [PASSED] fair_vram_1vf ==================
[06:52:05] ================ fair_vram_1vf_admin_only =================
[06:52:05] [PASSED] 3.50 GiB
[06:52:05] [PASSED] 11.5 GiB
[06:52:05] [PASSED] 15.5 GiB
[06:52:05] [PASSED] 31.5 GiB
[06:52:05] [PASSED] 63.5 GiB
[06:52:05] [PASSED] 1.91 GiB
[06:52:05] ============ [PASSED] fair_vram_1vf_admin_only =============
[06:52:05] ====================== fair_contexts ======================
[06:52:05] [PASSED] 1 VF
[06:52:05] [PASSED] 2 VFs
[06:52:05] [PASSED] 3 VFs
[06:52:05] [PASSED] 4 VFs
[06:52:05] [PASSED] 5 VFs
[06:52:05] [PASSED] 6 VFs
[06:52:05] [PASSED] 7 VFs
[06:52:05] [PASSED] 8 VFs
[06:52:05] [PASSED] 9 VFs
[06:52:05] [PASSED] 10 VFs
[06:52:05] [PASSED] 11 VFs
[06:52:05] [PASSED] 12 VFs
[06:52:05] [PASSED] 13 VFs
[06:52:05] [PASSED] 14 VFs
[06:52:05] [PASSED] 15 VFs
[06:52:05] [PASSED] 16 VFs
[06:52:05] [PASSED] 17 VFs
[06:52:05] [PASSED] 18 VFs
[06:52:05] [PASSED] 19 VFs
[06:52:05] [PASSED] 20 VFs
[06:52:05] [PASSED] 21 VFs
[06:52:05] [PASSED] 22 VFs
[06:52:05] [PASSED] 23 VFs
[06:52:05] [PASSED] 24 VFs
[06:52:05] [PASSED] 25 VFs
[06:52:05] [PASSED] 26 VFs
[06:52:05] [PASSED] 27 VFs
[06:52:05] [PASSED] 28 VFs
[06:52:05] [PASSED] 29 VFs
[06:52:05] [PASSED] 30 VFs
[06:52:05] [PASSED] 31 VFs
[06:52:05] [PASSED] 32 VFs
[06:52:05] [PASSED] 33 VFs
[06:52:05] [PASSED] 34 VFs
[06:52:05] [PASSED] 35 VFs
[06:52:05] [PASSED] 36 VFs
[06:52:05] [PASSED] 37 VFs
[06:52:05] [PASSED] 38 VFs
[06:52:05] [PASSED] 39 VFs
[06:52:05] [PASSED] 40 VFs
[06:52:05] [PASSED] 41 VFs
[06:52:05] [PASSED] 42 VFs
[06:52:05] [PASSED] 43 VFs
[06:52:05] [PASSED] 44 VFs
[06:52:05] [PASSED] 45 VFs
[06:52:05] [PASSED] 46 VFs
[06:52:05] [PASSED] 47 VFs
[06:52:05] [PASSED] 48 VFs
[06:52:05] [PASSED] 49 VFs
[06:52:05] [PASSED] 50 VFs
[06:52:05] [PASSED] 51 VFs
[06:52:05] [PASSED] 52 VFs
[06:52:05] [PASSED] 53 VFs
[06:52:05] [PASSED] 54 VFs
[06:52:05] [PASSED] 55 VFs
[06:52:05] [PASSED] 56 VFs
[06:52:05] [PASSED] 57 VFs
[06:52:05] [PASSED] 58 VFs
[06:52:05] [PASSED] 59 VFs
[06:52:05] [PASSED] 60 VFs
[06:52:05] [PASSED] 61 VFs
[06:52:05] [PASSED] 62 VFs
[06:52:05] [PASSED] 63 VFs
[06:52:05] ================== [PASSED] fair_contexts ==================
[06:52:05] ===================== fair_doorbells ======================
[06:52:05] [PASSED] 1 VF
[06:52:05] [PASSED] 2 VFs
[06:52:05] [PASSED] 3 VFs
[06:52:05] [PASSED] 4 VFs
[06:52:05] [PASSED] 5 VFs
[06:52:05] [PASSED] 6 VFs
[06:52:05] [PASSED] 7 VFs
[06:52:05] [PASSED] 8 VFs
[06:52:05] [PASSED] 9 VFs
[06:52:05] [PASSED] 10 VFs
[06:52:05] [PASSED] 11 VFs
[06:52:05] [PASSED] 12 VFs
[06:52:05] [PASSED] 13 VFs
[06:52:05] [PASSED] 14 VFs
[06:52:05] [PASSED] 15 VFs
[06:52:05] [PASSED] 16 VFs
[06:52:05] [PASSED] 17 VFs
[06:52:05] [PASSED] 18 VFs
[06:52:05] [PASSED] 19 VFs
[06:52:05] [PASSED] 20 VFs
[06:52:05] [PASSED] 21 VFs
[06:52:05] [PASSED] 22 VFs
[06:52:05] [PASSED] 23 VFs
[06:52:05] [PASSED] 24 VFs
[06:52:05] [PASSED] 25 VFs
[06:52:05] [PASSED] 26 VFs
[06:52:05] [PASSED] 27 VFs
[06:52:05] [PASSED] 28 VFs
[06:52:05] [PASSED] 29 VFs
[06:52:05] [PASSED] 30 VFs
[06:52:05] [PASSED] 31 VFs
[06:52:05] [PASSED] 32 VFs
[06:52:05] [PASSED] 33 VFs
[06:52:05] [PASSED] 34 VFs
[06:52:05] [PASSED] 35 VFs
[06:52:05] [PASSED] 36 VFs
[06:52:05] [PASSED] 37 VFs
[06:52:05] [PASSED] 38 VFs
[06:52:05] [PASSED] 39 VFs
[06:52:05] [PASSED] 40 VFs
[06:52:05] [PASSED] 41 VFs
[06:52:05] [PASSED] 42 VFs
[06:52:05] [PASSED] 43 VFs
[06:52:05] [PASSED] 44 VFs
[06:52:05] [PASSED] 45 VFs
[06:52:05] [PASSED] 46 VFs
[06:52:05] [PASSED] 47 VFs
[06:52:05] [PASSED] 48 VFs
[06:52:05] [PASSED] 49 VFs
[06:52:05] [PASSED] 50 VFs
[06:52:05] [PASSED] 51 VFs
[06:52:05] [PASSED] 52 VFs
[06:52:05] [PASSED] 53 VFs
[06:52:05] [PASSED] 54 VFs
[06:52:05] [PASSED] 55 VFs
[06:52:05] [PASSED] 56 VFs
[06:52:05] [PASSED] 57 VFs
[06:52:05] [PASSED] 58 VFs
[06:52:05] [PASSED] 59 VFs
[06:52:05] [PASSED] 60 VFs
[06:52:05] [PASSED] 61 VFs
[06:52:05] [PASSED] 62 VFs
[06:52:05] [PASSED] 63 VFs
[06:52:05] ================= [PASSED] fair_doorbells ==================
[06:52:05] ======================== fair_ggtt ========================
[06:52:05] [PASSED] 1 VF
[06:52:05] [PASSED] 2 VFs
[06:52:05] [PASSED] 3 VFs
[06:52:05] [PASSED] 4 VFs
[06:52:05] [PASSED] 5 VFs
[06:52:05] [PASSED] 6 VFs
[06:52:05] [PASSED] 7 VFs
[06:52:05] [PASSED] 8 VFs
[06:52:05] [PASSED] 9 VFs
[06:52:05] [PASSED] 10 VFs
[06:52:05] [PASSED] 11 VFs
[06:52:05] [PASSED] 12 VFs
[06:52:05] [PASSED] 13 VFs
[06:52:05] [PASSED] 14 VFs
[06:52:05] [PASSED] 15 VFs
[06:52:05] [PASSED] 16 VFs
[06:52:05] [PASSED] 17 VFs
[06:52:05] [PASSED] 18 VFs
[06:52:05] [PASSED] 19 VFs
[06:52:05] [PASSED] 20 VFs
[06:52:05] [PASSED] 21 VFs
[06:52:05] [PASSED] 22 VFs
[06:52:05] [PASSED] 23 VFs
[06:52:05] [PASSED] 24 VFs
[06:52:05] [PASSED] 25 VFs
[06:52:05] [PASSED] 26 VFs
[06:52:05] [PASSED] 27 VFs
[06:52:05] [PASSED] 28 VFs
[06:52:05] [PASSED] 29 VFs
[06:52:05] [PASSED] 30 VFs
[06:52:05] [PASSED] 31 VFs
[06:52:05] [PASSED] 32 VFs
[06:52:05] [PASSED] 33 VFs
[06:52:05] [PASSED] 34 VFs
[06:52:05] [PASSED] 35 VFs
[06:52:05] [PASSED] 36 VFs
[06:52:05] [PASSED] 37 VFs
[06:52:05] [PASSED] 38 VFs
[06:52:05] [PASSED] 39 VFs
[06:52:05] [PASSED] 40 VFs
[06:52:05] [PASSED] 41 VFs
[06:52:05] [PASSED] 42 VFs
[06:52:05] [PASSED] 43 VFs
[06:52:05] [PASSED] 44 VFs
[06:52:05] [PASSED] 45 VFs
[06:52:05] [PASSED] 46 VFs
[06:52:05] [PASSED] 47 VFs
[06:52:05] [PASSED] 48 VFs
[06:52:05] [PASSED] 49 VFs
[06:52:05] [PASSED] 50 VFs
[06:52:05] [PASSED] 51 VFs
[06:52:05] [PASSED] 52 VFs
[06:52:05] [PASSED] 53 VFs
[06:52:05] [PASSED] 54 VFs
[06:52:05] [PASSED] 55 VFs
[06:52:05] [PASSED] 56 VFs
[06:52:05] [PASSED] 57 VFs
[06:52:05] [PASSED] 58 VFs
[06:52:05] [PASSED] 59 VFs
[06:52:05] [PASSED] 60 VFs
[06:52:05] [PASSED] 61 VFs
[06:52:05] [PASSED] 62 VFs
[06:52:05] [PASSED] 63 VFs
[06:52:05] ==================== [PASSED] fair_ggtt ====================
[06:52:05] ======================== fair_vram ========================
[06:52:05] [PASSED] 1 VF
[06:52:05] [PASSED] 2 VFs
[06:52:05] [PASSED] 3 VFs
[06:52:05] [PASSED] 4 VFs
[06:52:05] [PASSED] 5 VFs
[06:52:05] [PASSED] 6 VFs
[06:52:05] [PASSED] 7 VFs
[06:52:05] [PASSED] 8 VFs
[06:52:05] [PASSED] 9 VFs
[06:52:05] [PASSED] 10 VFs
[06:52:05] [PASSED] 11 VFs
[06:52:05] [PASSED] 12 VFs
[06:52:05] [PASSED] 13 VFs
[06:52:05] [PASSED] 14 VFs
[06:52:05] [PASSED] 15 VFs
[06:52:05] [PASSED] 16 VFs
[06:52:05] [PASSED] 17 VFs
[06:52:05] [PASSED] 18 VFs
[06:52:05] [PASSED] 19 VFs
[06:52:05] [PASSED] 20 VFs
[06:52:05] [PASSED] 21 VFs
[06:52:05] [PASSED] 22 VFs
[06:52:05] [PASSED] 23 VFs
[06:52:05] [PASSED] 24 VFs
[06:52:05] [PASSED] 25 VFs
[06:52:05] [PASSED] 26 VFs
[06:52:05] [PASSED] 27 VFs
[06:52:05] [PASSED] 28 VFs
[06:52:05] [PASSED] 29 VFs
[06:52:05] [PASSED] 30 VFs
[06:52:05] [PASSED] 31 VFs
[06:52:05] [PASSED] 32 VFs
[06:52:05] [PASSED] 33 VFs
[06:52:05] [PASSED] 34 VFs
[06:52:05] [PASSED] 35 VFs
[06:52:05] [PASSED] 36 VFs
[06:52:05] [PASSED] 37 VFs
[06:52:05] [PASSED] 38 VFs
[06:52:05] [PASSED] 39 VFs
[06:52:05] [PASSED] 40 VFs
[06:52:05] [PASSED] 41 VFs
[06:52:05] [PASSED] 42 VFs
[06:52:05] [PASSED] 43 VFs
[06:52:05] [PASSED] 44 VFs
[06:52:05] [PASSED] 45 VFs
[06:52:05] [PASSED] 46 VFs
[06:52:05] [PASSED] 47 VFs
[06:52:05] [PASSED] 48 VFs
[06:52:05] [PASSED] 49 VFs
[06:52:05] [PASSED] 50 VFs
[06:52:05] [PASSED] 51 VFs
[06:52:05] [PASSED] 52 VFs
[06:52:05] [PASSED] 53 VFs
[06:52:05] [PASSED] 54 VFs
[06:52:05] [PASSED] 55 VFs
[06:52:05] [PASSED] 56 VFs
[06:52:05] [PASSED] 57 VFs
[06:52:05] [PASSED] 58 VFs
[06:52:05] [PASSED] 59 VFs
[06:52:05] [PASSED] 60 VFs
[06:52:05] [PASSED] 61 VFs
[06:52:05] [PASSED] 62 VFs
[06:52:05] [PASSED] 63 VFs
[06:52:05] ==================== [PASSED] fair_vram ====================
[06:52:05] ================== [PASSED] pf_gt_config ===================
[06:52:05] ===================== lmtt (1 subtest) =====================
[06:52:05] ======================== test_ops =========================
[06:52:05] [PASSED] 2-level
[06:52:05] [PASSED] multi-level
[06:52:05] ==================== [PASSED] test_ops =====================
[06:52:05] ====================== [PASSED] lmtt =======================
[06:52:05] ================= sriov_packet (1 subtest) =================
[06:52:05] [PASSED] test_descriptor_init
[06:52:05] ================== [PASSED] sriov_packet ===================
[06:52:05] ================= pf_service (11 subtests) =================
[06:52:05] [PASSED] pf_negotiate_any
[06:52:05] [PASSED] pf_negotiate_base_match
[06:52:05] [PASSED] pf_negotiate_base_newer
[06:52:05] [PASSED] pf_negotiate_base_next
[06:52:05] [SKIPPED] pf_negotiate_base_older (no older minor)
[06:52:05] [PASSED] pf_negotiate_base_prev
[06:52:05] [PASSED] pf_negotiate_latest_match
[06:52:05] [PASSED] pf_negotiate_latest_newer
[06:52:05] [PASSED] pf_negotiate_latest_next
[06:52:05] [SKIPPED] pf_negotiate_latest_older (no older minor)
[06:52:05] [SKIPPED] pf_negotiate_latest_prev (no prev major)
[06:52:05] =================== [PASSED] pf_service ====================
[06:52:05] ================= xe_guc_g2g (2 subtests) ==================
[06:52:05] ============== xe_live_guc_g2g_kunit_default ==============
[06:52:05] ========= [SKIPPED] xe_live_guc_g2g_kunit_default ==========
[06:52:05] ============== xe_live_guc_g2g_kunit_allmem ===============
[06:52:05] ========== [SKIPPED] xe_live_guc_g2g_kunit_allmem ==========
[06:52:05] =================== [SKIPPED] xe_guc_g2g ===================
[06:52:05] =================== xe_mocs (2 subtests) ===================
[06:52:05] ================ xe_live_mocs_kernel_kunit ================
[06:52:05] =========== [SKIPPED] xe_live_mocs_kernel_kunit ============
[06:52:05] ================ xe_live_mocs_reset_kunit =================
[06:52:05] ============ [SKIPPED] xe_live_mocs_reset_kunit ============
[06:52:05] ==================== [SKIPPED] xe_mocs =====================
[06:52:05] ================= xe_migrate (2 subtests) ==================
[06:52:05] ================= xe_migrate_sanity_kunit =================
[06:52:05] ============ [SKIPPED] xe_migrate_sanity_kunit =============
[06:52:05] ================== xe_validate_ccs_kunit ==================
[06:52:05] ============= [SKIPPED] xe_validate_ccs_kunit ==============
[06:52:05] =================== [SKIPPED] xe_migrate ===================
[06:52:05] ================== xe_dma_buf (1 subtest) ==================
[06:52:05] ==================== xe_dma_buf_kunit =====================
[06:52:05] ================ [SKIPPED] xe_dma_buf_kunit ================
[06:52:05] =================== [SKIPPED] xe_dma_buf ===================
[06:52:05] ================= xe_bo_shrink (1 subtest) =================
[06:52:05] =================== xe_bo_shrink_kunit ====================
[06:52:05] =============== [SKIPPED] xe_bo_shrink_kunit ===============
[06:52:05] ================== [SKIPPED] xe_bo_shrink ==================
[06:52:05] ==================== xe_bo (2 subtests) ====================
[06:52:05] ================== xe_ccs_migrate_kunit ===================
[06:52:05] ============== [SKIPPED] xe_ccs_migrate_kunit ==============
[06:52:05] ==================== xe_bo_evict_kunit ====================
[06:52:05] =============== [SKIPPED] xe_bo_evict_kunit ================
[06:52:05] ===================== [SKIPPED] xe_bo ======================
[06:52:05] =================== xe_any (9 subtests) ====================
[06:52:05] [PASSED] test_to_xe
[06:52:05] [PASSED] test_to_dev
[06:52:05] [PASSED] test_to_pdev
[06:52:05] [PASSED] test_to_drm
[06:52:05] [PASSED] test_if_pdev
[06:52:05] [PASSED] test_if_xe
[06:52:05] [PASSED] test_if_tile
[06:52:05] [PASSED] test_if_gt
[06:52:05] [PASSED] test_to_id
[06:52:05] ===================== [PASSED] xe_any ======================
[06:52:05] ==================== args (13 subtests) ====================
[06:52:05] [PASSED] count_args_test
[06:52:05] [PASSED] call_args_example
[06:52:05] [PASSED] call_args_test
[06:52:05] [PASSED] drop_first_arg_example
[06:52:05] [PASSED] drop_first_arg_test
[06:52:05] [PASSED] first_arg_example
[06:52:05] [PASSED] first_arg_test
[06:52:05] [PASSED] last_arg_example
[06:52:05] [PASSED] last_arg_test
[06:52:05] [PASSED] pick_arg_example
[06:52:05] [PASSED] if_args_example
[06:52:05] [PASSED] if_args_test
[06:52:05] [PASSED] sep_comma_example
[06:52:05] ====================== [PASSED] args =======================
[06:52:05] =================== xe_pci (3 subtests) ====================
[06:52:05] ==================== check_graphics_ip ====================
[06:52:05] [PASSED] 12.00 Xe_LP
[06:52:05] [PASSED] 12.10 Xe_LP+
[06:52:05] [PASSED] 12.55 Xe_HPG
[06:52:05] [PASSED] 12.60 Xe_HPC
[06:52:05] [PASSED] 12.70 Xe_LPG
[06:52:05] [PASSED] 12.71 Xe_LPG
[06:52:05] [PASSED] 12.74 Xe_LPG+
[06:52:05] [PASSED] 20.01 Xe2_HPG
[06:52:05] [PASSED] 20.02 Xe2_HPG
[06:52:05] [PASSED] 20.04 Xe2_LPG
[06:52:05] [PASSED] 30.00 Xe3_LPG
[06:52:05] [PASSED] 30.01 Xe3_LPG
[06:52:05] [PASSED] 30.03 Xe3_LPG
[06:52:05] [PASSED] 30.04 Xe3_LPG
[06:52:05] [PASSED] 30.05 Xe3_LPG
[06:52:05] [PASSED] 35.10 Xe3p_LPG
[06:52:05] [PASSED] 35.11 Xe3p_XPC
[06:52:05] ================ [PASSED] check_graphics_ip ================
[06:52:05] ===================== check_media_ip ======================
[06:52:05] [PASSED] 12.00 Xe_M
[06:52:05] [PASSED] 12.55 Xe_HPM
[06:52:05] [PASSED] 13.00 Xe_LPM+
[06:52:05] [PASSED] 13.01 Xe2_HPM
[06:52:05] [PASSED] 20.00 Xe2_LPM
[06:52:05] [PASSED] 30.00 Xe3_LPM
[06:52:05] [PASSED] 30.02 Xe3_LPM
[06:52:05] [PASSED] 35.00 Xe3p_LPM
[06:52:05] [PASSED] 35.03 Xe3p_HPM
[06:52:05] ================= [PASSED] check_media_ip ==================
[06:52:05] =================== check_platform_desc ===================
[06:52:05] [PASSED] 0x9A60 (TIGERLAKE)
[06:52:05] [PASSED] 0x9A68 (TIGERLAKE)
[06:52:05] [PASSED] 0x9A70 (TIGERLAKE)
[06:52:05] [PASSED] 0x9A40 (TIGERLAKE)
[06:52:05] [PASSED] 0x9A49 (TIGERLAKE)
[06:52:05] [PASSED] 0x9A59 (TIGERLAKE)
[06:52:05] [PASSED] 0x9A78 (TIGERLAKE)
[06:52:05] [PASSED] 0x9AC0 (TIGERLAKE)
[06:52:05] [PASSED] 0x9AC9 (TIGERLAKE)
[06:52:05] [PASSED] 0x9AD9 (TIGERLAKE)
[06:52:05] [PASSED] 0x9AF8 (TIGERLAKE)
[06:52:05] [PASSED] 0x4C80 (ROCKETLAKE)
[06:52:05] [PASSED] 0x4C8A (ROCKETLAKE)
[06:52:05] [PASSED] 0x4C8B (ROCKETLAKE)
[06:52:05] [PASSED] 0x4C8C (ROCKETLAKE)
[06:52:05] [PASSED] 0x4C90 (ROCKETLAKE)
[06:52:05] [PASSED] 0x4C9A (ROCKETLAKE)
[06:52:05] [PASSED] 0x4680 (ALDERLAKE_S)
[06:52:05] [PASSED] 0x4682 (ALDERLAKE_S)
[06:52:05] [PASSED] 0x4688 (ALDERLAKE_S)
[06:52:05] [PASSED] 0x468A (ALDERLAKE_S)
[06:52:05] [PASSED] 0x468B (ALDERLAKE_S)
[06:52:05] [PASSED] 0x4690 (ALDERLAKE_S)
[06:52:05] [PASSED] 0x4692 (ALDERLAKE_S)
[06:52:05] [PASSED] 0x4693 (ALDERLAKE_S)
[06:52:05] [PASSED] 0x46A0 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46A1 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46A2 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46A3 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46A6 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46A8 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46AA (ALDERLAKE_P)
[06:52:05] [PASSED] 0x462A (ALDERLAKE_P)
[06:52:05] [PASSED] 0x4626 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x4628 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46B0 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46B1 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46B2 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46B3 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46C0 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46C1 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46C2 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46C3 (ALDERLAKE_P)
[06:52:05] [PASSED] 0x46D0 (ALDERLAKE_N)
[06:52:05] [PASSED] 0x46D1 (ALDERLAKE_N)
[06:52:05] [PASSED] 0x46D2 (ALDERLAKE_N)
[06:52:05] [PASSED] 0x46D3 (ALDERLAKE_N)
[06:52:05] [PASSED] 0x46D4 (ALDERLAKE_N)
[06:52:05] [PASSED] 0xA721 (ALDERLAKE_P)
[06:52:05] [PASSED] 0xA7A1 (ALDERLAKE_P)
[06:52:05] [PASSED] 0xA7A9 (ALDERLAKE_P)
[06:52:05] [PASSED] 0xA7AC (ALDERLAKE_P)
[06:52:05] [PASSED] 0xA7AD (ALDERLAKE_P)
[06:52:05] [PASSED] 0xA720 (ALDERLAKE_P)
[06:52:05] [PASSED] 0xA7A0 (ALDERLAKE_P)
[06:52:05] [PASSED] 0xA7A8 (ALDERLAKE_P)
[06:52:05] [PASSED] 0xA7AA (ALDERLAKE_P)
[06:52:05] [PASSED] 0xA7AB (ALDERLAKE_P)
[06:52:05] [PASSED] 0xA780 (ALDERLAKE_S)
[06:52:05] [PASSED] 0xA781 (ALDERLAKE_S)
[06:52:05] [PASSED] 0xA782 (ALDERLAKE_S)
[06:52:05] [PASSED] 0xA783 (ALDERLAKE_S)
[06:52:05] [PASSED] 0xA788 (ALDERLAKE_S)
[06:52:05] [PASSED] 0xA789 (ALDERLAKE_S)
[06:52:05] [PASSED] 0xA78A (ALDERLAKE_S)
[06:52:05] [PASSED] 0xA78B (ALDERLAKE_S)
[06:52:05] [PASSED] 0x4905 (DG1)
[06:52:05] [PASSED] 0x4906 (DG1)
[06:52:05] [PASSED] 0x4907 (DG1)
[06:52:05] [PASSED] 0x4908 (DG1)
[06:52:05] [PASSED] 0x4909 (DG1)
[06:52:05] [PASSED] 0x56C0 (DG2)
[06:52:05] [PASSED] 0x56C2 (DG2)
[06:52:05] [PASSED] 0x56C1 (DG2)
[06:52:05] [PASSED] 0x7D51 (METEORLAKE)
[06:52:05] [PASSED] 0x7DD1 (METEORLAKE)
[06:52:05] [PASSED] 0x7D41 (METEORLAKE)
[06:52:05] [PASSED] 0x7D67 (METEORLAKE)
[06:52:05] [PASSED] 0xB640 (METEORLAKE)
[06:52:05] [PASSED] 0x56A0 (DG2)
[06:52:05] [PASSED] 0x56A1 (DG2)
[06:52:05] [PASSED] 0x56A2 (DG2)
[06:52:05] [PASSED] 0x56BE (DG2)
[06:52:05] [PASSED] 0x56BF (DG2)
[06:52:05] [PASSED] 0x5690 (DG2)
[06:52:05] [PASSED] 0x5691 (DG2)
[06:52:05] [PASSED] 0x5692 (DG2)
[06:52:05] [PASSED] 0x56A5 (DG2)
[06:52:05] [PASSED] 0x56A6 (DG2)
[06:52:05] [PASSED] 0x56B0 (DG2)
[06:52:05] [PASSED] 0x56B1 (DG2)
[06:52:05] [PASSED] 0x56BA (DG2)
[06:52:05] [PASSED] 0x56BB (DG2)
[06:52:05] [PASSED] 0x56BC (DG2)
[06:52:05] [PASSED] 0x56BD (DG2)
[06:52:05] [PASSED] 0x5693 (DG2)
[06:52:05] [PASSED] 0x5694 (DG2)
[06:52:05] [PASSED] 0x5695 (DG2)
[06:52:05] [PASSED] 0x56A3 (DG2)
[06:52:05] [PASSED] 0x56A4 (DG2)
[06:52:05] [PASSED] 0x56B2 (DG2)
[06:52:05] [PASSED] 0x56B3 (DG2)
[06:52:05] [PASSED] 0x5696 (DG2)
[06:52:05] [PASSED] 0x5697 (DG2)
[06:52:05] [PASSED] 0xB69 (PVC)
[06:52:05] [PASSED] 0xB6E (PVC)
[06:52:05] [PASSED] 0xBD4 (PVC)
[06:52:05] [PASSED] 0xBD5 (PVC)
[06:52:05] [PASSED] 0xBD6 (PVC)
[06:52:05] [PASSED] 0xBD7 (PVC)
[06:52:05] [PASSED] 0xBD8 (PVC)
[06:52:05] [PASSED] 0xBD9 (PVC)
[06:52:05] [PASSED] 0xBDA (PVC)
[06:52:05] [PASSED] 0xBDB (PVC)
[06:52:05] [PASSED] 0xBE0 (PVC)
[06:52:05] [PASSED] 0xBE1 (PVC)
[06:52:05] [PASSED] 0xBE5 (PVC)
[06:52:05] [PASSED] 0x7D40 (METEORLAKE)
[06:52:05] [PASSED] 0x7D45 (METEORLAKE)
[06:52:05] [PASSED] 0x7D55 (METEORLAKE)
[06:52:05] [PASSED] 0x7D60 (METEORLAKE)
[06:52:05] [PASSED] 0x7DD5 (METEORLAKE)
[06:52:05] [PASSED] 0x6420 (LUNARLAKE)
[06:52:05] [PASSED] 0x64A0 (LUNARLAKE)
[06:52:05] [PASSED] 0x64B0 (LUNARLAKE)
[06:52:05] [PASSED] 0xE202 (BATTLEMAGE)
[06:52:05] [PASSED] 0xE209 (BATTLEMAGE)
[06:52:05] [PASSED] 0xE20B (BATTLEMAGE)
[06:52:05] [PASSED] 0xE20C (BATTLEMAGE)
[06:52:05] [PASSED] 0xE20D (BATTLEMAGE)
[06:52:05] [PASSED] 0xE210 (BATTLEMAGE)
[06:52:05] [PASSED] 0xE211 (BATTLEMAGE)
[06:52:05] [PASSED] 0xE212 (BATTLEMAGE)
[06:52:05] [PASSED] 0xE216 (BATTLEMAGE)
[06:52:05] [PASSED] 0xE220 (BATTLEMAGE)
[06:52:05] [PASSED] 0xE221 (BATTLEMAGE)
[06:52:05] [PASSED] 0xE222 (BATTLEMAGE)
[06:52:05] [PASSED] 0xE223 (BATTLEMAGE)
[06:52:05] [PASSED] 0xB080 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB081 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB082 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB083 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB084 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB085 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB086 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB087 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB08F (PANTHERLAKE)
[06:52:05] [PASSED] 0xB090 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB0A0 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB0A1 (PANTHERLAKE)
[06:52:05] [PASSED] 0xB0B0 (PANTHERLAKE)
[06:52:05] [PASSED] 0xFD80 (PANTHERLAKE)
[06:52:05] [PASSED] 0xFD81 (PANTHERLAKE)
[06:52:05] [PASSED] 0xD740 (NOVALAKE_S)
[06:52:05] [PASSED] 0xD741 (NOVALAKE_S)
[06:52:05] [PASSED] 0xD742 (NOVALAKE_S)
[06:52:05] [PASSED] 0xD743 (NOVALAKE_S)
[06:52:05] [PASSED] 0xD745 (NOVALAKE_S)
[06:52:05] [PASSED] 0xD74A (NOVALAKE_S)
[06:52:05] [PASSED] 0xD74B (NOVALAKE_S)
[06:52:05] [PASSED] 0x674C (CRESCENTISLAND)
[06:52:05] [PASSED] 0x674D (CRESCENTISLAND)
[06:52:05] [PASSED] 0x674E (CRESCENTISLAND)
[06:52:05] [PASSED] 0x674F (CRESCENTISLAND)
[06:52:05] [PASSED] 0x6750 (CRESCENTISLAND)
[06:52:05] [PASSED] 0x6751 (CRESCENTISLAND)
[06:52:05] [PASSED] 0xD750 (NOVALAKE_P)
[06:52:05] [PASSED] 0xD751 (NOVALAKE_P)
[06:52:05] [PASSED] 0xD752 (NOVALAKE_P)
[06:52:05] [PASSED] 0xD753 (NOVALAKE_P)
[06:52:05] [PASSED] 0xD754 (NOVALAKE_P)
[06:52:05] [PASSED] 0xD755 (NOVALAKE_P)
[06:52:05] [PASSED] 0xD756 (NOVALAKE_P)
[06:52:05] [PASSED] 0xD757 (NOVALAKE_P)
[06:52:05] [PASSED] 0xD75F (NOVALAKE_P)
[06:52:05] =============== [PASSED] check_platform_desc ===============
[06:52:05] ===================== [PASSED] xe_pci ======================
[06:52:05] ============= xe_rtp_tables_test (5 subtests) ==============
[06:52:05] ================== xe_rtp_table_gt_test ===================
[06:52:05] [PASSED] gt_was/14011060649
[06:52:05] [PASSED] gt_was/14011059788
[06:52:05] [PASSED] gt_was/14015795083
[06:52:05] [PASSED] gt_was/16021867713
[06:52:05] [PASSED] gt_was/14019449301
[06:52:05] [PASSED] gt_was/16028005424
[06:52:05] [PASSED] gt_was/14026578760
[06:52:05] [PASSED] gt_was/1409420604
[06:52:05] [PASSED] gt_was/1408615072
[06:52:05] [PASSED] gt_was/22010523718
[06:52:05] [PASSED] gt_was/14011006942
[06:52:05] [PASSED] gt_was/14014830051
[06:52:05] [PASSED] gt_was/18018781329
[06:52:05] [PASSED] gt_was/1509235366
[06:52:05] [PASSED] gt_was/18018781329
[06:52:05] [PASSED] gt_was/16016694945
[06:52:05] [PASSED] gt_was/14018575942
[06:52:05] [PASSED] gt_was/22016670082
[06:52:05] [PASSED] gt_was/22016670082
[06:52:05] [PASSED] gt_was/14017421178
[06:52:05] [PASSED] gt_was/16025250150
[06:52:05] [PASSED] gt_was/14021871409
[06:52:05] [PASSED] gt_was/16021865536
[06:52:05] [PASSED] gt_was/14021486841
[06:52:05] [PASSED] gt_was/14025160223
[06:52:05] [PASSED] gt_was/14026144927, 16029437861, 14026127056
[06:52:05] [PASSED] gt_was/14025635424
[06:52:05] [PASSED] gt_was/16028005424
[06:52:05] ============== [PASSED] xe_rtp_table_gt_test ===============
[06:52:05] ================== xe_rtp_table_gt_test ===================
[06:52:05] [PASSED] gt_tunings/Tuning: Blend Fill Caching Optimization Disable
[06:52:05] [PASSED] gt_tunings/Tuning: 32B Access Enable
[06:52:05] [PASSED] gt_tunings/Tuning: L3 cache
[06:52:05] [PASSED] gt_tunings/Tuning: L3 cache - media
[06:52:05] [PASSED] gt_tunings/Tuning: Compression Overfetch
[06:52:05] [PASSED] gt_tunings/Tuning: Compression Overfetch - media
[06:52:05] [PASSED] gt_tunings/Tuning: Enable compressible partial write overfetch in L3
[06:52:05] [PASSED] gt_tunings/Tuning: Enable compressible partial write overfetch in L3 - media
[06:52:05] [PASSED] gt_tunings/Tuning: L2 Overfetch Compressible Only
[06:52:05] [PASSED] gt_tunings/Tuning: L2 Overfetch Compressible Only - media
[06:52:05] [PASSED] gt_tunings/Tuning: Stateless compression control
[06:52:05] [PASSED] gt_tunings/Tuning: Stateless compression control - media
[06:52:05] [PASSED] gt_tunings/Tuning: L3 RW flush all Cache
[06:52:05] [PASSED] gt_tunings/Tuning: L3 RW flush all cache - media
[06:52:05] [PASSED] gt_tunings/Tuning: Set STLB Bank Hash Mode to 4KB
[06:52:05] [PASSED] gt_tunings/Tuning: Force All Non-Compressible Memory Reads to be 256B Overfetches
[06:52:05] ============== [PASSED] xe_rtp_table_gt_test ===============
[06:52:05] ================== xe_rtp_table_oob_test ==================
[06:52:05] [PASSED] oob_was/1607983814
[06:52:05] [PASSED] oob_was/16010904313
[06:52:05] [PASSED] oob_was/18022495364
[06:52:05] [PASSED] oob_was/22012773006
[06:52:05] [PASSED] oob_was/14014475959
[06:52:05] [PASSED] oob_was/22011391025
[06:52:05] [PASSED] oob_was/22012727170
[06:52:05] [PASSED] oob_was/22012727685
[06:52:05] [PASSED] oob_was/22016596838
[06:52:05] [PASSED] oob_was/18020744125
[06:52:05] [PASSED] oob_was/1409600907
[06:52:05] [PASSED] oob_was/22014953428
[06:52:05] [PASSED] oob_was/16017236439
[06:52:05] [PASSED] oob_was/14019821291
[06:52:05] [PASSED] oob_was/14015076503
[06:52:05] [PASSED] oob_was/22016122933
[06:52:05] [PASSED] oob_was/14018913170
[06:52:05] [PASSED] oob_was/14018094691
[06:52:05] [PASSED] oob_was/18024947630
[06:52:05] [PASSED] oob_was/16022287689
[06:52:05] [PASSED] oob_was/13011645652
[06:52:05] [PASSED] oob_was/14022293748
[06:52:05] [PASSED] oob_was/22019794406
[06:52:05] [PASSED] oob_was/22019338487
[06:52:05] [PASSED] oob_was/16023588340
[06:52:05] [PASSED] oob_was/14019789679
[06:52:05] [PASSED] oob_was/14022866841
[06:52:05] [PASSED] oob_was/16021333562
[06:52:05] [PASSED] oob_was/14016712196
[06:52:05] [PASSED] oob_was/14015568240
[06:52:05] [PASSED] oob_was/18013179988
[06:52:05] [PASSED] oob_was/1508761755
[06:52:05] [PASSED] oob_was/16023105232
[06:52:05] [PASSED] oob_was/16026508708
[06:52:05] [PASSED] oob_was/14020001231
[06:52:05] [PASSED] oob_was/16023683509
[06:52:05] [PASSED] oob_was/14025515070
[06:52:05] [PASSED] oob_was/15015404425_disable
[06:52:05] [PASSED] oob_was/16026007364
[06:52:05] [PASSED] oob_was/14020316580
[06:52:05] [PASSED] oob_was/14025883347
[06:52:05] [PASSED] oob_was/16029380221
[06:52:05] [PASSED] oob_was/22022079272
[06:52:05] [PASSED] oob_was/16029897822
[06:52:05] [PASSED] oob_was/14027054324
[06:52:05] [PASSED] oob_was/14025941587
[06:52:05] [PASSED] oob_was/16030224309
[06:52:05] ============== [PASSED] xe_rtp_table_oob_test ==============
[06:52:05] ================ xe_rtp_table_dev_oob_test ================
[06:52:05] [PASSED] device_oob_was/22010954014
[06:52:05] [PASSED] device_oob_was/15015404425
[06:52:05] [PASSED] device_oob_was/22019338487_display
[06:52:05] [PASSED] device_oob_was/14022085890
[06:52:05] [PASSED] device_oob_was/14026539277
[06:52:05] [PASSED] device_oob_was/14026633728
[06:52:05] [PASSED] device_oob_was/14026746987
[06:52:05] [PASSED] device_oob_was/14026779378
[06:52:05] ============ [PASSED] xe_rtp_table_dev_oob_test ============
[06:52:05] ========== xe_rtp_table_missing_upper_bound_test ==========
[06:52:05] [PASSED] register_whitelist/WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865
[06:52:05] [PASSED] register_whitelist/1508744258, 14012131227, 1808121037
[06:52:05] [PASSED] register_whitelist/1806527549
[06:52:05] [PASSED] register_whitelist/allow_read_ctx_timestamp
[06:52:05] [PASSED] register_whitelist/allow_read_queue_timestamp
[06:52:05] [PASSED] register_whitelist/16014440446
[06:52:05] [PASSED] register_whitelist/16017236439
[06:52:05] [PASSED] register_whitelist/16020183090
[06:52:05] [PASSED] register_whitelist/14024997852
[06:52:05] [PASSED] register_whitelist/14024997852
[06:52:05] ====== [PASSED] xe_rtp_table_missing_upper_bound_test ======
[06:52:05] =============== [PASSED] xe_rtp_tables_test ================
[06:52:05] =================== xe_rtp (3 subtests) ====================
[06:52:05] =================== xe_rtp_rules_tests ====================
[06:52:05] [PASSED] no
[06:52:05] [PASSED] yes
[06:52:05] [PASSED] no-and-no
[06:52:05] [PASSED] no-and-yes
[06:52:05] [PASSED] yes-and-no
[06:52:05] [PASSED] yes-and-yes
[06:52:05] [PASSED] no-or-no
[06:52:05] [PASSED] no-or-yes
[06:52:05] [PASSED] yes-or-no
[06:52:05] [PASSED] yes-or-yes
[06:52:05] [PASSED] no-yes-or-yes-no
[06:52:05] [PASSED] no-yes-or-yes-yes
[06:52:05] [PASSED] yes-yes-or-no-yes
[06:52:05] [PASSED] yes-yes-or-yes-yes
[06:52:05] [PASSED] no-no-or-yes-or-no
[06:52:05] [PASSED] or
[06:52:05] [PASSED] or-yes
[06:52:05] [PASSED] or-no
[06:52:06] [PASSED] yes-or
[06:52:06] [PASSED] no-or
[06:52:06] [PASSED] no-or-or-yes
[06:52:06] [PASSED] yes-or-or-no
[06:52:06] [PASSED] no-or-or-no
[06:52:06] [PASSED] missing-context-engine-class
[06:52:06] [PASSED] missing-context-engine-class-or-yes
[06:52:06] [PASSED] missing-context-engine-class-or-or-yes
[06:52:06] =============== [PASSED] xe_rtp_rules_tests ================
[06:52:06] =============== xe_rtp_process_to_sr_tests ================
[06:52:06] [PASSED] coalesce-same-reg
[06:52:06] [PASSED] coalesce-same-reg-literal-and-func
[06:52:06] [PASSED] no-match-no-add
[06:52:06] [PASSED] two-regs-two-entries
[06:52:06] [PASSED] clr-one-set-other
[06:52:06] [PASSED] set-field
[06:52:06] [PASSED] conflict-duplicate
[06:52:06] [PASSED] conflict-not-disjoint
[06:52:06] [PASSED] conflict-not-disjoint-literal-and-func
[06:52:06] [PASSED] conflict-reg-type
[06:52:06] [PASSED] bad-mcr-reg-forced-to-regular
[06:52:06] [PASSED] bad-regular-reg-forced-to-mcr
[06:52:06] =========== [PASSED] xe_rtp_process_to_sr_tests ============
[06:52:06] ================== xe_rtp_process_tests ===================
[06:52:06] [PASSED] active1
[06:52:06] [PASSED] active2
[06:52:06] [PASSED] active-inactive
[06:52:06] [PASSED] inactive-active
[06:52:06] [PASSED] inactive-active-inactive
[06:52:06] [PASSED] inactive-inactive-inactive
[06:52:06] ============== [PASSED] xe_rtp_process_tests ===============
[06:52:06] ===================== [PASSED] xe_rtp ======================
[06:52:06] ==================== xe_wa (1 subtest) =====================
[06:52:06] ======================== xe_wa_gt =========================
[06:52:06] [PASSED] TIGERLAKE B0
[06:52:06] [PASSED] DG1 A0
[06:52:06] [PASSED] DG1 B0
[06:52:06] [PASSED] ALDERLAKE_S A0
[06:52:06] [PASSED] ALDERLAKE_S B0
[06:52:06] [PASSED] ALDERLAKE_S C0
[06:52:06] [PASSED] ALDERLAKE_S D0
[06:52:06] [PASSED] ALDERLAKE_P A0
[06:52:06] [PASSED] ALDERLAKE_P B0
[06:52:06] [PASSED] ALDERLAKE_P C0
[06:52:06] [PASSED] ALDERLAKE_S RPLS D0
[06:52:06] [PASSED] ALDERLAKE_P RPLU E0
[06:52:06] [PASSED] DG2 G10 C0
[06:52:06] [PASSED] DG2 G11 B1
[06:52:06] [PASSED] DG2 G12 A1
[06:52:06] [PASSED] METEORLAKE 12.70(Xe_LPG) A0 13.00(Xe_LPM+) A0
[06:52:06] [PASSED] METEORLAKE 12.71(Xe_LPG) A0 13.00(Xe_LPM+) A0
[06:52:06] [PASSED] METEORLAKE 12.74(Xe_LPG+) A0 13.00(Xe_LPM+) A0
[06:52:06] [PASSED] LUNARLAKE 20.04(Xe2_LPG) A0 20.00(Xe2_LPM) A0
[06:52:06] [PASSED] LUNARLAKE 20.04(Xe2_LPG) B0 20.00(Xe2_LPM) A0
[06:52:06] [PASSED] BATTLEMAGE 20.01(Xe2_HPG) A0 13.01(Xe2_HPM) A1
[06:52:06] [PASSED] PANTHERLAKE 30.00(Xe3_LPG) A0 30.00(Xe3_LPM) A0
[06:52:06] ==================== [PASSED] xe_wa_gt =====================
[06:52:06] ====================== [PASSED] xe_wa ======================
[06:52:06] ============================================================
[06:52:06] Testing complete. Ran 837 tests: passed: 809, skipped: 28
[06:52:06] Elapsed time: 42.005s total, 1.913s configuring, 39.325s building, 0.731s running
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/drm/tests/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/tests/.kunitconfig
[06:52:06] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[06:52:08] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[06:52:33] Starting KUnit Kernel (1/1)...
[06:52:33] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[06:52:33] ============ drm_test_pick_cmdline (2 subtests) ============
[06:52:33] [PASSED] drm_test_pick_cmdline_res_1920_1080_60
[06:52:33] =============== drm_test_pick_cmdline_named ===============
[06:52:33] [PASSED] NTSC
[06:52:33] [PASSED] NTSC-J
[06:52:33] [PASSED] PAL
[06:52:33] [PASSED] PAL-M
[06:52:33] =========== [PASSED] drm_test_pick_cmdline_named ===========
[06:52:33] ============== [PASSED] drm_test_pick_cmdline ==============
[06:52:33] == drm_test_atomic_get_connector_for_encoder (1 subtest) ===
[06:52:33] [PASSED] drm_test_drm_atomic_get_connector_for_encoder
[06:52:33] ==== [PASSED] drm_test_atomic_get_connector_for_encoder ====
[06:52:33] =========== drm_validate_clone_mode (2 subtests) ===========
[06:52:33] ============== drm_test_check_in_clone_mode ===============
[06:52:33] [PASSED] in_clone_mode
[06:52:33] [PASSED] not_in_clone_mode
[06:52:33] ========== [PASSED] drm_test_check_in_clone_mode ===========
[06:52:33] =============== drm_test_check_valid_clones ===============
[06:52:33] [PASSED] not_in_clone_mode
[06:52:33] [PASSED] valid_clone
[06:52:33] [PASSED] invalid_clone
[06:52:33] =========== [PASSED] drm_test_check_valid_clones ===========
[06:52:33] ============= [PASSED] drm_validate_clone_mode =============
[06:52:33] ============= drm_validate_modeset (1 subtest) =============
[06:52:33] [PASSED] drm_test_check_connector_changed_modeset
[06:52:33] ============== [PASSED] drm_validate_modeset ===============
[06:52:33] ====== drm_test_bridge_get_current_state (1 subtest) =======
[06:52:33] [PASSED] drm_test_drm_bridge_get_current_state_atomic
[06:52:33] ======== [PASSED] drm_test_bridge_get_current_state ========
[06:52:33] ====== drm_test_bridge_helper_reset_crtc (3 subtests) ======
[06:52:33] [PASSED] drm_test_drm_bridge_helper_reset_crtc_atomic
[06:52:33] [PASSED] drm_test_drm_bridge_helper_reset_crtc_atomic_disabled
[06:52:33] [PASSED] drm_test_drm_bridge_helper_hdmi_output_bus_fmts
[06:52:33] ======== [PASSED] drm_test_bridge_helper_reset_crtc ========
[06:52:33] ============== drm_bridge_alloc (2 subtests) ===============
[06:52:33] [PASSED] drm_test_drm_bridge_alloc_basic
[06:52:33] [PASSED] drm_test_drm_bridge_alloc_get_put
[06:52:33] ================ [PASSED] drm_bridge_alloc =================
[06:52:33] ============= drm_bridge_bus_fmt (5 subtests) ==============
[06:52:33] [PASSED] drm_test_bridge_rgb_yuv_rgb
[06:52:33] [PASSED] drm_test_bridge_must_convert_to_yuv444
[06:52:33] [PASSED] drm_test_bridge_hdmi_auto_rgb
[06:52:33] [PASSED] drm_test_bridge_auto_first
[06:52:33] [PASSED] drm_test_bridge_rgb_yuv_no_path
[06:52:33] =============== [PASSED] drm_bridge_bus_fmt ================
[06:52:33] ============= drm_cmdline_parser (40 subtests) =============
[06:52:33] [PASSED] drm_test_cmdline_force_d_only
[06:52:33] [PASSED] drm_test_cmdline_force_D_only_dvi
[06:52:33] [PASSED] drm_test_cmdline_force_D_only_hdmi
[06:52:33] [PASSED] drm_test_cmdline_force_D_only_not_digital
[06:52:33] [PASSED] drm_test_cmdline_force_e_only
[06:52:33] [PASSED] drm_test_cmdline_res
[06:52:33] [PASSED] drm_test_cmdline_res_vesa
[06:52:33] [PASSED] drm_test_cmdline_res_vesa_rblank
[06:52:33] [PASSED] drm_test_cmdline_res_rblank
[06:52:33] [PASSED] drm_test_cmdline_res_bpp
[06:52:33] [PASSED] drm_test_cmdline_res_refresh
[06:52:33] [PASSED] drm_test_cmdline_res_bpp_refresh
[06:52:33] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced
[06:52:33] [PASSED] drm_test_cmdline_res_bpp_refresh_margins
[06:52:33] [PASSED] drm_test_cmdline_res_bpp_refresh_force_off
[06:52:33] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on
[06:52:33] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_analog
[06:52:33] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_digital
[06:52:33] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced_margins_force_on
[06:52:33] [PASSED] drm_test_cmdline_res_margins_force_on
[06:52:33] [PASSED] drm_test_cmdline_res_vesa_margins
[06:52:33] [PASSED] drm_test_cmdline_name
[06:52:33] [PASSED] drm_test_cmdline_name_bpp
[06:52:33] [PASSED] drm_test_cmdline_name_option
[06:52:33] [PASSED] drm_test_cmdline_name_bpp_option
[06:52:33] [PASSED] drm_test_cmdline_rotate_0
[06:52:33] [PASSED] drm_test_cmdline_rotate_90
[06:52:33] [PASSED] drm_test_cmdline_rotate_180
[06:52:33] [PASSED] drm_test_cmdline_rotate_270
[06:52:33] [PASSED] drm_test_cmdline_hmirror
[06:52:33] [PASSED] drm_test_cmdline_vmirror
[06:52:33] [PASSED] drm_test_cmdline_margin_options
[06:52:33] [PASSED] drm_test_cmdline_multiple_options
[06:52:33] [PASSED] drm_test_cmdline_bpp_extra_and_option
[06:52:33] [PASSED] drm_test_cmdline_extra_and_option
[06:52:33] [PASSED] drm_test_cmdline_freestanding_options
[06:52:33] [PASSED] drm_test_cmdline_freestanding_force_e_and_options
[06:52:33] [PASSED] drm_test_cmdline_panel_orientation
[06:52:33] ================ drm_test_cmdline_invalid =================
[06:52:33] [PASSED] margin_only
[06:52:33] [PASSED] interlace_only
[06:52:33] [PASSED] res_missing_x
[06:52:33] [PASSED] res_missing_y
[06:52:33] [PASSED] res_bad_y
[06:52:33] [PASSED] res_missing_y_bpp
[06:52:33] [PASSED] res_bad_bpp
[06:52:33] [PASSED] res_bad_refresh
[06:52:33] [PASSED] res_bpp_refresh_force_on_off
[06:52:33] [PASSED] res_invalid_mode
[06:52:33] [PASSED] res_bpp_wrong_place_mode
[06:52:33] [PASSED] name_bpp_refresh
[06:52:33] [PASSED] name_refresh
[06:52:33] [PASSED] name_refresh_wrong_mode
[06:52:33] [PASSED] name_refresh_invalid_mode
[06:52:33] [PASSED] rotate_multiple
[06:52:33] [PASSED] rotate_invalid_val
[06:52:33] [PASSED] rotate_truncated
[06:52:33] [PASSED] invalid_option
[06:52:33] [PASSED] invalid_tv_option
[06:52:33] [PASSED] truncated_tv_option
[06:52:33] ============ [PASSED] drm_test_cmdline_invalid =============
[06:52:33] =============== drm_test_cmdline_tv_options ===============
[06:52:33] [PASSED] NTSC
[06:52:33] [PASSED] NTSC_443
[06:52:33] [PASSED] NTSC_J
[06:52:33] [PASSED] PAL
[06:52:33] [PASSED] PAL_M
[06:52:33] [PASSED] PAL_N
[06:52:33] [PASSED] SECAM
[06:52:33] [PASSED] MONO_525
[06:52:33] [PASSED] MONO_625
[06:52:33] =========== [PASSED] drm_test_cmdline_tv_options ===========
[06:52:33] =============== [PASSED] drm_cmdline_parser ================
[06:52:33] ========== drmm_connector_hdmi_init (20 subtests) ==========
[06:52:33] [PASSED] drm_test_connector_hdmi_init_valid
[06:52:33] [PASSED] drm_test_connector_hdmi_init_bpc_8
[06:52:33] [PASSED] drm_test_connector_hdmi_init_bpc_10
[06:52:33] [PASSED] drm_test_connector_hdmi_init_bpc_12
[06:52:33] [PASSED] drm_test_connector_hdmi_init_bpc_invalid
[06:52:33] [PASSED] drm_test_connector_hdmi_init_bpc_null
[06:52:33] [PASSED] drm_test_connector_hdmi_init_formats_empty
[06:52:33] [PASSED] drm_test_connector_hdmi_init_formats_no_rgb
[06:52:33] === drm_test_connector_hdmi_init_formats_yuv420_allowed ===
[06:52:33] [PASSED] supported_formats=0x9 yuv420_allowed=1
[06:52:33] [PASSED] supported_formats=0x9 yuv420_allowed=0
[06:52:33] [PASSED] supported_formats=0x5 yuv420_allowed=1
[06:52:33] [PASSED] supported_formats=0x5 yuv420_allowed=0
[06:52:33] === [PASSED] drm_test_connector_hdmi_init_formats_yuv420_allowed ===
[06:52:33] [PASSED] drm_test_connector_hdmi_init_null_ddc
[06:52:33] [PASSED] drm_test_connector_hdmi_init_null_product
[06:52:33] [PASSED] drm_test_connector_hdmi_init_null_vendor
[06:52:33] [PASSED] drm_test_connector_hdmi_init_product_length_exact
[06:52:33] [PASSED] drm_test_connector_hdmi_init_product_length_too_long
[06:52:33] [PASSED] drm_test_connector_hdmi_init_product_valid
[06:52:33] [PASSED] drm_test_connector_hdmi_init_vendor_length_exact
[06:52:33] [PASSED] drm_test_connector_hdmi_init_vendor_length_too_long
[06:52:33] [PASSED] drm_test_connector_hdmi_init_vendor_valid
[06:52:33] ========= drm_test_connector_hdmi_init_type_valid =========
[06:52:33] [PASSED] HDMI-A
[06:52:33] [PASSED] HDMI-B
[06:52:33] ===== [PASSED] drm_test_connector_hdmi_init_type_valid =====
[06:52:33] ======== drm_test_connector_hdmi_init_type_invalid ========
[06:52:33] [PASSED] Unknown
[06:52:33] [PASSED] VGA
[06:52:33] [PASSED] DVI-I
[06:52:33] [PASSED] DVI-D
[06:52:33] [PASSED] DVI-A
[06:52:33] [PASSED] Composite
[06:52:33] [PASSED] SVIDEO
[06:52:33] [PASSED] LVDS
[06:52:33] [PASSED] Component
[06:52:33] [PASSED] DIN
[06:52:33] [PASSED] DP
[06:52:33] [PASSED] TV
[06:52:33] [PASSED] eDP
[06:52:33] [PASSED] Virtual
[06:52:33] [PASSED] DSI
[06:52:33] [PASSED] DPI
[06:52:33] [PASSED] Writeback
[06:52:33] [PASSED] SPI
[06:52:33] [PASSED] USB
[06:52:33] ==== [PASSED] drm_test_connector_hdmi_init_type_invalid ====
[06:52:33] ============ [PASSED] drmm_connector_hdmi_init =============
[06:52:33] ============= drmm_connector_init (3 subtests) =============
[06:52:33] [PASSED] drm_test_drmm_connector_init
[06:52:33] [PASSED] drm_test_drmm_connector_init_null_ddc
[06:52:33] ========= drm_test_drmm_connector_init_type_valid =========
[06:52:33] [PASSED] Unknown
[06:52:33] [PASSED] VGA
[06:52:33] [PASSED] DVI-I
[06:52:33] [PASSED] DVI-D
[06:52:33] [PASSED] DVI-A
[06:52:33] [PASSED] Composite
[06:52:33] [PASSED] SVIDEO
[06:52:33] [PASSED] LVDS
[06:52:33] [PASSED] Component
[06:52:33] [PASSED] DIN
[06:52:33] [PASSED] DP
[06:52:33] [PASSED] HDMI-A
[06:52:33] [PASSED] HDMI-B
[06:52:33] [PASSED] TV
[06:52:33] [PASSED] eDP
[06:52:33] [PASSED] Virtual
[06:52:33] [PASSED] DSI
[06:52:33] [PASSED] DPI
[06:52:33] [PASSED] Writeback
[06:52:33] [PASSED] SPI
[06:52:33] [PASSED] USB
[06:52:33] ===== [PASSED] drm_test_drmm_connector_init_type_valid =====
[06:52:33] =============== [PASSED] drmm_connector_init ===============
[06:52:33] ========= drm_connector_dynamic_init (6 subtests) ==========
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_init
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_init_null_ddc
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_init_not_added
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_init_properties
[06:52:33] ===== drm_test_drm_connector_dynamic_init_type_valid ======
[06:52:33] [PASSED] Unknown
[06:52:33] [PASSED] VGA
[06:52:33] [PASSED] DVI-I
[06:52:33] [PASSED] DVI-D
[06:52:33] [PASSED] DVI-A
[06:52:33] [PASSED] Composite
[06:52:33] [PASSED] SVIDEO
[06:52:33] [PASSED] LVDS
[06:52:33] [PASSED] Component
[06:52:33] [PASSED] DIN
[06:52:33] [PASSED] DP
[06:52:33] [PASSED] HDMI-A
[06:52:33] [PASSED] HDMI-B
[06:52:33] [PASSED] TV
[06:52:33] [PASSED] eDP
[06:52:33] [PASSED] Virtual
[06:52:33] [PASSED] DSI
[06:52:33] [PASSED] DPI
[06:52:33] [PASSED] Writeback
[06:52:33] [PASSED] SPI
[06:52:33] [PASSED] USB
[06:52:33] = [PASSED] drm_test_drm_connector_dynamic_init_type_valid ==
[06:52:33] ======== drm_test_drm_connector_dynamic_init_name =========
[06:52:33] [PASSED] Unknown
[06:52:33] [PASSED] VGA
[06:52:33] [PASSED] DVI-I
[06:52:33] [PASSED] DVI-D
[06:52:33] [PASSED] DVI-A
[06:52:33] [PASSED] Composite
[06:52:33] [PASSED] SVIDEO
[06:52:33] [PASSED] LVDS
[06:52:33] [PASSED] Component
[06:52:33] [PASSED] DIN
[06:52:33] [PASSED] DP
[06:52:33] [PASSED] HDMI-A
[06:52:33] [PASSED] HDMI-B
[06:52:33] [PASSED] TV
[06:52:33] [PASSED] eDP
[06:52:33] [PASSED] Virtual
[06:52:33] [PASSED] DSI
[06:52:33] [PASSED] DPI
[06:52:33] [PASSED] Writeback
[06:52:33] [PASSED] SPI
[06:52:33] [PASSED] USB
[06:52:33] ==== [PASSED] drm_test_drm_connector_dynamic_init_name =====
[06:52:33] =========== [PASSED] drm_connector_dynamic_init ============
[06:52:33] ==== drm_connector_dynamic_register_early (4 subtests) =====
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_early_on_list
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_early_defer
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_early_no_init
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_early_no_mode_object
[06:52:33] ====== [PASSED] drm_connector_dynamic_register_early =======
[06:52:33] ======= drm_connector_dynamic_register (7 subtests) ========
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_on_list
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_no_defer
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_no_init
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_mode_object
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_sysfs
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_sysfs_name
[06:52:33] [PASSED] drm_test_drm_connector_dynamic_register_debugfs
[06:52:33] ========= [PASSED] drm_connector_dynamic_register ==========
[06:52:33] = drm_connector_attach_broadcast_rgb_property (2 subtests) =
[06:52:33] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property
[06:52:33] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector
[06:52:33] === [PASSED] drm_connector_attach_broadcast_rgb_property ===
[06:52:33] ========== drm_get_tv_mode_from_name (2 subtests) ==========
[06:52:33] ========== drm_test_get_tv_mode_from_name_valid ===========
[06:52:33] [PASSED] NTSC
[06:52:33] [PASSED] NTSC-443
[06:52:33] [PASSED] NTSC-J
[06:52:33] [PASSED] PAL
[06:52:33] [PASSED] PAL-M
[06:52:33] [PASSED] PAL-N
[06:52:33] [PASSED] SECAM
[06:52:33] [PASSED] Mono
[06:52:33] ====== [PASSED] drm_test_get_tv_mode_from_name_valid =======
[06:52:33] [PASSED] drm_test_get_tv_mode_from_name_truncated
[06:52:33] ============ [PASSED] drm_get_tv_mode_from_name ============
[06:52:33] = drm_test_connector_hdmi_compute_mode_clock (12 subtests) =
[06:52:33] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb
[06:52:33] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc
[06:52:33] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1
[06:52:33] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc
[06:52:33] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1
[06:52:33] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_double
[06:52:33] = drm_test_connector_hdmi_compute_mode_clock_yuv420_valid =
[06:52:33] [PASSED] VIC 96
[06:52:33] [PASSED] VIC 97
[06:52:33] [PASSED] VIC 101
[06:52:33] [PASSED] VIC 102
[06:52:33] [PASSED] VIC 106
[06:52:33] [PASSED] VIC 107
[06:52:33] === [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_valid ===
[06:52:33] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc
[06:52:33] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc
[06:52:33] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc
[06:52:33] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc
[06:52:33] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc
[06:52:33] === [PASSED] drm_test_connector_hdmi_compute_mode_clock ====
[06:52:33] == drm_hdmi_connector_get_broadcast_rgb_name (2 subtests) ==
[06:52:33] === drm_test_drm_hdmi_connector_get_broadcast_rgb_name ====
[06:52:33] [PASSED] Automatic
[06:52:33] [PASSED] Full
[06:52:33] [PASSED] Limited 16:235
[06:52:33] === [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name ===
[06:52:33] [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid
[06:52:33] ==== [PASSED] drm_hdmi_connector_get_broadcast_rgb_name ====
[06:52:33] == drm_hdmi_connector_get_output_format_name (2 subtests) ==
[06:52:33] === drm_test_drm_hdmi_connector_get_output_format_name ====
[06:52:33] [PASSED] RGB
[06:52:33] [PASSED] YUV 4:2:0
[06:52:33] [PASSED] YUV 4:2:2
[06:52:33] [PASSED] YUV 4:4:4
[06:52:33] === [PASSED] drm_test_drm_hdmi_connector_get_output_format_name ===
[06:52:33] [PASSED] drm_test_drm_hdmi_connector_get_output_format_name_invalid
[06:52:33] ==== [PASSED] drm_hdmi_connector_get_output_format_name ====
[06:52:33] ============= drm_damage_helper (21 subtests) ==============
[06:52:33] [PASSED] drm_test_damage_iter_no_damage
[06:52:33] [PASSED] drm_test_damage_iter_no_damage_fractional_src
[06:52:33] [PASSED] drm_test_damage_iter_no_damage_src_moved
[06:52:33] [PASSED] drm_test_damage_iter_no_damage_fractional_src_moved
[06:52:33] [PASSED] drm_test_damage_iter_no_damage_not_visible
[06:52:33] [PASSED] drm_test_damage_iter_no_damage_no_crtc
[06:52:33] [PASSED] drm_test_damage_iter_no_damage_no_fb
[06:52:33] [PASSED] drm_test_damage_iter_simple_damage
[06:52:33] [PASSED] drm_test_damage_iter_single_damage
[06:52:33] [PASSED] drm_test_damage_iter_single_damage_intersect_src
[06:52:33] [PASSED] drm_test_damage_iter_single_damage_outside_src
[06:52:33] [PASSED] drm_test_damage_iter_single_damage_fractional_src
[06:52:33] [PASSED] drm_test_damage_iter_single_damage_intersect_fractional_src
[06:52:33] [PASSED] drm_test_damage_iter_single_damage_outside_fractional_src
[06:52:33] [PASSED] drm_test_damage_iter_single_damage_src_moved
[06:52:33] [PASSED] drm_test_damage_iter_single_damage_fractional_src_moved
[06:52:33] [PASSED] drm_test_damage_iter_damage
[06:52:33] [PASSED] drm_test_damage_iter_damage_one_intersect
[06:52:33] [PASSED] drm_test_damage_iter_damage_one_outside
[06:52:33] [PASSED] drm_test_damage_iter_damage_src_moved
[06:52:33] [PASSED] drm_test_damage_iter_damage_not_visible
[06:52:33] ================ [PASSED] drm_damage_helper ================
[06:52:33] ============== drm_dp_mst_helper (3 subtests) ==============
[06:52:33] ============== drm_test_dp_mst_calc_pbn_mode ==============
[06:52:33] [PASSED] Clock 154000 BPP 30 DSC disabled
[06:52:33] [PASSED] Clock 234000 BPP 30 DSC disabled
[06:52:33] [PASSED] Clock 297000 BPP 24 DSC disabled
[06:52:33] [PASSED] Clock 332880 BPP 24 DSC enabled
[06:52:33] [PASSED] Clock 324540 BPP 24 DSC enabled
[06:52:33] ========== [PASSED] drm_test_dp_mst_calc_pbn_mode ==========
[06:52:33] ============== drm_test_dp_mst_calc_pbn_div ===============
[06:52:33] [PASSED] Link rate 2000000 lane count 4
[06:52:33] [PASSED] Link rate 2000000 lane count 2
[06:52:33] [PASSED] Link rate 2000000 lane count 1
[06:52:33] [PASSED] Link rate 1350000 lane count 4
[06:52:33] [PASSED] Link rate 1350000 lane count 2
[06:52:33] [PASSED] Link rate 1350000 lane count 1
[06:52:33] [PASSED] Link rate 1000000 lane count 4
[06:52:33] [PASSED] Link rate 1000000 lane count 2
[06:52:33] [PASSED] Link rate 1000000 lane count 1
[06:52:33] [PASSED] Link rate 810000 lane count 4
[06:52:33] [PASSED] Link rate 810000 lane count 2
[06:52:33] [PASSED] Link rate 810000 lane count 1
[06:52:33] [PASSED] Link rate 540000 lane count 4
[06:52:33] [PASSED] Link rate 540000 lane count 2
[06:52:33] [PASSED] Link rate 540000 lane count 1
[06:52:33] [PASSED] Link rate 270000 lane count 4
[06:52:33] [PASSED] Link rate 270000 lane count 2
[06:52:33] [PASSED] Link rate 270000 lane count 1
[06:52:33] [PASSED] Link rate 162000 lane count 4
[06:52:33] [PASSED] Link rate 162000 lane count 2
[06:52:33] [PASSED] Link rate 162000 lane count 1
[06:52:33] ========== [PASSED] drm_test_dp_mst_calc_pbn_div ===========
[06:52:33] ========= drm_test_dp_mst_sideband_msg_req_decode =========
[06:52:33] [PASSED] DP_ENUM_PATH_RESOURCES with port number
[06:52:33] [PASSED] DP_POWER_UP_PHY with port number
[06:52:33] [PASSED] DP_POWER_DOWN_PHY with port number
[06:52:33] [PASSED] DP_ALLOCATE_PAYLOAD with SDP stream sinks
[06:52:33] [PASSED] DP_ALLOCATE_PAYLOAD with port number
[06:52:33] [PASSED] DP_ALLOCATE_PAYLOAD with VCPI
[06:52:33] [PASSED] DP_ALLOCATE_PAYLOAD with PBN
[06:52:33] [PASSED] DP_QUERY_PAYLOAD with port number
[06:52:33] [PASSED] DP_QUERY_PAYLOAD with VCPI
[06:52:33] [PASSED] DP_REMOTE_DPCD_READ with port number
[06:52:33] [PASSED] DP_REMOTE_DPCD_READ with DPCD address
[06:52:33] [PASSED] DP_REMOTE_DPCD_READ with max number of bytes
[06:52:33] [PASSED] DP_REMOTE_DPCD_WRITE with port number
[06:52:33] [PASSED] DP_REMOTE_DPCD_WRITE with DPCD address
[06:52:33] [PASSED] DP_REMOTE_DPCD_WRITE with data array
[06:52:33] [PASSED] DP_REMOTE_I2C_READ with port number
[06:52:33] [PASSED] DP_REMOTE_I2C_READ with I2C device ID
[06:52:33] [PASSED] DP_REMOTE_I2C_READ with transactions array
[06:52:33] [PASSED] DP_REMOTE_I2C_WRITE with port number
[06:52:33] [PASSED] DP_REMOTE_I2C_WRITE with I2C device ID
[06:52:33] [PASSED] DP_REMOTE_I2C_WRITE with data array
[06:52:33] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream ID
[06:52:33] [PASSED] DP_QUERY_STREAM_ENC_STATUS with client ID
[06:52:33] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream event
[06:52:33] [PASSED] DP_QUERY_STREAM_ENC_STATUS with valid stream event
[06:52:33] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream behavior
[06:52:33] [PASSED] DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior
[06:52:33] ===== [PASSED] drm_test_dp_mst_sideband_msg_req_decode =====
[06:52:33] ================ [PASSED] drm_dp_mst_helper ================
[06:52:33] ================== drm_exec (7 subtests) ===================
[06:52:33] [PASSED] sanitycheck
[06:52:33] [PASSED] test_lock
[06:52:33] [PASSED] test_lock_unlock
[06:52:33] [PASSED] test_duplicates
[06:52:33] [PASSED] test_prepare
[06:52:33] [PASSED] test_prepare_array
[06:52:33] [PASSED] test_multiple_loops
[06:52:33] ==================== [PASSED] drm_exec =====================
[06:52:33] =========== drm_format_helper_test (17 subtests) ===========
[06:52:33] ============== drm_test_fb_xrgb8888_to_gray8 ==============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ========== [PASSED] drm_test_fb_xrgb8888_to_gray8 ==========
[06:52:33] ============= drm_test_fb_xrgb8888_to_rgb332 ==============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb332 ==========
[06:52:33] ============= drm_test_fb_xrgb8888_to_rgb565 ==============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb565 ==========
[06:52:33] ============ drm_test_fb_xrgb8888_to_xrgb1555 =============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ======== [PASSED] drm_test_fb_xrgb8888_to_xrgb1555 =========
[06:52:33] ============ drm_test_fb_xrgb8888_to_argb1555 =============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ======== [PASSED] drm_test_fb_xrgb8888_to_argb1555 =========
[06:52:33] ============ drm_test_fb_xrgb8888_to_rgba5551 =============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ======== [PASSED] drm_test_fb_xrgb8888_to_rgba5551 =========
[06:52:33] ============= drm_test_fb_xrgb8888_to_rgb888 ==============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb888 ==========
[06:52:33] ============= drm_test_fb_xrgb8888_to_bgr888 ==============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ========= [PASSED] drm_test_fb_xrgb8888_to_bgr888 ==========
[06:52:33] ============ drm_test_fb_xrgb8888_to_argb8888 =============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ======== [PASSED] drm_test_fb_xrgb8888_to_argb8888 =========
[06:52:33] =========== drm_test_fb_xrgb8888_to_xrgb2101010 ===========
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ======= [PASSED] drm_test_fb_xrgb8888_to_xrgb2101010 =======
[06:52:33] =========== drm_test_fb_xrgb8888_to_argb2101010 ===========
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ======= [PASSED] drm_test_fb_xrgb8888_to_argb2101010 =======
[06:52:33] ============== drm_test_fb_xrgb8888_to_mono ===============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ========== [PASSED] drm_test_fb_xrgb8888_to_mono ===========
[06:52:33] ==================== drm_test_fb_swab =====================
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ================ [PASSED] drm_test_fb_swab =================
[06:52:33] ============ drm_test_fb_xrgb8888_to_xbgr8888 =============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ======== [PASSED] drm_test_fb_xrgb8888_to_xbgr8888 =========
[06:52:33] ============ drm_test_fb_xrgb8888_to_abgr8888 =============
[06:52:33] [PASSED] single_pixel_source_buffer
[06:52:33] [PASSED] single_pixel_clip_rectangle
[06:52:33] [PASSED] well_known_colors
[06:52:33] [PASSED] destination_pitch
[06:52:33] ======== [PASSED] drm_test_fb_xrgb8888_to_abgr8888 =========
[06:52:33] ================= drm_test_fb_clip_offset =================
[06:52:33] [PASSED] pass through
[06:52:33] [PASSED] horizontal offset
[06:52:33] [PASSED] vertical offset
[06:52:33] [PASSED] horizontal and vertical offset
[06:52:33] [PASSED] horizontal offset (custom pitch)
[06:52:33] [PASSED] vertical offset (custom pitch)
[06:52:33] [PASSED] horizontal and vertical offset (custom pitch)
[06:52:33] ============= [PASSED] drm_test_fb_clip_offset =============
[06:52:33] =================== drm_test_fb_memcpy ====================
[06:52:33] [PASSED] single_pixel_source_buffer: XR24 little-endian (0x34325258)
[06:52:33] [PASSED] single_pixel_source_buffer: XRA8 little-endian (0x38415258)
[06:52:33] [PASSED] single_pixel_source_buffer: YU24 little-endian (0x34325559)
[06:52:33] [PASSED] single_pixel_clip_rectangle: XB24 little-endian (0x34324258)
[06:52:33] [PASSED] single_pixel_clip_rectangle: XRA8 little-endian (0x38415258)
[06:52:33] [PASSED] single_pixel_clip_rectangle: YU24 little-endian (0x34325559)
[06:52:33] [PASSED] well_known_colors: XB24 little-endian (0x34324258)
[06:52:33] [PASSED] well_known_colors: XRA8 little-endian (0x38415258)
[06:52:33] [PASSED] well_known_colors: YU24 little-endian (0x34325559)
[06:52:33] [PASSED] destination_pitch: XB24 little-endian (0x34324258)
[06:52:33] [PASSED] destination_pitch: XRA8 little-endian (0x38415258)
[06:52:33] [PASSED] destination_pitch: YU24 little-endian (0x34325559)
[06:52:33] =============== [PASSED] drm_test_fb_memcpy ================
[06:52:33] ============= [PASSED] drm_format_helper_test ==============
[06:52:33] ================= drm_format (18 subtests) =================
[06:52:33] [PASSED] drm_test_format_block_width_invalid
[06:52:33] [PASSED] drm_test_format_block_width_one_plane
[06:52:33] [PASSED] drm_test_format_block_width_two_plane
[06:52:33] [PASSED] drm_test_format_block_width_three_plane
[06:52:33] [PASSED] drm_test_format_block_width_tiled
[06:52:33] [PASSED] drm_test_format_block_height_invalid
[06:52:33] [PASSED] drm_test_format_block_height_one_plane
[06:52:33] [PASSED] drm_test_format_block_height_two_plane
[06:52:33] [PASSED] drm_test_format_block_height_three_plane
[06:52:33] [PASSED] drm_test_format_block_height_tiled
[06:52:33] [PASSED] drm_test_format_min_pitch_invalid
[06:52:33] [PASSED] drm_test_format_min_pitch_one_plane_8bpp
[06:52:33] [PASSED] drm_test_format_min_pitch_one_plane_16bpp
[06:52:33] [PASSED] drm_test_format_min_pitch_one_plane_24bpp
[06:52:33] [PASSED] drm_test_format_min_pitch_one_plane_32bpp
[06:52:33] [PASSED] drm_test_format_min_pitch_two_plane
[06:52:33] [PASSED] drm_test_format_min_pitch_three_plane_8bpp
[06:52:33] [PASSED] drm_test_format_min_pitch_tiled
[06:52:33] =================== [PASSED] drm_format ====================
[06:52:33] ============== drm_framebuffer (10 subtests) ===============
[06:52:33] ========== drm_test_framebuffer_check_src_coords ==========
[06:52:33] [PASSED] Success: source fits into fb
[06:52:33] [PASSED] Fail: overflowing fb with x-axis coordinate
[06:52:33] [PASSED] Fail: overflowing fb with y-axis coordinate
[06:52:33] [PASSED] Fail: overflowing fb with source width
[06:52:33] [PASSED] Fail: overflowing fb with source height
[06:52:33] ====== [PASSED] drm_test_framebuffer_check_src_coords ======
[06:52:33] [PASSED] drm_test_framebuffer_cleanup
[06:52:33] =============== drm_test_framebuffer_create ===============
[06:52:33] [PASSED] ABGR8888 normal sizes
[06:52:33] [PASSED] ABGR8888 max sizes
[06:52:33] [PASSED] ABGR8888 pitch greater than min required
[06:52:33] [PASSED] ABGR8888 pitch less than min required
[06:52:33] [PASSED] ABGR8888 Invalid width
[06:52:33] [PASSED] ABGR8888 Invalid buffer handle
[06:52:33] [PASSED] No pixel format
[06:52:33] [PASSED] ABGR8888 Width 0
[06:52:33] [PASSED] ABGR8888 Height 0
[06:52:33] [PASSED] ABGR8888 Out of bound height * pitch combination
[06:52:33] [PASSED] ABGR8888 Large buffer offset
[06:52:33] [PASSED] ABGR8888 Buffer offset for inexistent plane
[06:52:33] [PASSED] ABGR8888 Invalid flag
[06:52:33] [PASSED] ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers
[06:52:33] [PASSED] ABGR8888 Valid buffer modifier
[06:52:33] [PASSED] ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
[06:52:33] [PASSED] ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS
[06:52:33] [PASSED] ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS
[06:52:33] [PASSED] NV12 Normal sizes
[06:52:33] [PASSED] NV12 Max sizes
[06:52:33] [PASSED] NV12 Invalid pitch
[06:52:33] [PASSED] NV12 Invalid modifier/missing DRM_MODE_FB_MODIFIERS flag
[06:52:33] [PASSED] NV12 different modifier per-plane
[06:52:33] [PASSED] NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
[06:52:33] [PASSED] NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS
[06:52:33] [PASSED] NV12 Modifier for inexistent plane
[06:52:33] [PASSED] NV12 Handle for inexistent plane
[06:52:33] [PASSED] NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS
[06:52:33] [PASSED] YVU420 DRM_MODE_FB_MODIFIERS set without modifier
[06:52:33] [PASSED] YVU420 Normal sizes
[06:52:33] [PASSED] YVU420 Max sizes
[06:52:33] [PASSED] YVU420 Invalid pitch
[06:52:33] [PASSED] YVU420 Different pitches
[06:52:33] [PASSED] YVU420 Different buffer offsets/pitches
[06:52:33] [PASSED] YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS
[06:52:33] [PASSED] YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS
[06:52:33] [PASSED] YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS
[06:52:33] [PASSED] YVU420 Valid modifier
[06:52:33] [PASSED] YVU420 Different modifiers per plane
[06:52:33] [PASSED] YVU420 Modifier for inexistent plane
[06:52:33] [PASSED] YUV420_10BIT Invalid modifier(DRM_FORMAT_MOD_LINEAR)
[06:52:33] [PASSED] X0L2 Normal sizes
[06:52:33] [PASSED] X0L2 Max sizes
[06:52:33] [PASSED] X0L2 Invalid pitch
[06:52:33] [PASSED] X0L2 Pitch greater than minimum required
[06:52:33] [PASSED] X0L2 Handle for inexistent plane
[06:52:33] [PASSED] X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set
[06:52:33] [PASSED] X0L2 Modifier without DRM_MODE_FB_MODIFIERS set
[06:52:33] [PASSED] X0L2 Valid modifier
[06:52:33] [PASSED] X0L2 Modifier for inexistent plane
[06:52:33] =========== [PASSED] drm_test_framebuffer_create ===========
[06:52:33] [PASSED] drm_test_framebuffer_free
[06:52:33] [PASSED] drm_test_framebuffer_init
[06:52:33] [PASSED] drm_test_framebuffer_init_bad_format
[06:52:33] [PASSED] drm_test_framebuffer_init_dev_mismatch
[06:52:33] [PASSED] drm_test_framebuffer_lookup
[06:52:33] [PASSED] drm_test_framebuffer_lookup_inexistent
[06:52:33] [PASSED] drm_test_framebuffer_modifiers_not_supported
[06:52:33] ================= [PASSED] drm_framebuffer =================
[06:52:33] ================ drm_gem_shmem (8 subtests) ================
[06:52:33] [PASSED] drm_gem_shmem_test_obj_create
[06:52:33] [PASSED] drm_gem_shmem_test_obj_create_private
[06:52:33] [PASSED] drm_gem_shmem_test_pin_pages
[06:52:33] [PASSED] drm_gem_shmem_test_vmap
[06:52:33] [PASSED] drm_gem_shmem_test_get_sg_table
[06:52:33] [PASSED] drm_gem_shmem_test_get_pages_sgt
[06:52:33] [PASSED] drm_gem_shmem_test_madvise
[06:52:33] [PASSED] drm_gem_shmem_test_purge
[06:52:33] ================== [PASSED] drm_gem_shmem ==================
[06:52:33] === drm_atomic_helper_connector_hdmi_check (29 subtests) ===
[06:52:33] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode
[06:52:33] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode_vic_1
[06:52:33] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode
[06:52:33] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode_vic_1
[06:52:33] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode
[06:52:33] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode_vic_1
[06:52:33] ====== drm_test_check_broadcast_rgb_cea_mode_yuv420 =======
[06:52:33] [PASSED] Automatic
[06:52:33] [PASSED] Full
[06:52:33] [PASSED] Limited 16:235
[06:52:33] == [PASSED] drm_test_check_broadcast_rgb_cea_mode_yuv420 ===
[06:52:33] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_changed
[06:52:33] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_not_changed
[06:52:33] [PASSED] drm_test_check_disable_connector
[06:52:33] [PASSED] drm_test_check_hdmi_funcs_reject_rate
[06:52:33] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_rgb
[06:52:33] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_yuv420
[06:52:33] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422
[06:52:33] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420
[06:52:33] [PASSED] drm_test_check_driver_unsupported_fallback_yuv420
[06:52:33] [PASSED] drm_test_check_output_bpc_crtc_mode_changed
[06:52:33] [PASSED] drm_test_check_output_bpc_crtc_mode_not_changed
[06:52:33] [PASSED] drm_test_check_output_bpc_dvi
[06:52:33] [PASSED] drm_test_check_output_bpc_format_vic_1
[06:52:33] [PASSED] drm_test_check_output_bpc_format_display_8bpc_only
[06:52:33] [PASSED] drm_test_check_output_bpc_format_display_rgb_only
[06:52:33] [PASSED] drm_test_check_output_bpc_format_driver_8bpc_only
[06:52:33] [PASSED] drm_test_check_output_bpc_format_driver_rgb_only
[06:52:33] [PASSED] drm_test_check_tmds_char_rate_rgb_8bpc
[06:52:33] [PASSED] drm_test_check_tmds_char_rate_rgb_10bpc
[06:52:33] [PASSED] drm_test_check_tmds_char_rate_rgb_12bpc
[06:52:33] ============ drm_test_check_hdmi_color_format =============
[06:52:33] [PASSED] AUTO -> RGB
[06:52:33] [PASSED] YCBCR422 -> YUV422
[06:52:33] [PASSED] YCBCR420 -> YUV420
[06:52:33] [PASSED] YCBCR444 -> YUV444
[06:52:33] [PASSED] RGB -> RGB
[06:52:33] ======== [PASSED] drm_test_check_hdmi_color_format =========
[06:52:33] ======== drm_test_check_hdmi_color_format_420_only ========
[06:52:33] [PASSED] RGB should fail
[06:52:33] [PASSED] YUV444 should fail
[06:52:33] [PASSED] YUV422 should fail
[06:52:33] [PASSED] YUV420 should work
[06:52:33] ==== [PASSED] drm_test_check_hdmi_color_format_420_only ====
[06:52:33] ===== [PASSED] drm_atomic_helper_connector_hdmi_check ======
[06:52:33] === drm_atomic_helper_connector_hdmi_reset (6 subtests) ====
[06:52:33] [PASSED] drm_test_check_broadcast_rgb_value
[06:52:33] [PASSED] drm_test_check_bpc_8_value
[06:52:33] [PASSED] drm_test_check_bpc_10_value
[06:52:33] [PASSED] drm_test_check_bpc_12_value
[06:52:33] [PASSED] drm_test_check_format_value
[06:52:33] [PASSED] drm_test_check_tmds_char_value
[06:52:33] ===== [PASSED] drm_atomic_helper_connector_hdmi_reset ======
[06:52:33] = drm_atomic_helper_connector_hdmi_mode_valid (7 subtests) =
[06:52:33] [PASSED] drm_test_check_mode_valid
[06:52:33] [PASSED] drm_test_check_mode_valid_reject
[06:52:33] [PASSED] drm_test_check_mode_valid_reject_rate
[06:52:33] [PASSED] drm_test_check_mode_valid_reject_max_clock
[06:52:33] [PASSED] drm_test_check_mode_valid_yuv420_only_max_clock
[06:52:33] [PASSED] drm_test_check_mode_valid_reject_yuv420_only_connector
[06:52:33] [PASSED] drm_test_check_mode_valid_accept_yuv420_also_connector_rgb
[06:52:33] === [PASSED] drm_atomic_helper_connector_hdmi_mode_valid ===
[06:52:33] = drm_atomic_helper_connector_hdmi_infoframes (5 subtests) =
[06:52:33] [PASSED] drm_test_check_infoframes
[06:52:33] [PASSED] drm_test_check_reject_avi_infoframe
[06:52:33] [PASSED] drm_test_check_reject_hdr_infoframe_bpc_8
[06:52:33] [PASSED] drm_test_check_reject_hdr_infoframe_bpc_10
[06:52:33] [PASSED] drm_test_check_reject_audio_infoframe
[06:52:33] === [PASSED] drm_atomic_helper_connector_hdmi_infoframes ===
[06:52:33] ================= drm_managed (2 subtests) =================
[06:52:33] [PASSED] drm_test_managed_release_action
[06:52:33] [PASSED] drm_test_managed_run_action
[06:52:33] =================== [PASSED] drm_managed ===================
[06:52:33] =================== drm_mm (6 subtests) ====================
[06:52:33] [PASSED] drm_test_mm_init
[06:52:33] [PASSED] drm_test_mm_debug
[06:52:33] [PASSED] drm_test_mm_align32
[06:52:33] [PASSED] drm_test_mm_align64
[06:52:33] [PASSED] drm_test_mm_lowest
[06:52:33] [PASSED] drm_test_mm_highest
[06:52:33] ===================== [PASSED] drm_mm ======================
[06:52:33] ============= drm_modes_analog_tv (5 subtests) =============
[06:52:33] [PASSED] drm_test_modes_analog_tv_mono_576i
[06:52:33] [PASSED] drm_test_modes_analog_tv_ntsc_480i
[06:52:33] [PASSED] drm_test_modes_analog_tv_ntsc_480i_inlined
[06:52:33] [PASSED] drm_test_modes_analog_tv_pal_576i
[06:52:33] [PASSED] drm_test_modes_analog_tv_pal_576i_inlined
[06:52:33] =============== [PASSED] drm_modes_analog_tv ===============
[06:52:33] ============== drm_panic_helper (3 subtests) ===============
[06:52:33] ============= drm_test_panic_screen_user_map ==============
[06:52:33] [PASSED] Panic screen user, mode: 1024 x 768 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen user, mode: 494 x 494 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen user, mode: 1920 x 1080 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen user, mode: 1024 x 768 RG16 little-endian (0x36314752)
[06:52:33] [PASSED] Panic screen user, mode: 1024 x 768 RG24 little-endian (0x34324752)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1024 x 768 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen kmsg, mode: 494 x 494 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1920 x 1080 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1024 x 768 RG16 little-endian (0x36314752)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1024 x 768 RG24 little-endian (0x34324752)
[06:52:33] ========= [PASSED] drm_test_panic_screen_user_map ==========
[06:52:33] ============= drm_test_panic_screen_user_page =============
[06:52:33] [PASSED] Panic screen user, mode: 1024 x 768 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen user, mode: 494 x 494 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen user, mode: 1920 x 1080 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen user, mode: 1024 x 768 RG16 little-endian (0x36314752)
[06:52:33] [PASSED] Panic screen user, mode: 1024 x 768 RG24 little-endian (0x34324752)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1024 x 768 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen kmsg, mode: 494 x 494 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1920 x 1080 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1024 x 768 RG16 little-endian (0x36314752)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1024 x 768 RG24 little-endian (0x34324752)
[06:52:33] ========= [PASSED] drm_test_panic_screen_user_page =========
[06:52:33] ========== drm_test_panic_screen_user_set_pixel ===========
[06:52:33] [PASSED] Panic screen user, mode: 1024 x 768 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen user, mode: 494 x 494 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen user, mode: 1920 x 1080 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen user, mode: 1024 x 768 RG16 little-endian (0x36314752)
[06:52:33] [PASSED] Panic screen user, mode: 1024 x 768 RG24 little-endian (0x34324752)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1024 x 768 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen kmsg, mode: 494 x 494 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1920 x 1080 XR24 little-endian (0x34325258)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1024 x 768 RG16 little-endian (0x36314752)
[06:52:33] [PASSED] Panic screen kmsg, mode: 1024 x 768 RG24 little-endian (0x34324752)
[06:52:33] ====== [PASSED] drm_test_panic_screen_user_set_pixel =======
[06:52:33] ================ [PASSED] drm_panic_helper =================
[06:52:33] ============== drm_plane_helper (2 subtests) ===============
[06:52:33] =============== drm_test_check_plane_state ================
[06:52:33] [PASSED] clipping_simple
[06:52:33] [PASSED] clipping_rotate_reflect
[06:52:33] [PASSED] positioning_simple
[06:52:33] [PASSED] upscaling
[06:52:33] [PASSED] downscaling
[06:52:33] [PASSED] rounding1
[06:52:33] [PASSED] rounding2
[06:52:33] [PASSED] rounding3
[06:52:33] [PASSED] rounding4
[06:52:33] =========== [PASSED] drm_test_check_plane_state ============
[06:52:33] =========== drm_test_check_invalid_plane_state ============
[06:52:33] [PASSED] positioning_invalid
[06:52:33] [PASSED] upscaling_invalid
[06:52:33] [PASSED] downscaling_invalid
[06:52:33] ======= [PASSED] drm_test_check_invalid_plane_state ========
[06:52:33] ================ [PASSED] drm_plane_helper =================
[06:52:33] ====== drm_connector_helper_tv_get_modes (1 subtest) =======
[06:52:33] ====== drm_test_connector_helper_tv_get_modes_check =======
[06:52:33] [PASSED] None
[06:52:33] [PASSED] PAL
[06:52:33] [PASSED] NTSC
[06:52:33] [PASSED] Both, NTSC Default
[06:52:33] [PASSED] Both, PAL Default
[06:52:33] [PASSED] Both, NTSC Default, with PAL on command-line
[06:52:33] [PASSED] Both, PAL Default, with NTSC on command-line
[06:52:33] == [PASSED] drm_test_connector_helper_tv_get_modes_check ===
[06:52:33] ======== [PASSED] drm_connector_helper_tv_get_modes ========
[06:52:33] ================== drm_rect (9 subtests) ===================
[06:52:33] [PASSED] drm_test_rect_clip_scaled_div_by_zero
[06:52:33] [PASSED] drm_test_rect_clip_scaled_not_clipped
[06:52:33] [PASSED] drm_test_rect_clip_scaled_clipped
[06:52:33] [PASSED] drm_test_rect_clip_scaled_signed_vs_unsigned
[06:52:33] ================= drm_test_rect_intersect =================
[06:52:33] [PASSED] top-left x bottom-right: 2x2+1+1 x 2x2+0+0
[06:52:33] [PASSED] top-right x bottom-left: 2x2+0+0 x 2x2+1-1
[06:52:33] [PASSED] bottom-left x top-right: 2x2+1-1 x 2x2+0+0
[06:52:33] [PASSED] bottom-right x top-left: 2x2+0+0 x 2x2+1+1
[06:52:33] [PASSED] right x left: 2x1+0+0 x 3x1+1+0
[06:52:33] [PASSED] left x right: 3x1+1+0 x 2x1+0+0
[06:52:33] [PASSED] up x bottom: 1x2+0+0 x 1x3+0-1
[06:52:33] [PASSED] bottom x up: 1x3+0-1 x 1x2+0+0
[06:52:33] [PASSED] touching corner: 1x1+0+0 x 2x2+1+1
[06:52:33] [PASSED] touching side: 1x1+0+0 x 1x1+1+0
[06:52:33] [PASSED] equal rects: 2x2+0+0 x 2x2+0+0
[06:52:33] [PASSED] inside another: 2x2+0+0 x 1x1+1+1
[06:52:33] [PASSED] far away: 1x1+0+0 x 1x1+3+6
[06:52:33] [PASSED] points intersecting: 0x0+5+10 x 0x0+5+10
[06:52:33] [PASSED] points not intersecting: 0x0+0+0 x 0x0+5+10
[06:52:33] ============= [PASSED] drm_test_rect_intersect =============
[06:52:33] ================ drm_test_rect_calc_hscale ================
[06:52:33] [PASSED] normal use
[06:52:33] [PASSED] out of max range
[06:52:33] [PASSED] out of min range
[06:52:33] [PASSED] zero dst
[06:52:33] [PASSED] negative src
[06:52:33] [PASSED] negative dst
[06:52:33] ============ [PASSED] drm_test_rect_calc_hscale ============
[06:52:33] ================ drm_test_rect_calc_vscale ================
[06:52:33] [PASSED] normal use
[06:52:33] [PASSED] out of max range
[06:52:33] [PASSED] out of min range
[06:52:33] [PASSED] zero dst
[06:52:33] [PASSED] negative src
[06:52:33] [PASSED] negative dst
[06:52:33] ============ [PASSED] drm_test_rect_calc_vscale ============
[06:52:33] ================== drm_test_rect_rotate ===================
[06:52:33] [PASSED] reflect-x
[06:52:33] [PASSED] reflect-y
[06:52:33] [PASSED] rotate-0
[06:52:33] [PASSED] rotate-90
[06:52:33] [PASSED] rotate-180
[06:52:33] [PASSED] rotate-270
[06:52:33] ============== [PASSED] drm_test_rect_rotate ===============
[06:52:33] ================ drm_test_rect_rotate_inv =================
[06:52:33] [PASSED] reflect-x
[06:52:33] [PASSED] reflect-y
[06:52:33] [PASSED] rotate-0
[06:52:33] [PASSED] rotate-90
[06:52:33] [PASSED] rotate-180
[06:52:33] [PASSED] rotate-270
[06:52:33] ============ [PASSED] drm_test_rect_rotate_inv =============
[06:52:33] ==================== [PASSED] drm_rect =====================
[06:52:33] ============ drm_sysfb_modeset_test (1 subtest) ============
[06:52:33] ============ drm_test_sysfb_build_fourcc_list =============
[06:52:33] [PASSED] no native formats
[06:52:33] [PASSED] XRGB8888 as native format
[06:52:33] [PASSED] remove duplicates
[06:52:33] [PASSED] convert alpha formats
[06:52:33] [PASSED] random formats
[06:52:33] ======== [PASSED] drm_test_sysfb_build_fourcc_list =========
[06:52:33] ============= [PASSED] drm_sysfb_modeset_test ==============
[06:52:33] ================== drm_fixp (2 subtests) ===================
[06:52:33] [PASSED] drm_test_int2fixp
[06:52:33] [PASSED] drm_test_sm2fixp
[06:52:33] ==================== [PASSED] drm_fixp =====================
[06:52:33] ============================================================
[06:52:33] Testing complete. Ran 667 tests: passed: 667
[06:52:33] Elapsed time: 27.740s total, 1.842s configuring, 25.431s building, 0.459s running
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/drm/ttm/tests/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/ttm/tests/.kunitconfig
[06:52:34] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[06:52:35] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[06:52:46] Starting KUnit Kernel (1/1)...
[06:52:46] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[06:52:46] ================= ttm_device (5 subtests) ==================
[06:52:46] [PASSED] ttm_device_init_basic
[06:52:46] [PASSED] ttm_device_init_multiple
[06:52:46] [PASSED] ttm_device_fini_basic
[06:52:46] [PASSED] ttm_device_init_no_vma_man
[06:52:46] ================== ttm_device_init_pools ==================
[06:52:46] [PASSED] No DMA allocations, no DMA32 required
[06:52:46] [PASSED] DMA allocations, DMA32 required
[06:52:46] [PASSED] No DMA allocations, DMA32 required
[06:52:46] [PASSED] DMA allocations, no DMA32 required
[06:52:46] ============== [PASSED] ttm_device_init_pools ==============
[06:52:46] =================== [PASSED] ttm_device ====================
[06:52:46] ================== ttm_pool (8 subtests) ===================
[06:52:46] ================== ttm_pool_alloc_basic ===================
[06:52:46] [PASSED] One page
[06:52:46] [PASSED] More than one page
[06:52:46] [PASSED] Above the allocation limit
[06:52:46] [PASSED] One page, with coherent DMA mappings enabled
[06:52:46] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[06:52:46] ============== [PASSED] ttm_pool_alloc_basic ===============
[06:52:46] ============== ttm_pool_alloc_basic_dma_addr ==============
[06:52:46] [PASSED] One page
[06:52:46] [PASSED] More than one page
[06:52:46] [PASSED] Above the allocation limit
[06:52:46] [PASSED] One page, with coherent DMA mappings enabled
[06:52:46] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[06:52:46] ========== [PASSED] ttm_pool_alloc_basic_dma_addr ==========
[06:52:46] [PASSED] ttm_pool_alloc_order_caching_match
[06:52:46] [PASSED] ttm_pool_alloc_caching_mismatch
[06:52:46] [PASSED] ttm_pool_alloc_order_mismatch
[06:52:46] [PASSED] ttm_pool_free_dma_alloc
[06:52:46] [PASSED] ttm_pool_free_no_dma_alloc
[06:52:46] [PASSED] ttm_pool_fini_basic
[06:52:46] ==================== [PASSED] ttm_pool =====================
[06:52:46] ================ ttm_resource (8 subtests) =================
[06:52:46] ================= ttm_resource_init_basic =================
[06:52:46] [PASSED] Init resource in TTM_PL_SYSTEM
[06:52:46] [PASSED] Init resource in TTM_PL_VRAM
[06:52:46] [PASSED] Init resource in a private placement
[06:52:46] [PASSED] Init resource in TTM_PL_SYSTEM, set placement flags
[06:52:46] ============= [PASSED] ttm_resource_init_basic =============
[06:52:46] [PASSED] ttm_resource_init_pinned
[06:52:46] [PASSED] ttm_resource_fini_basic
[06:52:46] [PASSED] ttm_resource_manager_init_basic
[06:52:46] [PASSED] ttm_resource_manager_usage_basic
[06:52:46] [PASSED] ttm_resource_manager_set_used_basic
[06:52:46] [PASSED] ttm_sys_man_alloc_basic
[06:52:46] [PASSED] ttm_sys_man_free_basic
[06:52:46] ================== [PASSED] ttm_resource ===================
[06:52:46] =================== ttm_tt (15 subtests) ===================
[06:52:46] ==================== ttm_tt_init_basic ====================
[06:52:46] [PASSED] Page-aligned size
[06:52:46] [PASSED] Extra pages requested
[06:52:46] ================ [PASSED] ttm_tt_init_basic ================
[06:52:46] [PASSED] ttm_tt_init_misaligned
[06:52:46] [PASSED] ttm_tt_fini_basic
[06:52:46] [PASSED] ttm_tt_fini_sg
[06:52:46] [PASSED] ttm_tt_fini_shmem
[06:52:46] [PASSED] ttm_tt_create_basic
[06:52:46] [PASSED] ttm_tt_create_invalid_bo_type
[06:52:46] [PASSED] ttm_tt_create_ttm_exists
[06:52:46] [PASSED] ttm_tt_create_failed
[06:52:46] [PASSED] ttm_tt_destroy_basic
[06:52:46] [PASSED] ttm_tt_populate_null_ttm
[06:52:46] [PASSED] ttm_tt_populate_populated_ttm
[06:52:46] [PASSED] ttm_tt_unpopulate_basic
[06:52:46] [PASSED] ttm_tt_unpopulate_empty_ttm
[06:52:46] [PASSED] ttm_tt_swapin_basic
[06:52:46] ===================== [PASSED] ttm_tt ======================
[06:52:46] =================== ttm_bo (14 subtests) ===================
[06:52:46] =========== ttm_bo_reserve_optimistic_no_ticket ===========
[06:52:46] [PASSED] Cannot be interrupted and sleeps
[06:52:46] [PASSED] Cannot be interrupted, locks straight away
[06:52:46] [PASSED] Can be interrupted, sleeps
[06:52:46] ======= [PASSED] ttm_bo_reserve_optimistic_no_ticket =======
[06:52:46] [PASSED] ttm_bo_reserve_locked_no_sleep
[06:52:46] [PASSED] ttm_bo_reserve_no_wait_ticket
[06:52:46] [PASSED] ttm_bo_reserve_double_resv
[06:52:46] [PASSED] ttm_bo_reserve_interrupted
[06:52:46] [PASSED] ttm_bo_reserve_deadlock
[06:52:46] [PASSED] ttm_bo_unreserve_basic
[06:52:46] [PASSED] ttm_bo_unreserve_pinned
[06:52:46] [PASSED] ttm_bo_unreserve_bulk
[06:52:46] [PASSED] ttm_bo_fini_basic
[06:52:46] [PASSED] ttm_bo_fini_shared_resv
[06:52:46] [PASSED] ttm_bo_pin_basic
[06:52:46] [PASSED] ttm_bo_pin_unpin_resource
[06:52:46] [PASSED] ttm_bo_multiple_pin_one_unpin
[06:52:46] ===================== [PASSED] ttm_bo ======================
[06:52:46] ============== ttm_bo_validate (22 subtests) ===============
[06:52:46] ============== ttm_bo_init_reserved_sys_man ===============
[06:52:46] [PASSED] Buffer object for userspace
[06:52:46] [PASSED] Kernel buffer object
[06:52:46] [PASSED] Shared buffer object
[06:52:46] ========== [PASSED] ttm_bo_init_reserved_sys_man ===========
[06:52:46] ============== ttm_bo_init_reserved_mock_man ==============
[06:52:46] [PASSED] Buffer object for userspace
[06:52:46] [PASSED] Kernel buffer object
[06:52:46] [PASSED] Shared buffer object
[06:52:46] ========== [PASSED] ttm_bo_init_reserved_mock_man ==========
[06:52:46] [PASSED] ttm_bo_init_reserved_resv
[06:52:46] ================== ttm_bo_validate_basic ==================
[06:52:46] [PASSED] Buffer object for userspace
[06:52:46] [PASSED] Kernel buffer object
[06:52:46] [PASSED] Shared buffer object
[06:52:46] ============== [PASSED] ttm_bo_validate_basic ==============
[06:52:46] [PASSED] ttm_bo_validate_invalid_placement
[06:52:46] ============= ttm_bo_validate_same_placement ==============
[06:52:46] [PASSED] System manager
[06:52:46] [PASSED] VRAM manager
[06:52:46] ========= [PASSED] ttm_bo_validate_same_placement ==========
[06:52:46] [PASSED] ttm_bo_validate_failed_alloc
[06:52:46] [PASSED] ttm_bo_validate_pinned
[06:52:46] [PASSED] ttm_bo_validate_busy_placement
[06:52:46] ================ ttm_bo_validate_multihop =================
[06:52:46] [PASSED] Buffer object for userspace
[06:52:46] [PASSED] Kernel buffer object
[06:52:46] [PASSED] Shared buffer object
[06:52:46] ============ [PASSED] ttm_bo_validate_multihop =============
[06:52:46] ========== ttm_bo_validate_no_placement_signaled ==========
[06:52:46] [PASSED] Buffer object in system domain, no page vector
[06:52:46] [PASSED] Buffer object in system domain with an existing page vector
[06:52:46] ====== [PASSED] ttm_bo_validate_no_placement_signaled ======
[06:52:46] ======== ttm_bo_validate_no_placement_not_signaled ========
[06:52:46] [PASSED] Buffer object for userspace
[06:52:46] [PASSED] Kernel buffer object
[06:52:46] [PASSED] Shared buffer object
[06:52:46] ==== [PASSED] ttm_bo_validate_no_placement_not_signaled ====
[06:52:46] [PASSED] ttm_bo_validate_move_fence_signaled
[06:52:46] ========= ttm_bo_validate_move_fence_not_signaled =========
[06:52:46] [PASSED] Waits for GPU
[06:52:46] [PASSED] Tries to lock straight away
[06:52:46] ===== [PASSED] ttm_bo_validate_move_fence_not_signaled =====
[06:52:46] [PASSED] ttm_bo_validate_swapout
[06:52:46] [PASSED] ttm_bo_validate_happy_evict
[06:52:46] [PASSED] ttm_bo_validate_all_pinned_evict
[06:52:46] [PASSED] ttm_bo_validate_allowed_only_evict
[06:52:46] [PASSED] ttm_bo_validate_deleted_evict
[06:52:46] [PASSED] ttm_bo_validate_busy_domain_evict
[06:52:46] [PASSED] ttm_bo_validate_evict_gutting
[06:52:46] [PASSED] ttm_bo_validate_recrusive_evict
[06:52:46] ================= [PASSED] ttm_bo_validate =================
[06:52:46] ============================================================
[06:52:46] Testing complete. Ran 102 tests: passed: 102
[06:52:46] Elapsed time: 12.468s total, 1.793s configuring, 10.411s building, 0.232s running
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/dma-buf/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/dma-buf/.kunitconfig
[06:52:46] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[06:52:48] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[06:52:57] Starting KUnit Kernel (1/1)...
[06:52:57] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[06:52:57] =============== dma-buf-fence (12 subtests) ================
[06:52:57] [PASSED] test_sanitycheck
[06:52:57] [PASSED] test_signaling
[06:52:57] [PASSED] test_add_callback
[06:52:57] [PASSED] test_late_add_callback
[06:52:57] [PASSED] test_rm_callback
[06:52:57] [PASSED] test_late_rm_callback
[06:52:57] [PASSED] test_status
[06:52:57] [PASSED] test_error
[06:52:57] [PASSED] test_wait
[06:52:57] [PASSED] test_wait_timeout
[06:52:57] [PASSED] test_stub
[06:52:57] [SKIPPED] test_race_signal_callback (requires at least 2 CPUs)
[06:52:57] ================== [PASSED] dma-buf-fence ==================
[06:52:57] ============ dma-buf-fence-chain (11 subtests) =============
[06:52:57] [PASSED] test_sanitycheck
[06:52:57] [PASSED] test_find_seqno
[06:52:57] [PASSED] test_find_signaled
[06:52:57] [PASSED] test_find_out_of_order
[06:53:02] [PASSED] test_find_gap
[06:53:02] [PASSED] test_find_race
[06:53:02] [PASSED] test_signal_forward
[06:53:02] [PASSED] test_signal_backward
[06:53:02] [PASSED] test_wait_forward
[06:53:02] [PASSED] test_wait_backward
[06:53:02] [PASSED] test_wait_random
[06:53:02] =============== [PASSED] dma-buf-fence-chain ===============
[06:53:02] ============ dma-buf-fence-unwrap (11 subtests) ============
[06:53:02] [PASSED] test_sanitycheck
[06:53:02] [PASSED] test_unwrap_array
[06:53:02] [PASSED] test_unwrap_chain
[06:53:02] [PASSED] test_unwrap_chain_array
[06:53:02] [PASSED] test_unwrap_merge
[06:53:02] [PASSED] test_unwrap_merge_duplicate
[06:53:02] [PASSED] test_unwrap_merge_seqno
[06:53:02] [PASSED] test_unwrap_merge_order
[06:53:02] [PASSED] test_unwrap_merge_complex
[06:53:02] [PASSED] test_unwrap_merge_complex_seqno
[06:53:02] [PASSED] test_dedup_empty
[06:53:02] ============== [PASSED] dma-buf-fence-unwrap ===============
[06:53:02] ================ dma-buf-resv (5 subtests) =================
[06:53:02] [PASSED] test_sanitycheck
[06:53:02] ===================== test_signaling ======================
[06:53:02] [PASSED] kernel
[06:53:02] [PASSED] write
[06:53:02] [PASSED] read
[06:53:02] [PASSED] bookkeep
[06:53:02] ================= [PASSED] test_signaling ==================
[06:53:02] ====================== test_for_each ======================
[06:53:02] [PASSED] kernel
[06:53:02] [PASSED] write
[06:53:02] [PASSED] read
[06:53:02] [PASSED] bookkeep
[06:53:02] ================== [PASSED] test_for_each ==================
[06:53:02] ================= test_for_each_unlocked ==================
[06:53:02] [PASSED] kernel
[06:53:02] [PASSED] write
[06:53:02] [PASSED] read
[06:53:02] [PASSED] bookkeep
[06:53:02] ============= [PASSED] test_for_each_unlocked ==============
[06:53:02] ===================== test_get_fences =====================
[06:53:02] [PASSED] kernel
[06:53:02] [PASSED] write
[06:53:02] [PASSED] read
[06:53:02] [PASSED] bookkeep
[06:53:02] ================= [PASSED] test_get_fences =================
[06:53:02] ================== [PASSED] dma-buf-resv ===================
[06:53:02] ============================================================
[06:53:02] Testing complete. Ran 51 tests: passed: 50, skipped: 1
[06:53:02] Elapsed time: 16.106s total, 1.915s configuring, 8.819s building, 5.336s running
+ cleanup
++ stat -c %u:%g /kernel
+ chown -R 1003:1003 /kernel
^ permalink raw reply [flat|nested] 33+ messages in thread* ✗ CI.checksparse: warning for Migrate on fault for device pages (rev8)
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (13 preceding siblings ...)
2026-10-21 6:53 ` ✓ CI.KUnit: success " Patchwork
@ 2026-10-21 7:09 ` Patchwork
2026-10-21 7:29 ` ✓ Xe.CI.BAT: success " Patchwork
2026-10-21 9:50 ` ✗ Xe.CI.FULL: failure " Patchwork
16 siblings, 0 replies; 33+ messages in thread
From: Patchwork @ 2026-10-21 7:09 UTC (permalink / raw)
To: Mika Penttilä; +Cc: intel-xe
== Series Details ==
Series: Migrate on fault for device pages (rev8)
URL : https://patchwork.freedesktop.org/series/165953/
State : warning
== Summary ==
+ trap cleanup EXIT
+ KERNEL=/kernel
+ MT=/root/linux/maintainer-tools
+ git clone https://gitlab.freedesktop.org/drm/maintainer-tools /root/linux/maintainer-tools
Cloning into '/root/linux/maintainer-tools'...
warning: redirecting to https://gitlab.freedesktop.org/drm/maintainer-tools.git/
+ make -C /root/linux/maintainer-tools
make: Entering directory '/root/linux/maintainer-tools'
cc -O2 -g -Wextra -o remap-log remap-log.c
make: Leaving directory '/root/linux/maintainer-tools'
+ cd /kernel
+ git config --global --add safe.directory /kernel
+ /root/linux/maintainer-tools/dim sparse --fast f3bbda7128124e54c4881b56958249a18d79a110
Sparse version: 0.6.4 (Ubuntu: 0.6.4-4ubuntu3)
Fast mode used, each commit won't be checked separately.
+/kernel/Makefile:1300: C=1 specified, but sparse is not available or not up to date
+ cleanup
++ stat -c %u:%g /kernel
+ chown -R 1003:1003 /kernel
^ permalink raw reply [flat|nested] 33+ messages in thread* ✓ Xe.CI.BAT: success for Migrate on fault for device pages (rev8)
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (14 preceding siblings ...)
2026-10-21 7:09 ` ✗ CI.checksparse: warning " Patchwork
@ 2026-10-21 7:29 ` Patchwork
2026-10-21 9:50 ` ✗ Xe.CI.FULL: failure " Patchwork
16 siblings, 0 replies; 33+ messages in thread
From: Patchwork @ 2026-10-21 7:29 UTC (permalink / raw)
To: Mika Penttilä; +Cc: intel-xe
[-- Attachment #1: Type: text/plain, Size: 856 bytes --]
== Series Details ==
Series: Migrate on fault for device pages (rev8)
URL : https://patchwork.freedesktop.org/series/165953/
State : success
== Summary ==
CI Bug Log - changes from xe-5986-f3bbda7128124e54c4881b56958249a18d79a110_BAT -> xe-pw-165953v8_BAT
====================================================
Summary
-------
**SUCCESS**
No regressions found.
Participating hosts (15 -> 14)
------------------------------
Missing (1): bat-bmg-3
Changes
-------
No changes found
Build changes
-------------
* Linux: xe-5986-f3bbda7128124e54c4881b56958249a18d79a110 -> xe-pw-165953v8
IGT_9156: 9156
xe-5986-f3bbda7128124e54c4881b56958249a18d79a110: f3bbda7128124e54c4881b56958249a18d79a110
xe-pw-165953v8: 165953v8
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/index.html
[-- Attachment #2: Type: text/html, Size: 1404 bytes --]
^ permalink raw reply [flat|nested] 33+ messages in thread* ✗ Xe.CI.FULL: failure for Migrate on fault for device pages (rev8)
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
` (15 preceding siblings ...)
2026-10-21 7:29 ` ✓ Xe.CI.BAT: success " Patchwork
@ 2026-10-21 9:50 ` Patchwork
16 siblings, 0 replies; 33+ messages in thread
From: Patchwork @ 2026-10-21 9:50 UTC (permalink / raw)
To: Mika Penttilä; +Cc: intel-xe
[-- Attachment #1: Type: text/plain, Size: 65665 bytes --]
== Series Details ==
Series: Migrate on fault for device pages (rev8)
URL : https://patchwork.freedesktop.org/series/165953/
State : failure
== Summary ==
CI Bug Log - changes from xe-5986-f3bbda7128124e54c4881b56958249a18d79a110_FULL -> xe-pw-165953v8_FULL
====================================================
Summary
-------
**FAILURE**
Serious unknown changes coming with xe-pw-165953v8_FULL absolutely need to be
verified manually.
If you think the reported changes have nothing to do with the changes
introduced in xe-pw-165953v8_FULL, please notify your bug team (I915-ci-infra@lists.freedesktop.org) to allow them
to document this new failure mode, which will reduce false positives in CI.
Participating hosts (3 -> 3)
------------------------------
No changes in participating hosts
Possible new issues
-------------------
Here are the unknown changes that may have been introduced in xe-pw-165953v8_FULL:
### IGT changes ###
#### Possible regressions ####
* igt@kms_flip@2x-flip-vs-dpms-on-nop-interruptible:
- shard-bmg: [PASS][1] -> [DMESG-WARN][2] +11 other tests dmesg-warn
[1]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-2/igt@kms_flip@2x-flip-vs-dpms-on-nop-interruptible.html
[2]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_flip@2x-flip-vs-dpms-on-nop-interruptible.html
* igt@kms_setmode@basic-no-cpu-idle@pipe-c-dp-2-pipe-a-hdmi-a-3:
- shard-bmg: NOTRUN -> [FAIL][3] +2 other tests fail
[3]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_setmode@basic-no-cpu-idle@pipe-c-dp-2-pipe-a-hdmi-a-3.html
#### Warnings ####
* igt@xe_module_load@load:
- shard-bmg: ([PASS][4], [PASS][5], [PASS][6], [PASS][7], [PASS][8], [PASS][9], [PASS][10], [PASS][11], [PASS][12], [PASS][13], [PASS][14], [PASS][15], [SKIP][16], [PASS][17], [PASS][18], [PASS][19], [PASS][20], [PASS][21], [PASS][22], [PASS][23], [PASS][24], [PASS][25], [PASS][26], [PASS][27], [PASS][28], [PASS][29]) ([Intel XE#2457] / [Intel XE#7405]) -> ([PASS][30], [PASS][31], [PASS][32], [PASS][33], [PASS][34], [SKIP][35], [PASS][36], [PASS][37], [PASS][38], [PASS][39], [PASS][40], [PASS][41], [PASS][42], [PASS][43], [PASS][44], [PASS][45], [PASS][46], [PASS][47], [DMESG-WARN][48], [DMESG-WARN][49], [PASS][50], [PASS][51], [PASS][52], [PASS][53], [PASS][54], [PASS][55]) ([Intel XE#2457] / [Intel XE#7405])
[4]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-4/igt@xe_module_load@load.html
[5]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-5/igt@xe_module_load@load.html
[6]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-4/igt@xe_module_load@load.html
[7]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-2/igt@xe_module_load@load.html
[8]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-9/igt@xe_module_load@load.html
[9]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-9/igt@xe_module_load@load.html
[10]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-1/igt@xe_module_load@load.html
[11]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-1/igt@xe_module_load@load.html
[12]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-6/igt@xe_module_load@load.html
[13]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-6/igt@xe_module_load@load.html
[14]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-1/igt@xe_module_load@load.html
[15]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-8/igt@xe_module_load@load.html
[16]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-9/igt@xe_module_load@load.html
[17]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-4/igt@xe_module_load@load.html
[18]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-10/igt@xe_module_load@load.html
[19]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-3/igt@xe_module_load@load.html
[20]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-7/igt@xe_module_load@load.html
[21]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-2/igt@xe_module_load@load.html
[22]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-7/igt@xe_module_load@load.html
[23]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-7/igt@xe_module_load@load.html
[24]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-5/igt@xe_module_load@load.html
[25]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-8/igt@xe_module_load@load.html
[26]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-10/igt@xe_module_load@load.html
[27]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-8/igt@xe_module_load@load.html
[28]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-5/igt@xe_module_load@load.html
[29]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-9/igt@xe_module_load@load.html
[30]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-1/igt@xe_module_load@load.html
[31]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@xe_module_load@load.html
[32]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-5/igt@xe_module_load@load.html
[33]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-5/igt@xe_module_load@load.html
[34]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-2/igt@xe_module_load@load.html
[35]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-2/igt@xe_module_load@load.html
[36]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-2/igt@xe_module_load@load.html
[37]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-2/igt@xe_module_load@load.html
[38]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-9/igt@xe_module_load@load.html
[39]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-5/igt@xe_module_load@load.html
[40]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@xe_module_load@load.html
[41]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-1/igt@xe_module_load@load.html
[42]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-3/igt@xe_module_load@load.html
[43]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-3/igt@xe_module_load@load.html
[44]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_module_load@load.html
[45]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_module_load@load.html
[46]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-7/igt@xe_module_load@load.html
[47]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-1/igt@xe_module_load@load.html
[48]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_module_load@load.html
[49]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_module_load@load.html
[50]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-4/igt@xe_module_load@load.html
[51]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-4/igt@xe_module_load@load.html
[52]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-7/igt@xe_module_load@load.html
[53]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-7/igt@xe_module_load@load.html
[54]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-8/igt@xe_module_load@load.html
[55]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-8/igt@xe_module_load@load.html
Known issues
------------
Here are the changes found in xe-pw-165953v8_FULL that come from known issues:
### IGT changes ###
#### Issues hit ####
* igt@kms_3d@basic:
- shard-lnl: NOTRUN -> [SKIP][56] ([Intel XE#6011])
[56]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_3d@basic.html
* igt@kms_async_flips@alternate-sync-async-flip:
- shard-bmg: [PASS][57] -> [FAIL][58] ([Intel XE#3718] / [Intel XE#6078])
[57]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-1/igt@kms_async_flips@alternate-sync-async-flip.html
[58]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-2/igt@kms_async_flips@alternate-sync-async-flip.html
* igt@kms_async_flips@alternate-sync-async-flip@pipe-b-dp-2:
- shard-bmg: [PASS][59] -> [FAIL][60] ([Intel XE#6078])
[59]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-1/igt@kms_async_flips@alternate-sync-async-flip@pipe-b-dp-2.html
[60]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-2/igt@kms_async_flips@alternate-sync-async-flip@pipe-b-dp-2.html
* igt@kms_async_flips@async-flip-suspend-resume:
- shard-bmg: [PASS][61] -> [ABORT][62] ([Intel XE#9405])
[61]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-3/igt@kms_async_flips@async-flip-suspend-resume.html
[62]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-5/igt@kms_async_flips@async-flip-suspend-resume.html
* igt@kms_async_flips@async-flip-suspend-resume@pipe-c-dp-2:
- shard-bmg: [PASS][63] -> [DMESG-WARN][64] ([Intel XE#9365]) +1 other test dmesg-warn
[63]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-3/igt@kms_async_flips@async-flip-suspend-resume@pipe-c-dp-2.html
[64]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-5/igt@kms_async_flips@async-flip-suspend-resume@pipe-c-dp-2.html
* igt@kms_async_flips@async-flip-suspend-resume@pipe-d-hdmi-a-3:
- shard-bmg: [PASS][65] -> [ABORT][66] ([Intel XE#9375] / [Intel XE#9405])
[65]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-3/igt@kms_async_flips@async-flip-suspend-resume@pipe-d-hdmi-a-3.html
[66]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-5/igt@kms_async_flips@async-flip-suspend-resume@pipe-d-hdmi-a-3.html
* igt@kms_big_fb@4-tiled-64bpp-rotate-270:
- shard-bmg: NOTRUN -> [SKIP][67] ([Intel XE#2327]) +1 other test skip
[67]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_big_fb@4-tiled-64bpp-rotate-270.html
* igt@kms_big_fb@linear-max-hw-stride-64bpp-rotate-180-hflip:
- shard-bmg: NOTRUN -> [SKIP][68] ([Intel XE#7059] / [Intel XE#7085])
[68]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_big_fb@linear-max-hw-stride-64bpp-rotate-180-hflip.html
* igt@kms_big_fb@x-tiled-16bpp-rotate-270:
- shard-lnl: NOTRUN -> [SKIP][69] ([Intel XE#1407]) +1 other test skip
[69]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_big_fb@x-tiled-16bpp-rotate-270.html
* igt@kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip:
- shard-bmg: [PASS][70] -> [DMESG-WARN][71] ([Intel XE#9613])
[70]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-2/igt@kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip.html
[71]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_big_fb@x-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip.html
* igt@kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-0:
- shard-lnl: NOTRUN -> [SKIP][72] ([Intel XE#1124]) +1 other test skip
[72]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_big_fb@y-tiled-max-hw-stride-32bpp-rotate-0.html
* igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip:
- shard-bmg: NOTRUN -> [SKIP][73] ([Intel XE#1124]) +4 other tests skip
[73]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip.html
* igt@kms_big_fb@yf-tiled-64bpp-rotate-180:
- shard-ptl: NOTRUN -> [SKIP][74] ([Intel XE#5808]) +2 other tests skip
[74]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_big_fb@yf-tiled-64bpp-rotate-180.html
* igt@kms_bw@connected-linear-tiling-4-displays-target-2560x1440p:
- shard-lnl: NOTRUN -> [SKIP][75] ([Intel XE#8365]) +2 other tests skip
[75]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_bw@connected-linear-tiling-4-displays-target-2560x1440p.html
* igt@kms_bw@linear-tiling-2-displays-target-2160x1440p:
- shard-bmg: NOTRUN -> [SKIP][76] ([Intel XE#367])
[76]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_bw@linear-tiling-2-displays-target-2160x1440p.html
- shard-ptl: NOTRUN -> [SKIP][77] ([Intel XE#367])
[77]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_bw@linear-tiling-2-displays-target-2160x1440p.html
* igt@kms_ccs@bad-rotation-90-4-tiled-mtl-mc-ccs:
- shard-ptl: NOTRUN -> [SKIP][78] ([Intel XE#5822]) +3 other tests skip
[78]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_ccs@bad-rotation-90-4-tiled-mtl-mc-ccs.html
* igt@kms_ccs@crc-primary-basic-4-tiled-dg2-rc-ccs-cc:
- shard-bmg: NOTRUN -> [SKIP][79] ([Intel XE#2887]) +6 other tests skip
[79]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_ccs@crc-primary-basic-4-tiled-dg2-rc-ccs-cc.html
* igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs:
- shard-bmg: [PASS][80] -> [INCOMPLETE][81] ([Intel XE#7084] / [Intel XE#8150]) +1 other test incomplete
[80]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-10/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs.html
[81]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-4/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs.html
* igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-a-edp-1:
- shard-lnl: NOTRUN -> [SKIP][82] ([Intel XE#2669] / [Intel XE#3433] / [Intel XE#7389]) +3 other tests skip
[82]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-a-edp-1.html
* igt@kms_ccs@crc-primary-suspend-y-tiled-ccs:
- shard-bmg: NOTRUN -> [SKIP][83] ([Intel XE#3432])
[83]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_ccs@crc-primary-suspend-y-tiled-ccs.html
* igt@kms_ccs@random-ccs-data-4-tiled-mtl-mc-ccs:
- shard-lnl: NOTRUN -> [SKIP][84] ([Intel XE#2887]) +2 other tests skip
[84]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@kms_ccs@random-ccs-data-4-tiled-mtl-mc-ccs.html
* igt@kms_chamelium_color@ctm-negative:
- shard-lnl: NOTRUN -> [SKIP][85] ([Intel XE#306] / [Intel XE#7358])
[85]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_chamelium_color@ctm-negative.html
* igt@kms_chamelium_color@ctm-red-to-blue:
- shard-bmg: NOTRUN -> [SKIP][86] ([Intel XE#2325] / [Intel XE#7358])
[86]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_chamelium_color@ctm-red-to-blue.html
* igt@kms_chamelium_color_pipeline@plane-lut1d-ctm3x4:
- shard-ptl: NOTRUN -> [SKIP][87] ([Intel XE#8391])
[87]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_chamelium_color_pipeline@plane-lut1d-ctm3x4.html
- shard-bmg: NOTRUN -> [SKIP][88] ([Intel XE#7358])
[88]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_chamelium_color_pipeline@plane-lut1d-ctm3x4.html
* igt@kms_chamelium_frames@hdmi-crc-nonplanar-formats:
- shard-ptl: NOTRUN -> [SKIP][89] ([Intel XE#2252]) +1 other test skip
[89]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_chamelium_frames@hdmi-crc-nonplanar-formats.html
* igt@kms_chamelium_frames@hdmi-frame-dump:
- shard-bmg: NOTRUN -> [SKIP][90] ([Intel XE#2252]) +2 other tests skip
[90]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_chamelium_frames@hdmi-frame-dump.html
* igt@kms_chamelium_hpd@dp-hpd-enable-disable-mode:
- shard-lnl: NOTRUN -> [SKIP][91] ([Intel XE#373])
[91]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@kms_chamelium_hpd@dp-hpd-enable-disable-mode.html
* igt@kms_content_protection@atomic-dpms-hdcp14:
- shard-ptl: NOTRUN -> [SKIP][92] ([Intel XE#7642])
[92]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_content_protection@atomic-dpms-hdcp14.html
* igt@kms_content_protection@atomic-dpms-hdcp14@pipe-a-dp-2:
- shard-bmg: NOTRUN -> [FAIL][93] ([Intel XE#3304] / [Intel XE#7374]) +1 other test fail
[93]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_content_protection@atomic-dpms-hdcp14@pipe-a-dp-2.html
* igt@kms_content_protection@dp-mst-type-1:
- shard-lnl: NOTRUN -> [SKIP][94] ([Intel XE#307] / [Intel XE#6974])
[94]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@kms_content_protection@dp-mst-type-1.html
* igt@kms_content_protection@lic-type-0-hdcp14@pipe-a-dp-1:
- shard-bmg: NOTRUN -> [FAIL][95] ([Intel XE#3304])
[95]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-7/igt@kms_content_protection@lic-type-0-hdcp14@pipe-a-dp-1.html
* igt@kms_content_protection@lic-type-1:
- shard-bmg: NOTRUN -> [SKIP][96] ([Intel XE#7642])
[96]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_content_protection@lic-type-1.html
* igt@kms_cursor_crc@cursor-onscreen-32x10:
- shard-bmg: NOTRUN -> [SKIP][97] ([Intel XE#2320]) +2 other tests skip
[97]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_cursor_crc@cursor-onscreen-32x10.html
* igt@kms_cursor_crc@cursor-random-32x10:
- shard-ptl: NOTRUN -> [SKIP][98] ([Intel XE#5900]) +1 other test skip
[98]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_cursor_crc@cursor-random-32x10.html
* igt@kms_cursor_crc@cursor-sliding-max-size:
- shard-lnl: NOTRUN -> [SKIP][99] ([Intel XE#1424]) +1 other test skip
[99]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_cursor_crc@cursor-sliding-max-size.html
* igt@kms_cursor_legacy@cursora-vs-flipb-atomic-transitions:
- shard-lnl: NOTRUN -> [SKIP][100] ([Intel XE#309] / [Intel XE#7343])
[100]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@kms_cursor_legacy@cursora-vs-flipb-atomic-transitions.html
* igt@kms_cursor_legacy@cursorb-vs-flipb-varying-size:
- shard-ptl: NOTRUN -> [SKIP][101] ([Intel XE#5962] / [Intel XE#7343])
[101]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_cursor_legacy@cursorb-vs-flipb-varying-size.html
* igt@kms_cursor_legacy@short-busy-flip-before-cursor-atomic-transitions-varying-size:
- shard-ptl: NOTRUN -> [SKIP][102] ([Intel XE#6035])
[102]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_cursor_legacy@short-busy-flip-before-cursor-atomic-transitions-varying-size.html
- shard-bmg: NOTRUN -> [SKIP][103] ([Intel XE#2286] / [Intel XE#6035])
[103]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_cursor_legacy@short-busy-flip-before-cursor-atomic-transitions-varying-size.html
* igt@kms_dp_link_training@non-uhbr-sst:
- shard-lnl: NOTRUN -> [SKIP][104] ([Intel XE#9530])
[104]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@kms_dp_link_training@non-uhbr-sst.html
* igt@kms_dsc@dsc-fractional-bpp:
- shard-ptl: NOTRUN -> [SKIP][105] ([Intel XE#5907]) +1 other test skip
[105]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_dsc@dsc-fractional-bpp.html
* igt@kms_dsc@dsc-with-output-formats-with-bpc-ultrajoiner:
- shard-bmg: NOTRUN -> [SKIP][106] ([Intel XE#8265]) +3 other tests skip
[106]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_dsc@dsc-with-output-formats-with-bpc-ultrajoiner.html
* igt@kms_feature_discovery@display-2x:
- shard-lnl: NOTRUN -> [SKIP][107] ([Intel XE#702] / [Intel XE#7344])
[107]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@kms_feature_discovery@display-2x.html
* igt@kms_flip@2x-flip-vs-absolute-wf_vblank@ac-dp1-hdmi-a3:
- shard-bmg: [PASS][108] -> [FAIL][109] ([Intel XE#3098]) +1 other test fail
[108]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-7/igt@kms_flip@2x-flip-vs-absolute-wf_vblank@ac-dp1-hdmi-a3.html
[109]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-7/igt@kms_flip@2x-flip-vs-absolute-wf_vblank@ac-dp1-hdmi-a3.html
* igt@kms_flip@2x-flip-vs-blocking-wf-vblank@cd-dp2-hdmi-a3:
- shard-bmg: NOTRUN -> [DMESG-WARN][110] ([Intel XE#9613]) +1 other test dmesg-warn
[110]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_flip@2x-flip-vs-blocking-wf-vblank@cd-dp2-hdmi-a3.html
* igt@kms_flip@2x-wf_vblank-ts-check-interruptible:
- shard-ptl: NOTRUN -> [SKIP][111] ([Intel XE#2316]) +1 other test skip
[111]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_flip@2x-wf_vblank-ts-check-interruptible.html
* igt@kms_flip@flip-vs-expired-vblank@a-edp1:
- shard-lnl: [PASS][112] -> [FAIL][113] ([Intel XE#301]) +1 other test fail
[112]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-lnl-4/igt@kms_flip@flip-vs-expired-vblank@a-edp1.html
[113]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-7/igt@kms_flip@flip-vs-expired-vblank@a-edp1.html
* igt@kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-upscaling:
- shard-ptl: NOTRUN -> [SKIP][114] ([Intel XE#7178])
[114]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_flip_scaled_crc@flip-32bpp-xtile-to-64bpp-xtile-upscaling.html
* igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-16bpp-4tile-downscaling:
- shard-ptl: NOTRUN -> [SKIP][115] ([Intel XE#5828]) +1 other test skip
[115]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-16bpp-4tile-downscaling.html
* igt@kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-downscaling:
- shard-lnl: NOTRUN -> [SKIP][116] ([Intel XE#7178] / [Intel XE#7351])
[116]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-downscaling.html
* igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling:
- shard-bmg: NOTRUN -> [SKIP][117] ([Intel XE#7178] / [Intel XE#7351]) +1 other test skip
[117]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-16bpp-ytile-upscaling.html
* igt@kms_frontbuffer_tracking@drrshdr-2p-primscrn-cur-indfb-draw-render:
- shard-bmg: NOTRUN -> [SKIP][118] ([Intel XE#2311]) +24 other tests skip
[118]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_frontbuffer_tracking@drrshdr-2p-primscrn-cur-indfb-draw-render.html
* igt@kms_frontbuffer_tracking@drrshdr-rgb565-draw-blt:
- shard-lnl: NOTRUN -> [SKIP][119] ([Intel XE#6312])
[119]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_frontbuffer_tracking@drrshdr-rgb565-draw-blt.html
* igt@kms_frontbuffer_tracking@fbc-1p-offscreen-pri-shrfb-draw-blt:
- shard-bmg: NOTRUN -> [SKIP][120] ([Intel XE#4141]) +6 other tests skip
[120]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_frontbuffer_tracking@fbc-1p-offscreen-pri-shrfb-draw-blt.html
* igt@kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-cur-indfb-draw-blt:
- shard-lnl: NOTRUN -> [SKIP][121] ([Intel XE#6312] / [Intel XE#651]) +2 other tests skip
[121]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-cur-indfb-draw-blt.html
* igt@kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-shrfb-pgflip-blt:
- shard-lnl: NOTRUN -> [SKIP][122] ([Intel XE#656] / [Intel XE#7905]) +12 other tests skip
[122]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_frontbuffer_tracking@fbcdrrs-2p-scndscrn-shrfb-pgflip-blt.html
* igt@kms_frontbuffer_tracking@fbcdrrs-abgr161616f-draw-render:
- shard-bmg: NOTRUN -> [SKIP][123] ([Intel XE#7061] / [Intel XE#7356]) +4 other tests skip
[123]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_frontbuffer_tracking@fbcdrrs-abgr161616f-draw-render.html
* igt@kms_frontbuffer_tracking@fbcdrrs-tiling-4:
- shard-ptl: NOTRUN -> [SKIP][124] ([Intel XE#5800] / [Intel XE#6312]) +2 other tests skip
[124]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_frontbuffer_tracking@fbcdrrs-tiling-4.html
* igt@kms_frontbuffer_tracking@fbcdrrshdr-1p-offscreen-pri-indfb-draw-blt:
- shard-ptl: NOTRUN -> [SKIP][125] ([Intel XE#6312]) +3 other tests skip
[125]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_frontbuffer_tracking@fbcdrrshdr-1p-offscreen-pri-indfb-draw-blt.html
* igt@kms_frontbuffer_tracking@fbchdr-2p-scndscrn-pri-indfb-draw-blt:
- shard-lnl: NOTRUN -> [SKIP][126] ([Intel XE#7905]) +8 other tests skip
[126]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@kms_frontbuffer_tracking@fbchdr-2p-scndscrn-pri-indfb-draw-blt.html
* igt@kms_frontbuffer_tracking@fbcpsrhdr-modesetfrombusy:
- shard-ptl: NOTRUN -> [SKIP][127] ([Intel XE#7865]) +4 other tests skip
[127]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_frontbuffer_tracking@fbcpsrhdr-modesetfrombusy.html
* igt@kms_frontbuffer_tracking@hdr-1p-primscrn-spr-indfb-onoff:
- shard-lnl: NOTRUN -> [SKIP][128] ([Intel XE#7865]) +6 other tests skip
[128]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@kms_frontbuffer_tracking@hdr-1p-primscrn-spr-indfb-onoff.html
* igt@kms_frontbuffer_tracking@hdr-2p-primscrn-pri-shrfb-draw-mmap-wc:
- shard-bmg: [PASS][129] -> [SKIP][130] ([Intel XE#7865]) +5 other tests skip
[129]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-2/igt@kms_frontbuffer_tracking@hdr-2p-primscrn-pri-shrfb-draw-mmap-wc.html
[130]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_frontbuffer_tracking@hdr-2p-primscrn-pri-shrfb-draw-mmap-wc.html
* igt@kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-mmap-wc:
- shard-ptl: NOTRUN -> [SKIP][131] ([Intel XE#5812]) +16 other tests skip
[131]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_frontbuffer_tracking@psr-2p-primscrn-pri-shrfb-draw-mmap-wc.html
* igt@kms_frontbuffer_tracking@psr-abgr161616f-draw-blt:
- shard-lnl: NOTRUN -> [SKIP][132] ([Intel XE#7061] / [Intel XE#7356])
[132]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_frontbuffer_tracking@psr-abgr161616f-draw-blt.html
* igt@kms_frontbuffer_tracking@psr-abgr161616f-draw-render:
- shard-ptl: NOTRUN -> [SKIP][133] ([Intel XE#7061] / [Intel XE#7356]) +1 other test skip
[133]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_frontbuffer_tracking@psr-abgr161616f-draw-render.html
* igt@kms_frontbuffer_tracking@psrhdr-2p-scndscrn-pri-indfb-draw-mmap-wc:
- shard-bmg: NOTRUN -> [SKIP][134] ([Intel XE#2313]) +24 other tests skip
[134]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_frontbuffer_tracking@psrhdr-2p-scndscrn-pri-indfb-draw-mmap-wc.html
* igt@kms_frontbuffer_tracking@psrhdr-argb161616f-draw-mmap-wc:
- shard-bmg: NOTRUN -> [SKIP][135] ([Intel XE#7061])
[135]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_frontbuffer_tracking@psrhdr-argb161616f-draw-mmap-wc.html
- shard-ptl: NOTRUN -> [SKIP][136] ([Intel XE#7061])
[136]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_frontbuffer_tracking@psrhdr-argb161616f-draw-mmap-wc.html
* igt@kms_hdmi_audio_bw@audio-bw-hblank80:
- shard-ptl: NOTRUN -> [SKIP][137] ([Intel XE#9312])
[137]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_hdmi_audio_bw@audio-bw-hblank80.html
- shard-bmg: NOTRUN -> [FAIL][138] ([Intel XE#9313])
[138]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_hdmi_audio_bw@audio-bw-hblank80.html
* igt@kms_joiner@basic-force-ultra-joiner:
- shard-lnl: NOTRUN -> [SKIP][139] ([Intel XE#6900] / [Intel XE#7362])
[139]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_joiner@basic-force-ultra-joiner.html
* igt@kms_joiner@invalid-modeset-ultra-joiner:
- shard-bmg: NOTRUN -> [SKIP][140] ([Intel XE#6911] / [Intel XE#7378])
[140]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_joiner@invalid-modeset-ultra-joiner.html
* igt@kms_plane@pixel-format-4-tiled-bmg-ccs-modifier-source-clamping:
- shard-ptl: NOTRUN -> [SKIP][141] ([Intel XE#7283])
[141]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_plane@pixel-format-4-tiled-bmg-ccs-modifier-source-clamping.html
* igt@kms_plane@pixel-format-4-tiled-dg2-mc-ccs-modifier:
- shard-bmg: NOTRUN -> [SKIP][142] ([Intel XE#7283]) +1 other test skip
[142]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_plane@pixel-format-4-tiled-dg2-mc-ccs-modifier.html
* igt@kms_plane@pixel-format-4-tiled-modifier@pipe-a-plane-5:
- shard-bmg: NOTRUN -> [SKIP][143] ([Intel XE#8303]) +1 other test skip
[143]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_plane@pixel-format-4-tiled-modifier@pipe-a-plane-5.html
* igt@kms_plane_lowres@tiling-x@pipe-b-dp-2:
- shard-bmg: [PASS][144] -> [SKIP][145] ([Intel XE#7382]) +3 other tests skip
[144]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-2/igt@kms_plane_lowres@tiling-x@pipe-b-dp-2.html
[145]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_plane_lowres@tiling-x@pipe-b-dp-2.html
* igt@kms_plane_scaling@planes-upscale-factor-0-25-downscale-factor-0-5@pipe-c:
- shard-lnl: NOTRUN -> [SKIP][146] ([Intel XE#2763] / [Intel XE#6886]) +3 other tests skip
[146]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@kms_plane_scaling@planes-upscale-factor-0-25-downscale-factor-0-5@pipe-c.html
* igt@kms_pm_backlight@brightness-with-dpms:
- shard-bmg: NOTRUN -> [SKIP][147] ([Intel XE#2938] / [Intel XE#7376] / [Intel XE#7760])
[147]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_pm_backlight@brightness-with-dpms.html
* igt@kms_pm_rpm@modeset-non-lpsp:
- shard-lnl: NOTRUN -> [SKIP][148] ([Intel XE#1439] / [Intel XE#3141] / [Intel XE#7383])
[148]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@kms_pm_rpm@modeset-non-lpsp.html
* igt@kms_psr2_sf@fbc-pr-cursor-plane-move-continuous-exceed-sf:
- shard-bmg: NOTRUN -> [SKIP][149] ([Intel XE#1489]) +1 other test skip
[149]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_psr2_sf@fbc-pr-cursor-plane-move-continuous-exceed-sf.html
* igt@kms_psr@fbc-psr-primary-blt:
- shard-bmg: NOTRUN -> [SKIP][150] ([Intel XE#2234] / [Intel XE#2850]) +4 other tests skip
[150]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_psr@fbc-psr-primary-blt.html
* igt@kms_psr@fbc-psr2-basic:
- shard-lnl: NOTRUN -> [SKIP][151] ([Intel XE#1406] / [Intel XE#7345])
[151]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-4/igt@kms_psr@fbc-psr2-basic.html
* igt@kms_psr@fbc-psr2-basic@edp-1:
- shard-lnl: NOTRUN -> [SKIP][152] ([Intel XE#1406] / [Intel XE#4609] / [Intel XE#7345])
[152]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-4/igt@kms_psr@fbc-psr2-basic@edp-1.html
* igt@kms_psr@psr2-primary-render:
- shard-bmg: NOTRUN -> [SKIP][153] ([Intel XE#2234])
[153]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_psr@psr2-primary-render.html
* igt@kms_rotation_crc@primary-yf-tiled-reflect-x-90:
- shard-bmg: NOTRUN -> [SKIP][154] ([Intel XE#3904] / [Intel XE#7342])
[154]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_rotation_crc@primary-yf-tiled-reflect-x-90.html
* igt@kms_scaling_modes@scaling-mode-center:
- shard-bmg: NOTRUN -> [SKIP][155] ([Intel XE#2413])
[155]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_scaling_modes@scaling-mode-center.html
* igt@kms_setmode@invalid-clone-exclusive-crtc:
- shard-bmg: NOTRUN -> [SKIP][156] ([Intel XE#1435] / [Intel XE#8695])
[156]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_setmode@invalid-clone-exclusive-crtc.html
* igt@kms_setmode@invalid-clone-single-crtc:
- shard-ptl: NOTRUN -> [SKIP][157] ([Intel XE#5910]) +2 other tests skip
[157]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_setmode@invalid-clone-single-crtc.html
* igt@kms_sharpness_filter@filter-strength:
- shard-bmg: NOTRUN -> [SKIP][158] ([Intel XE#6503])
[158]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_sharpness_filter@filter-strength.html
* igt@kms_sharpness_filter@filter-suspend:
- shard-lnl: [PASS][159] -> [ABORT][160] ([Intel XE#9422]) +1 other test abort
[159]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-lnl-6/igt@kms_sharpness_filter@filter-suspend.html
[160]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-5/igt@kms_sharpness_filter@filter-suspend.html
* igt@kms_vblank@ts-continuation-dpms-suspend:
- shard-bmg: [PASS][161] -> [DMESG-WARN][162] ([Intel XE#9365] / [Intel XE#9465])
[161]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-9/igt@kms_vblank@ts-continuation-dpms-suspend.html
[162]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-2/igt@kms_vblank@ts-continuation-dpms-suspend.html
* igt@kms_vrr@cmrr-desktop-mode:
- shard-bmg: NOTRUN -> [SKIP][163] ([Intel XE#9271])
[163]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_vrr@cmrr-desktop-mode.html
* igt@kms_vrr@flip-basic-fastset:
- shard-ptl: [PASS][164] -> [FAIL][165] ([Intel XE#4227] / [Intel XE#7397])
[164]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-ptl-1/igt@kms_vrr@flip-basic-fastset.html
[165]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-7/igt@kms_vrr@flip-basic-fastset.html
* igt@kms_vrr@flip-basic-fastset@pipe-a-edp-1:
- shard-ptl: [PASS][166] -> [FAIL][167] ([Intel XE#6293] / [Intel XE#7397])
[166]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-ptl-1/igt@kms_vrr@flip-basic-fastset@pipe-a-edp-1.html
[167]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-7/igt@kms_vrr@flip-basic-fastset@pipe-a-edp-1.html
* igt@kms_vrr@seamless-rr-switch-vrr:
- shard-bmg: NOTRUN -> [SKIP][168] ([Intel XE#1499] / [Intel XE#9271])
[168]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@kms_vrr@seamless-rr-switch-vrr.html
- shard-ptl: NOTRUN -> [SKIP][169] ([Intel XE#5948] / [Intel XE#9277])
[169]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_vrr@seamless-rr-switch-vrr.html
* igt@xe_compute@ccs-mode-compute-kernel:
- shard-lnl: NOTRUN -> [SKIP][170] ([Intel XE#1447] / [Intel XE#7469])
[170]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@xe_compute@ccs-mode-compute-kernel.html
* igt@xe_evict@evict-beng-mixed-many-threads-small:
- shard-bmg: [PASS][171] -> [INCOMPLETE][172] ([Intel XE#6321] / [Intel XE#8355])
[171]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-4/igt@xe_evict@evict-beng-mixed-many-threads-small.html
[172]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-4/igt@xe_evict@evict-beng-mixed-many-threads-small.html
* igt@xe_evict@evict-beng-mixed-threads-large:
- shard-ptl: NOTRUN -> [SKIP][173] ([Intel XE#5764]) +1 other test skip
[173]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_evict@evict-beng-mixed-threads-large.html
* igt@xe_evict@evict-mixed-threads-small-multi-queue:
- shard-bmg: NOTRUN -> [SKIP][174] ([Intel XE#8370])
[174]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_evict@evict-mixed-threads-small-multi-queue.html
* igt@xe_evict@evict-threads-small-multi-vm:
- shard-lnl: NOTRUN -> [SKIP][175] ([Intel XE#6540] / [Intel XE#688]) +4 other tests skip
[175]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@xe_evict@evict-threads-small-multi-vm.html
* igt@xe_exec_balancer@no-exec-parallel-userptr-invalidate-race:
- shard-ptl: NOTRUN -> [SKIP][176] ([Intel XE#7482]) +1 other test skip
[176]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_exec_balancer@no-exec-parallel-userptr-invalidate-race.html
* igt@xe_exec_balancer@once-cm-parallel-userptr-invalidate-race:
- shard-lnl: NOTRUN -> [SKIP][177] ([Intel XE#7482])
[177]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@xe_exec_balancer@once-cm-parallel-userptr-invalidate-race.html
* igt@xe_exec_basic@multigpu-many-execqueues-many-vm-null:
- shard-bmg: NOTRUN -> [SKIP][178] ([Intel XE#2322] / [Intel XE#7372]) +3 other tests skip
[178]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_exec_basic@multigpu-many-execqueues-many-vm-null.html
* igt@xe_exec_basic@multigpu-no-exec-bindexecqueue-rebind:
- shard-lnl: NOTRUN -> [SKIP][179] ([Intel XE#1392]) +1 other test skip
[179]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@xe_exec_basic@multigpu-no-exec-bindexecqueue-rebind.html
* igt@xe_exec_basic@multigpu-once-userptr-invalidate-race:
- shard-ptl: NOTRUN -> [SKIP][180] ([Intel XE#5575] / [Intel XE#7484]) +1 other test skip
[180]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_exec_basic@multigpu-once-userptr-invalidate-race.html
* igt@xe_exec_fault_mode@atomic-many:
- shard-bmg: NOTRUN -> [FAIL][181] ([Intel XE#8578])
[181]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_exec_fault_mode@atomic-many.html
* igt@xe_exec_fault_mode@many-execqueues-multi-queue-rebind-prefetch:
- shard-bmg: NOTRUN -> [SKIP][182] ([Intel XE#8374]) +3 other tests skip
[182]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@xe_exec_fault_mode@many-execqueues-multi-queue-rebind-prefetch.html
- shard-ptl: NOTRUN -> [SKIP][183] ([Intel XE#8374]) +1 other test skip
[183]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_exec_fault_mode@many-execqueues-multi-queue-rebind-prefetch.html
* igt@xe_exec_multi_queue@many-queues-preempt-mode-basic-smem:
- shard-lnl: NOTRUN -> [SKIP][184] ([Intel XE#8364]) +5 other tests skip
[184]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@xe_exec_multi_queue@many-queues-preempt-mode-basic-smem.html
* igt@xe_exec_multi_queue@many-queues-preempt-mode-fault-priority:
- shard-ptl: NOTRUN -> [SKIP][185] ([Intel XE#8364]) +5 other tests skip
[185]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_exec_multi_queue@many-queues-preempt-mode-fault-priority.html
* igt@xe_exec_multi_queue@two-queues-basic-smem:
- shard-bmg: NOTRUN -> [SKIP][186] ([Intel XE#8364]) +12 other tests skip
[186]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@xe_exec_multi_queue@two-queues-basic-smem.html
* igt@xe_exec_reset@multi-queue-long-spin-many-queue-switch:
- shard-ptl: NOTRUN -> [SKIP][187] ([Intel XE#8369])
[187]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_exec_reset@multi-queue-long-spin-many-queue-switch.html
- shard-bmg: NOTRUN -> [SKIP][188] ([Intel XE#8369])
[188]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@xe_exec_reset@multi-queue-long-spin-many-queue-switch.html
* igt@xe_exec_threads@threads-multi-queue-cm-shared-vm-basic:
- shard-ptl: NOTRUN -> [SKIP][189] ([Intel XE#8378]) +1 other test skip
[189]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_exec_threads@threads-multi-queue-cm-shared-vm-basic.html
* igt@xe_exec_threads@threads-multi-queue-fd-userptr-rebind:
- shard-bmg: NOTRUN -> [SKIP][190] ([Intel XE#8378]) +4 other tests skip
[190]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_exec_threads@threads-multi-queue-fd-userptr-rebind.html
* igt@xe_live_ktest@xe_bo@xe_bo_evict_kunit:
- shard-lnl: NOTRUN -> [SKIP][191] ([Intel XE#2229])
[191]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@xe_live_ktest@xe_bo@xe_bo_evict_kunit.html
* igt@xe_multigpu_svm@mgpu-latency-copy-basic:
- shard-bmg: NOTRUN -> [SKIP][192] ([Intel XE#6964]) +1 other test skip
[192]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@xe_multigpu_svm@mgpu-latency-copy-basic.html
- shard-ptl: NOTRUN -> [SKIP][193] ([Intel XE#6964])
[193]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_multigpu_svm@mgpu-latency-copy-basic.html
* igt@xe_multigpu_svm@mgpu-migration-prefetch:
- shard-lnl: NOTRUN -> [SKIP][194] ([Intel XE#6964])
[194]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-6/igt@xe_multigpu_svm@mgpu-migration-prefetch.html
* igt@xe_page_reclaim@binds-1g-partial:
- shard-bmg: NOTRUN -> [SKIP][195] ([Intel XE#7793])
[195]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@xe_page_reclaim@binds-1g-partial.html
- shard-ptl: NOTRUN -> [SKIP][196] ([Intel XE#7793])
[196]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_page_reclaim@binds-1g-partial.html
* igt@xe_pat@pat-sw-hw-suspend:
- shard-bmg: NOTRUN -> [FAIL][197] ([Intel XE#7695])
[197]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_pat@pat-sw-hw-suspend.html
* igt@xe_peer2peer@read:
- shard-bmg: NOTRUN -> [SKIP][198] ([Intel XE#2427] / [Intel XE#6953] / [Intel XE#7326] / [Intel XE#7353])
[198]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@xe_peer2peer@read.html
- shard-ptl: NOTRUN -> [SKIP][199] ([Intel XE#6588])
[199]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_peer2peer@read.html
* igt@xe_pm@s4-vm-bind-unbind-all:
- shard-lnl: [PASS][200] -> [ABORT][201] ([Intel XE#9362])
[200]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-lnl-7/igt@xe_pm@s4-vm-bind-unbind-all.html
[201]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@xe_pm@s4-vm-bind-unbind-all.html
* igt@xe_pm_residency@cpg-basic:
- shard-lnl: NOTRUN -> [SKIP][202] ([Intel XE#584] / [Intel XE#7369])
[202]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@xe_pm_residency@cpg-basic.html
* igt@xe_pxp@pxp-stale-queue-post-termination-irq:
- shard-bmg: NOTRUN -> [SKIP][203] ([Intel XE#4733] / [Intel XE#7417]) +1 other test skip
[203]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@xe_pxp@pxp-stale-queue-post-termination-irq.html
* igt@xe_query@multigpu-query-invalid-cs-cycles:
- shard-bmg: NOTRUN -> [SKIP][204] ([Intel XE#944]) +1 other test skip
[204]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@xe_query@multigpu-query-invalid-cs-cycles.html
- shard-ptl: NOTRUN -> [SKIP][205] ([Intel XE#6019])
[205]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_query@multigpu-query-invalid-cs-cycles.html
* igt@xe_vm@overcommit-nonfault-vram-lr-external-nodefer:
- shard-lnl: NOTRUN -> [SKIP][206] ([Intel XE#9597])
[206]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-4/igt@xe_vm@overcommit-nonfault-vram-lr-external-nodefer.html
#### Possible fixes ####
* igt@core_hotunplug@hotreplug-with-load:
- shard-bmg: [ABORT][207] ([Intel XE#9463]) -> [PASS][208]
[207]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-2/igt@core_hotunplug@hotreplug-with-load.html
[208]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-10/igt@core_hotunplug@hotreplug-with-load.html
* igt@kms_flip@flip-vs-suspend-interruptible:
- shard-bmg: [DMESG-WARN][209] ([Intel XE#9365]) -> [PASS][210] +1 other test pass
[209]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-7/igt@kms_flip@flip-vs-suspend-interruptible.html
[210]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-7/igt@kms_flip@flip-vs-suspend-interruptible.html
* igt@kms_plane_scaling@plane-downscale-factor-0-75-with-modifiers:
- shard-ptl: [DMESG-WARN][211] ([Intel XE#9513]) -> [PASS][212] +1 other test pass
[211]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-ptl-1/igt@kms_plane_scaling@plane-downscale-factor-0-75-with-modifiers.html
[212]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-8/igt@kms_plane_scaling@plane-downscale-factor-0-75-with-modifiers.html
* igt@kms_vrr@flip-dpms@pipe-a-edp-1:
- shard-ptl: [FAIL][213] ([Intel XE#4227] / [Intel XE#7397]) -> [PASS][214] +1 other test pass
[213]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-ptl-8/igt@kms_vrr@flip-dpms@pipe-a-edp-1.html
[214]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@kms_vrr@flip-dpms@pipe-a-edp-1.html
* igt@xe_ccs@suspend-resume:
- shard-bmg: [ABORT][215] ([Intel XE#9362] / [Intel XE#9581]) -> [PASS][216]
[215]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-10/igt@xe_ccs@suspend-resume.html
[216]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_ccs@suspend-resume.html
* igt@xe_ccs@suspend-resume@tile4-compressed-compfmt0-system-vram01:
- shard-bmg: [ABORT][217] ([Intel XE#9362]) -> [PASS][218]
[217]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-10/igt@xe_ccs@suspend-resume@tile4-compressed-compfmt0-system-vram01.html
[218]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@xe_ccs@suspend-resume@tile4-compressed-compfmt0-system-vram01.html
* igt@xe_evict@evict-mixed-many-threads-small:
- shard-bmg: [INCOMPLETE][219] ([Intel XE#6321] / [Intel XE#8355]) -> [PASS][220]
[219]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-4/igt@xe_evict@evict-mixed-many-threads-small.html
[220]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-4/igt@xe_evict@evict-mixed-many-threads-small.html
* igt@xe_exec_threads@threads-hang-fd-userptr-invalidate-race:
- shard-ptl: [FAIL][221] ([Intel XE#9096]) -> [PASS][222]
[221]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-ptl-3/igt@xe_exec_threads@threads-hang-fd-userptr-invalidate-race.html
[222]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-5/igt@xe_exec_threads@threads-hang-fd-userptr-invalidate-race.html
* igt@xe_pm@s4-basic:
- shard-ptl: [DMESG-WARN][223] ([Intel XE#7727]) -> [PASS][224]
[223]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-ptl-6/igt@xe_pm@s4-basic.html
[224]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-5/igt@xe_pm@s4-basic.html
* igt@xe_pm@s4-basic-exec:
- shard-lnl: [ABORT][225] ([Intel XE#9362]) -> [PASS][226] +1 other test pass
[225]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-lnl-6/igt@xe_pm@s4-basic-exec.html
[226]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-1/igt@xe_pm@s4-basic-exec.html
* igt@xe_pm@s4-vm-bind-userptr:
- shard-ptl: [ABORT][227] ([Intel XE#9362]) -> [PASS][228]
[227]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-ptl-4/igt@xe_pm@s4-vm-bind-userptr.html
[228]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-ptl-3/igt@xe_pm@s4-vm-bind-userptr.html
#### Warnings ####
* igt@kms_content_protection@atomic-dpms:
- shard-bmg: [FAIL][229] ([Intel XE#1178] / [Intel XE#3304] / [Intel XE#7374]) -> [INCOMPLETE][230] ([Intel XE#8479] / [Intel XE#9550])
[229]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-bmg-2/igt@kms_content_protection@atomic-dpms.html
[230]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-bmg-6/igt@kms_content_protection@atomic-dpms.html
* igt@kms_cursor_legacy@cursorb-vs-flipb-atomic-transitions:
- shard-lnl: [SKIP][231] ([Intel XE#309] / [Intel XE#7343]) -> [SKIP][232] ([Intel XE#309] / [Intel XE#7343] / [Intel XE#7935])
[231]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-lnl-4/igt@kms_cursor_legacy@cursorb-vs-flipb-atomic-transitions.html
[232]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-8/igt@kms_cursor_legacy@cursorb-vs-flipb-atomic-transitions.html
* igt@xe_pm@s4-mocs:
- shard-lnl: [ABORT][233] ([Intel XE#9362]) -> [DMESG-WARN][234] ([Intel XE#7727])
[233]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5986-f3bbda7128124e54c4881b56958249a18d79a110/shard-lnl-1/igt@xe_pm@s4-mocs.html
[234]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/shard-lnl-4/igt@xe_pm@s4-mocs.html
[Intel XE#1124]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1124
[Intel XE#1178]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1178
[Intel XE#1392]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1392
[Intel XE#1406]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1406
[Intel XE#1407]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1407
[Intel XE#1424]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1424
[Intel XE#1435]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1435
[Intel XE#1439]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1439
[Intel XE#1447]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1447
[Intel XE#1489]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1489
[Intel XE#1499]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1499
[Intel XE#2229]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2229
[Intel XE#2234]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2234
[Intel XE#2252]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2252
[Intel XE#2286]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2286
[Intel XE#2311]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2311
[Intel XE#2313]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2313
[Intel XE#2316]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2316
[Intel XE#2320]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2320
[Intel XE#2322]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2322
[Intel XE#2325]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2325
[Intel XE#2327]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2327
[Intel XE#2413]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2413
[Intel XE#2427]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2427
[Intel XE#2457]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2457
[Intel XE#2669]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2669
[Intel XE#2763]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2763
[Intel XE#2850]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2850
[Intel XE#2887]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2887
[Intel XE#2938]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2938
[Intel XE#301]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/301
[Intel XE#306]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/306
[Intel XE#307]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/307
[Intel XE#309]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/309
[Intel XE#3098]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3098
[Intel XE#3141]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3141
[Intel XE#3304]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3304
[Intel XE#3432]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3432
[Intel XE#3433]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3433
[Intel XE#367]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/367
[Intel XE#3718]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3718
[Intel XE#373]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/373
[Intel XE#3904]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3904
[Intel XE#4141]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4141
[Intel XE#4227]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4227
[Intel XE#4609]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4609
[Intel XE#4733]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4733
[Intel XE#5575]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5575
[Intel XE#5764]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5764
[Intel XE#5800]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5800
[Intel XE#5808]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5808
[Intel XE#5812]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5812
[Intel XE#5822]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5822
[Intel XE#5828]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5828
[Intel XE#584]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/584
[Intel XE#5900]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5900
[Intel XE#5907]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5907
[Intel XE#5910]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5910
[Intel XE#5948]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5948
[Intel XE#5962]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5962
[Intel XE#6011]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6011
[Intel XE#6019]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6019
[Intel XE#6035]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6035
[Intel XE#6078]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6078
[Intel XE#6293]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6293
[Intel XE#6312]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6312
[Intel XE#6321]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6321
[Intel XE#6503]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6503
[Intel XE#651]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/651
[Intel XE#6540]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6540
[Intel XE#656]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/656
[Intel XE#6588]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6588
[Intel XE#688]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/688
[Intel XE#6886]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6886
[Intel XE#6900]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6900
[Intel XE#6911]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6911
[Intel XE#6953]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6953
[Intel XE#6964]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6964
[Intel XE#6974]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6974
[Intel XE#702]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/702
[Intel XE#7059]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7059
[Intel XE#7061]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7061
[Intel XE#7084]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7084
[Intel XE#7085]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7085
[Intel XE#7178]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7178
[Intel XE#7283]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7283
[Intel XE#7326]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7326
[Intel XE#7342]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7342
[Intel XE#7343]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7343
[Intel XE#7344]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7344
[Intel XE#7345]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7345
[Intel XE#7351]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7351
[Intel XE#7353]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7353
[Intel XE#7356]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7356
[Intel XE#7358]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7358
[Intel XE#7362]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7362
[Intel XE#7369]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7369
[Intel XE#7372]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7372
[Intel XE#7374]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7374
[Intel XE#7376]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7376
[Intel XE#7378]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7378
[Intel XE#7382]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7382
[Intel XE#7383]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7383
[Intel XE#7389]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7389
[Intel XE#7397]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7397
[Intel XE#7405]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7405
[Intel XE#7417]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7417
[Intel XE#7469]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7469
[Intel XE#7482]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7482
[Intel XE#7484]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7484
[Intel XE#7642]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7642
[Intel XE#7695]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7695
[Intel XE#7727]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7727
[Intel XE#7760]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7760
[Intel XE#7793]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7793
[Intel XE#7865]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7865
[Intel XE#7905]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7905
[Intel XE#7935]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7935
[Intel XE#8150]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8150
[Intel XE#8265]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8265
[Intel XE#8303]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8303
[Intel XE#8355]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8355
[Intel XE#8364]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8364
[Intel XE#8365]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8365
[Intel XE#8369]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8369
[Intel XE#8370]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8370
[Intel XE#8374]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8374
[Intel XE#8378]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8378
[Intel XE#8391]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8391
[Intel XE#8479]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8479
[Intel XE#8578]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8578
[Intel XE#8695]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8695
[Intel XE#9096]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9096
[Intel XE#9271]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9271
[Intel XE#9277]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9277
[Intel XE#9312]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9312
[Intel XE#9313]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9313
[Intel XE#9362]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9362
[Intel XE#9365]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9365
[Intel XE#9375]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9375
[Intel XE#9405]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9405
[Intel XE#9422]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9422
[Intel XE#944]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/944
[Intel XE#9463]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9463
[Intel XE#9465]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9465
[Intel XE#9513]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9513
[Intel XE#9530]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9530
[Intel XE#9550]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9550
[Intel XE#9581]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9581
[Intel XE#9597]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9597
[Intel XE#9613]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9613
Build changes
-------------
* Linux: xe-5986-f3bbda7128124e54c4881b56958249a18d79a110 -> xe-pw-165953v8
IGT_9156: 9156
xe-5986-f3bbda7128124e54c4881b56958249a18d79a110: f3bbda7128124e54c4881b56958249a18d79a110
xe-pw-165953v8: 165953v8
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-165953v8/index.html
[-- Attachment #2: Type: text/html, Size: 74205 bytes --]
^ permalink raw reply [flat|nested] 33+ messages in thread